OCaml HTML5 parser/serialiser based on Python's JustHTML

Merge remote-tracking branch 'origin/imap-more'

+11707 -6232
+13
mail-flag/dune-project
···
··· 1 + (lang dune 3.0) 2 + (name mail-flag) 3 + (generate_opam_files true) 4 + 5 + (package 6 + (name mail-flag) 7 + (synopsis "Unified message flags and mailbox attributes for IMAP/JMAP") 8 + (description 9 + "Type-safe message keywords, system flags, and mailbox attributes for email protocols. Supports RFC 9051 (IMAP4rev2), RFC 8621 (JMAP Mail), RFC 6154 (Special-Use), and draft-ietf-mailmaint extensions.") 10 + (depends 11 + (ocaml (>= 5.0)) 12 + (fmt (>= 0.9)) 13 + (alcotest :with-test)))
+4
mail-flag/lib/dune
···
··· 1 + (library 2 + (name mail_flag) 3 + (public_name mail-flag) 4 + (libraries fmt))
+101
mail-flag/lib/flag_color.ml
···
··· 1 + (*--------------------------------------------------------------------------- 2 + Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 + 6 + (** Apple Mail flag colors. 7 + 8 + See {{:https://datatracker.ietf.org/doc/draft-ietf-mailmaint-messageflag-mailboxattribute#section-3} 9 + draft-ietf-mailmaint-messageflag-mailboxattribute Section 3}. 10 + 11 + The Apple Mail flag color encoding uses three keywords to represent 12 + colors as a 3-bit pattern: 13 + - [$MailFlagBit0]: bit 0 14 + - [$MailFlagBit1]: bit 1 15 + - [$MailFlagBit2]: bit 2 16 + 17 + Bit patterns (bit0, bit1, bit2): 18 + - Red: (false, false, false) = 000 19 + - Orange: (true, false, false) = 100 20 + - Yellow: (false, true, false) = 010 21 + - Green: (true, true, false) = 110 22 + - Blue: (false, false, true) = 001 23 + - Purple: (true, false, true) = 101 24 + - Gray: (false, true, true) = 011 25 + - 111: undefined *) 26 + 27 + type t = 28 + | Red (** Bit pattern: 000 *) 29 + | Orange (** Bit pattern: 100 *) 30 + | Yellow (** Bit pattern: 010 *) 31 + | Green (** Bit pattern: 110 *) 32 + | Blue (** Bit pattern: 001 *) 33 + | Purple (** Bit pattern: 101 *) 34 + | Gray (** Bit pattern: 011 *) 35 + 36 + let to_bits = function 37 + | Red -> (false, false, false) (* 000 *) 38 + | Orange -> (true, false, false) (* 100 *) 39 + | Yellow -> (false, true, false) (* 010 *) 40 + | Green -> (true, true, false) (* 110 *) 41 + | Blue -> (false, false, true) (* 001 *) 42 + | Purple -> (true, false, true) (* 101 *) 43 + | Gray -> (false, true, true) (* 011 *) 44 + 45 + let of_bits = function 46 + | (false, false, false) -> Some Red (* 000 *) 47 + | (true, false, false) -> Some Orange (* 100 *) 48 + | (false, true, false) -> Some Yellow (* 010 *) 49 + | (true, true, false) -> Some Green (* 110 *) 50 + | (false, false, true) -> Some Blue (* 001 *) 51 + | (true, false, true) -> Some Purple (* 101 *) 52 + | (false, true, true) -> Some Gray (* 011 *) 53 + | (true, true, true) -> None (* 111 - undefined *) 54 + 55 + let to_keywords = function 56 + | Red -> [] 57 + | Orange -> [ `MailFlagBit0 ] 58 + | Yellow -> [ `MailFlagBit1 ] 59 + | Green -> [ `MailFlagBit0; `MailFlagBit1 ] 60 + | Blue -> [ `MailFlagBit2 ] 61 + | Purple -> [ `MailFlagBit0; `MailFlagBit2 ] 62 + | Gray -> [ `MailFlagBit1; `MailFlagBit2 ] 63 + 64 + let of_keywords (keywords : [ `MailFlagBit0 | `MailFlagBit1 | `MailFlagBit2 ] list) = 65 + let has k = List.exists (fun x -> x = k) keywords in 66 + let bit0 = has `MailFlagBit0 in 67 + let bit1 = has `MailFlagBit1 in 68 + let bit2 = has `MailFlagBit2 in 69 + (* If no bits are set, we cannot distinguish between "no flag color" 70 + and "Red" (which is 000). Return None to indicate ambiguity. *) 71 + if not bit0 && not bit1 && not bit2 then None 72 + else of_bits (bit0, bit1, bit2) 73 + 74 + let of_keywords_default_red (keywords : [ `MailFlagBit0 | `MailFlagBit1 | `MailFlagBit2 ] list) = 75 + let has k = List.exists (fun x -> x = k) keywords in 76 + let bit0 = has `MailFlagBit0 in 77 + let bit1 = has `MailFlagBit1 in 78 + let bit2 = has `MailFlagBit2 in 79 + of_bits (bit0, bit1, bit2) 80 + 81 + let to_string = function 82 + | Red -> "red" 83 + | Orange -> "orange" 84 + | Yellow -> "yellow" 85 + | Green -> "green" 86 + | Blue -> "blue" 87 + | Purple -> "purple" 88 + | Gray -> "gray" 89 + 90 + let of_string s = 91 + match String.lowercase_ascii s with 92 + | "red" -> Some Red 93 + | "orange" -> Some Orange 94 + | "yellow" -> Some Yellow 95 + | "green" -> Some Green 96 + | "blue" -> Some Blue 97 + | "purple" -> Some Purple 98 + | "gray" | "grey" -> Some Gray 99 + | _ -> None 100 + 101 + let pp ppf color = Format.pp_print_string ppf (to_string color)
+72
mail-flag/lib/flag_color.mli
···
··· 1 + (*--------------------------------------------------------------------------- 2 + Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 + 6 + (** Apple Mail flag colors. 7 + 8 + This module implements the Apple Mail flag color encoding using the 9 + [$MailFlagBit0], [$MailFlagBit1], and [$MailFlagBit2] keywords. 10 + 11 + See {{:https://datatracker.ietf.org/doc/draft-ietf-mailmaint-messageflag-mailboxattribute#section-3} 12 + draft-ietf-mailmaint-messageflag-mailboxattribute Section 3}. 13 + 14 + Colors are encoded as a 3-bit pattern where each bit corresponds to 15 + a keyword: 16 + - Bit 0: [$MailFlagBit0] 17 + - Bit 1: [$MailFlagBit1] 18 + - Bit 2: [$MailFlagBit2] 19 + 20 + The bit patterns are: 21 + - Red: 000 (no bits set) 22 + - Orange: 100 (bit 0 only) 23 + - Yellow: 010 (bit 1 only) 24 + - Green: 110 (bits 0 and 1) 25 + - Blue: 001 (bit 2 only) 26 + - Purple: 101 (bits 0 and 2) 27 + - Gray: 011 (bits 1 and 2) 28 + - 111: undefined (all bits set) *) 29 + 30 + type t = 31 + | Red (** Bit pattern: 000 *) 32 + | Orange (** Bit pattern: 100 *) 33 + | Yellow (** Bit pattern: 010 *) 34 + | Green (** Bit pattern: 110 *) 35 + | Blue (** Bit pattern: 001 *) 36 + | Purple (** Bit pattern: 101 *) 37 + | Gray (** Bit pattern: 011 *) 38 + 39 + val to_bits : t -> bool * bool * bool 40 + (** [to_bits color] converts [color] to a [(bit0, bit1, bit2)] tuple 41 + representing which [$MailFlagBit*] keywords should be set. 42 + 43 + Example: [to_bits Green] returns [(true, true, false)]. *) 44 + 45 + val of_bits : bool * bool * bool -> t option 46 + (** [of_bits (bit0, bit1, bit2)] converts a bit pattern to a color. 47 + Returns [None] for the undefined pattern [(true, true, true)] (111). *) 48 + 49 + val to_keywords : t -> [ `MailFlagBit0 | `MailFlagBit1 | `MailFlagBit2 ] list 50 + (** [to_keywords color] returns the list of keyword bits that should be 51 + set for [color]. Red returns an empty list since no bits are needed. *) 52 + 53 + val of_keywords : [ `MailFlagBit0 | `MailFlagBit1 | `MailFlagBit2 ] list -> t option 54 + (** [of_keywords keywords] extracts a color from a list of keyword bits. 55 + Returns [None] if the pattern is 111 (undefined) or if no bits are 56 + present in the list (which would indicate no flag color is set, 57 + rather than Red). Use {!of_keywords_default_red} if you want to 58 + treat an empty list as Red. *) 59 + 60 + val of_keywords_default_red : [ `MailFlagBit0 | `MailFlagBit1 | `MailFlagBit2 ] list -> t option 61 + (** [of_keywords_default_red keywords] is like {!of_keywords} but treats 62 + an empty keyword list as Red. Returns [None] only for pattern 111. *) 63 + 64 + val pp : Format.formatter -> t -> unit 65 + (** [pp ppf color] pretty-prints the color name to [ppf]. *) 66 + 67 + val to_string : t -> string 68 + (** [to_string color] returns the lowercase color name. *) 69 + 70 + val of_string : string -> t option 71 + (** [of_string s] parses a color name (case-insensitive). 72 + Returns [None] if [s] is not a valid color name. *)
+70
mail-flag/lib/imap_wire.ml
···
··· 1 + (*--------------------------------------------------------------------------- 2 + Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 + 6 + (** IMAP Wire Format Conversion 7 + 8 + Implementation of IMAP wire format conversion for message flags and 9 + mailbox attributes. See {{:https://datatracker.ietf.org/doc/html/rfc9051#section-2.3.2}RFC 9051 Section 2.3.2}. *) 10 + 11 + type flag = 12 + | System of [ `Seen | `Answered | `Flagged | `Deleted | `Draft ] 13 + | Keyword of Keyword.t 14 + 15 + (** Check if a string represents an IMAP system flag. 16 + Returns the system flag variant if recognized, None otherwise. *) 17 + let parse_system_flag s = 18 + let s = String.lowercase_ascii s in 19 + (* Remove backslash prefix if present *) 20 + let s = if String.length s > 0 && s.[0] = '\\' then 21 + String.sub s 1 (String.length s - 1) 22 + else s 23 + in 24 + match s with 25 + | "seen" -> Some `Seen 26 + | "answered" -> Some `Answered 27 + | "flagged" -> Some `Flagged 28 + | "deleted" -> Some `Deleted 29 + | "draft" -> Some `Draft 30 + | _ -> None 31 + 32 + let flag_of_string s = 33 + match parse_system_flag s with 34 + | Some sys -> System sys 35 + | None -> Keyword (Keyword.of_string s) 36 + 37 + let flag_to_string = function 38 + | System `Seen -> "\\Seen" 39 + | System `Answered -> "\\Answered" 40 + | System `Flagged -> "\\Flagged" 41 + | System `Deleted -> "\\Deleted" 42 + | System `Draft -> "\\Draft" 43 + | Keyword k -> Keyword.to_imap_string k 44 + 45 + let flags_of_keywords keywords = 46 + List.map (fun k -> 47 + match k with 48 + | `Seen -> System `Seen 49 + | `Answered -> System `Answered 50 + | `Flagged -> System `Flagged 51 + | `Deleted -> System `Deleted 52 + | `Draft -> System `Draft 53 + | other -> Keyword other 54 + ) keywords 55 + 56 + let keywords_of_flags flags = 57 + List.map (fun flag -> 58 + match flag with 59 + | System `Seen -> `Seen 60 + | System `Answered -> `Answered 61 + | System `Flagged -> `Flagged 62 + | System `Deleted -> `Deleted 63 + | System `Draft -> `Draft 64 + | Keyword k -> k 65 + ) flags 66 + 67 + let attr_of_string = Mailbox_attr.of_string 68 + let attr_to_string = Mailbox_attr.to_string 69 + 70 + let pp_flag ppf flag = Fmt.string ppf (flag_to_string flag)
+106
mail-flag/lib/imap_wire.mli
···
··· 1 + (*--------------------------------------------------------------------------- 2 + Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 + 6 + (** IMAP Wire Format Conversion 7 + 8 + Converts between mail-flag types and IMAP protocol format. 9 + See {{:https://datatracker.ietf.org/doc/html/rfc9051#section-2.3.2}RFC 9051 Section 2.3.2} 10 + for the flag format specification. 11 + 12 + {2 IMAP Flag Format} 13 + 14 + IMAP uses two types of message flags: 15 + - {b System flags} prefixed with backslash: [\Seen], [\Answered], [\Flagged], [\Deleted], [\Draft] 16 + - {b Keywords} prefixed with dollar sign: [$Forwarded], [$Junk], etc. 17 + 18 + This module handles the conversion between the internal {!Keyword.t} representation 19 + and the IMAP wire format. *) 20 + 21 + (** {1 Message Flags} *) 22 + 23 + (** IMAP message flag - either system flag or keyword. 24 + 25 + System flags are the five flags defined in 26 + {{:https://datatracker.ietf.org/doc/html/rfc9051#section-2.3.2}RFC 9051 Section 2.3.2}: 27 + [\Seen], [\Answered], [\Flagged], [\Deleted], [\Draft]. 28 + 29 + Keywords are user-defined or server-defined flags that start with [$]. *) 30 + type flag = 31 + | System of [ `Seen | `Answered | `Flagged | `Deleted | `Draft ] 32 + | Keyword of Keyword.t 33 + 34 + val flag_of_string : string -> flag 35 + (** [flag_of_string s] parses an IMAP flag string. 36 + 37 + System flags are recognized with or without the backslash prefix, 38 + case-insensitively. Keywords are parsed using {!Keyword.of_string}. 39 + 40 + Examples: 41 + - ["\\Seen"] -> [System `Seen] 42 + - ["Seen"] -> [System `Seen] 43 + - ["$forwarded"] -> [Keyword `Forwarded] 44 + - ["$custom"] -> [Keyword (`Custom "custom")] *) 45 + 46 + val flag_to_string : flag -> string 47 + (** [flag_to_string flag] converts a flag to IMAP wire format. 48 + 49 + System flags are returned with backslash prefix. 50 + Keywords are returned with dollar sign prefix. 51 + 52 + Examples: 53 + - [System `Seen] -> ["\\Seen"] 54 + - [Keyword `Forwarded] -> ["$Forwarded"] *) 55 + 56 + val flags_of_keywords : Keyword.t list -> flag list 57 + (** [flags_of_keywords keywords] converts a list of keywords to IMAP flags. 58 + 59 + Keywords that correspond to IMAP system flags ([`Seen], [`Answered], 60 + [`Flagged], [`Deleted], [`Draft]) are converted to [System] flags. 61 + All other keywords remain as [Keyword] flags. 62 + 63 + Example: 64 + {[ 65 + flags_of_keywords [`Seen; `Forwarded; `Custom "label"] 66 + (* returns [System `Seen; Keyword `Forwarded; Keyword (`Custom "label")] *) 67 + ]} *) 68 + 69 + val keywords_of_flags : flag list -> Keyword.t list 70 + (** [keywords_of_flags flags] converts IMAP flags to keywords. 71 + 72 + System flags are converted to their corresponding standard keywords. 73 + Keyword flags are returned as-is. 74 + 75 + Example: 76 + {[ 77 + keywords_of_flags [System `Seen; Keyword `Forwarded] 78 + (* returns [`Seen; `Forwarded] *) 79 + ]} *) 80 + 81 + (** {1 Mailbox Attributes} *) 82 + 83 + val attr_of_string : string -> Mailbox_attr.t 84 + (** [attr_of_string s] parses an IMAP mailbox attribute. 85 + 86 + Delegates to {!Mailbox_attr.of_string}. The input may optionally 87 + include the leading backslash. Parsing is case-insensitive. 88 + 89 + Examples: 90 + - ["\\Drafts"] -> [`Drafts] 91 + - ["HasChildren"] -> [`HasChildren] *) 92 + 93 + val attr_to_string : Mailbox_attr.t -> string 94 + (** [attr_to_string attr] converts an attribute to IMAP wire format. 95 + 96 + Delegates to {!Mailbox_attr.to_string}. Returns the attribute with 97 + leading backslash prefix. 98 + 99 + Examples: 100 + - [`Drafts] -> ["\\Drafts"] 101 + - [`HasChildren] -> ["\\HasChildren"] *) 102 + 103 + (** {1 Pretty Printing} *) 104 + 105 + val pp_flag : Format.formatter -> flag -> unit 106 + (** [pp_flag ppf flag] pretty-prints a flag in IMAP wire format. *)
+34
mail-flag/lib/jmap_wire.ml
···
··· 1 + (*--------------------------------------------------------------------------- 2 + Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 + 6 + (** JMAP Wire Format Conversion 7 + 8 + Implementation of JMAP wire format conversion for message keywords and 9 + mailbox roles. See {{:https://datatracker.ietf.org/doc/html/rfc8621#section-4.1.1}RFC 8621 Section 4.1.1}. *) 10 + 11 + let keywords_to_assoc keywords = 12 + List.map (fun k -> (Keyword.to_string k, true)) keywords 13 + 14 + let keywords_of_assoc assoc = 15 + List.filter_map (fun (s, v) -> 16 + if v then Some (Keyword.of_string s) else None 17 + ) assoc 18 + 19 + let role_to_string = function 20 + | `All -> "all" 21 + | `Archive -> "archive" 22 + | `Drafts -> "drafts" 23 + | `Flagged -> "flagged" 24 + | `Important -> "important" 25 + | `Inbox -> "inbox" 26 + | `Junk -> "junk" 27 + | `Sent -> "sent" 28 + | `Subscribed -> "subscribed" 29 + | `Trash -> "trash" 30 + | `Snoozed -> "snoozed" 31 + | `Scheduled -> "scheduled" 32 + | `Memos -> "memos" 33 + 34 + let role_of_string = Mailbox_attr.of_jmap_role
+80
mail-flag/lib/jmap_wire.mli
···
··· 1 + (*--------------------------------------------------------------------------- 2 + Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 + 6 + (** JMAP Wire Format Conversion 7 + 8 + Converts between mail-flag types and JMAP JSON format. 9 + See {{:https://datatracker.ietf.org/doc/html/rfc8621#section-4.1.1}RFC 8621 Section 4.1.1} 10 + for the keywords format specification. 11 + 12 + {2 JMAP Keywords Format} 13 + 14 + In JMAP, message keywords are represented as a JSON object where each key 15 + is a keyword string (with [$] prefix for standard keywords) and the value 16 + is always [true]: 17 + 18 + {v 19 + { 20 + "$seen": true, 21 + "$flagged": true, 22 + "$forwarded": true, 23 + "my-custom-label": true 24 + } 25 + v} 26 + 27 + Keywords with [false] values are simply absent from the object. This module 28 + provides conversion functions between the internal {!Keyword.t} list 29 + representation and the association list format used for JSON encoding. *) 30 + 31 + (** {1 Keywords as JSON} *) 32 + 33 + val keywords_to_assoc : Keyword.t list -> (string * bool) list 34 + (** [keywords_to_assoc keywords] converts a keyword list to JMAP keywords 35 + object entries. 36 + 37 + Each keyword is converted to a [(string, true)] pair using 38 + {!Keyword.to_string} for the string representation. 39 + 40 + Example: 41 + {[ 42 + keywords_to_assoc [`Seen; `Flagged; `Custom "label"] 43 + (* returns [("$seen", true); ("$flagged", true); ("label", true)] *) 44 + ]} *) 45 + 46 + val keywords_of_assoc : (string * bool) list -> Keyword.t list 47 + (** [keywords_of_assoc assoc] parses JMAP keywords from object entries. 48 + 49 + Only entries with [true] value are included in the result. 50 + Entries with [false] value are ignored (they represent the absence 51 + of the keyword). 52 + 53 + Example: 54 + {[ 55 + keywords_of_assoc [("$seen", true); ("$draft", false); ("label", true)] 56 + (* returns [`Seen; `Custom "label"] *) 57 + ]} *) 58 + 59 + (** {1 Mailbox Roles} *) 60 + 61 + val role_to_string : Mailbox_attr.special_use -> string 62 + (** [role_to_string role] converts a special-use attribute to JMAP role string. 63 + 64 + JMAP roles are lowercase strings without any prefix. 65 + 66 + Examples: 67 + - [`Drafts] -> ["drafts"] 68 + - [`Inbox] -> ["inbox"] 69 + - [`Junk] -> ["junk"] *) 70 + 71 + val role_of_string : string -> Mailbox_attr.special_use option 72 + (** [role_of_string s] parses a JMAP role string into a special-use attribute. 73 + 74 + Returns [None] if the role string is not recognized. The input should 75 + be lowercase as per JMAP conventions, but parsing is case-insensitive. 76 + 77 + Examples: 78 + - ["drafts"] -> [Some `Drafts] 79 + - ["inbox"] -> [Some `Inbox] 80 + - ["unknown"] -> [None] *)
+207
mail-flag/lib/keyword.ml
···
··· 1 + (*--------------------------------------------------------------------------- 2 + Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 + 6 + (** Implementation of unified message keywords. *) 7 + 8 + type standard = [ 9 + | `Seen 10 + | `Answered 11 + | `Flagged 12 + | `Draft 13 + | `Deleted 14 + | `Forwarded 15 + ] 16 + 17 + type spam = [ 18 + | `Phishing 19 + | `Junk 20 + | `NotJunk 21 + ] 22 + 23 + type extended = [ 24 + | `HasAttachment 25 + | `HasNoAttachment 26 + | `Memo 27 + | `HasMemo 28 + | `CanUnsubscribe 29 + | `Unsubscribed 30 + | `Muted 31 + | `Followed 32 + | `AutoSent 33 + | `Imported 34 + | `IsTrusted 35 + | `MaskedEmail 36 + | `New 37 + | `Notify 38 + ] 39 + 40 + type flag_bit = [ 41 + | `MailFlagBit0 42 + | `MailFlagBit1 43 + | `MailFlagBit2 44 + ] 45 + 46 + type t = [ standard | spam | extended | flag_bit | `Custom of string ] 47 + 48 + (** Normalize a keyword string by removing the $ prefix and converting to lowercase. *) 49 + let normalize s = 50 + let s = String.lowercase_ascii s in 51 + if String.length s > 0 && s.[0] = '$' then 52 + String.sub s 1 (String.length s - 1) 53 + else if String.length s > 0 && s.[0] = '\\' then 54 + String.sub s 1 (String.length s - 1) 55 + else 56 + s 57 + 58 + let of_string s = 59 + match normalize s with 60 + | "seen" -> `Seen 61 + | "answered" -> `Answered 62 + | "flagged" -> `Flagged 63 + | "draft" -> `Draft 64 + | "deleted" -> `Deleted 65 + | "forwarded" -> `Forwarded 66 + | "phishing" -> `Phishing 67 + | "junk" -> `Junk 68 + | "notjunk" -> `NotJunk 69 + | "hasattachment" -> `HasAttachment 70 + | "hasnoattachment" -> `HasNoAttachment 71 + | "memo" -> `Memo 72 + | "hasmemo" -> `HasMemo 73 + | "canunsubscribe" -> `CanUnsubscribe 74 + | "unsubscribed" -> `Unsubscribed 75 + | "muted" -> `Muted 76 + | "followed" -> `Followed 77 + | "autosent" -> `AutoSent 78 + | "imported" -> `Imported 79 + | "istrusted" -> `IsTrusted 80 + | "maskedemail" -> `MaskedEmail 81 + | "new" -> `New 82 + | "notify" -> `Notify 83 + | "mailflagbit0" -> `MailFlagBit0 84 + | "mailflagbit1" -> `MailFlagBit1 85 + | "mailflagbit2" -> `MailFlagBit2 86 + | other -> `Custom other 87 + 88 + let to_string = function 89 + | `Seen -> "$seen" 90 + | `Answered -> "$answered" 91 + | `Flagged -> "$flagged" 92 + | `Draft -> "$draft" 93 + | `Deleted -> "$deleted" 94 + | `Forwarded -> "$forwarded" 95 + | `Phishing -> "$phishing" 96 + | `Junk -> "$junk" 97 + | `NotJunk -> "$notjunk" 98 + | `HasAttachment -> "$hasattachment" 99 + | `HasNoAttachment -> "$hasnoattachment" 100 + | `Memo -> "$memo" 101 + | `HasMemo -> "$hasmemo" 102 + | `CanUnsubscribe -> "$canunsubscribe" 103 + | `Unsubscribed -> "$unsubscribed" 104 + | `Muted -> "$muted" 105 + | `Followed -> "$followed" 106 + | `AutoSent -> "$autosent" 107 + | `Imported -> "$imported" 108 + | `IsTrusted -> "$istrusted" 109 + | `MaskedEmail -> "$maskedemail" 110 + | `New -> "$new" 111 + | `Notify -> "$notify" 112 + | `MailFlagBit0 -> "$MailFlagBit0" 113 + | `MailFlagBit1 -> "$MailFlagBit1" 114 + | `MailFlagBit2 -> "$MailFlagBit2" 115 + | `Custom s -> s 116 + 117 + let to_imap_string = function 118 + (* Standard keywords that map to IMAP system flags *) 119 + | `Seen -> "\\Seen" 120 + | `Answered -> "\\Answered" 121 + | `Flagged -> "\\Flagged" 122 + | `Draft -> "\\Draft" 123 + | `Deleted -> "\\Deleted" 124 + (* Non-system keywords use $ prefix *) 125 + | `Forwarded -> "$Forwarded" 126 + | `Phishing -> "$Phishing" 127 + | `Junk -> "$Junk" 128 + | `NotJunk -> "$NotJunk" 129 + | `HasAttachment -> "$HasAttachment" 130 + | `HasNoAttachment -> "$HasNoAttachment" 131 + | `Memo -> "$Memo" 132 + | `HasMemo -> "$HasMemo" 133 + | `CanUnsubscribe -> "$CanUnsubscribe" 134 + | `Unsubscribed -> "$Unsubscribed" 135 + | `Muted -> "$Muted" 136 + | `Followed -> "$Followed" 137 + | `AutoSent -> "$AutoSent" 138 + | `Imported -> "$Imported" 139 + | `IsTrusted -> "$IsTrusted" 140 + | `MaskedEmail -> "$MaskedEmail" 141 + | `New -> "$New" 142 + | `Notify -> "$Notify" 143 + | `MailFlagBit0 -> "$MailFlagBit0" 144 + | `MailFlagBit1 -> "$MailFlagBit1" 145 + | `MailFlagBit2 -> "$MailFlagBit2" 146 + | `Custom s -> 147 + if String.length s > 0 && (s.[0] = '$' || s.[0] = '\\') then s 148 + else "$" ^ s 149 + 150 + let is_standard = function 151 + | `Seen | `Answered | `Flagged | `Draft | `Deleted -> true 152 + | _ -> false 153 + 154 + let is_mutually_exclusive k1 k2 = 155 + match (k1, k2) with 156 + | (`HasAttachment, `HasNoAttachment) | (`HasNoAttachment, `HasAttachment) -> true 157 + | (`Junk, `NotJunk) | (`NotJunk, `Junk) -> true 158 + | (`Muted, `Followed) | (`Followed, `Muted) -> true 159 + | _ -> false 160 + 161 + let pp ppf k = Fmt.string ppf (to_string k) 162 + 163 + let equal k1 k2 = 164 + match (k1, k2) with 165 + | (`Custom s1, `Custom s2) -> String.equal (String.lowercase_ascii s1) (String.lowercase_ascii s2) 166 + | _ -> k1 = k2 167 + 168 + let compare k1 k2 = 169 + match (k1, k2) with 170 + | (`Custom s1, `Custom s2) -> String.compare (String.lowercase_ascii s1) (String.lowercase_ascii s2) 171 + | (`Custom _, _) -> 1 172 + | (_, `Custom _) -> -1 173 + | _ -> Stdlib.compare k1 k2 174 + 175 + (** Apple Mail flag colors *) 176 + type flag_color = [ 177 + | `Red 178 + | `Orange 179 + | `Yellow 180 + | `Green 181 + | `Blue 182 + | `Purple 183 + | `Gray 184 + ] 185 + 186 + let flag_color_of_keywords keywords = 187 + let has_bit0 = List.exists (fun k -> k = `MailFlagBit0) keywords in 188 + let has_bit1 = List.exists (fun k -> k = `MailFlagBit1) keywords in 189 + let has_bit2 = List.exists (fun k -> k = `MailFlagBit2) keywords in 190 + match (has_bit0, has_bit1, has_bit2) with 191 + | (false, false, false) -> Some `Red 192 + | (true, false, false) -> Some `Orange 193 + | (false, true, false) -> Some `Yellow 194 + | (true, true, true) -> Some `Green 195 + | (false, false, true) -> Some `Blue 196 + | (true, false, true) -> Some `Purple 197 + | (false, true, true) -> Some `Gray 198 + | (true, true, false) -> None (* Invalid encoding *) 199 + 200 + let flag_color_to_keywords = function 201 + | `Red -> [] 202 + | `Orange -> [`MailFlagBit0] 203 + | `Yellow -> [`MailFlagBit1] 204 + | `Green -> [`MailFlagBit0; `MailFlagBit1; `MailFlagBit2] 205 + | `Blue -> [`MailFlagBit2] 206 + | `Purple -> [`MailFlagBit0; `MailFlagBit2] 207 + | `Gray -> [`MailFlagBit1; `MailFlagBit2]
+177
mail-flag/lib/keyword.mli
···
··· 1 + (*--------------------------------------------------------------------------- 2 + Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 + 6 + (** Unified Message Keywords for IMAP and JMAP 7 + 8 + This module provides a unified representation of message keywords that 9 + works across both IMAP ({{:https://datatracker.ietf.org/doc/html/rfc9051}RFC 9051}) 10 + and JMAP ({{:https://datatracker.ietf.org/doc/html/rfc8621}RFC 8621}) protocols. 11 + 12 + {2 Keyword Types} 13 + 14 + Keywords are organized into categories based on their specification: 15 + - {!standard}: Core flags from RFC 8621 Section 4.1.1 that map to IMAP system flags 16 + - {!spam}: Spam-related keywords for junk mail handling 17 + - {!extended}: Extended keywords from draft-ietf-mailmaint 18 + - {!flag_bit}: Apple Mail flag color bits 19 + 20 + {2 Protocol Mapping} 21 + 22 + IMAP system flags ([\Seen], [\Answered], etc.) map to JMAP keywords 23 + ([$seen], [$answered], etc.). The {!to_string} and {!to_imap_string} 24 + functions handle these conversions. *) 25 + 26 + (** {1 Keyword Types} *) 27 + 28 + (** Standard keywords per {{:https://datatracker.ietf.org/doc/html/rfc8621#section-4.1.1}RFC 8621 Section 4.1.1}. 29 + 30 + These keywords have direct mappings to IMAP system flags defined in 31 + {{:https://datatracker.ietf.org/doc/html/rfc9051#section-2.3.2}RFC 9051 Section 2.3.2}. *) 32 + type standard = [ 33 + | `Seen (** Message has been read. Maps to IMAP [\Seen]. *) 34 + | `Answered (** Message has been answered. Maps to IMAP [\Answered]. *) 35 + | `Flagged (** Message is flagged/starred. Maps to IMAP [\Flagged]. *) 36 + | `Draft (** Message is a draft. Maps to IMAP [\Draft]. *) 37 + | `Deleted (** Message marked for deletion. IMAP only, maps to [\Deleted]. *) 38 + | `Forwarded (** Message has been forwarded. JMAP [$forwarded] keyword. *) 39 + ] 40 + 41 + (** Spam-related keywords for junk mail handling. 42 + 43 + These keywords help mail clients and servers coordinate spam filtering 44 + decisions across protocol boundaries. *) 45 + type spam = [ 46 + | `Phishing (** Message is a phishing attempt. JMAP [$phishing]. *) 47 + | `Junk (** Message is spam/junk. JMAP [$junk]. *) 48 + | `NotJunk (** Message explicitly marked as not junk. JMAP [$notjunk]. *) 49 + ] 50 + 51 + (** Extended keywords per draft-ietf-mailmaint. 52 + 53 + These keywords provide additional metadata for enhanced mail client features 54 + beyond basic read/reply tracking. *) 55 + type extended = [ 56 + | `HasAttachment (** Message has attachments. *) 57 + | `HasNoAttachment (** Message has no attachments. Mutually exclusive with [`HasAttachment]. *) 58 + | `Memo (** Message is a memo. *) 59 + | `HasMemo (** Message has an associated memo. *) 60 + | `CanUnsubscribe (** Message has unsubscribe capability (List-Unsubscribe header). *) 61 + | `Unsubscribed (** User has unsubscribed from this sender. *) 62 + | `Muted (** Thread is muted. Mutually exclusive with [`Followed]. *) 63 + | `Followed (** Thread is followed. Mutually exclusive with [`Muted]. *) 64 + | `AutoSent (** Message was sent automatically. *) 65 + | `Imported (** Message was imported from another source. *) 66 + | `IsTrusted (** Sender is trusted. *) 67 + | `MaskedEmail (** Message was sent to a masked email address. *) 68 + | `New (** Message is new (not yet processed by client). *) 69 + | `Notify (** User should be notified about this message. *) 70 + ] 71 + 72 + (** Apple Mail flag color bits. 73 + 74 + Apple Mail uses a 3-bit encoding for flag colors. The color is determined 75 + by the combination of bits set. See {!flag_color_of_keywords} for the 76 + mapping. *) 77 + type flag_bit = [ 78 + | `MailFlagBit0 (** Bit 0 of Apple Mail flag color encoding. *) 79 + | `MailFlagBit1 (** Bit 1 of Apple Mail flag color encoding. *) 80 + | `MailFlagBit2 (** Bit 2 of Apple Mail flag color encoding. *) 81 + ] 82 + 83 + (** Unified keyword type combining all keyword categories. 84 + 85 + Use [`Custom s] for server-specific or application-specific keywords 86 + not covered by the standard categories. *) 87 + type t = [ standard | spam | extended | flag_bit | `Custom of string ] 88 + 89 + (** {1 Conversion Functions} *) 90 + 91 + val of_string : string -> t 92 + (** [of_string s] parses a keyword string. 93 + 94 + Handles both JMAP format ([$seen]) and bare format ([seen]). 95 + Parsing is case-insensitive for known keywords. 96 + 97 + Examples: 98 + - ["$seen"] -> [`Seen] 99 + - ["seen"] -> [`Seen] 100 + - ["SEEN"] -> [`Seen] 101 + - ["\\Seen"] -> [`Seen] (IMAP system flag format) 102 + - ["my-custom-flag"] -> [`Custom "my-custom-flag"] *) 103 + 104 + val to_string : t -> string 105 + (** [to_string k] converts a keyword to canonical JMAP format. 106 + 107 + Standard and extended keywords are returned with [$] prefix in lowercase. 108 + Apple Mail flag bits preserve their mixed case. 109 + Custom keywords are returned as-is. 110 + 111 + Examples: 112 + - [`Seen] -> ["$seen"] 113 + - [`MailFlagBit0] -> ["$MailFlagBit0"] 114 + - [`Custom "foo"] -> ["foo"] *) 115 + 116 + val to_imap_string : t -> string 117 + (** [to_imap_string k] converts a keyword to IMAP format. 118 + 119 + Standard keywords that map to IMAP system flags use backslash prefix. 120 + Other keywords use [$] prefix with appropriate casing. 121 + 122 + Examples: 123 + - [`Seen] -> ["\\Seen"] 124 + - [`Deleted] -> ["\\Deleted"] 125 + - [`Forwarded] -> ["$Forwarded"] 126 + - [`MailFlagBit0] -> ["$MailFlagBit0"] *) 127 + 128 + (** {1 Predicates} *) 129 + 130 + val is_standard : t -> bool 131 + (** [is_standard k] returns [true] if [k] maps to an IMAP system flag. 132 + 133 + The standard keywords are: [`Seen], [`Answered], [`Flagged], [`Draft], 134 + and [`Deleted]. Note that [`Forwarded] is {i not} an IMAP system flag. *) 135 + 136 + val is_mutually_exclusive : t -> t -> bool 137 + (** [is_mutually_exclusive k1 k2] returns [true] if keywords [k1] and [k2] 138 + cannot both be set on the same message. 139 + 140 + Mutually exclusive pairs: 141 + - [`HasAttachment] and [`HasNoAttachment] 142 + - [`Junk] and [`NotJunk] 143 + - [`Muted] and [`Followed] *) 144 + 145 + (** {1 Pretty Printing} *) 146 + 147 + val pp : Format.formatter -> t -> unit 148 + (** [pp ppf k] pretty-prints keyword [k] in JMAP format. *) 149 + 150 + val equal : t -> t -> bool 151 + (** [equal k1 k2] tests equality of keywords. *) 152 + 153 + val compare : t -> t -> int 154 + (** [compare k1 k2] provides total ordering on keywords. *) 155 + 156 + (** {1 Apple Mail Flag Colors} *) 157 + 158 + (** Apple Mail flag colors encoded as 3-bit values. *) 159 + type flag_color = [ 160 + | `Red (** No bits set *) 161 + | `Orange (** Bit 0 only *) 162 + | `Yellow (** Bit 1 only *) 163 + | `Green (** All bits set *) 164 + | `Blue (** Bit 2 only *) 165 + | `Purple (** Bits 0 and 2 *) 166 + | `Gray (** Bits 1 and 2 *) 167 + ] 168 + 169 + val flag_color_of_keywords : t list -> flag_color option 170 + (** [flag_color_of_keywords keywords] extracts the Apple Mail flag color 171 + from a list of keywords. 172 + 173 + Returns [None] if bits 0 and 1 are set but not bit 2 (invalid encoding). *) 174 + 175 + val flag_color_to_keywords : flag_color -> t list 176 + (** [flag_color_to_keywords color] returns the keyword bits needed to 177 + represent the given flag color. *)
+149
mail-flag/lib/mailbox_attr.ml
···
··· 1 + (*--------------------------------------------------------------------------- 2 + Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 + 6 + (** Implementation of unified mailbox attributes and roles. *) 7 + 8 + type list_attr = [ 9 + | `Noinferiors 10 + | `Noselect 11 + | `Marked 12 + | `Unmarked 13 + | `Subscribed 14 + | `HasChildren 15 + | `HasNoChildren 16 + | `NonExistent 17 + | `Remote 18 + ] 19 + 20 + type special_use = [ 21 + | `All 22 + | `Archive 23 + | `Drafts 24 + | `Flagged 25 + | `Important 26 + | `Inbox 27 + | `Junk 28 + | `Sent 29 + | `Subscribed 30 + | `Trash 31 + | `Snoozed 32 + | `Scheduled 33 + | `Memos 34 + ] 35 + 36 + type t = [ list_attr | special_use | `Extension of string ] 37 + 38 + (** Normalize attribute string by removing backslash prefix and converting to lowercase. *) 39 + let normalize s = 40 + let s = String.lowercase_ascii s in 41 + if String.length s > 0 && s.[0] = '\\' then 42 + String.sub s 1 (String.length s - 1) 43 + else 44 + s 45 + 46 + let of_string s = 47 + match normalize s with 48 + (* LIST attributes *) 49 + | "noinferiors" -> `Noinferiors 50 + | "noselect" -> `Noselect 51 + | "marked" -> `Marked 52 + | "unmarked" -> `Unmarked 53 + | "subscribed" -> `Subscribed 54 + | "haschildren" -> `HasChildren 55 + | "hasnochildren" -> `HasNoChildren 56 + | "nonexistent" -> `NonExistent 57 + | "remote" -> `Remote 58 + (* Special-use roles *) 59 + | "all" -> `All 60 + | "archive" -> `Archive 61 + | "drafts" -> `Drafts 62 + | "flagged" -> `Flagged 63 + | "important" -> `Important 64 + | "inbox" -> `Inbox 65 + | "junk" | "spam" -> `Junk 66 + | "sent" -> `Sent 67 + | "trash" -> `Trash 68 + | "snoozed" -> `Snoozed 69 + | "scheduled" -> `Scheduled 70 + | "memos" -> `Memos 71 + | other -> `Extension other 72 + 73 + let to_string = function 74 + (* LIST attributes *) 75 + | `Noinferiors -> "\\Noinferiors" 76 + | `Noselect -> "\\Noselect" 77 + | `Marked -> "\\Marked" 78 + | `Unmarked -> "\\Unmarked" 79 + | `Subscribed -> "\\Subscribed" 80 + | `HasChildren -> "\\HasChildren" 81 + | `HasNoChildren -> "\\HasNoChildren" 82 + | `NonExistent -> "\\NonExistent" 83 + | `Remote -> "\\Remote" 84 + (* Special-use roles *) 85 + | `All -> "\\All" 86 + | `Archive -> "\\Archive" 87 + | `Drafts -> "\\Drafts" 88 + | `Flagged -> "\\Flagged" 89 + | `Important -> "\\Important" 90 + | `Inbox -> "\\Inbox" 91 + | `Junk -> "\\Junk" 92 + | `Sent -> "\\Sent" 93 + | `Trash -> "\\Trash" 94 + | `Snoozed -> "\\Snoozed" 95 + | `Scheduled -> "\\Scheduled" 96 + | `Memos -> "\\Memos" 97 + | `Extension s -> 98 + if String.length s > 0 && s.[0] = '\\' then s 99 + else "\\" ^ s 100 + 101 + let to_jmap_role = function 102 + (* Special-use roles have JMAP equivalents *) 103 + | `All -> Some "all" 104 + | `Archive -> Some "archive" 105 + | `Drafts -> Some "drafts" 106 + | `Flagged -> Some "flagged" 107 + | `Important -> Some "important" 108 + | `Inbox -> Some "inbox" 109 + | `Junk -> Some "junk" 110 + | `Sent -> Some "sent" 111 + | `Trash -> Some "trash" 112 + | `Snoozed -> Some "snoozed" 113 + | `Scheduled -> Some "scheduled" 114 + | `Memos -> Some "memos" 115 + (* LIST attributes and extensions have no JMAP role *) 116 + | `Noinferiors | `Noselect | `Marked | `Unmarked | `Subscribed 117 + | `HasChildren | `HasNoChildren | `NonExistent | `Remote 118 + | `Extension _ -> None 119 + 120 + let of_jmap_role s = 121 + match String.lowercase_ascii s with 122 + | "all" -> Some `All 123 + | "archive" -> Some `Archive 124 + | "drafts" -> Some `Drafts 125 + | "flagged" -> Some `Flagged 126 + | "important" -> Some `Important 127 + | "inbox" -> Some `Inbox 128 + | "junk" -> Some `Junk 129 + | "sent" -> Some `Sent 130 + | "trash" -> Some `Trash 131 + | "snoozed" -> Some `Snoozed 132 + | "scheduled" -> Some `Scheduled 133 + | "memos" -> Some `Memos 134 + | "subscribed" -> Some `Subscribed 135 + | _ -> None 136 + 137 + let is_special_use = function 138 + | `All | `Archive | `Drafts | `Flagged | `Important | `Inbox 139 + | `Junk | `Sent | `Trash | `Snoozed | `Scheduled | `Memos -> true 140 + | `Subscribed -> true (* Also a JMAP role *) 141 + | `Noinferiors | `Noselect | `Marked | `Unmarked 142 + | `HasChildren | `HasNoChildren | `NonExistent | `Remote 143 + | `Extension _ -> false 144 + 145 + let is_selectable = function 146 + | `Noselect | `NonExistent -> false 147 + | _ -> true 148 + 149 + let pp ppf attr = Fmt.string ppf (to_string attr)
+188
mail-flag/lib/mailbox_attr.mli
···
··· 1 + (*--------------------------------------------------------------------------- 2 + Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 + 6 + (** Unified Mailbox Attributes and Roles 7 + 8 + This module provides a unified representation of mailbox attributes 9 + across IMAP and JMAP protocols. It combines IMAP LIST response attributes 10 + ({{:https://www.rfc-editor.org/rfc/rfc9051#section-7.2.2}RFC 9051 Section 7.2.2}), 11 + special-use mailbox flags ({{:https://www.rfc-editor.org/rfc/rfc6154}RFC 6154}), 12 + and JMAP mailbox roles ({{:https://www.rfc-editor.org/rfc/rfc8621}RFC 8621}). 13 + 14 + {2 References} 15 + - {{:https://www.rfc-editor.org/rfc/rfc9051}RFC 9051} - IMAP4rev2 16 + - {{:https://www.rfc-editor.org/rfc/rfc6154}RFC 6154} - IMAP LIST Extension for Special-Use Mailboxes 17 + - {{:https://www.rfc-editor.org/rfc/rfc5258}RFC 5258} - IMAP4 LIST Command Extensions 18 + - {{:https://www.rfc-editor.org/rfc/rfc8457}RFC 8457} - IMAP \$Important Keyword and \Important Special-Use Attribute 19 + - {{:https://www.rfc-editor.org/rfc/rfc8621}RFC 8621} - JMAP for Mail *) 20 + 21 + (** {1 IMAP LIST Attributes} 22 + 23 + Attributes returned in IMAP LIST responses per 24 + {{:https://www.rfc-editor.org/rfc/rfc9051#section-7.2.2}RFC 9051 Section 7.2.2}. *) 25 + 26 + type list_attr = [ 27 + | `Noinferiors 28 + (** [\Noinferiors] - No child mailboxes are possible under this mailbox. 29 + The mailbox cannot have inferior (child) mailboxes, either because the 30 + underlying storage doesn't support it or because the mailbox name is at 31 + the hierarchy depth limit for this mailbox store. *) 32 + | `Noselect 33 + (** [\Noselect] - This mailbox cannot be selected. It exists only to hold 34 + child mailboxes and is not a valid destination for messages. Stratum 35 + only, not a real mailbox. *) 36 + | `Marked 37 + (** [\Marked] - The mailbox has been marked "interesting" by the server. 38 + This typically indicates the mailbox contains new messages since the 39 + last time it was selected. *) 40 + | `Unmarked 41 + (** [\Unmarked] - The mailbox is not "interesting". The mailbox does not 42 + contain new messages since the last time it was selected. *) 43 + | `Subscribed 44 + (** [\Subscribed] - The mailbox is subscribed. Returned when the 45 + SUBSCRIBED selection option is specified or implied. *) 46 + | `HasChildren 47 + (** [\HasChildren] - The mailbox has child mailboxes. Part of the 48 + CHILDREN return option ({{:https://www.rfc-editor.org/rfc/rfc5258}RFC 5258}). *) 49 + | `HasNoChildren 50 + (** [\HasNoChildren] - The mailbox has no child mailboxes. Part of the 51 + CHILDREN return option ({{:https://www.rfc-editor.org/rfc/rfc5258}RFC 5258}). *) 52 + | `NonExistent 53 + (** [\NonExistent] - The mailbox name does not refer to an existing mailbox. 54 + This attribute is returned when a mailbox is part of the hierarchy but 55 + doesn't actually exist ({{:https://www.rfc-editor.org/rfc/rfc5258}RFC 5258}). 56 + Implies [\Noselect]. *) 57 + | `Remote 58 + (** [\Remote] - The mailbox is located on a remote server. 59 + ({{:https://www.rfc-editor.org/rfc/rfc5258}RFC 5258}) *) 60 + ] 61 + 62 + (** {1 Special-Use Roles} 63 + 64 + Special-use mailbox roles per {{:https://www.rfc-editor.org/rfc/rfc6154}RFC 6154} 65 + and {{:https://www.rfc-editor.org/rfc/rfc8621}RFC 8621}. These identify 66 + mailboxes with specific purposes. *) 67 + 68 + type special_use = [ 69 + | `All 70 + (** [\All] - A virtual mailbox containing all messages in the user's 71 + message store. Implementations may omit some messages. *) 72 + | `Archive 73 + (** [\Archive] - A mailbox used to archive messages. The meaning of 74 + "archived" may vary by server. *) 75 + | `Drafts 76 + (** [\Drafts] - A mailbox used to hold draft messages, typically messages 77 + being composed but not yet sent. *) 78 + | `Flagged 79 + (** [\Flagged] - A virtual mailbox containing all messages marked with 80 + the [\Flagged] flag. *) 81 + | `Important 82 + (** [\Important] - A mailbox used to hold messages deemed important to 83 + the user. ({{:https://www.rfc-editor.org/rfc/rfc8457}RFC 8457}) *) 84 + | `Inbox 85 + (** [inbox] - The user's inbox. This is a JMAP role 86 + ({{:https://www.rfc-editor.org/rfc/rfc8621}RFC 8621}) without a direct 87 + IMAP special-use equivalent since INBOX is always special in IMAP. *) 88 + | `Junk 89 + (** [\Junk] - A mailbox used to hold messages that have been identified 90 + as spam or junk mail. Also known as "Spam" folder. *) 91 + | `Sent 92 + (** [\Sent] - A mailbox used to hold copies of messages that have been 93 + sent. *) 94 + | `Subscribed 95 + (** [subscribed] - A JMAP virtual mailbox role 96 + ({{:https://www.rfc-editor.org/rfc/rfc8621}RFC 8621}) representing 97 + all subscribed mailboxes. *) 98 + | `Trash 99 + (** [\Trash] - A mailbox used to hold messages that have been deleted or 100 + marked for deletion. *) 101 + | `Snoozed 102 + (** [snoozed] - A mailbox for messages that have been snoozed until a 103 + later time. (draft-ietf-mailmaint-special-use-extensions) *) 104 + | `Scheduled 105 + (** [scheduled] - A mailbox for messages scheduled to be sent at a 106 + future time. (draft-ietf-mailmaint-special-use-extensions) *) 107 + | `Memos 108 + (** [memos] - A mailbox for memo/note messages. 109 + (draft-ietf-mailmaint-special-use-extensions) *) 110 + ] 111 + 112 + (** {1 Unified Attribute Type} *) 113 + 114 + type t = [ list_attr | special_use | `Extension of string ] 115 + (** The unified mailbox attribute type combining LIST attributes, special-use 116 + roles, and server-specific extensions. Extensions are represented with 117 + their original string form (without leading backslash if present). *) 118 + 119 + (** {1 Conversion Functions} *) 120 + 121 + val of_string : string -> t 122 + (** [of_string s] parses a mailbox attribute from its IMAP wire format. 123 + The input may optionally include the leading backslash. Parsing is 124 + case-insensitive. Unknown attributes are returned as [`Extension s]. 125 + 126 + Examples: 127 + - [of_string "\\Drafts"] returns [`Drafts] 128 + - [of_string "drafts"] returns [`Drafts] 129 + - [of_string "\\X-Custom"] returns [`Extension "X-Custom"] *) 130 + 131 + val to_string : t -> string 132 + (** [to_string attr] converts an attribute to its IMAP wire format with 133 + the leading backslash prefix for standard attributes. 134 + 135 + Examples: 136 + - [to_string `Drafts] returns ["\\Drafts"] 137 + - [to_string `HasChildren] returns ["\\HasChildren"] 138 + - [to_string (`Extension "X-Custom")] returns ["\\X-Custom"] *) 139 + 140 + val to_jmap_role : t -> string option 141 + (** [to_jmap_role attr] converts a special-use attribute to its JMAP role 142 + string (lowercase). Returns [None] for LIST attributes that don't 143 + correspond to JMAP roles. 144 + 145 + Examples: 146 + - [to_jmap_role `Drafts] returns [Some "drafts"] 147 + - [to_jmap_role `Inbox] returns [Some "inbox"] 148 + - [to_jmap_role `Noselect] returns [None] *) 149 + 150 + val of_jmap_role : string -> special_use option 151 + (** [of_jmap_role s] parses a JMAP role string into a special-use attribute. 152 + Returns [None] if the role string is not recognized. The input should 153 + be lowercase as per JMAP conventions. 154 + 155 + Examples: 156 + - [of_jmap_role "drafts"] returns [Some `Drafts] 157 + - [of_jmap_role "inbox"] returns [Some `Inbox] 158 + - [of_jmap_role "unknown"] returns [None] *) 159 + 160 + (** {1 Predicates} *) 161 + 162 + val is_special_use : t -> bool 163 + (** [is_special_use attr] returns [true] if the attribute is a special-use 164 + role (as opposed to a LIST attribute or extension). 165 + 166 + Examples: 167 + - [is_special_use `Drafts] returns [true] 168 + - [is_special_use `Noselect] returns [false] 169 + - [is_special_use (`Extension "x")] returns [false] *) 170 + 171 + val is_selectable : t -> bool 172 + (** [is_selectable attr] returns [false] if the attribute indicates the 173 + mailbox cannot be selected. This is [true] for [`Noselect] and 174 + [`NonExistent] attributes, and [false] for all others. 175 + 176 + Note: A mailbox may have multiple attributes. To determine if a mailbox 177 + is selectable, check that no attribute returns [false] from this function. 178 + 179 + Examples: 180 + - [is_selectable `Noselect] returns [false] 181 + - [is_selectable `NonExistent] returns [false] 182 + - [is_selectable `Drafts] returns [true] 183 + - [is_selectable `HasChildren] returns [true] *) 184 + 185 + (** {1 Pretty Printing} *) 186 + 187 + val pp : Format.formatter -> t -> unit 188 + (** [pp ppf attr] pretty-prints the attribute in IMAP wire format. *)
+26
mail-flag/mail-flag.opam
···
··· 1 + # This file is generated by dune, edit dune-project instead 2 + opam-version: "2.0" 3 + synopsis: "Unified message flags and mailbox attributes for IMAP/JMAP" 4 + description: 5 + "Type-safe message keywords, system flags, and mailbox attributes for email protocols. Supports RFC 9051 (IMAP4rev2), RFC 8621 (JMAP Mail), RFC 6154 (Special-Use), and draft-ietf-mailmaint extensions." 6 + depends: [ 7 + "dune" {>= "3.0"} 8 + "ocaml" {>= "5.0"} 9 + "fmt" {>= "0.9"} 10 + "alcotest" {with-test} 11 + "odoc" {with-doc} 12 + ] 13 + build: [ 14 + ["dune" "subst"] {dev} 15 + [ 16 + "dune" 17 + "build" 18 + "-p" 19 + name 20 + "-j" 21 + jobs 22 + "@install" 23 + "@runtest" {with-test} 24 + "@doc" {with-doc} 25 + ] 26 + ]
+15
mail-flag/test/dune
···
··· 1 + (test 2 + (name test_keyword) 3 + (libraries mail-flag alcotest)) 4 + 5 + (test 6 + (name test_mailbox_attr) 7 + (libraries mail-flag alcotest)) 8 + 9 + (test 10 + (name test_flag_color) 11 + (libraries mail-flag alcotest)) 12 + 13 + (test 14 + (name test_wire) 15 + (libraries mail-flag alcotest))
+165
mail-flag/test/test_flag_color.ml
···
··· 1 + (*--------------------------------------------------------------------------- 2 + Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 + 6 + (** Tests for the Flag_color module. *) 7 + 8 + open Mail_flag 9 + 10 + let color_testable = 11 + Alcotest.testable Flag_color.pp (=) 12 + 13 + let test_to_bits () = 14 + (* Test color to bit pattern conversion *) 15 + Alcotest.(check (triple bool bool bool)) "red" (false, false, false) (Flag_color.to_bits Red); 16 + Alcotest.(check (triple bool bool bool)) "orange" (true, false, false) (Flag_color.to_bits Orange); 17 + Alcotest.(check (triple bool bool bool)) "yellow" (false, true, false) (Flag_color.to_bits Yellow); 18 + Alcotest.(check (triple bool bool bool)) "green" (true, true, false) (Flag_color.to_bits Green); 19 + Alcotest.(check (triple bool bool bool)) "blue" (false, false, true) (Flag_color.to_bits Blue); 20 + Alcotest.(check (triple bool bool bool)) "purple" (true, false, true) (Flag_color.to_bits Purple); 21 + Alcotest.(check (triple bool bool bool)) "gray" (false, true, true) (Flag_color.to_bits Gray) 22 + 23 + let test_of_bits () = 24 + (* Test bit pattern to color conversion *) 25 + Alcotest.(check (option color_testable)) "000 = red" (Some Red) (Flag_color.of_bits (false, false, false)); 26 + Alcotest.(check (option color_testable)) "100 = orange" (Some Orange) (Flag_color.of_bits (true, false, false)); 27 + Alcotest.(check (option color_testable)) "010 = yellow" (Some Yellow) (Flag_color.of_bits (false, true, false)); 28 + Alcotest.(check (option color_testable)) "110 = green" (Some Green) (Flag_color.of_bits (true, true, false)); 29 + Alcotest.(check (option color_testable)) "001 = blue" (Some Blue) (Flag_color.of_bits (false, false, true)); 30 + Alcotest.(check (option color_testable)) "101 = purple" (Some Purple) (Flag_color.of_bits (true, false, true)); 31 + Alcotest.(check (option color_testable)) "011 = gray" (Some Gray) (Flag_color.of_bits (false, true, true)); 32 + (* 111 is undefined *) 33 + Alcotest.(check (option color_testable)) "111 = undefined" None (Flag_color.of_bits (true, true, true)) 34 + 35 + let test_bits_roundtrip () = 36 + (* Test that to_bits -> of_bits preserves the color *) 37 + let test_color c = 38 + let bits = Flag_color.to_bits c in 39 + Alcotest.(check (option color_testable)) (Flag_color.to_string c) (Some c) (Flag_color.of_bits bits) 40 + in 41 + test_color Red; 42 + test_color Orange; 43 + test_color Yellow; 44 + test_color Green; 45 + test_color Blue; 46 + test_color Purple; 47 + test_color Gray 48 + 49 + let test_to_keywords () = 50 + (* Test color to keyword list conversion *) 51 + Alcotest.(check int) "red = 0 keywords" 0 (List.length (Flag_color.to_keywords Red)); 52 + Alcotest.(check int) "orange = 1 keyword" 1 (List.length (Flag_color.to_keywords Orange)); 53 + Alcotest.(check int) "yellow = 1 keyword" 1 (List.length (Flag_color.to_keywords Yellow)); 54 + Alcotest.(check int) "green = 2 keywords" 2 (List.length (Flag_color.to_keywords Green)); 55 + Alcotest.(check int) "blue = 1 keyword" 1 (List.length (Flag_color.to_keywords Blue)); 56 + Alcotest.(check int) "purple = 2 keywords" 2 (List.length (Flag_color.to_keywords Purple)); 57 + Alcotest.(check int) "gray = 2 keywords" 2 (List.length (Flag_color.to_keywords Gray)); 58 + (* Check specific keywords *) 59 + Alcotest.(check bool) "orange has bit0" true (List.mem `MailFlagBit0 (Flag_color.to_keywords Orange)); 60 + Alcotest.(check bool) "yellow has bit1" true (List.mem `MailFlagBit1 (Flag_color.to_keywords Yellow)); 61 + Alcotest.(check bool) "blue has bit2" true (List.mem `MailFlagBit2 (Flag_color.to_keywords Blue)); 62 + Alcotest.(check bool) "green has bit0" true (List.mem `MailFlagBit0 (Flag_color.to_keywords Green)); 63 + Alcotest.(check bool) "green has bit1" true (List.mem `MailFlagBit1 (Flag_color.to_keywords Green)); 64 + Alcotest.(check bool) "purple has bit0" true (List.mem `MailFlagBit0 (Flag_color.to_keywords Purple)); 65 + Alcotest.(check bool) "purple has bit2" true (List.mem `MailFlagBit2 (Flag_color.to_keywords Purple)); 66 + Alcotest.(check bool) "gray has bit1" true (List.mem `MailFlagBit1 (Flag_color.to_keywords Gray)); 67 + Alcotest.(check bool) "gray has bit2" true (List.mem `MailFlagBit2 (Flag_color.to_keywords Gray)) 68 + 69 + let test_of_keywords () = 70 + (* Test keyword list to color conversion *) 71 + (* Empty list returns None (ambiguous: no color vs Red) *) 72 + Alcotest.(check (option color_testable)) "empty = None" None (Flag_color.of_keywords []); 73 + Alcotest.(check (option color_testable)) "bit0 = orange" (Some Orange) (Flag_color.of_keywords [`MailFlagBit0]); 74 + Alcotest.(check (option color_testable)) "bit1 = yellow" (Some Yellow) (Flag_color.of_keywords [`MailFlagBit1]); 75 + Alcotest.(check (option color_testable)) "bit2 = blue" (Some Blue) (Flag_color.of_keywords [`MailFlagBit2]); 76 + Alcotest.(check (option color_testable)) "bits 0,1 = green" (Some Green) (Flag_color.of_keywords [`MailFlagBit0; `MailFlagBit1]); 77 + Alcotest.(check (option color_testable)) "bits 0,2 = purple" (Some Purple) (Flag_color.of_keywords [`MailFlagBit0; `MailFlagBit2]); 78 + Alcotest.(check (option color_testable)) "bits 1,2 = gray" (Some Gray) (Flag_color.of_keywords [`MailFlagBit1; `MailFlagBit2]); 79 + (* All bits = undefined *) 80 + Alcotest.(check (option color_testable)) "all bits = undefined" None 81 + (Flag_color.of_keywords [`MailFlagBit0; `MailFlagBit1; `MailFlagBit2]) 82 + 83 + let test_of_keywords_default_red () = 84 + (* Test keyword list to color with Red default for empty list *) 85 + Alcotest.(check (option color_testable)) "empty = red" (Some Red) (Flag_color.of_keywords_default_red []); 86 + Alcotest.(check (option color_testable)) "bit0 = orange" (Some Orange) (Flag_color.of_keywords_default_red [`MailFlagBit0]); 87 + Alcotest.(check (option color_testable)) "bits 0,1 = green" (Some Green) 88 + (Flag_color.of_keywords_default_red [`MailFlagBit0; `MailFlagBit1]); 89 + (* All bits still undefined *) 90 + Alcotest.(check (option color_testable)) "all bits = undefined" None 91 + (Flag_color.of_keywords_default_red [`MailFlagBit0; `MailFlagBit1; `MailFlagBit2]) 92 + 93 + let test_keywords_roundtrip () = 94 + (* Test that to_keywords -> of_keywords_default_red preserves non-red colors *) 95 + let test_color c = 96 + let kws = Flag_color.to_keywords c in 97 + Alcotest.(check (option color_testable)) (Flag_color.to_string c) (Some c) (Flag_color.of_keywords_default_red kws) 98 + in 99 + test_color Red; 100 + test_color Orange; 101 + test_color Yellow; 102 + test_color Green; 103 + test_color Blue; 104 + test_color Purple; 105 + test_color Gray 106 + 107 + let test_to_string () = 108 + (* Test color to string conversion *) 109 + Alcotest.(check string) "red" "red" (Flag_color.to_string Red); 110 + Alcotest.(check string) "orange" "orange" (Flag_color.to_string Orange); 111 + Alcotest.(check string) "yellow" "yellow" (Flag_color.to_string Yellow); 112 + Alcotest.(check string) "green" "green" (Flag_color.to_string Green); 113 + Alcotest.(check string) "blue" "blue" (Flag_color.to_string Blue); 114 + Alcotest.(check string) "purple" "purple" (Flag_color.to_string Purple); 115 + Alcotest.(check string) "gray" "gray" (Flag_color.to_string Gray) 116 + 117 + let test_of_string () = 118 + (* Test string to color conversion *) 119 + Alcotest.(check (option color_testable)) "red" (Some Red) (Flag_color.of_string "red"); 120 + Alcotest.(check (option color_testable)) "orange" (Some Orange) (Flag_color.of_string "orange"); 121 + Alcotest.(check (option color_testable)) "yellow" (Some Yellow) (Flag_color.of_string "yellow"); 122 + Alcotest.(check (option color_testable)) "green" (Some Green) (Flag_color.of_string "green"); 123 + Alcotest.(check (option color_testable)) "blue" (Some Blue) (Flag_color.of_string "blue"); 124 + Alcotest.(check (option color_testable)) "purple" (Some Purple) (Flag_color.of_string "purple"); 125 + Alcotest.(check (option color_testable)) "gray" (Some Gray) (Flag_color.of_string "gray"); 126 + Alcotest.(check (option color_testable)) "grey" (Some Gray) (Flag_color.of_string "grey"); 127 + (* Case insensitive *) 128 + Alcotest.(check (option color_testable)) "RED" (Some Red) (Flag_color.of_string "RED"); 129 + Alcotest.(check (option color_testable)) "Orange" (Some Orange) (Flag_color.of_string "Orange"); 130 + (* Unknown *) 131 + Alcotest.(check (option color_testable)) "unknown" None (Flag_color.of_string "unknown") 132 + 133 + let test_string_roundtrip () = 134 + (* Test that to_string -> of_string preserves the color *) 135 + let test_color c = 136 + let s = Flag_color.to_string c in 137 + Alcotest.(check (option color_testable)) s (Some c) (Flag_color.of_string s) 138 + in 139 + test_color Red; 140 + test_color Orange; 141 + test_color Yellow; 142 + test_color Green; 143 + test_color Blue; 144 + test_color Purple; 145 + test_color Gray 146 + 147 + let () = 148 + Alcotest.run "Flag_color" [ 149 + "bits", [ 150 + Alcotest.test_case "to_bits" `Quick test_to_bits; 151 + Alcotest.test_case "of_bits" `Quick test_of_bits; 152 + Alcotest.test_case "roundtrip" `Quick test_bits_roundtrip; 153 + ]; 154 + "keywords", [ 155 + Alcotest.test_case "to_keywords" `Quick test_to_keywords; 156 + Alcotest.test_case "of_keywords" `Quick test_of_keywords; 157 + Alcotest.test_case "of_keywords_default_red" `Quick test_of_keywords_default_red; 158 + Alcotest.test_case "roundtrip" `Quick test_keywords_roundtrip; 159 + ]; 160 + "strings", [ 161 + Alcotest.test_case "to_string" `Quick test_to_string; 162 + Alcotest.test_case "of_string" `Quick test_of_string; 163 + Alcotest.test_case "roundtrip" `Quick test_string_roundtrip; 164 + ]; 165 + ]
+212
mail-flag/test/test_keyword.ml
···
··· 1 + (*--------------------------------------------------------------------------- 2 + Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 + 6 + (** Tests for the Keyword module. *) 7 + 8 + open Mail_flag 9 + 10 + let keyword_testable = 11 + Alcotest.testable Keyword.pp Keyword.equal 12 + 13 + let test_of_string_standard () = 14 + (* Test standard keywords with $ prefix *) 15 + Alcotest.(check keyword_testable) "seen with $" `Seen (Keyword.of_string "$seen"); 16 + Alcotest.(check keyword_testable) "answered with $" `Answered (Keyword.of_string "$answered"); 17 + Alcotest.(check keyword_testable) "flagged with $" `Flagged (Keyword.of_string "$flagged"); 18 + Alcotest.(check keyword_testable) "draft with $" `Draft (Keyword.of_string "$draft"); 19 + Alcotest.(check keyword_testable) "deleted with $" `Deleted (Keyword.of_string "$deleted"); 20 + Alcotest.(check keyword_testable) "forwarded with $" `Forwarded (Keyword.of_string "$forwarded") 21 + 22 + let test_of_string_no_prefix () = 23 + (* Test standard keywords without prefix *) 24 + Alcotest.(check keyword_testable) "seen no prefix" `Seen (Keyword.of_string "seen"); 25 + Alcotest.(check keyword_testable) "answered no prefix" `Answered (Keyword.of_string "answered"); 26 + Alcotest.(check keyword_testable) "flagged no prefix" `Flagged (Keyword.of_string "flagged") 27 + 28 + let test_of_string_case_insensitive () = 29 + (* Test case insensitivity *) 30 + Alcotest.(check keyword_testable) "SEEN uppercase" `Seen (Keyword.of_string "$SEEN"); 31 + Alcotest.(check keyword_testable) "Seen mixed" `Seen (Keyword.of_string "Seen"); 32 + Alcotest.(check keyword_testable) "FORWARDED uppercase" `Forwarded (Keyword.of_string "$FORWARDED") 33 + 34 + let test_of_string_imap_format () = 35 + (* Test IMAP system flag format with backslash *) 36 + Alcotest.(check keyword_testable) "\\Seen" `Seen (Keyword.of_string "\\Seen"); 37 + Alcotest.(check keyword_testable) "\\Answered" `Answered (Keyword.of_string "\\Answered"); 38 + Alcotest.(check keyword_testable) "\\Draft" `Draft (Keyword.of_string "\\Draft") 39 + 40 + let test_of_string_spam () = 41 + (* Test spam-related keywords *) 42 + Alcotest.(check keyword_testable) "phishing" `Phishing (Keyword.of_string "$phishing"); 43 + Alcotest.(check keyword_testable) "junk" `Junk (Keyword.of_string "$junk"); 44 + Alcotest.(check keyword_testable) "notjunk" `NotJunk (Keyword.of_string "$notjunk") 45 + 46 + let test_of_string_extended () = 47 + (* Test extended keywords *) 48 + Alcotest.(check keyword_testable) "hasattachment" `HasAttachment (Keyword.of_string "$hasattachment"); 49 + Alcotest.(check keyword_testable) "hasnoattachment" `HasNoAttachment (Keyword.of_string "$hasnoattachment"); 50 + Alcotest.(check keyword_testable) "muted" `Muted (Keyword.of_string "$muted"); 51 + Alcotest.(check keyword_testable) "followed" `Followed (Keyword.of_string "$followed") 52 + 53 + let test_of_string_flag_bits () = 54 + (* Test Apple Mail flag bits *) 55 + Alcotest.(check keyword_testable) "mailflagbit0" `MailFlagBit0 (Keyword.of_string "$mailflagbit0"); 56 + Alcotest.(check keyword_testable) "mailflagbit1" `MailFlagBit1 (Keyword.of_string "$mailflagbit1"); 57 + Alcotest.(check keyword_testable) "mailflagbit2" `MailFlagBit2 (Keyword.of_string "$mailflagbit2") 58 + 59 + let test_of_string_custom () = 60 + (* Test custom keywords *) 61 + Alcotest.(check keyword_testable) "custom keyword" (`Custom "my-label") (Keyword.of_string "my-label"); 62 + Alcotest.(check keyword_testable) "custom with $" (`Custom "custom") (Keyword.of_string "$custom") 63 + 64 + let test_to_string () = 65 + (* Test conversion to JMAP format *) 66 + Alcotest.(check string) "seen" "$seen" (Keyword.to_string `Seen); 67 + Alcotest.(check string) "answered" "$answered" (Keyword.to_string `Answered); 68 + Alcotest.(check string) "flagged" "$flagged" (Keyword.to_string `Flagged); 69 + Alcotest.(check string) "draft" "$draft" (Keyword.to_string `Draft); 70 + Alcotest.(check string) "deleted" "$deleted" (Keyword.to_string `Deleted); 71 + Alcotest.(check string) "forwarded" "$forwarded" (Keyword.to_string `Forwarded); 72 + Alcotest.(check string) "junk" "$junk" (Keyword.to_string `Junk); 73 + Alcotest.(check string) "mailflagbit0" "$MailFlagBit0" (Keyword.to_string `MailFlagBit0); 74 + Alcotest.(check string) "custom" "my-label" (Keyword.to_string (`Custom "my-label")) 75 + 76 + let test_to_imap_string () = 77 + (* Test conversion to IMAP format *) 78 + Alcotest.(check string) "seen" "\\Seen" (Keyword.to_imap_string `Seen); 79 + Alcotest.(check string) "answered" "\\Answered" (Keyword.to_imap_string `Answered); 80 + Alcotest.(check string) "flagged" "\\Flagged" (Keyword.to_imap_string `Flagged); 81 + Alcotest.(check string) "draft" "\\Draft" (Keyword.to_imap_string `Draft); 82 + Alcotest.(check string) "deleted" "\\Deleted" (Keyword.to_imap_string `Deleted); 83 + (* Non-system flags use $ prefix *) 84 + Alcotest.(check string) "forwarded" "$Forwarded" (Keyword.to_imap_string `Forwarded); 85 + Alcotest.(check string) "junk" "$Junk" (Keyword.to_imap_string `Junk); 86 + Alcotest.(check string) "mailflagbit0" "$MailFlagBit0" (Keyword.to_imap_string `MailFlagBit0) 87 + 88 + let test_is_standard () = 89 + (* Test is_standard predicate *) 90 + Alcotest.(check bool) "seen is standard" true (Keyword.is_standard `Seen); 91 + Alcotest.(check bool) "answered is standard" true (Keyword.is_standard `Answered); 92 + Alcotest.(check bool) "flagged is standard" true (Keyword.is_standard `Flagged); 93 + Alcotest.(check bool) "draft is standard" true (Keyword.is_standard `Draft); 94 + Alcotest.(check bool) "deleted is standard" true (Keyword.is_standard `Deleted); 95 + (* Forwarded is NOT an IMAP system flag *) 96 + Alcotest.(check bool) "forwarded is not standard" false (Keyword.is_standard `Forwarded); 97 + Alcotest.(check bool) "junk is not standard" false (Keyword.is_standard `Junk); 98 + Alcotest.(check bool) "custom is not standard" false (Keyword.is_standard (`Custom "x")) 99 + 100 + let test_mutual_exclusion () = 101 + (* Test mutually exclusive pairs *) 102 + Alcotest.(check bool) "has/hasno attachment" true 103 + (Keyword.is_mutually_exclusive `HasAttachment `HasNoAttachment); 104 + Alcotest.(check bool) "hasno/has attachment" true 105 + (Keyword.is_mutually_exclusive `HasNoAttachment `HasAttachment); 106 + Alcotest.(check bool) "junk/notjunk" true 107 + (Keyword.is_mutually_exclusive `Junk `NotJunk); 108 + Alcotest.(check bool) "notjunk/junk" true 109 + (Keyword.is_mutually_exclusive `NotJunk `Junk); 110 + Alcotest.(check bool) "muted/followed" true 111 + (Keyword.is_mutually_exclusive `Muted `Followed); 112 + Alcotest.(check bool) "followed/muted" true 113 + (Keyword.is_mutually_exclusive `Followed `Muted); 114 + (* Non-exclusive pairs *) 115 + Alcotest.(check bool) "seen/flagged" false 116 + (Keyword.is_mutually_exclusive `Seen `Flagged); 117 + Alcotest.(check bool) "seen/seen" false 118 + (Keyword.is_mutually_exclusive `Seen `Seen); 119 + Alcotest.(check bool) "junk/muted" false 120 + (Keyword.is_mutually_exclusive `Junk `Muted) 121 + 122 + let test_equal () = 123 + (* Test equality *) 124 + Alcotest.(check bool) "same keyword" true (Keyword.equal `Seen `Seen); 125 + Alcotest.(check bool) "different keywords" false (Keyword.equal `Seen `Flagged); 126 + (* Custom keywords are compared case-insensitively *) 127 + Alcotest.(check bool) "custom same" true (Keyword.equal (`Custom "label") (`Custom "label")); 128 + Alcotest.(check bool) "custom case insensitive" true (Keyword.equal (`Custom "Label") (`Custom "label")); 129 + Alcotest.(check bool) "custom different" false (Keyword.equal (`Custom "a") (`Custom "b")) 130 + 131 + let test_compare () = 132 + (* Test comparison *) 133 + Alcotest.(check int) "same keyword" 0 (Keyword.compare `Seen `Seen); 134 + Alcotest.(check bool) "custom vs non-custom" true (Keyword.compare (`Custom "a") `Seen > 0); 135 + Alcotest.(check bool) "non-custom vs custom" true (Keyword.compare `Seen (`Custom "a") < 0) 136 + 137 + let pp_flag_color ppf c = 138 + let s = match c with 139 + | `Red -> "Red" | `Orange -> "Orange" | `Yellow -> "Yellow" 140 + | `Green -> "Green" | `Blue -> "Blue" | `Purple -> "Purple" | `Gray -> "Gray" 141 + in 142 + Format.pp_print_string ppf s 143 + 144 + let eq_flag_color a b = 145 + match (a, b) with 146 + | `Red, `Red | `Orange, `Orange | `Yellow, `Yellow 147 + | `Green, `Green | `Blue, `Blue | `Purple, `Purple | `Gray, `Gray -> true 148 + | _ -> false 149 + 150 + let flag_color_testable = Alcotest.testable pp_flag_color eq_flag_color 151 + 152 + let test_flag_color_of_keywords () = 153 + (* Test Apple Mail flag color extraction *) 154 + Alcotest.(check (option flag_color_testable)) 155 + "no bits = red" (Some `Red) (Keyword.flag_color_of_keywords []); 156 + Alcotest.(check (option flag_color_testable)) 157 + "bit0 = orange" (Some `Orange) (Keyword.flag_color_of_keywords [`MailFlagBit0]); 158 + Alcotest.(check (option flag_color_testable)) 159 + "bit1 = yellow" (Some `Yellow) (Keyword.flag_color_of_keywords [`MailFlagBit1]); 160 + Alcotest.(check (option flag_color_testable)) 161 + "bit2 = blue" (Some `Blue) (Keyword.flag_color_of_keywords [`MailFlagBit2]); 162 + Alcotest.(check (option flag_color_testable)) 163 + "bits 0,2 = purple" (Some `Purple) (Keyword.flag_color_of_keywords [`MailFlagBit0; `MailFlagBit2]); 164 + Alcotest.(check (option flag_color_testable)) 165 + "bits 1,2 = gray" (Some `Gray) (Keyword.flag_color_of_keywords [`MailFlagBit1; `MailFlagBit2]); 166 + Alcotest.(check (option flag_color_testable)) 167 + "all bits = green" (Some `Green) (Keyword.flag_color_of_keywords [`MailFlagBit0; `MailFlagBit1; `MailFlagBit2]); 168 + (* Invalid encoding: bits 0 and 1 but not 2 *) 169 + Alcotest.(check (option flag_color_testable)) 170 + "bits 0,1 = invalid" None (Keyword.flag_color_of_keywords [`MailFlagBit0; `MailFlagBit1]) 171 + 172 + let test_flag_color_to_keywords () = 173 + (* Test Apple Mail flag color encoding *) 174 + Alcotest.(check int) "red = no bits" 0 (List.length (Keyword.flag_color_to_keywords `Red)); 175 + Alcotest.(check int) "orange = 1 bit" 1 (List.length (Keyword.flag_color_to_keywords `Orange)); 176 + Alcotest.(check int) "yellow = 1 bit" 1 (List.length (Keyword.flag_color_to_keywords `Yellow)); 177 + Alcotest.(check int) "blue = 1 bit" 1 (List.length (Keyword.flag_color_to_keywords `Blue)); 178 + Alcotest.(check int) "purple = 2 bits" 2 (List.length (Keyword.flag_color_to_keywords `Purple)); 179 + Alcotest.(check int) "gray = 2 bits" 2 (List.length (Keyword.flag_color_to_keywords `Gray)); 180 + Alcotest.(check int) "green = 3 bits" 3 (List.length (Keyword.flag_color_to_keywords `Green)) 181 + 182 + let () = 183 + Alcotest.run "Keyword" [ 184 + "of_string", [ 185 + Alcotest.test_case "standard keywords" `Quick test_of_string_standard; 186 + Alcotest.test_case "no prefix" `Quick test_of_string_no_prefix; 187 + Alcotest.test_case "case insensitive" `Quick test_of_string_case_insensitive; 188 + Alcotest.test_case "IMAP format" `Quick test_of_string_imap_format; 189 + Alcotest.test_case "spam keywords" `Quick test_of_string_spam; 190 + Alcotest.test_case "extended keywords" `Quick test_of_string_extended; 191 + Alcotest.test_case "flag bits" `Quick test_of_string_flag_bits; 192 + Alcotest.test_case "custom" `Quick test_of_string_custom; 193 + ]; 194 + "to_string", [ 195 + Alcotest.test_case "JMAP format" `Quick test_to_string; 196 + ]; 197 + "to_imap_string", [ 198 + Alcotest.test_case "IMAP format" `Quick test_to_imap_string; 199 + ]; 200 + "predicates", [ 201 + Alcotest.test_case "is_standard" `Quick test_is_standard; 202 + Alcotest.test_case "is_mutually_exclusive" `Quick test_mutual_exclusion; 203 + ]; 204 + "equality", [ 205 + Alcotest.test_case "equal" `Quick test_equal; 206 + Alcotest.test_case "compare" `Quick test_compare; 207 + ]; 208 + "flag_color", [ 209 + Alcotest.test_case "of_keywords" `Quick test_flag_color_of_keywords; 210 + Alcotest.test_case "to_keywords" `Quick test_flag_color_to_keywords; 211 + ]; 212 + ]
+174
mail-flag/test/test_mailbox_attr.ml
···
··· 1 + (*--------------------------------------------------------------------------- 2 + Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 + 6 + (** Tests for the Mailbox_attr module. *) 7 + 8 + open Mail_flag 9 + 10 + let attr_testable = 11 + Alcotest.testable Mailbox_attr.pp (fun a b -> 12 + Mailbox_attr.to_string a = Mailbox_attr.to_string b) 13 + 14 + (* A testable for special_use which is a subtype of t *) 15 + let pp_special_use ppf (x : Mailbox_attr.special_use) = 16 + Mailbox_attr.pp ppf (x :> Mailbox_attr.t) 17 + 18 + let special_use_testable : Mailbox_attr.special_use Alcotest.testable = 19 + Alcotest.testable pp_special_use (fun a b -> 20 + Mailbox_attr.to_string (a :> Mailbox_attr.t) = Mailbox_attr.to_string (b :> Mailbox_attr.t)) 21 + 22 + let test_of_string_special_use () = 23 + (* Test special-use attributes with backslash prefix *) 24 + Alcotest.(check attr_testable) "\\Drafts" `Drafts (Mailbox_attr.of_string "\\Drafts"); 25 + Alcotest.(check attr_testable) "\\Sent" `Sent (Mailbox_attr.of_string "\\Sent"); 26 + Alcotest.(check attr_testable) "\\Trash" `Trash (Mailbox_attr.of_string "\\Trash"); 27 + Alcotest.(check attr_testable) "\\Junk" `Junk (Mailbox_attr.of_string "\\Junk"); 28 + Alcotest.(check attr_testable) "\\Archive" `Archive (Mailbox_attr.of_string "\\Archive"); 29 + Alcotest.(check attr_testable) "\\All" `All (Mailbox_attr.of_string "\\All"); 30 + Alcotest.(check attr_testable) "\\Flagged" `Flagged (Mailbox_attr.of_string "\\Flagged"); 31 + Alcotest.(check attr_testable) "\\Important" `Important (Mailbox_attr.of_string "\\Important"); 32 + Alcotest.(check attr_testable) "\\Inbox" `Inbox (Mailbox_attr.of_string "\\Inbox") 33 + 34 + let test_of_string_no_backslash () = 35 + (* Test special-use attributes without backslash prefix *) 36 + Alcotest.(check attr_testable) "drafts" `Drafts (Mailbox_attr.of_string "drafts"); 37 + Alcotest.(check attr_testable) "sent" `Sent (Mailbox_attr.of_string "sent"); 38 + Alcotest.(check attr_testable) "trash" `Trash (Mailbox_attr.of_string "trash"); 39 + Alcotest.(check attr_testable) "inbox" `Inbox (Mailbox_attr.of_string "inbox") 40 + 41 + let test_of_string_case_insensitive () = 42 + (* Test case insensitivity *) 43 + Alcotest.(check attr_testable) "DRAFTS" `Drafts (Mailbox_attr.of_string "DRAFTS"); 44 + Alcotest.(check attr_testable) "\\SENT" `Sent (Mailbox_attr.of_string "\\SENT"); 45 + Alcotest.(check attr_testable) "Trash" `Trash (Mailbox_attr.of_string "Trash") 46 + 47 + let test_of_string_list_attrs () = 48 + (* Test LIST attributes *) 49 + Alcotest.(check attr_testable) "\\Noinferiors" `Noinferiors (Mailbox_attr.of_string "\\Noinferiors"); 50 + Alcotest.(check attr_testable) "\\Noselect" `Noselect (Mailbox_attr.of_string "\\Noselect"); 51 + Alcotest.(check attr_testable) "\\Marked" `Marked (Mailbox_attr.of_string "\\Marked"); 52 + Alcotest.(check attr_testable) "\\Unmarked" `Unmarked (Mailbox_attr.of_string "\\Unmarked"); 53 + Alcotest.(check attr_testable) "\\Subscribed" `Subscribed (Mailbox_attr.of_string "\\Subscribed"); 54 + Alcotest.(check attr_testable) "\\HasChildren" `HasChildren (Mailbox_attr.of_string "\\HasChildren"); 55 + Alcotest.(check attr_testable) "\\HasNoChildren" `HasNoChildren (Mailbox_attr.of_string "\\HasNoChildren"); 56 + Alcotest.(check attr_testable) "\\NonExistent" `NonExistent (Mailbox_attr.of_string "\\NonExistent"); 57 + Alcotest.(check attr_testable) "\\Remote" `Remote (Mailbox_attr.of_string "\\Remote") 58 + 59 + let test_of_string_junk_alias () = 60 + (* Test that "spam" is recognized as Junk *) 61 + Alcotest.(check attr_testable) "spam" `Junk (Mailbox_attr.of_string "spam"); 62 + Alcotest.(check attr_testable) "\\Spam" `Junk (Mailbox_attr.of_string "\\Spam") 63 + 64 + let test_of_string_extended () = 65 + (* Test extended special-use attributes *) 66 + Alcotest.(check attr_testable) "\\Snoozed" `Snoozed (Mailbox_attr.of_string "\\Snoozed"); 67 + Alcotest.(check attr_testable) "\\Scheduled" `Scheduled (Mailbox_attr.of_string "\\Scheduled"); 68 + Alcotest.(check attr_testable) "\\Memos" `Memos (Mailbox_attr.of_string "\\Memos") 69 + 70 + let test_of_string_extension () = 71 + (* Test unknown extensions *) 72 + Alcotest.(check attr_testable) "X-Custom" (`Extension "x-custom") (Mailbox_attr.of_string "X-Custom"); 73 + Alcotest.(check attr_testable) "\\X-MyAttr" (`Extension "x-myattr") (Mailbox_attr.of_string "\\X-MyAttr") 74 + 75 + let test_to_string () = 76 + (* Test conversion to IMAP wire format *) 77 + Alcotest.(check string) "Drafts" "\\Drafts" (Mailbox_attr.to_string `Drafts); 78 + Alcotest.(check string) "Sent" "\\Sent" (Mailbox_attr.to_string `Sent); 79 + Alcotest.(check string) "Trash" "\\Trash" (Mailbox_attr.to_string `Trash); 80 + Alcotest.(check string) "Junk" "\\Junk" (Mailbox_attr.to_string `Junk); 81 + Alcotest.(check string) "Inbox" "\\Inbox" (Mailbox_attr.to_string `Inbox); 82 + Alcotest.(check string) "Noselect" "\\Noselect" (Mailbox_attr.to_string `Noselect); 83 + Alcotest.(check string) "HasChildren" "\\HasChildren" (Mailbox_attr.to_string `HasChildren); 84 + Alcotest.(check string) "Extension" "\\x-custom" (Mailbox_attr.to_string (`Extension "x-custom")) 85 + 86 + let test_to_jmap_role () = 87 + (* Test special-use to JMAP role conversion *) 88 + Alcotest.(check (option string)) "drafts role" (Some "drafts") (Mailbox_attr.to_jmap_role `Drafts); 89 + Alcotest.(check (option string)) "sent role" (Some "sent") (Mailbox_attr.to_jmap_role `Sent); 90 + Alcotest.(check (option string)) "trash role" (Some "trash") (Mailbox_attr.to_jmap_role `Trash); 91 + Alcotest.(check (option string)) "junk role" (Some "junk") (Mailbox_attr.to_jmap_role `Junk); 92 + Alcotest.(check (option string)) "inbox role" (Some "inbox") (Mailbox_attr.to_jmap_role `Inbox); 93 + Alcotest.(check (option string)) "archive role" (Some "archive") (Mailbox_attr.to_jmap_role `Archive); 94 + Alcotest.(check (option string)) "all role" (Some "all") (Mailbox_attr.to_jmap_role `All); 95 + Alcotest.(check (option string)) "flagged role" (Some "flagged") (Mailbox_attr.to_jmap_role `Flagged); 96 + Alcotest.(check (option string)) "important role" (Some "important") (Mailbox_attr.to_jmap_role `Important); 97 + Alcotest.(check (option string)) "snoozed role" (Some "snoozed") (Mailbox_attr.to_jmap_role `Snoozed); 98 + Alcotest.(check (option string)) "scheduled role" (Some "scheduled") (Mailbox_attr.to_jmap_role `Scheduled); 99 + Alcotest.(check (option string)) "memos role" (Some "memos") (Mailbox_attr.to_jmap_role `Memos); 100 + (* LIST attributes have no JMAP role *) 101 + Alcotest.(check (option string)) "noselect no role" None (Mailbox_attr.to_jmap_role `Noselect); 102 + Alcotest.(check (option string)) "haschildren no role" None (Mailbox_attr.to_jmap_role `HasChildren); 103 + Alcotest.(check (option string)) "extension no role" None (Mailbox_attr.to_jmap_role (`Extension "x")) 104 + 105 + let test_of_jmap_role () = 106 + (* Test JMAP role to special-use conversion *) 107 + Alcotest.(check (option special_use_testable)) "drafts" (Some `Drafts) (Mailbox_attr.of_jmap_role "drafts"); 108 + Alcotest.(check (option special_use_testable)) "sent" (Some `Sent) (Mailbox_attr.of_jmap_role "sent"); 109 + Alcotest.(check (option special_use_testable)) "trash" (Some `Trash) (Mailbox_attr.of_jmap_role "trash"); 110 + Alcotest.(check (option special_use_testable)) "junk" (Some `Junk) (Mailbox_attr.of_jmap_role "junk"); 111 + Alcotest.(check (option special_use_testable)) "inbox" (Some `Inbox) (Mailbox_attr.of_jmap_role "inbox"); 112 + Alcotest.(check (option special_use_testable)) "unknown" None (Mailbox_attr.of_jmap_role "unknown") 113 + 114 + let test_is_special_use () = 115 + (* Test is_special_use predicate *) 116 + Alcotest.(check bool) "drafts is special-use" true (Mailbox_attr.is_special_use `Drafts); 117 + Alcotest.(check bool) "sent is special-use" true (Mailbox_attr.is_special_use `Sent); 118 + Alcotest.(check bool) "inbox is special-use" true (Mailbox_attr.is_special_use `Inbox); 119 + Alcotest.(check bool) "subscribed is special-use" true (Mailbox_attr.is_special_use `Subscribed); 120 + (* LIST attributes are not special-use *) 121 + Alcotest.(check bool) "noselect not special-use" false (Mailbox_attr.is_special_use `Noselect); 122 + Alcotest.(check bool) "haschildren not special-use" false (Mailbox_attr.is_special_use `HasChildren); 123 + Alcotest.(check bool) "extension not special-use" false (Mailbox_attr.is_special_use (`Extension "x")) 124 + 125 + let test_is_selectable () = 126 + (* Test is_selectable predicate *) 127 + Alcotest.(check bool) "drafts selectable" true (Mailbox_attr.is_selectable `Drafts); 128 + Alcotest.(check bool) "inbox selectable" true (Mailbox_attr.is_selectable `Inbox); 129 + Alcotest.(check bool) "haschildren selectable" true (Mailbox_attr.is_selectable `HasChildren); 130 + (* Noselect and NonExistent are not selectable *) 131 + Alcotest.(check bool) "noselect not selectable" false (Mailbox_attr.is_selectable `Noselect); 132 + Alcotest.(check bool) "nonexistent not selectable" false (Mailbox_attr.is_selectable `NonExistent) 133 + 134 + let test_roundtrip () = 135 + (* Test that to_string -> of_string preserves the attribute *) 136 + let test_attr attr = 137 + let s = Mailbox_attr.to_string attr in 138 + Alcotest.(check attr_testable) ("roundtrip " ^ s) attr (Mailbox_attr.of_string s) 139 + in 140 + test_attr `Drafts; 141 + test_attr `Sent; 142 + test_attr `Trash; 143 + test_attr `Junk; 144 + test_attr `Inbox; 145 + test_attr `Noselect; 146 + test_attr `HasChildren; 147 + test_attr `Snoozed 148 + 149 + let () = 150 + Alcotest.run "Mailbox_attr" [ 151 + "of_string", [ 152 + Alcotest.test_case "special-use with backslash" `Quick test_of_string_special_use; 153 + Alcotest.test_case "special-use no backslash" `Quick test_of_string_no_backslash; 154 + Alcotest.test_case "case insensitive" `Quick test_of_string_case_insensitive; 155 + Alcotest.test_case "LIST attributes" `Quick test_of_string_list_attrs; 156 + Alcotest.test_case "junk/spam alias" `Quick test_of_string_junk_alias; 157 + Alcotest.test_case "extended attributes" `Quick test_of_string_extended; 158 + Alcotest.test_case "extensions" `Quick test_of_string_extension; 159 + ]; 160 + "to_string", [ 161 + Alcotest.test_case "IMAP wire format" `Quick test_to_string; 162 + ]; 163 + "JMAP roles", [ 164 + Alcotest.test_case "to_jmap_role" `Quick test_to_jmap_role; 165 + Alcotest.test_case "of_jmap_role" `Quick test_of_jmap_role; 166 + ]; 167 + "predicates", [ 168 + Alcotest.test_case "is_special_use" `Quick test_is_special_use; 169 + Alcotest.test_case "is_selectable" `Quick test_is_selectable; 170 + ]; 171 + "roundtrip", [ 172 + Alcotest.test_case "to_string -> of_string" `Quick test_roundtrip; 173 + ]; 174 + ]
+190
mail-flag/test/test_wire.ml
···
··· 1 + (*--------------------------------------------------------------------------- 2 + Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 + 6 + (** Tests for the Imap_wire and Jmap_wire modules. *) 7 + 8 + open Mail_flag 9 + 10 + let keyword_testable = 11 + Alcotest.testable Keyword.pp Keyword.equal 12 + 13 + let flag_testable = 14 + Alcotest.testable Imap_wire.pp_flag (fun a b -> 15 + Imap_wire.flag_to_string a = Imap_wire.flag_to_string b) 16 + 17 + (* IMAP Wire Tests *) 18 + 19 + let test_imap_flag_of_string_system () = 20 + (* Test parsing of IMAP system flags *) 21 + Alcotest.(check flag_testable) "\\Seen" (Imap_wire.System `Seen) (Imap_wire.flag_of_string "\\Seen"); 22 + Alcotest.(check flag_testable) "\\Answered" (Imap_wire.System `Answered) (Imap_wire.flag_of_string "\\Answered"); 23 + Alcotest.(check flag_testable) "\\Flagged" (Imap_wire.System `Flagged) (Imap_wire.flag_of_string "\\Flagged"); 24 + Alcotest.(check flag_testable) "\\Deleted" (Imap_wire.System `Deleted) (Imap_wire.flag_of_string "\\Deleted"); 25 + Alcotest.(check flag_testable) "\\Draft" (Imap_wire.System `Draft) (Imap_wire.flag_of_string "\\Draft") 26 + 27 + let test_imap_flag_of_string_system_no_backslash () = 28 + (* Test parsing of system flags without backslash *) 29 + Alcotest.(check flag_testable) "Seen" (Imap_wire.System `Seen) (Imap_wire.flag_of_string "Seen"); 30 + Alcotest.(check flag_testable) "answered" (Imap_wire.System `Answered) (Imap_wire.flag_of_string "answered") 31 + 32 + let test_imap_flag_of_string_keyword () = 33 + (* Test parsing of IMAP keywords *) 34 + Alcotest.(check flag_testable) "$forwarded" (Imap_wire.Keyword `Forwarded) (Imap_wire.flag_of_string "$forwarded"); 35 + Alcotest.(check flag_testable) "$junk" (Imap_wire.Keyword `Junk) (Imap_wire.flag_of_string "$junk"); 36 + Alcotest.(check flag_testable) "$MailFlagBit0" (Imap_wire.Keyword `MailFlagBit0) (Imap_wire.flag_of_string "$MailFlagBit0") 37 + 38 + let test_imap_flag_of_string_custom () = 39 + (* Test parsing of custom keywords *) 40 + Alcotest.(check flag_testable) "custom" (Imap_wire.Keyword (`Custom "custom")) (Imap_wire.flag_of_string "custom") 41 + 42 + let test_imap_flag_to_string () = 43 + (* Test conversion to IMAP wire format *) 44 + Alcotest.(check string) "\\Seen" "\\Seen" (Imap_wire.flag_to_string (System `Seen)); 45 + Alcotest.(check string) "\\Answered" "\\Answered" (Imap_wire.flag_to_string (System `Answered)); 46 + Alcotest.(check string) "\\Flagged" "\\Flagged" (Imap_wire.flag_to_string (System `Flagged)); 47 + Alcotest.(check string) "\\Deleted" "\\Deleted" (Imap_wire.flag_to_string (System `Deleted)); 48 + Alcotest.(check string) "\\Draft" "\\Draft" (Imap_wire.flag_to_string (System `Draft)); 49 + Alcotest.(check string) "$Forwarded" "$Forwarded" (Imap_wire.flag_to_string (Keyword `Forwarded)); 50 + Alcotest.(check string) "$Junk" "$Junk" (Imap_wire.flag_to_string (Keyword `Junk)) 51 + 52 + let test_imap_flags_of_keywords () = 53 + (* Test conversion from keyword list to flag list *) 54 + let flags = Imap_wire.flags_of_keywords [`Seen; `Forwarded; `Custom "label"] in 55 + Alcotest.(check int) "3 flags" 3 (List.length flags); 56 + Alcotest.(check flag_testable) "first is system" (System `Seen) (List.nth flags 0); 57 + Alcotest.(check flag_testable) "second is keyword" (Keyword `Forwarded) (List.nth flags 1); 58 + Alcotest.(check flag_testable) "third is custom" (Keyword (`Custom "label")) (List.nth flags 2) 59 + 60 + let test_imap_keywords_of_flags () = 61 + (* Test conversion from flag list to keyword list *) 62 + let keywords = Imap_wire.keywords_of_flags [System `Seen; Keyword `Forwarded] in 63 + Alcotest.(check int) "2 keywords" 2 (List.length keywords); 64 + Alcotest.(check keyword_testable) "first" `Seen (List.nth keywords 0); 65 + Alcotest.(check keyword_testable) "second" `Forwarded (List.nth keywords 1) 66 + 67 + let test_imap_attr_of_string () = 68 + (* Test mailbox attribute parsing *) 69 + let attr = Imap_wire.attr_of_string "\\Drafts" in 70 + Alcotest.(check string) "\\Drafts" "\\Drafts" (Imap_wire.attr_to_string attr) 71 + 72 + let test_imap_attr_to_string () = 73 + (* Test mailbox attribute to string *) 74 + Alcotest.(check string) "\\Drafts" "\\Drafts" (Imap_wire.attr_to_string `Drafts); 75 + Alcotest.(check string) "\\HasChildren" "\\HasChildren" (Imap_wire.attr_to_string `HasChildren) 76 + 77 + (* JMAP Wire Tests *) 78 + 79 + let test_jmap_keywords_to_assoc () = 80 + (* Test conversion to JMAP keywords object *) 81 + let kws = [`Seen; `Flagged; `Custom "label"] in 82 + let assoc = Jmap_wire.keywords_to_assoc kws in 83 + Alcotest.(check int) "3 entries" 3 (List.length assoc); 84 + (* Check that all values are true *) 85 + List.iter (fun (_, v) -> 86 + Alcotest.(check bool) "value is true" true v 87 + ) assoc; 88 + (* Check specific keys *) 89 + Alcotest.(check bool) "$seen present" true (List.mem_assoc "$seen" assoc); 90 + Alcotest.(check bool) "$flagged present" true (List.mem_assoc "$flagged" assoc); 91 + Alcotest.(check bool) "label present" true (List.mem_assoc "label" assoc) 92 + 93 + let test_jmap_keywords_of_assoc () = 94 + (* Test conversion from JMAP keywords object *) 95 + let assoc = [("$seen", true); ("$draft", false); ("label", true)] in 96 + let keywords = Jmap_wire.keywords_of_assoc assoc in 97 + (* Only entries with true value are included *) 98 + Alcotest.(check int) "2 keywords" 2 (List.length keywords); 99 + Alcotest.(check bool) "seen present" true (List.exists (Keyword.equal `Seen) keywords); 100 + Alcotest.(check bool) "draft not present" false (List.exists (Keyword.equal `Draft) keywords); 101 + Alcotest.(check bool) "custom present" true (List.exists (Keyword.equal (`Custom "label")) keywords) 102 + 103 + let test_jmap_keywords_roundtrip () = 104 + (* Test roundtrip: keywords -> assoc -> keywords *) 105 + let original = [`Seen; `Flagged; `Forwarded] in 106 + let assoc = Jmap_wire.keywords_to_assoc original in 107 + let result = Jmap_wire.keywords_of_assoc assoc in 108 + Alcotest.(check int) "same length" (List.length original) (List.length result); 109 + List.iter (fun k -> 110 + Alcotest.(check bool) (Keyword.to_string k) true (List.exists (Keyword.equal k) result) 111 + ) original 112 + 113 + let test_jmap_role_to_string () = 114 + (* Test role to string conversion *) 115 + Alcotest.(check string) "drafts" "drafts" (Jmap_wire.role_to_string `Drafts); 116 + Alcotest.(check string) "sent" "sent" (Jmap_wire.role_to_string `Sent); 117 + Alcotest.(check string) "trash" "trash" (Jmap_wire.role_to_string `Trash); 118 + Alcotest.(check string) "junk" "junk" (Jmap_wire.role_to_string `Junk); 119 + Alcotest.(check string) "inbox" "inbox" (Jmap_wire.role_to_string `Inbox); 120 + Alcotest.(check string) "archive" "archive" (Jmap_wire.role_to_string `Archive); 121 + Alcotest.(check string) "all" "all" (Jmap_wire.role_to_string `All); 122 + Alcotest.(check string) "flagged" "flagged" (Jmap_wire.role_to_string `Flagged); 123 + Alcotest.(check string) "important" "important" (Jmap_wire.role_to_string `Important); 124 + Alcotest.(check string) "subscribed" "subscribed" (Jmap_wire.role_to_string `Subscribed); 125 + Alcotest.(check string) "snoozed" "snoozed" (Jmap_wire.role_to_string `Snoozed); 126 + Alcotest.(check string) "scheduled" "scheduled" (Jmap_wire.role_to_string `Scheduled); 127 + Alcotest.(check string) "memos" "memos" (Jmap_wire.role_to_string `Memos) 128 + 129 + let pp_special_use ppf (su : Mailbox_attr.special_use) = 130 + Mailbox_attr.pp ppf (su :> Mailbox_attr.t) 131 + 132 + let special_use_testable : Mailbox_attr.special_use Alcotest.testable = 133 + Alcotest.testable pp_special_use (fun a b -> 134 + Mailbox_attr.to_string (a :> Mailbox_attr.t) = Mailbox_attr.to_string (b :> Mailbox_attr.t)) 135 + 136 + let test_jmap_role_of_string () = 137 + (* Test string to role conversion *) 138 + Alcotest.(check (option special_use_testable)) "drafts" (Some `Drafts) (Jmap_wire.role_of_string "drafts"); 139 + Alcotest.(check (option special_use_testable)) "sent" (Some `Sent) (Jmap_wire.role_of_string "sent"); 140 + Alcotest.(check (option special_use_testable)) "inbox" (Some `Inbox) (Jmap_wire.role_of_string "inbox"); 141 + Alcotest.(check (option special_use_testable)) "unknown" None (Jmap_wire.role_of_string "unknown") 142 + 143 + let test_jmap_role_roundtrip () = 144 + (* Test roundtrip: role -> string -> role *) 145 + let test_role role = 146 + let s = Jmap_wire.role_to_string role in 147 + Alcotest.(check (option special_use_testable)) s (Some role) (Jmap_wire.role_of_string s) 148 + in 149 + test_role `Drafts; 150 + test_role `Sent; 151 + test_role `Trash; 152 + test_role `Junk; 153 + test_role `Inbox; 154 + test_role `Archive; 155 + test_role `All; 156 + test_role `Flagged; 157 + test_role `Important; 158 + test_role `Subscribed; 159 + test_role `Snoozed; 160 + test_role `Scheduled; 161 + test_role `Memos 162 + 163 + let () = 164 + Alcotest.run "Wire formats" [ 165 + "Imap_wire.flag", [ 166 + Alcotest.test_case "flag_of_string system" `Quick test_imap_flag_of_string_system; 167 + Alcotest.test_case "flag_of_string no backslash" `Quick test_imap_flag_of_string_system_no_backslash; 168 + Alcotest.test_case "flag_of_string keyword" `Quick test_imap_flag_of_string_keyword; 169 + Alcotest.test_case "flag_of_string custom" `Quick test_imap_flag_of_string_custom; 170 + Alcotest.test_case "flag_to_string" `Quick test_imap_flag_to_string; 171 + ]; 172 + "Imap_wire.flags", [ 173 + Alcotest.test_case "flags_of_keywords" `Quick test_imap_flags_of_keywords; 174 + Alcotest.test_case "keywords_of_flags" `Quick test_imap_keywords_of_flags; 175 + ]; 176 + "Imap_wire.attr", [ 177 + Alcotest.test_case "attr_of_string" `Quick test_imap_attr_of_string; 178 + Alcotest.test_case "attr_to_string" `Quick test_imap_attr_to_string; 179 + ]; 180 + "Jmap_wire.keywords", [ 181 + Alcotest.test_case "keywords_to_assoc" `Quick test_jmap_keywords_to_assoc; 182 + Alcotest.test_case "keywords_of_assoc" `Quick test_jmap_keywords_of_assoc; 183 + Alcotest.test_case "roundtrip" `Quick test_jmap_keywords_roundtrip; 184 + ]; 185 + "Jmap_wire.role", [ 186 + Alcotest.test_case "role_to_string" `Quick test_jmap_role_to_string; 187 + Alcotest.test_case "role_of_string" `Quick test_jmap_role_of_string; 188 + Alcotest.test_case "roundtrip" `Quick test_jmap_role_roundtrip; 189 + ]; 190 + ]
+35 -31
monopam/lib/monopam.ml
··· 713 end 714 else begin 715 let checkout_eio = Eio.Path.(fs / Fpath.to_string checkout_dir) in 716 - match Eio.Path.kind ~follow:true checkout_eio with 717 - | exception Eio.Io _ -> 718 - Log.debug (fun m -> 719 - m "Checkout %a does not exist, skipping" Fpath.pp checkout_dir); 720 - Ok () 721 - | `Directory when Git.is_repo ~proc ~fs checkout_dir -> 722 - let monorepo_eio = Eio.Path.(fs / Fpath.to_string monorepo) in 723 - let checkout_path = Fpath.to_string checkout_dir in 724 - (* Push subtree to a sync branch (avoids "branch is checked out" error) *) 725 - Log.info (fun m -> m "Pushing subtree %s to checkout" prefix); 726 - let* _ = 727 - run_git_in ~proc ~cwd:monorepo_eio 728 - [ 729 - "subtree"; "push"; "--prefix"; prefix; checkout_path; sync_branch; 730 - ] 731 - in 732 - (* Merge sync branch into the target branch in checkout *) 733 - Log.debug (fun m -> m "Merging %s into %s" sync_branch branch); 734 - let* _ = 735 - run_git_in ~proc ~cwd:checkout_eio 736 - [ "merge"; "--ff-only"; sync_branch ] 737 - in 738 - (* Delete the sync branch *) 739 - Log.debug (fun m -> m "Cleaning up %s branch" sync_branch); 740 - ignore 741 - (run_git_in ~proc ~cwd:checkout_eio [ "branch"; "-d"; sync_branch ]); 742 - Ok () 743 - | _ -> 744 - Log.debug (fun m -> 745 - m "Checkout %a is not a git repo, skipping" Fpath.pp checkout_dir); 746 - Ok () 747 end 748 749 let push ~proc ~fs ~config ?package ?(upstream = false) () =
··· 713 end 714 else begin 715 let checkout_eio = Eio.Path.(fs / Fpath.to_string checkout_dir) in 716 + let needs_clone = 717 + match Eio.Path.kind ~follow:true checkout_eio with 718 + | exception Eio.Io _ -> true 719 + | `Directory when Git.is_repo ~proc ~fs checkout_dir -> false 720 + | _ -> true 721 + in 722 + let* () = 723 + if needs_clone then begin 724 + Log.info (fun m -> 725 + m "Creating checkout for %s" (Package.repo_name pkg)); 726 + ensure_checkout ~proc ~fs:(fs :> _ Eio.Path.t) ~config pkg 727 + end 728 + else Ok () 729 + in 730 + let monorepo_eio = Eio.Path.(fs / Fpath.to_string monorepo) in 731 + let checkout_path = Fpath.to_string checkout_dir in 732 + (* Push subtree to a sync branch (avoids "branch is checked out" error) *) 733 + Log.info (fun m -> m "Pushing subtree %s to checkout" prefix); 734 + let* _ = 735 + run_git_in ~proc ~cwd:monorepo_eio 736 + [ 737 + "subtree"; "push"; "--prefix"; prefix; checkout_path; sync_branch; 738 + ] 739 + in 740 + (* Merge sync branch into the target branch in checkout *) 741 + Log.debug (fun m -> m "Merging %s into %s" sync_branch branch); 742 + let* _ = 743 + run_git_in ~proc ~cwd:checkout_eio 744 + [ "merge"; "--ff-only"; sync_branch ] 745 + in 746 + (* Delete the sync branch *) 747 + Log.debug (fun m -> m "Cleaning up %s branch" sync_branch); 748 + ignore 749 + (run_git_in ~proc ~cwd:checkout_eio [ "branch"; "-d"; sync_branch ]); 750 + Ok () 751 end 752 753 let push ~proc ~fs ~config ?package ?(upstream = false) () =
+76 -76
ocaml-atp/lexicons/atproto/atp_lexicon_atproto.ml
··· 16 module Com = struct 17 module Atproto = struct 18 module Repo = struct 19 - module StrongRef = struct 20 - type main = { 21 - cid : string; 22 - uri : string; 23 - } 24 - 25 - let main_jsont = 26 - Jsont.Object.map ~kind:"Main" 27 - (fun _typ cid uri -> { cid; uri }) 28 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"com.atproto.repo.strongRef" ~enc:(fun _ -> "com.atproto.repo.strongRef") 29 - |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 30 - |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 31 - |> Jsont.Object.finish 32 - 33 - end 34 module Defs = struct 35 type commit_meta = { 36 cid : string; ··· 43 |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"com.atproto.repo.defs#commitMeta" ~enc:(fun _ -> "com.atproto.repo.defs#commitMeta") 44 |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 45 |> Jsont.Object.mem "rev" Jsont.string ~enc:(fun r -> r.rev) 46 |> Jsont.Object.finish 47 48 end ··· 105 |> Jsont.Object.finish 106 107 end 108 - module GetRecord = struct 109 - type params = { 110 - cid : string option; 111 - collection : string; 112 - repo : string; 113 - rkey : string; 114 - } 115 - 116 - let params_jsont = 117 - Jsont.Object.map ~kind:"Params" 118 - (fun cid collection repo rkey -> { 119 - cid; 120 - collection; 121 - repo; 122 - rkey; 123 - }) 124 - |> Jsont.Object.opt_mem "cid" Jsont.string 125 - ~enc:(fun r -> r.cid) 126 - |> Jsont.Object.mem "collection" Jsont.string 127 - ~enc:(fun r -> r.collection) 128 - |> Jsont.Object.mem "repo" Jsont.string 129 - ~enc:(fun r -> r.repo) 130 - |> Jsont.Object.mem "rkey" Jsont.string 131 - ~enc:(fun r -> r.rkey) 132 - |> Jsont.Object.finish 133 - 134 - type output = { 135 - cid : string option; 136 uri : string; 137 - value : Jsont.json; 138 } 139 140 - let output_jsont = 141 - Jsont.Object.map ~kind:"Output" 142 - (fun _typ cid uri value -> { cid; uri; value }) 143 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"com.atproto.repo.getRecord#output" ~enc:(fun _ -> "com.atproto.repo.getRecord#output") 144 - |> Jsont.Object.opt_mem "cid" Jsont.string ~enc:(fun r -> r.cid) 145 |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 146 - |> Jsont.Object.mem "value" Jsont.json ~enc:(fun r -> r.value) 147 |> Jsont.Object.finish 148 149 end ··· 189 |> Jsont.Object.finish 190 191 end 192 - module DeleteRecord = struct 193 type input = { 194 collection : string; 195 repo : string; 196 - rkey : string; 197 swap_commit : string option; 198 - swap_record : string option; 199 } 200 201 let input_jsont = 202 Jsont.Object.map ~kind:"Input" 203 - (fun _typ collection repo rkey swap_commit swap_record -> { collection; repo; rkey; swap_commit; swap_record }) 204 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"com.atproto.repo.deleteRecord#input" ~enc:(fun _ -> "com.atproto.repo.deleteRecord#input") 205 |> Jsont.Object.mem "collection" Jsont.string ~enc:(fun r -> r.collection) 206 |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 207 - |> Jsont.Object.mem "rkey" Jsont.string ~enc:(fun r -> r.rkey) 208 |> Jsont.Object.opt_mem "swapCommit" Jsont.string ~enc:(fun r -> r.swap_commit) 209 - |> Jsont.Object.opt_mem "swapRecord" Jsont.string ~enc:(fun r -> r.swap_record) 210 |> Jsont.Object.finish 211 212 type output = { 213 commit : Defs.commit_meta option; 214 } 215 216 let output_jsont = 217 Jsont.Object.map ~kind:"Output" 218 - (fun _typ commit -> { commit }) 219 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"com.atproto.repo.deleteRecord#output" ~enc:(fun _ -> "com.atproto.repo.deleteRecord#output") 220 |> Jsont.Object.opt_mem "commit" Defs.commit_meta_jsont ~enc:(fun r -> r.commit) 221 |> Jsont.Object.finish 222 223 end 224 - module CreateRecord = struct 225 type input = { 226 collection : string; 227 - record : Jsont.json; 228 repo : string; 229 - rkey : string option; 230 swap_commit : string option; 231 - validate : bool option; 232 } 233 234 let input_jsont = 235 Jsont.Object.map ~kind:"Input" 236 - (fun _typ collection record repo rkey swap_commit validate -> { collection; record; repo; rkey; swap_commit; validate }) 237 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"com.atproto.repo.createRecord#input" ~enc:(fun _ -> "com.atproto.repo.createRecord#input") 238 |> Jsont.Object.mem "collection" Jsont.string ~enc:(fun r -> r.collection) 239 - |> Jsont.Object.mem "record" Jsont.json ~enc:(fun r -> r.record) 240 |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 241 - |> Jsont.Object.opt_mem "rkey" Jsont.string ~enc:(fun r -> r.rkey) 242 |> Jsont.Object.opt_mem "swapCommit" Jsont.string ~enc:(fun r -> r.swap_commit) 243 - |> Jsont.Object.opt_mem "validate" Jsont.bool ~enc:(fun r -> r.validate) 244 |> Jsont.Object.finish 245 246 type output = { 247 - cid : string; 248 commit : Defs.commit_meta option; 249 - uri : string; 250 - validation_status : string option; 251 } 252 253 let output_jsont = 254 Jsont.Object.map ~kind:"Output" 255 - (fun _typ cid commit uri validation_status -> { cid; commit; uri; validation_status }) 256 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"com.atproto.repo.createRecord#output" ~enc:(fun _ -> "com.atproto.repo.createRecord#output") 257 - |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 258 |> Jsont.Object.opt_mem "commit" Defs.commit_meta_jsont ~enc:(fun r -> r.commit) 259 - |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 260 - |> Jsont.Object.opt_mem "validationStatus" Jsont.string ~enc:(fun r -> r.validation_status) 261 |> Jsont.Object.finish 262 263 end
··· 16 module Com = struct 17 module Atproto = struct 18 module Repo = struct 19 module Defs = struct 20 type commit_meta = { 21 cid : string; ··· 28 |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"com.atproto.repo.defs#commitMeta" ~enc:(fun _ -> "com.atproto.repo.defs#commitMeta") 29 |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 30 |> Jsont.Object.mem "rev" Jsont.string ~enc:(fun r -> r.rev) 31 + |> Jsont.Object.finish 32 + 33 + end 34 + module GetRecord = struct 35 + type params = { 36 + cid : string option; 37 + collection : string; 38 + repo : string; 39 + rkey : string; 40 + } 41 + 42 + let params_jsont = 43 + Jsont.Object.map ~kind:"Params" 44 + (fun cid collection repo rkey -> { 45 + cid; 46 + collection; 47 + repo; 48 + rkey; 49 + }) 50 + |> Jsont.Object.opt_mem "cid" Jsont.string 51 + ~enc:(fun r -> r.cid) 52 + |> Jsont.Object.mem "collection" Jsont.string 53 + ~enc:(fun r -> r.collection) 54 + |> Jsont.Object.mem "repo" Jsont.string 55 + ~enc:(fun r -> r.repo) 56 + |> Jsont.Object.mem "rkey" Jsont.string 57 + ~enc:(fun r -> r.rkey) 58 + |> Jsont.Object.finish 59 + 60 + type output = { 61 + cid : string option; 62 + uri : string; 63 + value : Jsont.json; 64 + } 65 + 66 + let output_jsont = 67 + Jsont.Object.map ~kind:"Output" 68 + (fun _typ cid uri value -> { cid; uri; value }) 69 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"com.atproto.repo.getRecord#output" ~enc:(fun _ -> "com.atproto.repo.getRecord#output") 70 + |> Jsont.Object.opt_mem "cid" Jsont.string ~enc:(fun r -> r.cid) 71 + |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 72 + |> Jsont.Object.mem "value" Jsont.json ~enc:(fun r -> r.value) 73 |> Jsont.Object.finish 74 75 end ··· 132 |> Jsont.Object.finish 133 134 end 135 + module StrongRef = struct 136 + type main = { 137 + cid : string; 138 uri : string; 139 } 140 141 + let main_jsont = 142 + Jsont.Object.map ~kind:"Main" 143 + (fun _typ cid uri -> { cid; uri }) 144 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"com.atproto.repo.strongRef" ~enc:(fun _ -> "com.atproto.repo.strongRef") 145 + |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 146 |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 147 |> Jsont.Object.finish 148 149 end ··· 189 |> Jsont.Object.finish 190 191 end 192 + module CreateRecord = struct 193 type input = { 194 collection : string; 195 + record : Jsont.json; 196 repo : string; 197 + rkey : string option; 198 swap_commit : string option; 199 + validate : bool option; 200 } 201 202 let input_jsont = 203 Jsont.Object.map ~kind:"Input" 204 + (fun _typ collection record repo rkey swap_commit validate -> { collection; record; repo; rkey; swap_commit; validate }) 205 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"com.atproto.repo.createRecord#input" ~enc:(fun _ -> "com.atproto.repo.createRecord#input") 206 |> Jsont.Object.mem "collection" Jsont.string ~enc:(fun r -> r.collection) 207 + |> Jsont.Object.mem "record" Jsont.json ~enc:(fun r -> r.record) 208 |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 209 + |> Jsont.Object.opt_mem "rkey" Jsont.string ~enc:(fun r -> r.rkey) 210 |> Jsont.Object.opt_mem "swapCommit" Jsont.string ~enc:(fun r -> r.swap_commit) 211 + |> Jsont.Object.opt_mem "validate" Jsont.bool ~enc:(fun r -> r.validate) 212 |> Jsont.Object.finish 213 214 type output = { 215 + cid : string; 216 commit : Defs.commit_meta option; 217 + uri : string; 218 + validation_status : string option; 219 } 220 221 let output_jsont = 222 Jsont.Object.map ~kind:"Output" 223 + (fun _typ cid commit uri validation_status -> { cid; commit; uri; validation_status }) 224 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"com.atproto.repo.createRecord#output" ~enc:(fun _ -> "com.atproto.repo.createRecord#output") 225 + |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 226 |> Jsont.Object.opt_mem "commit" Defs.commit_meta_jsont ~enc:(fun r -> r.commit) 227 + |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 228 + |> Jsont.Object.opt_mem "validationStatus" Jsont.string ~enc:(fun r -> r.validation_status) 229 |> Jsont.Object.finish 230 231 end 232 + module DeleteRecord = struct 233 type input = { 234 collection : string; 235 repo : string; 236 + rkey : string; 237 swap_commit : string option; 238 + swap_record : string option; 239 } 240 241 let input_jsont = 242 Jsont.Object.map ~kind:"Input" 243 + (fun _typ collection repo rkey swap_commit swap_record -> { collection; repo; rkey; swap_commit; swap_record }) 244 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"com.atproto.repo.deleteRecord#input" ~enc:(fun _ -> "com.atproto.repo.deleteRecord#input") 245 |> Jsont.Object.mem "collection" Jsont.string ~enc:(fun r -> r.collection) 246 |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 247 + |> Jsont.Object.mem "rkey" Jsont.string ~enc:(fun r -> r.rkey) 248 |> Jsont.Object.opt_mem "swapCommit" Jsont.string ~enc:(fun r -> r.swap_commit) 249 + |> Jsont.Object.opt_mem "swapRecord" Jsont.string ~enc:(fun r -> r.swap_record) 250 |> Jsont.Object.finish 251 252 type output = { 253 commit : Defs.commit_meta option; 254 } 255 256 let output_jsont = 257 Jsont.Object.map ~kind:"Output" 258 + (fun _typ commit -> { commit }) 259 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"com.atproto.repo.deleteRecord#output" ~enc:(fun _ -> "com.atproto.repo.deleteRecord#output") 260 |> Jsont.Object.opt_mem "commit" Defs.commit_meta_jsont ~enc:(fun r -> r.commit) 261 |> Jsont.Object.finish 262 263 end
+42 -42
ocaml-atp/lexicons/atproto/atp_lexicon_atproto.mli
··· 13 module Com : sig 14 module Atproto : sig 15 module Repo : sig 16 - module StrongRef : sig 17 - 18 - type main = { 19 - cid : string; 20 - uri : string; 21 - } 22 - 23 - (** Jsont codec for {!type:main}. *) 24 - val main_jsont : main Jsont.t 25 - 26 - end 27 module Defs : sig 28 29 type commit_meta = { ··· 33 34 (** Jsont codec for {!type:commit_meta}. *) 35 val commit_meta_jsont : commit_meta Jsont.t 36 37 end 38 module ListRecords : sig ··· 70 val output_jsont : output Jsont.t 71 72 end 73 - module GetRecord : sig 74 - (** Get a single record from a repository. Does not require auth. *) 75 - 76 - (** Query/procedure parameters. *) 77 - type params = { 78 - cid : string option; (** The CID of the version of the record. If not specified, then return the most recent version. *) 79 - collection : string; (** The NSID of the record collection. *) 80 - repo : string; (** The handle or DID of the repo. *) 81 - rkey : string; (** The Record Key. *) 82 - } 83 - 84 - (** Jsont codec for {!type:params}. *) 85 - val params_jsont : params Jsont.t 86 - 87 88 - type output = { 89 - cid : string option; 90 uri : string; 91 - value : Jsont.json; 92 } 93 94 - (** Jsont codec for {!type:output}. *) 95 - val output_jsont : output Jsont.t 96 97 end 98 module PutRecord : sig ··· 124 val output_jsont : output Jsont.t 125 126 end 127 - module DeleteRecord : sig 128 - (** Delete a repository record, or ensure it doesn't exist. Requires auth, implemented by PDS. *) 129 130 131 type input = { 132 collection : string; (** The NSID of the record collection. *) 133 repo : string; (** The handle or DID of the repo (aka, current account). *) 134 - rkey : string; (** The Record Key. *) 135 swap_commit : string option; (** Compare and swap with the previous commit by CID. *) 136 - swap_record : string option; (** Compare and swap with the previous record by CID. *) 137 } 138 139 (** Jsont codec for {!type:input}. *) ··· 141 142 143 type output = { 144 commit : Defs.commit_meta option; 145 } 146 147 (** Jsont codec for {!type:output}. *) 148 val output_jsont : output Jsont.t 149 150 end 151 - module CreateRecord : sig 152 - (** Create a single new repository record. Requires auth, implemented by PDS. *) 153 154 155 type input = { 156 collection : string; (** The NSID of the record collection. *) 157 - record : Jsont.json; (** The record itself. Must contain a $type field. *) 158 repo : string; (** The handle or DID of the repo (aka, current account). *) 159 - rkey : string option; (** The Record Key. *) 160 swap_commit : string option; (** Compare and swap with the previous commit by CID. *) 161 - validate : bool option; (** Can be set to 'false' to skip Lexicon schema validation of record data, 'true' to require it, or leave unset to validate only for known Lexicons. *) 162 } 163 164 (** Jsont codec for {!type:input}. *) ··· 166 167 168 type output = { 169 - cid : string; 170 commit : Defs.commit_meta option; 171 - uri : string; 172 - validation_status : string option; 173 } 174 175 (** Jsont codec for {!type:output}. *)
··· 13 module Com : sig 14 module Atproto : sig 15 module Repo : sig 16 module Defs : sig 17 18 type commit_meta = { ··· 22 23 (** Jsont codec for {!type:commit_meta}. *) 24 val commit_meta_jsont : commit_meta Jsont.t 25 + 26 + end 27 + module GetRecord : sig 28 + (** Get a single record from a repository. Does not require auth. *) 29 + 30 + (** Query/procedure parameters. *) 31 + type params = { 32 + cid : string option; (** The CID of the version of the record. If not specified, then return the most recent version. *) 33 + collection : string; (** The NSID of the record collection. *) 34 + repo : string; (** The handle or DID of the repo. *) 35 + rkey : string; (** The Record Key. *) 36 + } 37 + 38 + (** Jsont codec for {!type:params}. *) 39 + val params_jsont : params Jsont.t 40 + 41 + 42 + type output = { 43 + cid : string option; 44 + uri : string; 45 + value : Jsont.json; 46 + } 47 + 48 + (** Jsont codec for {!type:output}. *) 49 + val output_jsont : output Jsont.t 50 51 end 52 module ListRecords : sig ··· 84 val output_jsont : output Jsont.t 85 86 end 87 + module StrongRef : sig 88 89 + type main = { 90 + cid : string; 91 uri : string; 92 } 93 94 + (** Jsont codec for {!type:main}. *) 95 + val main_jsont : main Jsont.t 96 97 end 98 module PutRecord : sig ··· 124 val output_jsont : output Jsont.t 125 126 end 127 + module CreateRecord : sig 128 + (** Create a single new repository record. Requires auth, implemented by PDS. *) 129 130 131 type input = { 132 collection : string; (** The NSID of the record collection. *) 133 + record : Jsont.json; (** The record itself. Must contain a $type field. *) 134 repo : string; (** The handle or DID of the repo (aka, current account). *) 135 + rkey : string option; (** The Record Key. *) 136 swap_commit : string option; (** Compare and swap with the previous commit by CID. *) 137 + validate : bool option; (** Can be set to 'false' to skip Lexicon schema validation of record data, 'true' to require it, or leave unset to validate only for known Lexicons. *) 138 } 139 140 (** Jsont codec for {!type:input}. *) ··· 142 143 144 type output = { 145 + cid : string; 146 commit : Defs.commit_meta option; 147 + uri : string; 148 + validation_status : string option; 149 } 150 151 (** Jsont codec for {!type:output}. *) 152 val output_jsont : output Jsont.t 153 154 end 155 + module DeleteRecord : sig 156 + (** Delete a repository record, or ensure it doesn't exist. Requires auth, implemented by PDS. *) 157 158 159 type input = { 160 collection : string; (** The NSID of the record collection. *) 161 repo : string; (** The handle or DID of the repo (aka, current account). *) 162 + rkey : string; (** The Record Key. *) 163 swap_commit : string option; (** Compare and swap with the previous commit by CID. *) 164 + swap_record : string option; (** Compare and swap with the previous record by CID. *) 165 } 166 167 (** Jsont codec for {!type:input}. *) ··· 169 170 171 type output = { 172 commit : Defs.commit_meta option; 173 } 174 175 (** Jsont codec for {!type:output}. *)
+2499 -2499
ocaml-atp/lexicons/bsky/atp_lexicon_bsky.ml
··· 15 16 module Com = struct 17 module Atproto = struct 18 module Label = struct 19 module Defs = struct 20 type self_label = { ··· 124 125 end 126 end 127 - module Moderation = struct 128 - module Defs = struct 129 - type subject_type = string 130 - let subject_type_jsont = Jsont.string 131 - 132 - type reason_violation = string 133 - let reason_violation_jsont = Jsont.string 134 - 135 - type reason_type = string 136 - let reason_type_jsont = Jsont.string 137 - 138 - type reason_spam = string 139 - let reason_spam_jsont = Jsont.string 140 - 141 - type reason_sexual = string 142 - let reason_sexual_jsont = Jsont.string 143 - 144 - type reason_rude = string 145 - let reason_rude_jsont = Jsont.string 146 - 147 - type reason_other = string 148 - let reason_other_jsont = Jsont.string 149 - 150 - type reason_misleading = string 151 - let reason_misleading_jsont = Jsont.string 152 - 153 - type reason_appeal = string 154 - let reason_appeal_jsont = Jsont.string 155 - 156 - end 157 - end 158 end 159 end 160 module App = struct 161 module Bsky = struct 162 - module AuthManageLabelerService = struct 163 type main = unit 164 let main_jsont = Jsont.ignore 165 ··· 169 let main_jsont = Jsont.ignore 170 171 end 172 - module AuthManageModeration = struct 173 - type main = unit 174 - let main_jsont = Jsont.ignore 175 - 176 - end 177 - module Richtext = struct 178 - module Facet = struct 179 - type tag = { 180 - tag : string; 181 - } 182 - 183 - let tag_jsont = 184 - Jsont.Object.map ~kind:"Tag" 185 - (fun _typ tag -> { tag }) 186 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.richtext.facet#tag" ~enc:(fun _ -> "app.bsky.richtext.facet#tag") 187 - |> Jsont.Object.mem "tag" Jsont.string ~enc:(fun r -> r.tag) 188 - |> Jsont.Object.finish 189 - 190 - type mention = { 191 - did : string; 192 - } 193 - 194 - let mention_jsont = 195 - Jsont.Object.map ~kind:"Mention" 196 - (fun _typ did -> { did }) 197 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.richtext.facet#mention" ~enc:(fun _ -> "app.bsky.richtext.facet#mention") 198 - |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 199 - |> Jsont.Object.finish 200 - 201 - type link = { 202 - uri : string; 203 - } 204 - 205 - let link_jsont = 206 - Jsont.Object.map ~kind:"Link" 207 - (fun _typ uri -> { uri }) 208 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.richtext.facet#link" ~enc:(fun _ -> "app.bsky.richtext.facet#link") 209 - |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 210 - |> Jsont.Object.finish 211 - 212 - type byte_slice = { 213 - byte_end : int; 214 - byte_start : int; 215 - } 216 - 217 - let byte_slice_jsont = 218 - Jsont.Object.map ~kind:"Byte_slice" 219 - (fun _typ byte_end byte_start -> { byte_end; byte_start }) 220 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.richtext.facet#byteSlice" ~enc:(fun _ -> "app.bsky.richtext.facet#byteSlice") 221 - |> Jsont.Object.mem "byteEnd" Jsont.int ~enc:(fun r -> r.byte_end) 222 - |> Jsont.Object.mem "byteStart" Jsont.int ~enc:(fun r -> r.byte_start) 223 - |> Jsont.Object.finish 224 - 225 - type main = { 226 - features : Jsont.json list; 227 - index : byte_slice; 228 - } 229 - 230 - let main_jsont = 231 - Jsont.Object.map ~kind:"Main" 232 - (fun _typ features index -> { features; index }) 233 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.richtext.facet" ~enc:(fun _ -> "app.bsky.richtext.facet") 234 - |> Jsont.Object.mem "features" (Jsont.list Jsont.json) ~enc:(fun r -> r.features) 235 - |> Jsont.Object.mem "index" byte_slice_jsont ~enc:(fun r -> r.index) 236 - |> Jsont.Object.finish 237 - 238 - end 239 - end 240 module AuthManageFeedDeclarations = struct 241 type main = unit 242 let main_jsont = Jsont.ignore 243 244 end 245 - module AuthFullApp = struct 246 type main = unit 247 let main_jsont = Jsont.ignore 248 249 end 250 - module AuthManageNotifications = struct 251 type main = unit 252 let main_jsont = Jsont.ignore 253 ··· 257 let main_jsont = Jsont.ignore 258 259 end 260 - module Ageassurance = struct 261 - module Defs = struct 262 - type status = string 263 - let status_jsont = Jsont.string 264 - 265 - type state_metadata = { 266 - account_created_at : string option; 267 - } 268 - 269 - let state_metadata_jsont = 270 - Jsont.Object.map ~kind:"State_metadata" 271 - (fun _typ account_created_at -> { account_created_at }) 272 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.defs#stateMetadata" ~enc:(fun _ -> "app.bsky.ageassurance.defs#stateMetadata") 273 - |> Jsont.Object.opt_mem "accountCreatedAt" Jsont.string ~enc:(fun r -> r.account_created_at) 274 - |> Jsont.Object.finish 275 - 276 - type event = { 277 - access : string; 278 - attempt_id : string; 279 - complete_ip : string option; 280 - complete_ua : string option; 281 - country_code : string; 282 - created_at : string; 283 - email : string option; 284 - init_ip : string option; 285 - init_ua : string option; 286 - region_code : string option; 287 - status : string; 288 - } 289 - 290 - let event_jsont = 291 - Jsont.Object.map ~kind:"Event" 292 - (fun _typ access attempt_id complete_ip complete_ua country_code created_at email init_ip init_ua region_code status -> { access; attempt_id; complete_ip; complete_ua; country_code; created_at; email; init_ip; init_ua; region_code; status }) 293 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.defs#event" ~enc:(fun _ -> "app.bsky.ageassurance.defs#event") 294 - |> Jsont.Object.mem "access" Jsont.string ~enc:(fun r -> r.access) 295 - |> Jsont.Object.mem "attemptId" Jsont.string ~enc:(fun r -> r.attempt_id) 296 - |> Jsont.Object.opt_mem "completeIp" Jsont.string ~enc:(fun r -> r.complete_ip) 297 - |> Jsont.Object.opt_mem "completeUa" Jsont.string ~enc:(fun r -> r.complete_ua) 298 - |> Jsont.Object.mem "countryCode" Jsont.string ~enc:(fun r -> r.country_code) 299 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 300 - |> Jsont.Object.opt_mem "email" Jsont.string ~enc:(fun r -> r.email) 301 - |> Jsont.Object.opt_mem "initIp" Jsont.string ~enc:(fun r -> r.init_ip) 302 - |> Jsont.Object.opt_mem "initUa" Jsont.string ~enc:(fun r -> r.init_ua) 303 - |> Jsont.Object.opt_mem "regionCode" Jsont.string ~enc:(fun r -> r.region_code) 304 - |> Jsont.Object.mem "status" Jsont.string ~enc:(fun r -> r.status) 305 - |> Jsont.Object.finish 306 - 307 - type config_region = { 308 - country_code : string; 309 - min_access_age : int; 310 - region_code : string option; 311 - rules : Jsont.json list; 312 - } 313 - 314 - let config_region_jsont = 315 - Jsont.Object.map ~kind:"Config_region" 316 - (fun _typ country_code min_access_age region_code rules -> { country_code; min_access_age; region_code; rules }) 317 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.defs#configRegion" ~enc:(fun _ -> "app.bsky.ageassurance.defs#configRegion") 318 - |> Jsont.Object.mem "countryCode" Jsont.string ~enc:(fun r -> r.country_code) 319 - |> Jsont.Object.mem "minAccessAge" Jsont.int ~enc:(fun r -> r.min_access_age) 320 - |> Jsont.Object.opt_mem "regionCode" Jsont.string ~enc:(fun r -> r.region_code) 321 - |> Jsont.Object.mem "rules" (Jsont.list Jsont.json) ~enc:(fun r -> r.rules) 322 - |> Jsont.Object.finish 323 - 324 - type access = string 325 - let access_jsont = Jsont.string 326 - 327 - type state = { 328 - access : access; 329 - last_initiated_at : string option; 330 - status : status; 331 - } 332 - 333 - let state_jsont = 334 - Jsont.Object.map ~kind:"State" 335 - (fun _typ access last_initiated_at status -> { access; last_initiated_at; status }) 336 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.defs#state" ~enc:(fun _ -> "app.bsky.ageassurance.defs#state") 337 - |> Jsont.Object.mem "access" access_jsont ~enc:(fun r -> r.access) 338 - |> Jsont.Object.opt_mem "lastInitiatedAt" Jsont.string ~enc:(fun r -> r.last_initiated_at) 339 - |> Jsont.Object.mem "status" status_jsont ~enc:(fun r -> r.status) 340 - |> Jsont.Object.finish 341 - 342 - type config_region_rule_if_declared_under_age = { 343 - access : access; 344 - age : int; 345 - } 346 - 347 - let config_region_rule_if_declared_under_age_jsont = 348 - Jsont.Object.map ~kind:"Config_region_rule_if_declared_under_age" 349 - (fun _typ access age -> { access; age }) 350 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.defs#configRegionRuleIfDeclaredUnderAge" ~enc:(fun _ -> "app.bsky.ageassurance.defs#configRegionRuleIfDeclaredUnderAge") 351 - |> Jsont.Object.mem "access" access_jsont ~enc:(fun r -> r.access) 352 - |> Jsont.Object.mem "age" Jsont.int ~enc:(fun r -> r.age) 353 - |> Jsont.Object.finish 354 - 355 - type config_region_rule_if_declared_over_age = { 356 - access : access; 357 - age : int; 358 - } 359 - 360 - let config_region_rule_if_declared_over_age_jsont = 361 - Jsont.Object.map ~kind:"Config_region_rule_if_declared_over_age" 362 - (fun _typ access age -> { access; age }) 363 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.defs#configRegionRuleIfDeclaredOverAge" ~enc:(fun _ -> "app.bsky.ageassurance.defs#configRegionRuleIfDeclaredOverAge") 364 - |> Jsont.Object.mem "access" access_jsont ~enc:(fun r -> r.access) 365 - |> Jsont.Object.mem "age" Jsont.int ~enc:(fun r -> r.age) 366 - |> Jsont.Object.finish 367 - 368 - type config_region_rule_if_assured_under_age = { 369 - access : access; 370 - age : int; 371 - } 372 - 373 - let config_region_rule_if_assured_under_age_jsont = 374 - Jsont.Object.map ~kind:"Config_region_rule_if_assured_under_age" 375 - (fun _typ access age -> { access; age }) 376 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.defs#configRegionRuleIfAssuredUnderAge" ~enc:(fun _ -> "app.bsky.ageassurance.defs#configRegionRuleIfAssuredUnderAge") 377 - |> Jsont.Object.mem "access" access_jsont ~enc:(fun r -> r.access) 378 - |> Jsont.Object.mem "age" Jsont.int ~enc:(fun r -> r.age) 379 - |> Jsont.Object.finish 380 - 381 - type config_region_rule_if_assured_over_age = { 382 - access : access; 383 - age : int; 384 - } 385 - 386 - let config_region_rule_if_assured_over_age_jsont = 387 - Jsont.Object.map ~kind:"Config_region_rule_if_assured_over_age" 388 - (fun _typ access age -> { access; age }) 389 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.defs#configRegionRuleIfAssuredOverAge" ~enc:(fun _ -> "app.bsky.ageassurance.defs#configRegionRuleIfAssuredOverAge") 390 - |> Jsont.Object.mem "access" access_jsont ~enc:(fun r -> r.access) 391 - |> Jsont.Object.mem "age" Jsont.int ~enc:(fun r -> r.age) 392 - |> Jsont.Object.finish 393 - 394 - type config_region_rule_if_account_older_than = { 395 - access : access; 396 - date : string; 397 - } 398 - 399 - let config_region_rule_if_account_older_than_jsont = 400 - Jsont.Object.map ~kind:"Config_region_rule_if_account_older_than" 401 - (fun _typ access date -> { access; date }) 402 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.defs#configRegionRuleIfAccountOlderThan" ~enc:(fun _ -> "app.bsky.ageassurance.defs#configRegionRuleIfAccountOlderThan") 403 - |> Jsont.Object.mem "access" access_jsont ~enc:(fun r -> r.access) 404 - |> Jsont.Object.mem "date" Jsont.string ~enc:(fun r -> r.date) 405 - |> Jsont.Object.finish 406 - 407 - type config_region_rule_if_account_newer_than = { 408 - access : access; 409 - date : string; 410 - } 411 - 412 - let config_region_rule_if_account_newer_than_jsont = 413 - Jsont.Object.map ~kind:"Config_region_rule_if_account_newer_than" 414 - (fun _typ access date -> { access; date }) 415 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.defs#configRegionRuleIfAccountNewerThan" ~enc:(fun _ -> "app.bsky.ageassurance.defs#configRegionRuleIfAccountNewerThan") 416 - |> Jsont.Object.mem "access" access_jsont ~enc:(fun r -> r.access) 417 - |> Jsont.Object.mem "date" Jsont.string ~enc:(fun r -> r.date) 418 - |> Jsont.Object.finish 419 - 420 - type config_region_rule_default = { 421 - access : access; 422 - } 423 - 424 - let config_region_rule_default_jsont = 425 - Jsont.Object.map ~kind:"Config_region_rule_default" 426 - (fun _typ access -> { access }) 427 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.defs#configRegionRuleDefault" ~enc:(fun _ -> "app.bsky.ageassurance.defs#configRegionRuleDefault") 428 - |> Jsont.Object.mem "access" access_jsont ~enc:(fun r -> r.access) 429 - |> Jsont.Object.finish 430 - 431 - type config = { 432 - regions : config_region list; 433 - } 434 - 435 - let config_jsont = 436 - Jsont.Object.map ~kind:"Config" 437 - (fun _typ regions -> { regions }) 438 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.defs#config" ~enc:(fun _ -> "app.bsky.ageassurance.defs#config") 439 - |> Jsont.Object.mem "regions" (Jsont.list config_region_jsont) ~enc:(fun r -> r.regions) 440 - |> Jsont.Object.finish 441 - 442 - end 443 - module Begin = struct 444 - type input = { 445 - country_code : string; 446 - email : string; 447 - language : string; 448 - region_code : string option; 449 - } 450 - 451 - let input_jsont = 452 - Jsont.Object.map ~kind:"Input" 453 - (fun _typ country_code email language region_code -> { country_code; email; language; region_code }) 454 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.begin#input" ~enc:(fun _ -> "app.bsky.ageassurance.begin#input") 455 - |> Jsont.Object.mem "countryCode" Jsont.string ~enc:(fun r -> r.country_code) 456 - |> Jsont.Object.mem "email" Jsont.string ~enc:(fun r -> r.email) 457 - |> Jsont.Object.mem "language" Jsont.string ~enc:(fun r -> r.language) 458 - |> Jsont.Object.opt_mem "regionCode" Jsont.string ~enc:(fun r -> r.region_code) 459 - |> Jsont.Object.finish 460 - 461 - type output = Defs.state 462 - 463 - let output_jsont = Defs.state_jsont 464 - 465 - end 466 - module GetState = struct 467 - type params = { 468 - country_code : string; 469 - region_code : string option; 470 - } 471 - 472 - let params_jsont = 473 - Jsont.Object.map ~kind:"Params" 474 - (fun country_code region_code -> { 475 - country_code; 476 - region_code; 477 - }) 478 - |> Jsont.Object.mem "countryCode" Jsont.string 479 - ~enc:(fun r -> r.country_code) 480 - |> Jsont.Object.opt_mem "regionCode" Jsont.string 481 - ~enc:(fun r -> r.region_code) 482 - |> Jsont.Object.finish 483 - 484 - type output = { 485 - metadata : Defs.state_metadata; 486 - state : Defs.state; 487 - } 488 - 489 - let output_jsont = 490 - Jsont.Object.map ~kind:"Output" 491 - (fun _typ metadata state -> { metadata; state }) 492 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.getState#output" ~enc:(fun _ -> "app.bsky.ageassurance.getState#output") 493 - |> Jsont.Object.mem "metadata" Defs.state_metadata_jsont ~enc:(fun r -> r.metadata) 494 - |> Jsont.Object.mem "state" Defs.state_jsont ~enc:(fun r -> r.state) 495 - |> Jsont.Object.finish 496 - 497 - end 498 - module GetConfig = struct 499 - type output = Defs.config 500 - 501 - let output_jsont = Defs.config_jsont 502 - 503 - end 504 - end 505 - module Labeler = struct 506 - module Defs = struct 507 - type labeler_viewer_state = { 508 - like : string option; 509 - } 510 - 511 - let labeler_viewer_state_jsont = 512 - Jsont.Object.map ~kind:"Labeler_viewer_state" 513 - (fun _typ like -> { like }) 514 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.labeler.defs#labelerViewerState" ~enc:(fun _ -> "app.bsky.labeler.defs#labelerViewerState") 515 - |> Jsont.Object.opt_mem "like" Jsont.string ~enc:(fun r -> r.like) 516 - |> Jsont.Object.finish 517 - 518 - type labeler_policies = { 519 - label_value_definitions : Com.Atproto.Label.Defs.label_value_definition list option; 520 - label_values : Com.Atproto.Label.Defs.label_value list; 521 - } 522 - 523 - let labeler_policies_jsont = 524 - Jsont.Object.map ~kind:"Labeler_policies" 525 - (fun _typ label_value_definitions label_values -> { label_value_definitions; label_values }) 526 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.labeler.defs#labelerPolicies" ~enc:(fun _ -> "app.bsky.labeler.defs#labelerPolicies") 527 - |> Jsont.Object.opt_mem "labelValueDefinitions" (Jsont.list Com.Atproto.Label.Defs.label_value_definition_jsont) ~enc:(fun r -> r.label_value_definitions) 528 - |> Jsont.Object.mem "labelValues" (Jsont.list Com.Atproto.Label.Defs.label_value_jsont) ~enc:(fun r -> r.label_values) 529 - |> Jsont.Object.finish 530 - 531 - type labeler_view_detailed = { 532 - cid : string; 533 - creator : Jsont.json; 534 - indexed_at : string; 535 - labels : Com.Atproto.Label.Defs.label list option; 536 - like_count : int option; 537 - policies : Jsont.json; 538 - reason_types : Com.Atproto.Moderation.Defs.reason_type list option; 539 - subject_collections : string list option; 540 - subject_types : Com.Atproto.Moderation.Defs.subject_type list option; 541 - uri : string; 542 - viewer : Jsont.json option; 543 - } 544 - 545 - let labeler_view_detailed_jsont = 546 - Jsont.Object.map ~kind:"Labeler_view_detailed" 547 - (fun _typ cid creator indexed_at labels like_count policies reason_types subject_collections subject_types uri viewer -> { cid; creator; indexed_at; labels; like_count; policies; reason_types; subject_collections; subject_types; uri; viewer }) 548 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.labeler.defs#labelerViewDetailed" ~enc:(fun _ -> "app.bsky.labeler.defs#labelerViewDetailed") 549 - |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 550 - |> Jsont.Object.mem "creator" Jsont.json ~enc:(fun r -> r.creator) 551 - |> Jsont.Object.mem "indexedAt" Jsont.string ~enc:(fun r -> r.indexed_at) 552 - |> Jsont.Object.opt_mem "labels" (Jsont.list Com.Atproto.Label.Defs.label_jsont) ~enc:(fun r -> r.labels) 553 - |> Jsont.Object.opt_mem "likeCount" Jsont.int ~enc:(fun r -> r.like_count) 554 - |> Jsont.Object.mem "policies" Jsont.json ~enc:(fun r -> r.policies) 555 - |> Jsont.Object.opt_mem "reasonTypes" (Jsont.list Com.Atproto.Moderation.Defs.reason_type_jsont) ~enc:(fun r -> r.reason_types) 556 - |> Jsont.Object.opt_mem "subjectCollections" (Jsont.list Jsont.string) ~enc:(fun r -> r.subject_collections) 557 - |> Jsont.Object.opt_mem "subjectTypes" (Jsont.list Com.Atproto.Moderation.Defs.subject_type_jsont) ~enc:(fun r -> r.subject_types) 558 - |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 559 - |> Jsont.Object.opt_mem "viewer" Jsont.json ~enc:(fun r -> r.viewer) 560 - |> Jsont.Object.finish 561 - 562 - type labeler_view = { 563 - cid : string; 564 - creator : Jsont.json; 565 - indexed_at : string; 566 - labels : Com.Atproto.Label.Defs.label list option; 567 - like_count : int option; 568 - uri : string; 569 - viewer : Jsont.json option; 570 - } 571 - 572 - let labeler_view_jsont = 573 - Jsont.Object.map ~kind:"Labeler_view" 574 - (fun _typ cid creator indexed_at labels like_count uri viewer -> { cid; creator; indexed_at; labels; like_count; uri; viewer }) 575 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.labeler.defs#labelerView" ~enc:(fun _ -> "app.bsky.labeler.defs#labelerView") 576 - |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 577 - |> Jsont.Object.mem "creator" Jsont.json ~enc:(fun r -> r.creator) 578 - |> Jsont.Object.mem "indexedAt" Jsont.string ~enc:(fun r -> r.indexed_at) 579 - |> Jsont.Object.opt_mem "labels" (Jsont.list Com.Atproto.Label.Defs.label_jsont) ~enc:(fun r -> r.labels) 580 - |> Jsont.Object.opt_mem "likeCount" Jsont.int ~enc:(fun r -> r.like_count) 581 - |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 582 - |> Jsont.Object.opt_mem "viewer" Jsont.json ~enc:(fun r -> r.viewer) 583 - |> Jsont.Object.finish 584 - 585 - end 586 - module Service = struct 587 - type main = { 588 - created_at : string; 589 - labels : Com.Atproto.Label.Defs.self_labels option; 590 - policies : Jsont.json; 591 - reason_types : Com.Atproto.Moderation.Defs.reason_type list option; 592 - subject_collections : string list option; 593 - subject_types : Com.Atproto.Moderation.Defs.subject_type list option; 594 - } 595 - 596 - let main_jsont = 597 - Jsont.Object.map ~kind:"Main" 598 - (fun _typ created_at labels policies reason_types subject_collections subject_types -> { created_at; labels; policies; reason_types; subject_collections; subject_types }) 599 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.labeler.service" ~enc:(fun _ -> "app.bsky.labeler.service") 600 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 601 - |> Jsont.Object.opt_mem "labels" Com.Atproto.Label.Defs.self_labels_jsont ~enc:(fun r -> r.labels) 602 - |> Jsont.Object.mem "policies" Jsont.json ~enc:(fun r -> r.policies) 603 - |> Jsont.Object.opt_mem "reasonTypes" (Jsont.list Com.Atproto.Moderation.Defs.reason_type_jsont) ~enc:(fun r -> r.reason_types) 604 - |> Jsont.Object.opt_mem "subjectCollections" (Jsont.list Jsont.string) ~enc:(fun r -> r.subject_collections) 605 - |> Jsont.Object.opt_mem "subjectTypes" (Jsont.list Com.Atproto.Moderation.Defs.subject_type_jsont) ~enc:(fun r -> r.subject_types) 606 - |> Jsont.Object.finish 607 - 608 - end 609 - module GetServices = struct 610 - type params = { 611 - detailed : bool option; 612 - dids : string list; 613 - } 614 - 615 - let params_jsont = 616 - Jsont.Object.map ~kind:"Params" 617 - (fun detailed dids -> { 618 - detailed; 619 - dids; 620 - }) 621 - |> Jsont.Object.opt_mem "detailed" Jsont.bool 622 - ~enc:(fun r -> r.detailed) 623 - |> Jsont.Object.mem "dids" (Jsont.list Jsont.string) 624 - ~enc:(fun r -> r.dids) 625 - |> Jsont.Object.finish 626 - 627 - type output = { 628 - views : Jsont.json list; 629 - } 630 - 631 - let output_jsont = 632 - Jsont.Object.map ~kind:"Output" 633 - (fun _typ views -> { views }) 634 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.labeler.getServices#output" ~enc:(fun _ -> "app.bsky.labeler.getServices#output") 635 - |> Jsont.Object.mem "views" (Jsont.list Jsont.json) ~enc:(fun r -> r.views) 636 - |> Jsont.Object.finish 637 - 638 - end 639 - end 640 - module AuthCreatePosts = struct 641 type main = unit 642 let main_jsont = Jsont.ignore 643 644 end 645 - module Video = struct 646 - module GetUploadLimits = struct 647 - type output = { 648 - can_upload : bool; 649 - error : string option; 650 - message : string option; 651 - remaining_daily_bytes : int option; 652 - remaining_daily_videos : int option; 653 - } 654 - 655 - let output_jsont = 656 - Jsont.Object.map ~kind:"Output" 657 - (fun _typ can_upload error message remaining_daily_bytes remaining_daily_videos -> { can_upload; error; message; remaining_daily_bytes; remaining_daily_videos }) 658 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.video.getUploadLimits#output" ~enc:(fun _ -> "app.bsky.video.getUploadLimits#output") 659 - |> Jsont.Object.mem "canUpload" Jsont.bool ~enc:(fun r -> r.can_upload) 660 - |> Jsont.Object.opt_mem "error" Jsont.string ~enc:(fun r -> r.error) 661 - |> Jsont.Object.opt_mem "message" Jsont.string ~enc:(fun r -> r.message) 662 - |> Jsont.Object.opt_mem "remainingDailyBytes" Jsont.int ~enc:(fun r -> r.remaining_daily_bytes) 663 - |> Jsont.Object.opt_mem "remainingDailyVideos" Jsont.int ~enc:(fun r -> r.remaining_daily_videos) 664 - |> Jsont.Object.finish 665 - 666 - end 667 - module Defs = struct 668 - type job_status = { 669 - blob : Atp.Blob_ref.t option; 670 - did : string; 671 - error : string option; 672 - job_id : string; 673 - message : string option; 674 - progress : int option; 675 - state : string; 676 - } 677 - 678 - let job_status_jsont = 679 - Jsont.Object.map ~kind:"Job_status" 680 - (fun _typ blob did error job_id message progress state -> { blob; did; error; job_id; message; progress; state }) 681 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.video.defs#jobStatus" ~enc:(fun _ -> "app.bsky.video.defs#jobStatus") 682 - |> Jsont.Object.opt_mem "blob" Atp.Blob_ref.jsont ~enc:(fun r -> r.blob) 683 - |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 684 - |> Jsont.Object.opt_mem "error" Jsont.string ~enc:(fun r -> r.error) 685 - |> Jsont.Object.mem "jobId" Jsont.string ~enc:(fun r -> r.job_id) 686 - |> Jsont.Object.opt_mem "message" Jsont.string ~enc:(fun r -> r.message) 687 - |> Jsont.Object.opt_mem "progress" Jsont.int ~enc:(fun r -> r.progress) 688 - |> Jsont.Object.mem "state" Jsont.string ~enc:(fun r -> r.state) 689 - |> Jsont.Object.finish 690 - 691 - end 692 - module UploadVideo = struct 693 - type input = unit 694 - let input_jsont = Jsont.ignore 695 - 696 - type output = { 697 - job_status : Defs.job_status; 698 - } 699 - 700 - let output_jsont = 701 - Jsont.Object.map ~kind:"Output" 702 - (fun _typ job_status -> { job_status }) 703 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.video.uploadVideo#output" ~enc:(fun _ -> "app.bsky.video.uploadVideo#output") 704 - |> Jsont.Object.mem "jobStatus" Defs.job_status_jsont ~enc:(fun r -> r.job_status) 705 - |> Jsont.Object.finish 706 - 707 - end 708 - module GetJobStatus = struct 709 type params = { 710 - job_id : string; 711 } 712 713 let params_jsont = 714 Jsont.Object.map ~kind:"Params" 715 - (fun job_id -> { 716 - job_id; 717 }) 718 - |> Jsont.Object.mem "jobId" Jsont.string 719 - ~enc:(fun r -> r.job_id) 720 |> Jsont.Object.finish 721 722 type output = { 723 - job_status : Defs.job_status; 724 } 725 726 let output_jsont = 727 Jsont.Object.map ~kind:"Output" 728 - (fun _typ job_status -> { job_status }) 729 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.video.getJobStatus#output" ~enc:(fun _ -> "app.bsky.video.getJobStatus#output") 730 - |> Jsont.Object.mem "jobStatus" Defs.job_status_jsont ~enc:(fun r -> r.job_status) 731 - |> Jsont.Object.finish 732 - 733 - end 734 - end 735 - module Embed = struct 736 - module External = struct 737 - type view_external = { 738 - description : string; 739 - thumb : string option; 740 - title : string; 741 - uri : string; 742 - } 743 - 744 - let view_external_jsont = 745 - Jsont.Object.map ~kind:"View_external" 746 - (fun _typ description thumb title uri -> { description; thumb; title; uri }) 747 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.external#viewExternal" ~enc:(fun _ -> "app.bsky.embed.external#viewExternal") 748 - |> Jsont.Object.mem "description" Jsont.string ~enc:(fun r -> r.description) 749 - |> Jsont.Object.opt_mem "thumb" Jsont.string ~enc:(fun r -> r.thumb) 750 - |> Jsont.Object.mem "title" Jsont.string ~enc:(fun r -> r.title) 751 - |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 752 - |> Jsont.Object.finish 753 - 754 - type external_ = { 755 - description : string; 756 - thumb : Atp.Blob_ref.t option; 757 - title : string; 758 - uri : string; 759 - } 760 - 761 - let external__jsont = 762 - Jsont.Object.map ~kind:"External_" 763 - (fun _typ description thumb title uri -> { description; thumb; title; uri }) 764 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.external#external" ~enc:(fun _ -> "app.bsky.embed.external#external") 765 - |> Jsont.Object.mem "description" Jsont.string ~enc:(fun r -> r.description) 766 - |> Jsont.Object.opt_mem "thumb" Atp.Blob_ref.jsont ~enc:(fun r -> r.thumb) 767 - |> Jsont.Object.mem "title" Jsont.string ~enc:(fun r -> r.title) 768 - |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 769 - |> Jsont.Object.finish 770 - 771 - type view = { 772 - external_ : Jsont.json; 773 - } 774 - 775 - let view_jsont = 776 - Jsont.Object.map ~kind:"View" 777 - (fun _typ external_ -> { external_ }) 778 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.external#view" ~enc:(fun _ -> "app.bsky.embed.external#view") 779 - |> Jsont.Object.mem "external" Jsont.json ~enc:(fun r -> r.external_) 780 - |> Jsont.Object.finish 781 - 782 - type main = { 783 - external_ : Jsont.json; 784 - } 785 - 786 - let main_jsont = 787 - Jsont.Object.map ~kind:"Main" 788 - (fun _typ external_ -> { external_ }) 789 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.external" ~enc:(fun _ -> "app.bsky.embed.external") 790 - |> Jsont.Object.mem "external" Jsont.json ~enc:(fun r -> r.external_) 791 |> Jsont.Object.finish 792 793 end 794 - module Defs = struct 795 - type aspect_ratio = { 796 - height : int; 797 - width : int; 798 - } 799 - 800 - let aspect_ratio_jsont = 801 - Jsont.Object.map ~kind:"Aspect_ratio" 802 - (fun _typ height width -> { height; width }) 803 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.defs#aspectRatio" ~enc:(fun _ -> "app.bsky.embed.defs#aspectRatio") 804 - |> Jsont.Object.mem "height" Jsont.int ~enc:(fun r -> r.height) 805 - |> Jsont.Object.mem "width" Jsont.int ~enc:(fun r -> r.width) 806 - |> Jsont.Object.finish 807 - 808 - end 809 - module Images = struct 810 - type view_image = { 811 - alt : string; 812 - aspect_ratio : Jsont.json option; 813 - fullsize : string; 814 - thumb : string; 815 - } 816 - 817 - let view_image_jsont = 818 - Jsont.Object.map ~kind:"View_image" 819 - (fun _typ alt aspect_ratio fullsize thumb -> { alt; aspect_ratio; fullsize; thumb }) 820 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.images#viewImage" ~enc:(fun _ -> "app.bsky.embed.images#viewImage") 821 - |> Jsont.Object.mem "alt" Jsont.string ~enc:(fun r -> r.alt) 822 - |> Jsont.Object.opt_mem "aspectRatio" Jsont.json ~enc:(fun r -> r.aspect_ratio) 823 - |> Jsont.Object.mem "fullsize" Jsont.string ~enc:(fun r -> r.fullsize) 824 - |> Jsont.Object.mem "thumb" Jsont.string ~enc:(fun r -> r.thumb) 825 - |> Jsont.Object.finish 826 - 827 - type image = { 828 - alt : string; 829 - aspect_ratio : Jsont.json option; 830 - image : Atp.Blob_ref.t; 831 - } 832 - 833 - let image_jsont = 834 - Jsont.Object.map ~kind:"Image" 835 - (fun _typ alt aspect_ratio image -> { alt; aspect_ratio; image }) 836 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.images#image" ~enc:(fun _ -> "app.bsky.embed.images#image") 837 - |> Jsont.Object.mem "alt" Jsont.string ~enc:(fun r -> r.alt) 838 - |> Jsont.Object.opt_mem "aspectRatio" Jsont.json ~enc:(fun r -> r.aspect_ratio) 839 - |> Jsont.Object.mem "image" Atp.Blob_ref.jsont ~enc:(fun r -> r.image) 840 - |> Jsont.Object.finish 841 - 842 - type view = { 843 - images : Jsont.json list; 844 - } 845 - 846 - let view_jsont = 847 - Jsont.Object.map ~kind:"View" 848 - (fun _typ images -> { images }) 849 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.images#view" ~enc:(fun _ -> "app.bsky.embed.images#view") 850 - |> Jsont.Object.mem "images" (Jsont.list Jsont.json) ~enc:(fun r -> r.images) 851 - |> Jsont.Object.finish 852 - 853 - type main = { 854 - images : Jsont.json list; 855 - } 856 - 857 - let main_jsont = 858 - Jsont.Object.map ~kind:"Main" 859 - (fun _typ images -> { images }) 860 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.images" ~enc:(fun _ -> "app.bsky.embed.images") 861 - |> Jsont.Object.mem "images" (Jsont.list Jsont.json) ~enc:(fun r -> r.images) 862 - |> Jsont.Object.finish 863 - 864 - end 865 - module Video = struct 866 - type view = { 867 - alt : string option; 868 - aspect_ratio : Jsont.json option; 869 - cid : string; 870 - playlist : string; 871 - thumbnail : string option; 872 - } 873 - 874 - let view_jsont = 875 - Jsont.Object.map ~kind:"View" 876 - (fun _typ alt aspect_ratio cid playlist thumbnail -> { alt; aspect_ratio; cid; playlist; thumbnail }) 877 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.video#view" ~enc:(fun _ -> "app.bsky.embed.video#view") 878 - |> Jsont.Object.opt_mem "alt" Jsont.string ~enc:(fun r -> r.alt) 879 - |> Jsont.Object.opt_mem "aspectRatio" Jsont.json ~enc:(fun r -> r.aspect_ratio) 880 - |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 881 - |> Jsont.Object.mem "playlist" Jsont.string ~enc:(fun r -> r.playlist) 882 - |> Jsont.Object.opt_mem "thumbnail" Jsont.string ~enc:(fun r -> r.thumbnail) 883 - |> Jsont.Object.finish 884 - 885 - type caption = { 886 - file : Atp.Blob_ref.t; 887 - lang : string; 888 - } 889 - 890 - let caption_jsont = 891 - Jsont.Object.map ~kind:"Caption" 892 - (fun _typ file lang -> { file; lang }) 893 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.video#caption" ~enc:(fun _ -> "app.bsky.embed.video#caption") 894 - |> Jsont.Object.mem "file" Atp.Blob_ref.jsont ~enc:(fun r -> r.file) 895 - |> Jsont.Object.mem "lang" Jsont.string ~enc:(fun r -> r.lang) 896 - |> Jsont.Object.finish 897 - 898 - type main = { 899 - alt : string option; 900 - aspect_ratio : Jsont.json option; 901 - captions : Jsont.json list option; 902 - video : Atp.Blob_ref.t; 903 - } 904 - 905 - let main_jsont = 906 - Jsont.Object.map ~kind:"Main" 907 - (fun _typ alt aspect_ratio captions video -> { alt; aspect_ratio; captions; video }) 908 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.video" ~enc:(fun _ -> "app.bsky.embed.video") 909 - |> Jsont.Object.opt_mem "alt" Jsont.string ~enc:(fun r -> r.alt) 910 - |> Jsont.Object.opt_mem "aspectRatio" Jsont.json ~enc:(fun r -> r.aspect_ratio) 911 - |> Jsont.Object.opt_mem "captions" (Jsont.list Jsont.json) ~enc:(fun r -> r.captions) 912 - |> Jsont.Object.mem "video" Atp.Blob_ref.jsont ~enc:(fun r -> r.video) 913 - |> Jsont.Object.finish 914 - 915 - end 916 - module RecordWithMedia = struct 917 - type view = { 918 - media : Jsont.json; 919 - record : Jsont.json; 920 - } 921 - 922 - let view_jsont = 923 - Jsont.Object.map ~kind:"View" 924 - (fun _typ media record -> { media; record }) 925 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.recordWithMedia#view" ~enc:(fun _ -> "app.bsky.embed.recordWithMedia#view") 926 - |> Jsont.Object.mem "media" Jsont.json ~enc:(fun r -> r.media) 927 - |> Jsont.Object.mem "record" Jsont.json ~enc:(fun r -> r.record) 928 - |> Jsont.Object.finish 929 - 930 - type main = { 931 - media : Jsont.json; 932 - record : Jsont.json; 933 - } 934 - 935 - let main_jsont = 936 - Jsont.Object.map ~kind:"Main" 937 - (fun _typ media record -> { media; record }) 938 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.recordWithMedia" ~enc:(fun _ -> "app.bsky.embed.recordWithMedia") 939 - |> Jsont.Object.mem "media" Jsont.json ~enc:(fun r -> r.media) 940 - |> Jsont.Object.mem "record" Jsont.json ~enc:(fun r -> r.record) 941 - |> Jsont.Object.finish 942 - 943 - end 944 - module Record = struct 945 - type view_record = { 946 - author : Jsont.json; 947 - cid : string; 948 - embeds : Jsont.json list option; 949 - indexed_at : string; 950 - labels : Com.Atproto.Label.Defs.label list option; 951 - like_count : int option; 952 - quote_count : int option; 953 - reply_count : int option; 954 - repost_count : int option; 955 - uri : string; 956 - value : Jsont.json; 957 - } 958 - 959 - let view_record_jsont = 960 - Jsont.Object.map ~kind:"View_record" 961 - (fun _typ author cid embeds indexed_at labels like_count quote_count reply_count repost_count uri value -> { author; cid; embeds; indexed_at; labels; like_count; quote_count; reply_count; repost_count; uri; value }) 962 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.record#viewRecord" ~enc:(fun _ -> "app.bsky.embed.record#viewRecord") 963 - |> Jsont.Object.mem "author" Jsont.json ~enc:(fun r -> r.author) 964 - |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 965 - |> Jsont.Object.opt_mem "embeds" (Jsont.list Jsont.json) ~enc:(fun r -> r.embeds) 966 - |> Jsont.Object.mem "indexedAt" Jsont.string ~enc:(fun r -> r.indexed_at) 967 - |> Jsont.Object.opt_mem "labels" (Jsont.list Com.Atproto.Label.Defs.label_jsont) ~enc:(fun r -> r.labels) 968 - |> Jsont.Object.opt_mem "likeCount" Jsont.int ~enc:(fun r -> r.like_count) 969 - |> Jsont.Object.opt_mem "quoteCount" Jsont.int ~enc:(fun r -> r.quote_count) 970 - |> Jsont.Object.opt_mem "replyCount" Jsont.int ~enc:(fun r -> r.reply_count) 971 - |> Jsont.Object.opt_mem "repostCount" Jsont.int ~enc:(fun r -> r.repost_count) 972 - |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 973 - |> Jsont.Object.mem "value" Jsont.json ~enc:(fun r -> r.value) 974 - |> Jsont.Object.finish 975 - 976 - type view_not_found = { 977 - not_found : bool; 978 - uri : string; 979 - } 980 - 981 - let view_not_found_jsont = 982 - Jsont.Object.map ~kind:"View_not_found" 983 - (fun _typ not_found uri -> { not_found; uri }) 984 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.record#viewNotFound" ~enc:(fun _ -> "app.bsky.embed.record#viewNotFound") 985 - |> Jsont.Object.mem "notFound" Jsont.bool ~enc:(fun r -> r.not_found) 986 - |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 987 - |> Jsont.Object.finish 988 - 989 - type view_detached = { 990 - detached : bool; 991 - uri : string; 992 - } 993 - 994 - let view_detached_jsont = 995 - Jsont.Object.map ~kind:"View_detached" 996 - (fun _typ detached uri -> { detached; uri }) 997 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.record#viewDetached" ~enc:(fun _ -> "app.bsky.embed.record#viewDetached") 998 - |> Jsont.Object.mem "detached" Jsont.bool ~enc:(fun r -> r.detached) 999 - |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 1000 - |> Jsont.Object.finish 1001 - 1002 - type view_blocked = { 1003 - author : Jsont.json; 1004 - blocked : bool; 1005 - uri : string; 1006 - } 1007 - 1008 - let view_blocked_jsont = 1009 - Jsont.Object.map ~kind:"View_blocked" 1010 - (fun _typ author blocked uri -> { author; blocked; uri }) 1011 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.record#viewBlocked" ~enc:(fun _ -> "app.bsky.embed.record#viewBlocked") 1012 - |> Jsont.Object.mem "author" Jsont.json ~enc:(fun r -> r.author) 1013 - |> Jsont.Object.mem "blocked" Jsont.bool ~enc:(fun r -> r.blocked) 1014 - |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 1015 - |> Jsont.Object.finish 1016 - 1017 - type view = { 1018 - record : Jsont.json; 1019 - } 1020 - 1021 - let view_jsont = 1022 - Jsont.Object.map ~kind:"View" 1023 - (fun _typ record -> { record }) 1024 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.record#view" ~enc:(fun _ -> "app.bsky.embed.record#view") 1025 - |> Jsont.Object.mem "record" Jsont.json ~enc:(fun r -> r.record) 1026 - |> Jsont.Object.finish 1027 - 1028 - type main = { 1029 - record : Com.Atproto.Repo.StrongRef.main; 1030 - } 1031 - 1032 - let main_jsont = 1033 - Jsont.Object.map ~kind:"Main" 1034 - (fun _typ record -> { record }) 1035 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.record" ~enc:(fun _ -> "app.bsky.embed.record") 1036 - |> Jsont.Object.mem "record" Com.Atproto.Repo.StrongRef.main_jsont ~enc:(fun r -> r.record) 1037 - |> Jsont.Object.finish 1038 - 1039 - end 1040 - end 1041 - module Notification = struct 1042 module UpdateSeen = struct 1043 type input = { 1044 seen_at : string; ··· 1049 (fun _typ seen_at -> { seen_at }) 1050 |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.notification.updateSeen#input" ~enc:(fun _ -> "app.bsky.notification.updateSeen#input") 1051 |> Jsont.Object.mem "seenAt" Jsont.string ~enc:(fun r -> r.seen_at) 1052 - |> Jsont.Object.finish 1053 - 1054 - end 1055 - module RegisterPush = struct 1056 - type input = { 1057 - age_restricted : bool option; 1058 - app_id : string; 1059 - platform : string; 1060 - service_did : string; 1061 - token : string; 1062 - } 1063 - 1064 - let input_jsont = 1065 - Jsont.Object.map ~kind:"Input" 1066 - (fun _typ age_restricted app_id platform service_did token -> { age_restricted; app_id; platform; service_did; token }) 1067 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.notification.registerPush#input" ~enc:(fun _ -> "app.bsky.notification.registerPush#input") 1068 - |> Jsont.Object.opt_mem "ageRestricted" Jsont.bool ~enc:(fun r -> r.age_restricted) 1069 - |> Jsont.Object.mem "appId" Jsont.string ~enc:(fun r -> r.app_id) 1070 - |> Jsont.Object.mem "platform" Jsont.string ~enc:(fun r -> r.platform) 1071 - |> Jsont.Object.mem "serviceDid" Jsont.string ~enc:(fun r -> r.service_did) 1072 - |> Jsont.Object.mem "token" Jsont.string ~enc:(fun r -> r.token) 1073 |> Jsont.Object.finish 1074 1075 end ··· 1148 |> Jsont.Object.finish 1149 1150 end 1151 - module GetUnreadCount = struct 1152 - type params = { 1153 - priority : bool option; 1154 - seen_at : string option; 1155 } 1156 1157 - let params_jsont = 1158 - Jsont.Object.map ~kind:"Params" 1159 - (fun priority seen_at -> { 1160 - priority; 1161 - seen_at; 1162 - }) 1163 - |> Jsont.Object.opt_mem "priority" Jsont.bool 1164 - ~enc:(fun r -> r.priority) 1165 - |> Jsont.Object.opt_mem "seenAt" Jsont.string 1166 - ~enc:(fun r -> r.seen_at) 1167 |> Jsont.Object.finish 1168 1169 - type output = { 1170 - count : int; 1171 } 1172 1173 - let output_jsont = 1174 - Jsont.Object.map ~kind:"Output" 1175 - (fun _typ count -> { count }) 1176 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.notification.getUnreadCount#output" ~enc:(fun _ -> "app.bsky.notification.getUnreadCount#output") 1177 - |> Jsont.Object.mem "count" Jsont.int ~enc:(fun r -> r.count) 1178 |> Jsont.Object.finish 1179 1180 end 1181 - module UnregisterPush = struct 1182 type input = { 1183 app_id : string; 1184 platform : string; 1185 service_did : string; ··· 1188 1189 let input_jsont = 1190 Jsont.Object.map ~kind:"Input" 1191 - (fun _typ app_id platform service_did token -> { app_id; platform; service_did; token }) 1192 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.notification.unregisterPush#input" ~enc:(fun _ -> "app.bsky.notification.unregisterPush#input") 1193 |> Jsont.Object.mem "appId" Jsont.string ~enc:(fun r -> r.app_id) 1194 |> Jsont.Object.mem "platform" Jsont.string ~enc:(fun r -> r.platform) 1195 |> Jsont.Object.mem "serviceDid" Jsont.string ~enc:(fun r -> r.service_did) ··· 1197 |> Jsont.Object.finish 1198 1199 end 1200 - module PutPreferences = struct 1201 type input = { 1202 - priority : bool; 1203 } 1204 1205 let input_jsont = 1206 Jsont.Object.map ~kind:"Input" 1207 - (fun _typ priority -> { priority }) 1208 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.notification.putPreferences#input" ~enc:(fun _ -> "app.bsky.notification.putPreferences#input") 1209 - |> Jsont.Object.mem "priority" Jsont.bool ~enc:(fun r -> r.priority) 1210 |> Jsont.Object.finish 1211 1212 end ··· 1318 |> Jsont.Object.finish 1319 1320 end 1321 - module Declaration = struct 1322 - type main = { 1323 - allow_subscriptions : string; 1324 - } 1325 - 1326 - let main_jsont = 1327 - Jsont.Object.map ~kind:"Main" 1328 - (fun _typ allow_subscriptions -> { allow_subscriptions }) 1329 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.notification.declaration" ~enc:(fun _ -> "app.bsky.notification.declaration") 1330 - |> Jsont.Object.mem "allowSubscriptions" Jsont.string ~enc:(fun r -> r.allow_subscriptions) 1331 - |> Jsont.Object.finish 1332 - 1333 - end 1334 module ListActivitySubscriptions = struct 1335 type params = { 1336 cursor : string option; ··· 1457 1458 end 1459 end 1460 module Actor = struct 1461 module Status = struct 1462 type live = string ··· 1477 |> Jsont.Object.opt_mem "durationMinutes" Jsont.int ~enc:(fun r -> r.duration_minutes) 1478 |> Jsont.Object.opt_mem "embed" Jsont.json ~enc:(fun r -> r.embed) 1479 |> Jsont.Object.mem "status" Jsont.string ~enc:(fun r -> r.status) 1480 - |> Jsont.Object.finish 1481 - 1482 - end 1483 - module Profile = struct 1484 - type main = { 1485 - avatar : Atp.Blob_ref.t option; 1486 - banner : Atp.Blob_ref.t option; 1487 - created_at : string option; 1488 - description : string option; 1489 - display_name : string option; 1490 - joined_via_starter_pack : Com.Atproto.Repo.StrongRef.main option; 1491 - labels : Com.Atproto.Label.Defs.self_labels option; 1492 - pinned_post : Com.Atproto.Repo.StrongRef.main option; 1493 - pronouns : string option; 1494 - website : string option; 1495 - } 1496 - 1497 - let main_jsont = 1498 - Jsont.Object.map ~kind:"Main" 1499 - (fun _typ avatar banner created_at description display_name joined_via_starter_pack labels pinned_post pronouns website -> { avatar; banner; created_at; description; display_name; joined_via_starter_pack; labels; pinned_post; pronouns; website }) 1500 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.actor.profile" ~enc:(fun _ -> "app.bsky.actor.profile") 1501 - |> Jsont.Object.opt_mem "avatar" Atp.Blob_ref.jsont ~enc:(fun r -> r.avatar) 1502 - |> Jsont.Object.opt_mem "banner" Atp.Blob_ref.jsont ~enc:(fun r -> r.banner) 1503 - |> Jsont.Object.opt_mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 1504 - |> Jsont.Object.opt_mem "description" Jsont.string ~enc:(fun r -> r.description) 1505 - |> Jsont.Object.opt_mem "displayName" Jsont.string ~enc:(fun r -> r.display_name) 1506 - |> Jsont.Object.opt_mem "joinedViaStarterPack" Com.Atproto.Repo.StrongRef.main_jsont ~enc:(fun r -> r.joined_via_starter_pack) 1507 - |> Jsont.Object.opt_mem "labels" Com.Atproto.Label.Defs.self_labels_jsont ~enc:(fun r -> r.labels) 1508 - |> Jsont.Object.opt_mem "pinnedPost" Com.Atproto.Repo.StrongRef.main_jsont ~enc:(fun r -> r.pinned_post) 1509 - |> Jsont.Object.opt_mem "pronouns" Jsont.string ~enc:(fun r -> r.pronouns) 1510 - |> Jsont.Object.opt_mem "website" Jsont.string ~enc:(fun r -> r.website) 1511 |> Jsont.Object.finish 1512 1513 end ··· 2048 |> Jsont.Object.finish 2049 2050 end 2051 module GetPreferences = struct 2052 type params = unit 2053 ··· 2065 |> Jsont.Object.finish 2066 2067 end 2068 - module SearchActorsTypeahead = struct 2069 type params = { 2070 limit : int option; 2071 - q : string option; 2072 - term : string option; 2073 } 2074 2075 let params_jsont = 2076 Jsont.Object.map ~kind:"Params" 2077 - (fun limit q term -> { 2078 limit; 2079 - q; 2080 - term; 2081 }) 2082 |> Jsont.Object.opt_mem "limit" Jsont.int 2083 ~enc:(fun r -> r.limit) 2084 - |> Jsont.Object.opt_mem "q" Jsont.string 2085 - ~enc:(fun r -> r.q) 2086 - |> Jsont.Object.opt_mem "term" Jsont.string 2087 - ~enc:(fun r -> r.term) 2088 |> Jsont.Object.finish 2089 2090 type output = { 2091 actors : Jsont.json list; 2092 } 2093 2094 let output_jsont = 2095 Jsont.Object.map ~kind:"Output" 2096 - (fun _typ actors -> { actors }) 2097 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.actor.searchActorsTypeahead#output" ~enc:(fun _ -> "app.bsky.actor.searchActorsTypeahead#output") 2098 |> Jsont.Object.mem "actors" (Jsont.list Jsont.json) ~enc:(fun r -> r.actors) 2099 |> Jsont.Object.finish 2100 2101 end ··· 2158 |> Jsont.Object.finish 2159 2160 end 2161 - module GetSuggestions = struct 2162 type params = { 2163 - cursor : string option; 2164 limit : int option; 2165 } 2166 2167 let params_jsont = 2168 Jsont.Object.map ~kind:"Params" 2169 - (fun cursor limit -> { 2170 - cursor; 2171 limit; 2172 }) 2173 - |> Jsont.Object.opt_mem "cursor" Jsont.string 2174 - ~enc:(fun r -> r.cursor) 2175 |> Jsont.Object.opt_mem "limit" Jsont.int 2176 ~enc:(fun r -> r.limit) 2177 |> Jsont.Object.finish 2178 2179 type output = { 2180 actors : Jsont.json list; 2181 - cursor : string option; 2182 - rec_id : int option; 2183 } 2184 2185 let output_jsont = 2186 Jsont.Object.map ~kind:"Output" 2187 - (fun _typ actors cursor rec_id -> { actors; cursor; rec_id }) 2188 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.actor.getSuggestions#output" ~enc:(fun _ -> "app.bsky.actor.getSuggestions#output") 2189 |> Jsont.Object.mem "actors" (Jsont.list Jsont.json) ~enc:(fun r -> r.actors) 2190 - |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 2191 - |> Jsont.Object.opt_mem "recId" Jsont.int ~enc:(fun r -> r.rec_id) 2192 |> Jsont.Object.finish 2193 2194 end 2195 - module GetProfiles = struct 2196 - type params = { 2197 - actors : string list; 2198 - } 2199 - 2200 - let params_jsont = 2201 - Jsont.Object.map ~kind:"Params" 2202 - (fun actors -> { 2203 - actors; 2204 - }) 2205 - |> Jsont.Object.mem "actors" (Jsont.list Jsont.string) 2206 - ~enc:(fun r -> r.actors) 2207 - |> Jsont.Object.finish 2208 - 2209 type output = { 2210 - profiles : Jsont.json list; 2211 } 2212 2213 let output_jsont = 2214 Jsont.Object.map ~kind:"Output" 2215 - (fun _typ profiles -> { profiles }) 2216 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.actor.getProfiles#output" ~enc:(fun _ -> "app.bsky.actor.getProfiles#output") 2217 - |> Jsont.Object.mem "profiles" (Jsont.list Jsont.json) ~enc:(fun r -> r.profiles) 2218 |> Jsont.Object.finish 2219 2220 end 2221 - module PutPreferences = struct 2222 - type input = { 2223 - preferences : Jsont.json; 2224 } 2225 2226 - let input_jsont = 2227 - Jsont.Object.map ~kind:"Input" 2228 - (fun _typ preferences -> { preferences }) 2229 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.actor.putPreferences#input" ~enc:(fun _ -> "app.bsky.actor.putPreferences#input") 2230 - |> Jsont.Object.mem "preferences" Jsont.json ~enc:(fun r -> r.preferences) 2231 |> Jsont.Object.finish 2232 2233 end 2234 - end 2235 - module Contact = struct 2236 - module Defs = struct 2237 - type sync_status = { 2238 - matches_count : int; 2239 - synced_at : string; 2240 - } 2241 - 2242 - let sync_status_jsont = 2243 - Jsont.Object.map ~kind:"Sync_status" 2244 - (fun _typ matches_count synced_at -> { matches_count; synced_at }) 2245 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.contact.defs#syncStatus" ~enc:(fun _ -> "app.bsky.contact.defs#syncStatus") 2246 - |> Jsont.Object.mem "matchesCount" Jsont.int ~enc:(fun r -> r.matches_count) 2247 - |> Jsont.Object.mem "syncedAt" Jsont.string ~enc:(fun r -> r.synced_at) 2248 - |> Jsont.Object.finish 2249 - 2250 - type notification = { 2251 - from : string; 2252 - to_ : string; 2253 } 2254 2255 - let notification_jsont = 2256 - Jsont.Object.map ~kind:"Notification" 2257 - (fun _typ from to_ -> { from; to_ }) 2258 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.contact.defs#notification" ~enc:(fun _ -> "app.bsky.contact.defs#notification") 2259 - |> Jsont.Object.mem "from" Jsont.string ~enc:(fun r -> r.from) 2260 - |> Jsont.Object.mem "to" Jsont.string ~enc:(fun r -> r.to_) 2261 |> Jsont.Object.finish 2262 2263 - type match_and_contact_index = { 2264 - contact_index : int; 2265 - match_ : Jsont.json; 2266 } 2267 2268 - let match_and_contact_index_jsont = 2269 - Jsont.Object.map ~kind:"Match_and_contact_index" 2270 - (fun _typ contact_index match_ -> { contact_index; match_ }) 2271 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.contact.defs#matchAndContactIndex" ~enc:(fun _ -> "app.bsky.contact.defs#matchAndContactIndex") 2272 - |> Jsont.Object.mem "contactIndex" Jsont.int ~enc:(fun r -> r.contact_index) 2273 - |> Jsont.Object.mem "match" Jsont.json ~enc:(fun r -> r.match_) 2274 |> Jsont.Object.finish 2275 2276 end 2277 - module RemoveData = struct 2278 type input = unit 2279 - 2280 let input_jsont = Jsont.ignore 2281 2282 - type output = unit 2283 - 2284 - let output_jsont = Jsont.ignore 2285 - 2286 - end 2287 - module DismissMatch = struct 2288 - type input = { 2289 - subject : string; 2290 - } 2291 - 2292 - let input_jsont = 2293 - Jsont.Object.map ~kind:"Input" 2294 - (fun _typ subject -> { subject }) 2295 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.contact.dismissMatch#input" ~enc:(fun _ -> "app.bsky.contact.dismissMatch#input") 2296 - |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 2297 - |> Jsont.Object.finish 2298 - 2299 - type output = unit 2300 - 2301 - let output_jsont = Jsont.ignore 2302 - 2303 - end 2304 - module GetMatches = struct 2305 - type params = { 2306 - cursor : string option; 2307 - limit : int option; 2308 - } 2309 - 2310 - let params_jsont = 2311 - Jsont.Object.map ~kind:"Params" 2312 - (fun cursor limit -> { 2313 - cursor; 2314 - limit; 2315 - }) 2316 - |> Jsont.Object.opt_mem "cursor" Jsont.string 2317 - ~enc:(fun r -> r.cursor) 2318 - |> Jsont.Object.opt_mem "limit" Jsont.int 2319 - ~enc:(fun r -> r.limit) 2320 - |> Jsont.Object.finish 2321 - 2322 type output = { 2323 - cursor : string option; 2324 - matches : Jsont.json list; 2325 } 2326 2327 let output_jsont = 2328 Jsont.Object.map ~kind:"Output" 2329 - (fun _typ cursor matches -> { cursor; matches }) 2330 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.contact.getMatches#output" ~enc:(fun _ -> "app.bsky.contact.getMatches#output") 2331 - |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 2332 - |> Jsont.Object.mem "matches" (Jsont.list Jsont.json) ~enc:(fun r -> r.matches) 2333 |> Jsont.Object.finish 2334 2335 end 2336 - module VerifyPhone = struct 2337 - type input = { 2338 - code : string; 2339 - phone : string; 2340 } 2341 2342 - let input_jsont = 2343 - Jsont.Object.map ~kind:"Input" 2344 - (fun _typ code phone -> { code; phone }) 2345 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.contact.verifyPhone#input" ~enc:(fun _ -> "app.bsky.contact.verifyPhone#input") 2346 - |> Jsont.Object.mem "code" Jsont.string ~enc:(fun r -> r.code) 2347 - |> Jsont.Object.mem "phone" Jsont.string ~enc:(fun r -> r.phone) 2348 |> Jsont.Object.finish 2349 2350 - type output = { 2351 - token : string; 2352 } 2353 2354 - let output_jsont = 2355 - Jsont.Object.map ~kind:"Output" 2356 - (fun _typ token -> { token }) 2357 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.contact.verifyPhone#output" ~enc:(fun _ -> "app.bsky.contact.verifyPhone#output") 2358 - |> Jsont.Object.mem "token" Jsont.string ~enc:(fun r -> r.token) 2359 |> Jsont.Object.finish 2360 2361 - end 2362 - module StartPhoneVerification = struct 2363 - type input = { 2364 - phone : string; 2365 } 2366 2367 - let input_jsont = 2368 - Jsont.Object.map ~kind:"Input" 2369 - (fun _typ phone -> { phone }) 2370 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.contact.startPhoneVerification#input" ~enc:(fun _ -> "app.bsky.contact.startPhoneVerification#input") 2371 - |> Jsont.Object.mem "phone" Jsont.string ~enc:(fun r -> r.phone) 2372 |> Jsont.Object.finish 2373 2374 - type output = unit 2375 - 2376 - let output_jsont = Jsont.ignore 2377 - 2378 - end 2379 - module SendNotification = struct 2380 - type input = { 2381 - from : string; 2382 - to_ : string; 2383 } 2384 2385 - let input_jsont = 2386 - Jsont.Object.map ~kind:"Input" 2387 - (fun _typ from to_ -> { from; to_ }) 2388 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.contact.sendNotification#input" ~enc:(fun _ -> "app.bsky.contact.sendNotification#input") 2389 - |> Jsont.Object.mem "from" Jsont.string ~enc:(fun r -> r.from) 2390 - |> Jsont.Object.mem "to" Jsont.string ~enc:(fun r -> r.to_) 2391 |> Jsont.Object.finish 2392 2393 - type output = unit 2394 2395 - let output_jsont = Jsont.ignore 2396 2397 end 2398 - module GetSyncStatus = struct 2399 - type params = unit 2400 2401 - let params_jsont = Jsont.ignore 2402 2403 - type output = { 2404 - sync_status : Defs.sync_status option; 2405 } 2406 2407 - let output_jsont = 2408 - Jsont.Object.map ~kind:"Output" 2409 - (fun _typ sync_status -> { sync_status }) 2410 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.contact.getSyncStatus#output" ~enc:(fun _ -> "app.bsky.contact.getSyncStatus#output") 2411 - |> Jsont.Object.opt_mem "syncStatus" Defs.sync_status_jsont ~enc:(fun r -> r.sync_status) 2412 |> Jsont.Object.finish 2413 2414 - end 2415 - module ImportContacts = struct 2416 - type input = { 2417 - contacts : string list; 2418 - token : string; 2419 } 2420 2421 - let input_jsont = 2422 - Jsont.Object.map ~kind:"Input" 2423 - (fun _typ contacts token -> { contacts; token }) 2424 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.contact.importContacts#input" ~enc:(fun _ -> "app.bsky.contact.importContacts#input") 2425 - |> Jsont.Object.mem "contacts" (Jsont.list Jsont.string) ~enc:(fun r -> r.contacts) 2426 - |> Jsont.Object.mem "token" Jsont.string ~enc:(fun r -> r.token) 2427 |> Jsont.Object.finish 2428 2429 - type output = { 2430 - matches_and_contact_indexes : Defs.match_and_contact_index list; 2431 } 2432 2433 - let output_jsont = 2434 - Jsont.Object.map ~kind:"Output" 2435 - (fun _typ matches_and_contact_indexes -> { matches_and_contact_indexes }) 2436 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.contact.importContacts#output" ~enc:(fun _ -> "app.bsky.contact.importContacts#output") 2437 - |> Jsont.Object.mem "matchesAndContactIndexes" (Jsont.list Defs.match_and_contact_index_jsont) ~enc:(fun r -> r.matches_and_contact_indexes) 2438 |> Jsont.Object.finish 2439 2440 - end 2441 - end 2442 - module Graph = struct 2443 - module Starterpack = struct 2444 - type feed_item = { 2445 - uri : string; 2446 } 2447 2448 - let feed_item_jsont = 2449 - Jsont.Object.map ~kind:"Feed_item" 2450 - (fun _typ uri -> { uri }) 2451 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.starterpack#feedItem" ~enc:(fun _ -> "app.bsky.graph.starterpack#feedItem") 2452 - |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 2453 |> Jsont.Object.finish 2454 2455 - type main = { 2456 - created_at : string; 2457 - description : string option; 2458 - description_facets : Richtext.Facet.main list option; 2459 - feeds : Jsont.json list option; 2460 - list_ : string; 2461 - name : string; 2462 } 2463 2464 - let main_jsont = 2465 - Jsont.Object.map ~kind:"Main" 2466 - (fun _typ created_at description description_facets feeds list_ name -> { created_at; description; description_facets; feeds; list_; name }) 2467 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.starterpack" ~enc:(fun _ -> "app.bsky.graph.starterpack") 2468 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 2469 - |> Jsont.Object.opt_mem "description" Jsont.string ~enc:(fun r -> r.description) 2470 - |> Jsont.Object.opt_mem "descriptionFacets" (Jsont.list Richtext.Facet.main_jsont) ~enc:(fun r -> r.description_facets) 2471 - |> Jsont.Object.opt_mem "feeds" (Jsont.list Jsont.json) ~enc:(fun r -> r.feeds) 2472 - |> Jsont.Object.mem "list" Jsont.string ~enc:(fun r -> r.list_) 2473 - |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 2474 |> Jsont.Object.finish 2475 2476 - end 2477 - module GetFollows = struct 2478 - type params = { 2479 - actor : string; 2480 - cursor : string option; 2481 - limit : int option; 2482 } 2483 2484 - let params_jsont = 2485 - Jsont.Object.map ~kind:"Params" 2486 - (fun actor cursor limit -> { 2487 - actor; 2488 - cursor; 2489 - limit; 2490 - }) 2491 - |> Jsont.Object.mem "actor" Jsont.string 2492 - ~enc:(fun r -> r.actor) 2493 - |> Jsont.Object.opt_mem "cursor" Jsont.string 2494 - ~enc:(fun r -> r.cursor) 2495 - |> Jsont.Object.opt_mem "limit" Jsont.int 2496 - ~enc:(fun r -> r.limit) 2497 |> Jsont.Object.finish 2498 2499 - type output = { 2500 - cursor : string option; 2501 - follows : Jsont.json list; 2502 - subject : Jsont.json; 2503 } 2504 2505 - let output_jsont = 2506 - Jsont.Object.map ~kind:"Output" 2507 - (fun _typ cursor follows subject -> { cursor; follows; subject }) 2508 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getFollows#output" ~enc:(fun _ -> "app.bsky.graph.getFollows#output") 2509 - |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 2510 - |> Jsont.Object.mem "follows" (Jsont.list Jsont.json) ~enc:(fun r -> r.follows) 2511 - |> Jsont.Object.mem "subject" Jsont.json ~enc:(fun r -> r.subject) 2512 |> Jsont.Object.finish 2513 2514 - end 2515 - module GetSuggestedFollowsByActor = struct 2516 - type params = { 2517 - actor : string; 2518 } 2519 2520 - let params_jsont = 2521 - Jsont.Object.map ~kind:"Params" 2522 - (fun actor -> { 2523 - actor; 2524 - }) 2525 - |> Jsont.Object.mem "actor" Jsont.string 2526 - ~enc:(fun r -> r.actor) 2527 |> Jsont.Object.finish 2528 2529 - type output = { 2530 - is_fallback : bool option; 2531 - rec_id : int option; 2532 - suggestions : Jsont.json list; 2533 } 2534 2535 - let output_jsont = 2536 - Jsont.Object.map ~kind:"Output" 2537 - (fun _typ is_fallback rec_id suggestions -> { is_fallback; rec_id; suggestions }) 2538 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getSuggestedFollowsByActor#output" ~enc:(fun _ -> "app.bsky.graph.getSuggestedFollowsByActor#output") 2539 - |> Jsont.Object.opt_mem "isFallback" Jsont.bool ~enc:(fun r -> r.is_fallback) 2540 - |> Jsont.Object.opt_mem "recId" Jsont.int ~enc:(fun r -> r.rec_id) 2541 - |> Jsont.Object.mem "suggestions" (Jsont.list Jsont.json) ~enc:(fun r -> r.suggestions) 2542 |> Jsont.Object.finish 2543 2544 - end 2545 - module Block = struct 2546 - type main = { 2547 - created_at : string; 2548 - subject : string; 2549 } 2550 2551 - let main_jsont = 2552 - Jsont.Object.map ~kind:"Main" 2553 - (fun _typ created_at subject -> { created_at; subject }) 2554 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.block" ~enc:(fun _ -> "app.bsky.graph.block") 2555 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 2556 - |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 2557 |> Jsont.Object.finish 2558 2559 - end 2560 - module Listblock = struct 2561 - type main = { 2562 - created_at : string; 2563 - subject : string; 2564 } 2565 2566 - let main_jsont = 2567 - Jsont.Object.map ~kind:"Main" 2568 - (fun _typ created_at subject -> { created_at; subject }) 2569 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.listblock" ~enc:(fun _ -> "app.bsky.graph.listblock") 2570 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 2571 - |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 2572 |> Jsont.Object.finish 2573 2574 - end 2575 - module MuteThread = struct 2576 - type input = { 2577 - root : string; 2578 } 2579 2580 - let input_jsont = 2581 - Jsont.Object.map ~kind:"Input" 2582 - (fun _typ root -> { root }) 2583 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.muteThread#input" ~enc:(fun _ -> "app.bsky.graph.muteThread#input") 2584 - |> Jsont.Object.mem "root" Jsont.string ~enc:(fun r -> r.root) 2585 |> Jsont.Object.finish 2586 2587 end 2588 - module GetFollowers = struct 2589 type params = { 2590 - actor : string; 2591 - cursor : string option; 2592 - limit : int option; 2593 } 2594 2595 let params_jsont = 2596 Jsont.Object.map ~kind:"Params" 2597 - (fun actor cursor limit -> { 2598 - actor; 2599 - cursor; 2600 - limit; 2601 }) 2602 - |> Jsont.Object.mem "actor" Jsont.string 2603 - ~enc:(fun r -> r.actor) 2604 - |> Jsont.Object.opt_mem "cursor" Jsont.string 2605 - ~enc:(fun r -> r.cursor) 2606 - |> Jsont.Object.opt_mem "limit" Jsont.int 2607 - ~enc:(fun r -> r.limit) 2608 |> Jsont.Object.finish 2609 2610 type output = { 2611 - cursor : string option; 2612 - followers : Jsont.json list; 2613 - subject : Jsont.json; 2614 } 2615 2616 let output_jsont = 2617 Jsont.Object.map ~kind:"Output" 2618 - (fun _typ cursor followers subject -> { cursor; followers; subject }) 2619 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getFollowers#output" ~enc:(fun _ -> "app.bsky.graph.getFollowers#output") 2620 - |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 2621 - |> Jsont.Object.mem "followers" (Jsont.list Jsont.json) ~enc:(fun r -> r.followers) 2622 - |> Jsont.Object.mem "subject" Jsont.json ~enc:(fun r -> r.subject) 2623 |> Jsont.Object.finish 2624 2625 end 2626 - module UnmuteThread = struct 2627 type input = { 2628 - root : string; 2629 } 2630 2631 let input_jsont = 2632 Jsont.Object.map ~kind:"Input" 2633 - (fun _typ root -> { root }) 2634 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.unmuteThread#input" ~enc:(fun _ -> "app.bsky.graph.unmuteThread#input") 2635 - |> Jsont.Object.mem "root" Jsont.string ~enc:(fun r -> r.root) 2636 |> Jsont.Object.finish 2637 2638 end 2639 - module Follow = struct 2640 - type main = { 2641 - created_at : string; 2642 - subject : string; 2643 - via : Com.Atproto.Repo.StrongRef.main option; 2644 } 2645 2646 - let main_jsont = 2647 - Jsont.Object.map ~kind:"Main" 2648 - (fun _typ created_at subject via -> { created_at; subject; via }) 2649 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.follow" ~enc:(fun _ -> "app.bsky.graph.follow") 2650 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 2651 - |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 2652 - |> Jsont.Object.opt_mem "via" Com.Atproto.Repo.StrongRef.main_jsont ~enc:(fun r -> r.via) 2653 |> Jsont.Object.finish 2654 2655 end 2656 - module UnmuteActor = struct 2657 - type input = { 2658 - actor : string; 2659 } 2660 2661 - let input_jsont = 2662 - Jsont.Object.map ~kind:"Input" 2663 - (fun _typ actor -> { actor }) 2664 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.unmuteActor#input" ~enc:(fun _ -> "app.bsky.graph.unmuteActor#input") 2665 - |> Jsont.Object.mem "actor" Jsont.string ~enc:(fun r -> r.actor) 2666 |> Jsont.Object.finish 2667 2668 - end 2669 - module MuteActorList = struct 2670 - type input = { 2671 - list_ : string; 2672 } 2673 2674 - let input_jsont = 2675 - Jsont.Object.map ~kind:"Input" 2676 - (fun _typ list_ -> { list_ }) 2677 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.muteActorList#input" ~enc:(fun _ -> "app.bsky.graph.muteActorList#input") 2678 - |> Jsont.Object.mem "list" Jsont.string ~enc:(fun r -> r.list_) 2679 |> Jsont.Object.finish 2680 2681 - end 2682 - module UnmuteActorList = struct 2683 - type input = { 2684 - list_ : string; 2685 } 2686 2687 - let input_jsont = 2688 - Jsont.Object.map ~kind:"Input" 2689 - (fun _typ list_ -> { list_ }) 2690 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.unmuteActorList#input" ~enc:(fun _ -> "app.bsky.graph.unmuteActorList#input") 2691 - |> Jsont.Object.mem "list" Jsont.string ~enc:(fun r -> r.list_) 2692 |> Jsont.Object.finish 2693 2694 end 2695 - module GetKnownFollowers = struct 2696 - type params = { 2697 - actor : string; 2698 - cursor : string option; 2699 - limit : int option; 2700 } 2701 2702 - let params_jsont = 2703 - Jsont.Object.map ~kind:"Params" 2704 - (fun actor cursor limit -> { 2705 - actor; 2706 - cursor; 2707 - limit; 2708 - }) 2709 - |> Jsont.Object.mem "actor" Jsont.string 2710 - ~enc:(fun r -> r.actor) 2711 - |> Jsont.Object.opt_mem "cursor" Jsont.string 2712 - ~enc:(fun r -> r.cursor) 2713 - |> Jsont.Object.opt_mem "limit" Jsont.int 2714 - ~enc:(fun r -> r.limit) 2715 |> Jsont.Object.finish 2716 2717 - type output = { 2718 - cursor : string option; 2719 - followers : Jsont.json list; 2720 - subject : Jsont.json; 2721 } 2722 2723 - let output_jsont = 2724 - Jsont.Object.map ~kind:"Output" 2725 - (fun _typ cursor followers subject -> { cursor; followers; subject }) 2726 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getKnownFollowers#output" ~enc:(fun _ -> "app.bsky.graph.getKnownFollowers#output") 2727 - |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 2728 - |> Jsont.Object.mem "followers" (Jsont.list Jsont.json) ~enc:(fun r -> r.followers) 2729 - |> Jsont.Object.mem "subject" Jsont.json ~enc:(fun r -> r.subject) 2730 |> Jsont.Object.finish 2731 2732 - end 2733 - module MuteActor = struct 2734 - type input = { 2735 - actor : string; 2736 } 2737 2738 - let input_jsont = 2739 - Jsont.Object.map ~kind:"Input" 2740 - (fun _typ actor -> { actor }) 2741 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.muteActor#input" ~enc:(fun _ -> "app.bsky.graph.muteActor#input") 2742 - |> Jsont.Object.mem "actor" Jsont.string ~enc:(fun r -> r.actor) 2743 |> Jsont.Object.finish 2744 2745 - end 2746 - module Listitem = struct 2747 type main = { 2748 - created_at : string; 2749 - list_ : string; 2750 - subject : string; 2751 } 2752 2753 let main_jsont = 2754 Jsont.Object.map ~kind:"Main" 2755 - (fun _typ created_at list_ subject -> { created_at; list_; subject }) 2756 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.listitem" ~enc:(fun _ -> "app.bsky.graph.listitem") 2757 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 2758 - |> Jsont.Object.mem "list" Jsont.string ~enc:(fun r -> r.list_) 2759 - |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 2760 |> Jsont.Object.finish 2761 2762 end 2763 - module Defs = struct 2764 - type starter_pack_view_basic = { 2765 cid : string; 2766 - creator : Jsont.json; 2767 - indexed_at : string; 2768 - joined_all_time_count : int option; 2769 - joined_week_count : int option; 2770 - labels : Com.Atproto.Label.Defs.label list option; 2771 - list_item_count : int option; 2772 - record : Jsont.json; 2773 - uri : string; 2774 } 2775 2776 - let starter_pack_view_basic_jsont = 2777 - Jsont.Object.map ~kind:"Starter_pack_view_basic" 2778 - (fun _typ cid creator indexed_at joined_all_time_count joined_week_count labels list_item_count record uri -> { cid; creator; indexed_at; joined_all_time_count; joined_week_count; labels; list_item_count; record; uri }) 2779 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.defs#starterPackViewBasic" ~enc:(fun _ -> "app.bsky.graph.defs#starterPackViewBasic") 2780 |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 2781 - |> Jsont.Object.mem "creator" Jsont.json ~enc:(fun r -> r.creator) 2782 - |> Jsont.Object.mem "indexedAt" Jsont.string ~enc:(fun r -> r.indexed_at) 2783 - |> Jsont.Object.opt_mem "joinedAllTimeCount" Jsont.int ~enc:(fun r -> r.joined_all_time_count) 2784 - |> Jsont.Object.opt_mem "joinedWeekCount" Jsont.int ~enc:(fun r -> r.joined_week_count) 2785 - |> Jsont.Object.opt_mem "labels" (Jsont.list Com.Atproto.Label.Defs.label_jsont) ~enc:(fun r -> r.labels) 2786 - |> Jsont.Object.opt_mem "listItemCount" Jsont.int ~enc:(fun r -> r.list_item_count) 2787 - |> Jsont.Object.mem "record" Jsont.json ~enc:(fun r -> r.record) 2788 - |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 2789 |> Jsont.Object.finish 2790 2791 - type relationship = { 2792 - blocked_by : string option; 2793 - blocked_by_list : string option; 2794 - blocking : string option; 2795 - blocking_by_list : string option; 2796 - did : string; 2797 - followed_by : string option; 2798 - following : string option; 2799 } 2800 2801 - let relationship_jsont = 2802 - Jsont.Object.map ~kind:"Relationship" 2803 - (fun _typ blocked_by blocked_by_list blocking blocking_by_list did followed_by following -> { blocked_by; blocked_by_list; blocking; blocking_by_list; did; followed_by; following }) 2804 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.defs#relationship" ~enc:(fun _ -> "app.bsky.graph.defs#relationship") 2805 - |> Jsont.Object.opt_mem "blockedBy" Jsont.string ~enc:(fun r -> r.blocked_by) 2806 - |> Jsont.Object.opt_mem "blockedByList" Jsont.string ~enc:(fun r -> r.blocked_by_list) 2807 - |> Jsont.Object.opt_mem "blocking" Jsont.string ~enc:(fun r -> r.blocking) 2808 - |> Jsont.Object.opt_mem "blockingByList" Jsont.string ~enc:(fun r -> r.blocking_by_list) 2809 - |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 2810 - |> Jsont.Object.opt_mem "followedBy" Jsont.string ~enc:(fun r -> r.followed_by) 2811 - |> Jsont.Object.opt_mem "following" Jsont.string ~enc:(fun r -> r.following) 2812 |> Jsont.Object.finish 2813 2814 - type referencelist = string 2815 - let referencelist_jsont = Jsont.string 2816 - 2817 - type not_found_actor = { 2818 - actor : string; 2819 - not_found : bool; 2820 } 2821 2822 - let not_found_actor_jsont = 2823 - Jsont.Object.map ~kind:"Not_found_actor" 2824 - (fun _typ actor not_found -> { actor; not_found }) 2825 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.defs#notFoundActor" ~enc:(fun _ -> "app.bsky.graph.defs#notFoundActor") 2826 - |> Jsont.Object.mem "actor" Jsont.string ~enc:(fun r -> r.actor) 2827 - |> Jsont.Object.mem "notFound" Jsont.bool ~enc:(fun r -> r.not_found) 2828 |> Jsont.Object.finish 2829 2830 - type modlist = string 2831 - let modlist_jsont = Jsont.string 2832 - 2833 - type list_viewer_state = { 2834 - blocked : string option; 2835 - muted : bool option; 2836 } 2837 2838 - let list_viewer_state_jsont = 2839 - Jsont.Object.map ~kind:"List_viewer_state" 2840 - (fun _typ blocked muted -> { blocked; muted }) 2841 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.defs#listViewerState" ~enc:(fun _ -> "app.bsky.graph.defs#listViewerState") 2842 - |> Jsont.Object.opt_mem "blocked" Jsont.string ~enc:(fun r -> r.blocked) 2843 - |> Jsont.Object.opt_mem "muted" Jsont.bool ~enc:(fun r -> r.muted) 2844 |> Jsont.Object.finish 2845 2846 - type list_purpose = string 2847 - let list_purpose_jsont = Jsont.string 2848 - 2849 - type list_item_view = { 2850 - subject : Jsont.json; 2851 - uri : string; 2852 } 2853 2854 - let list_item_view_jsont = 2855 - Jsont.Object.map ~kind:"List_item_view" 2856 - (fun _typ subject uri -> { subject; uri }) 2857 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.defs#listItemView" ~enc:(fun _ -> "app.bsky.graph.defs#listItemView") 2858 - |> Jsont.Object.mem "subject" Jsont.json ~enc:(fun r -> r.subject) 2859 - |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 2860 |> Jsont.Object.finish 2861 2862 - type curatelist = string 2863 - let curatelist_jsont = Jsont.string 2864 - 2865 - type list_view_basic = { 2866 - avatar : string option; 2867 cid : string; 2868 - indexed_at : string option; 2869 labels : Com.Atproto.Label.Defs.label list option; 2870 - list_item_count : int option; 2871 - name : string; 2872 - purpose : Jsont.json; 2873 uri : string; 2874 - viewer : Jsont.json option; 2875 } 2876 2877 - let list_view_basic_jsont = 2878 - Jsont.Object.map ~kind:"List_view_basic" 2879 - (fun _typ avatar cid indexed_at labels list_item_count name purpose uri viewer -> { avatar; cid; indexed_at; labels; list_item_count; name; purpose; uri; viewer }) 2880 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.defs#listViewBasic" ~enc:(fun _ -> "app.bsky.graph.defs#listViewBasic") 2881 - |> Jsont.Object.opt_mem "avatar" Jsont.string ~enc:(fun r -> r.avatar) 2882 |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 2883 - |> Jsont.Object.opt_mem "indexedAt" Jsont.string ~enc:(fun r -> r.indexed_at) 2884 |> Jsont.Object.opt_mem "labels" (Jsont.list Com.Atproto.Label.Defs.label_jsont) ~enc:(fun r -> r.labels) 2885 - |> Jsont.Object.opt_mem "listItemCount" Jsont.int ~enc:(fun r -> r.list_item_count) 2886 - |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 2887 - |> Jsont.Object.mem "purpose" Jsont.json ~enc:(fun r -> r.purpose) 2888 |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 2889 - |> Jsont.Object.opt_mem "viewer" Jsont.json ~enc:(fun r -> r.viewer) 2890 |> Jsont.Object.finish 2891 2892 - type list_view = { 2893 - avatar : string option; 2894 - cid : string; 2895 - creator : Jsont.json; 2896 - description : string option; 2897 - description_facets : Richtext.Facet.main list option; 2898 - indexed_at : string; 2899 - labels : Com.Atproto.Label.Defs.label list option; 2900 - list_item_count : int option; 2901 - name : string; 2902 - purpose : Jsont.json; 2903 uri : string; 2904 - viewer : Jsont.json option; 2905 } 2906 2907 - let list_view_jsont = 2908 - Jsont.Object.map ~kind:"List_view" 2909 - (fun _typ avatar cid creator description description_facets indexed_at labels list_item_count name purpose uri viewer -> { avatar; cid; creator; description; description_facets; indexed_at; labels; list_item_count; name; purpose; uri; viewer }) 2910 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.defs#listView" ~enc:(fun _ -> "app.bsky.graph.defs#listView") 2911 - |> Jsont.Object.opt_mem "avatar" Jsont.string ~enc:(fun r -> r.avatar) 2912 - |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 2913 - |> Jsont.Object.mem "creator" Jsont.json ~enc:(fun r -> r.creator) 2914 - |> Jsont.Object.opt_mem "description" Jsont.string ~enc:(fun r -> r.description) 2915 - |> Jsont.Object.opt_mem "descriptionFacets" (Jsont.list Richtext.Facet.main_jsont) ~enc:(fun r -> r.description_facets) 2916 - |> Jsont.Object.mem "indexedAt" Jsont.string ~enc:(fun r -> r.indexed_at) 2917 - |> Jsont.Object.opt_mem "labels" (Jsont.list Com.Atproto.Label.Defs.label_jsont) ~enc:(fun r -> r.labels) 2918 - |> Jsont.Object.opt_mem "listItemCount" Jsont.int ~enc:(fun r -> r.list_item_count) 2919 - |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 2920 - |> Jsont.Object.mem "purpose" Jsont.json ~enc:(fun r -> r.purpose) 2921 |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 2922 - |> Jsont.Object.opt_mem "viewer" Jsont.json ~enc:(fun r -> r.viewer) 2923 |> Jsont.Object.finish 2924 2925 - type starter_pack_view = { 2926 - cid : string; 2927 - creator : Jsont.json; 2928 - feeds : Jsont.json list option; 2929 - indexed_at : string; 2930 - joined_all_time_count : int option; 2931 - joined_week_count : int option; 2932 - labels : Com.Atproto.Label.Defs.label list option; 2933 - list_ : Jsont.json option; 2934 - list_items_sample : Jsont.json list option; 2935 - record : Jsont.json; 2936 uri : string; 2937 } 2938 2939 - let starter_pack_view_jsont = 2940 - Jsont.Object.map ~kind:"Starter_pack_view" 2941 - (fun _typ cid creator feeds indexed_at joined_all_time_count joined_week_count labels list_ list_items_sample record uri -> { cid; creator; feeds; indexed_at; joined_all_time_count; joined_week_count; labels; list_; list_items_sample; record; uri }) 2942 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.defs#starterPackView" ~enc:(fun _ -> "app.bsky.graph.defs#starterPackView") 2943 - |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 2944 - |> Jsont.Object.mem "creator" Jsont.json ~enc:(fun r -> r.creator) 2945 - |> Jsont.Object.opt_mem "feeds" (Jsont.list Jsont.json) ~enc:(fun r -> r.feeds) 2946 - |> Jsont.Object.mem "indexedAt" Jsont.string ~enc:(fun r -> r.indexed_at) 2947 - |> Jsont.Object.opt_mem "joinedAllTimeCount" Jsont.int ~enc:(fun r -> r.joined_all_time_count) 2948 - |> Jsont.Object.opt_mem "joinedWeekCount" Jsont.int ~enc:(fun r -> r.joined_week_count) 2949 - |> Jsont.Object.opt_mem "labels" (Jsont.list Com.Atproto.Label.Defs.label_jsont) ~enc:(fun r -> r.labels) 2950 - |> Jsont.Object.opt_mem "list" Jsont.json ~enc:(fun r -> r.list_) 2951 - |> Jsont.Object.opt_mem "listItemsSample" (Jsont.list Jsont.json) ~enc:(fun r -> r.list_items_sample) 2952 - |> Jsont.Object.mem "record" Jsont.json ~enc:(fun r -> r.record) 2953 |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 2954 |> Jsont.Object.finish 2955 2956 - end 2957 - module GetBlocks = struct 2958 - type params = { 2959 - cursor : string option; 2960 - limit : int option; 2961 } 2962 2963 - let params_jsont = 2964 - Jsont.Object.map ~kind:"Params" 2965 - (fun cursor limit -> { 2966 - cursor; 2967 - limit; 2968 - }) 2969 - |> Jsont.Object.opt_mem "cursor" Jsont.string 2970 - ~enc:(fun r -> r.cursor) 2971 - |> Jsont.Object.opt_mem "limit" Jsont.int 2972 - ~enc:(fun r -> r.limit) 2973 |> Jsont.Object.finish 2974 2975 - type output = { 2976 - blocks : Jsont.json list; 2977 - cursor : string option; 2978 } 2979 2980 - let output_jsont = 2981 - Jsont.Object.map ~kind:"Output" 2982 - (fun _typ blocks cursor -> { blocks; cursor }) 2983 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getBlocks#output" ~enc:(fun _ -> "app.bsky.graph.getBlocks#output") 2984 - |> Jsont.Object.mem "blocks" (Jsont.list Jsont.json) ~enc:(fun r -> r.blocks) 2985 - |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 2986 |> Jsont.Object.finish 2987 2988 - end 2989 - module Verification = struct 2990 type main = { 2991 - created_at : string; 2992 - display_name : string; 2993 - handle : string; 2994 - subject : string; 2995 } 2996 2997 let main_jsont = 2998 Jsont.Object.map ~kind:"Main" 2999 - (fun _typ created_at display_name handle subject -> { created_at; display_name; handle; subject }) 3000 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.verification" ~enc:(fun _ -> "app.bsky.graph.verification") 3001 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 3002 - |> Jsont.Object.mem "displayName" Jsont.string ~enc:(fun r -> r.display_name) 3003 - |> Jsont.Object.mem "handle" Jsont.string ~enc:(fun r -> r.handle) 3004 - |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 3005 |> Jsont.Object.finish 3006 3007 end 3008 - module GetMutes = struct 3009 - type params = { 3010 - cursor : string option; 3011 - limit : int option; 3012 } 3013 3014 - let params_jsont = 3015 - Jsont.Object.map ~kind:"Params" 3016 - (fun cursor limit -> { 3017 - cursor; 3018 - limit; 3019 - }) 3020 - |> Jsont.Object.opt_mem "cursor" Jsont.string 3021 - ~enc:(fun r -> r.cursor) 3022 - |> Jsont.Object.opt_mem "limit" Jsont.int 3023 - ~enc:(fun r -> r.limit) 3024 |> Jsont.Object.finish 3025 3026 - type output = { 3027 - cursor : string option; 3028 - mutes : Jsont.json list; 3029 - } 3030 3031 - let output_jsont = 3032 - Jsont.Object.map ~kind:"Output" 3033 - (fun _typ cursor mutes -> { cursor; mutes }) 3034 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getMutes#output" ~enc:(fun _ -> "app.bsky.graph.getMutes#output") 3035 - |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 3036 - |> Jsont.Object.mem "mutes" (Jsont.list Jsont.json) ~enc:(fun r -> r.mutes) 3037 - |> Jsont.Object.finish 3038 3039 end 3040 - module GetRelationships = struct 3041 - type params = { 3042 - actor : string; 3043 - others : string list option; 3044 } 3045 3046 - let params_jsont = 3047 - Jsont.Object.map ~kind:"Params" 3048 - (fun actor others -> { 3049 - actor; 3050 - others; 3051 - }) 3052 - |> Jsont.Object.mem "actor" Jsont.string 3053 - ~enc:(fun r -> r.actor) 3054 - |> Jsont.Object.opt_mem "others" (Jsont.list Jsont.string) 3055 - ~enc:(fun r -> r.others) 3056 |> Jsont.Object.finish 3057 3058 - type output = { 3059 - actor : string option; 3060 - relationships : Jsont.json list; 3061 - } 3062 3063 - let output_jsont = 3064 - Jsont.Object.map ~kind:"Output" 3065 - (fun _typ actor relationships -> { actor; relationships }) 3066 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getRelationships#output" ~enc:(fun _ -> "app.bsky.graph.getRelationships#output") 3067 - |> Jsont.Object.opt_mem "actor" Jsont.string ~enc:(fun r -> r.actor) 3068 - |> Jsont.Object.mem "relationships" (Jsont.list Jsont.json) ~enc:(fun r -> r.relationships) 3069 - |> Jsont.Object.finish 3070 3071 end 3072 - module GetStarterPacksWithMembership = struct 3073 - type starter_pack_with_membership = { 3074 - list_item : Jsont.json option; 3075 - starter_pack : Jsont.json; 3076 - } 3077 - 3078 - let starter_pack_with_membership_jsont = 3079 - Jsont.Object.map ~kind:"Starter_pack_with_membership" 3080 - (fun _typ list_item starter_pack -> { list_item; starter_pack }) 3081 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getStarterPacksWithMembership#starterPackWithMembership" ~enc:(fun _ -> "app.bsky.graph.getStarterPacksWithMembership#starterPackWithMembership") 3082 - |> Jsont.Object.opt_mem "listItem" Jsont.json ~enc:(fun r -> r.list_item) 3083 - |> Jsont.Object.mem "starterPack" Jsont.json ~enc:(fun r -> r.starter_pack) 3084 - |> Jsont.Object.finish 3085 - 3086 type params = { 3087 - actor : string; 3088 cursor : string option; 3089 limit : int option; 3090 } 3091 3092 let params_jsont = 3093 Jsont.Object.map ~kind:"Params" 3094 - (fun actor cursor limit -> { 3095 - actor; 3096 cursor; 3097 limit; 3098 }) 3099 - |> Jsont.Object.mem "actor" Jsont.string 3100 - ~enc:(fun r -> r.actor) 3101 |> Jsont.Object.opt_mem "cursor" Jsont.string 3102 ~enc:(fun r -> r.cursor) 3103 |> Jsont.Object.opt_mem "limit" Jsont.int ··· 3106 3107 type output = { 3108 cursor : string option; 3109 - starter_packs_with_membership : Jsont.json list; 3110 } 3111 3112 let output_jsont = 3113 Jsont.Object.map ~kind:"Output" 3114 - (fun _typ cursor starter_packs_with_membership -> { cursor; starter_packs_with_membership }) 3115 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getStarterPacksWithMembership#output" ~enc:(fun _ -> "app.bsky.graph.getStarterPacksWithMembership#output") 3116 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 3117 - |> Jsont.Object.mem "starterPacksWithMembership" (Jsont.list Jsont.json) ~enc:(fun r -> r.starter_packs_with_membership) 3118 |> Jsont.Object.finish 3119 3120 end 3121 - module GetActorStarterPacks = struct 3122 - type params = { 3123 - actor : string; 3124 - cursor : string option; 3125 - limit : int option; 3126 } 3127 3128 - let params_jsont = 3129 - Jsont.Object.map ~kind:"Params" 3130 - (fun actor cursor limit -> { 3131 - actor; 3132 - cursor; 3133 - limit; 3134 - }) 3135 - |> Jsont.Object.mem "actor" Jsont.string 3136 - ~enc:(fun r -> r.actor) 3137 - |> Jsont.Object.opt_mem "cursor" Jsont.string 3138 - ~enc:(fun r -> r.cursor) 3139 - |> Jsont.Object.opt_mem "limit" Jsont.int 3140 - ~enc:(fun r -> r.limit) 3141 |> Jsont.Object.finish 3142 3143 type output = { 3144 - cursor : string option; 3145 - starter_packs : Jsont.json list; 3146 } 3147 3148 let output_jsont = 3149 Jsont.Object.map ~kind:"Output" 3150 - (fun _typ cursor starter_packs -> { cursor; starter_packs }) 3151 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getActorStarterPacks#output" ~enc:(fun _ -> "app.bsky.graph.getActorStarterPacks#output") 3152 - |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 3153 - |> Jsont.Object.mem "starterPacks" (Jsont.list Jsont.json) ~enc:(fun r -> r.starter_packs) 3154 |> Jsont.Object.finish 3155 3156 end 3157 - module List = struct 3158 - type main = { 3159 - avatar : Atp.Blob_ref.t option; 3160 - created_at : string; 3161 - description : string option; 3162 - description_facets : Richtext.Facet.main list option; 3163 - labels : Com.Atproto.Label.Defs.self_labels option; 3164 - name : string; 3165 - purpose : Jsont.json; 3166 - } 3167 3168 - let main_jsont = 3169 - Jsont.Object.map ~kind:"Main" 3170 - (fun _typ avatar created_at description description_facets labels name purpose -> { avatar; created_at; description; description_facets; labels; name; purpose }) 3171 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.list" ~enc:(fun _ -> "app.bsky.graph.list") 3172 - |> Jsont.Object.opt_mem "avatar" Atp.Blob_ref.jsont ~enc:(fun r -> r.avatar) 3173 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 3174 - |> Jsont.Object.opt_mem "description" Jsont.string ~enc:(fun r -> r.description) 3175 - |> Jsont.Object.opt_mem "descriptionFacets" (Jsont.list Richtext.Facet.main_jsont) ~enc:(fun r -> r.description_facets) 3176 - |> Jsont.Object.opt_mem "labels" Com.Atproto.Label.Defs.self_labels_jsont ~enc:(fun r -> r.labels) 3177 - |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 3178 - |> Jsont.Object.mem "purpose" Jsont.json ~enc:(fun r -> r.purpose) 3179 - |> Jsont.Object.finish 3180 3181 - end 3182 - module SearchStarterPacks = struct 3183 - type params = { 3184 - cursor : string option; 3185 - limit : int option; 3186 - q : string; 3187 - } 3188 3189 - let params_jsont = 3190 - Jsont.Object.map ~kind:"Params" 3191 - (fun cursor limit q -> { 3192 - cursor; 3193 - limit; 3194 - q; 3195 - }) 3196 - |> Jsont.Object.opt_mem "cursor" Jsont.string 3197 - ~enc:(fun r -> r.cursor) 3198 - |> Jsont.Object.opt_mem "limit" Jsont.int 3199 - ~enc:(fun r -> r.limit) 3200 - |> Jsont.Object.mem "q" Jsont.string 3201 - ~enc:(fun r -> r.q) 3202 - |> Jsont.Object.finish 3203 3204 - type output = { 3205 - cursor : string option; 3206 - starter_packs : Jsont.json list; 3207 } 3208 3209 - let output_jsont = 3210 - Jsont.Object.map ~kind:"Output" 3211 - (fun _typ cursor starter_packs -> { cursor; starter_packs }) 3212 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.searchStarterPacks#output" ~enc:(fun _ -> "app.bsky.graph.searchStarterPacks#output") 3213 - |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 3214 - |> Jsont.Object.mem "starterPacks" (Jsont.list Jsont.json) ~enc:(fun r -> r.starter_packs) 3215 |> Jsont.Object.finish 3216 3217 - end 3218 - module GetList = struct 3219 - type params = { 3220 - cursor : string option; 3221 - limit : int option; 3222 - list_ : string; 3223 } 3224 3225 - let params_jsont = 3226 - Jsont.Object.map ~kind:"Params" 3227 - (fun cursor limit list_ -> { 3228 - cursor; 3229 - limit; 3230 - list_; 3231 - }) 3232 - |> Jsont.Object.opt_mem "cursor" Jsont.string 3233 - ~enc:(fun r -> r.cursor) 3234 - |> Jsont.Object.opt_mem "limit" Jsont.int 3235 - ~enc:(fun r -> r.limit) 3236 - |> Jsont.Object.mem "list" Jsont.string 3237 - ~enc:(fun r -> r.list_) 3238 |> Jsont.Object.finish 3239 3240 - type output = { 3241 - cursor : string option; 3242 - items : Jsont.json list; 3243 - list_ : Jsont.json; 3244 } 3245 3246 - let output_jsont = 3247 - Jsont.Object.map ~kind:"Output" 3248 - (fun _typ cursor items list_ -> { cursor; items; list_ }) 3249 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getList#output" ~enc:(fun _ -> "app.bsky.graph.getList#output") 3250 - |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 3251 - |> Jsont.Object.mem "items" (Jsont.list Jsont.json) ~enc:(fun r -> r.items) 3252 - |> Jsont.Object.mem "list" Jsont.json ~enc:(fun r -> r.list_) 3253 |> Jsont.Object.finish 3254 3255 end 3256 - module GetListBlocks = struct 3257 - type params = { 3258 - cursor : string option; 3259 - limit : int option; 3260 } 3261 3262 - let params_jsont = 3263 - Jsont.Object.map ~kind:"Params" 3264 - (fun cursor limit -> { 3265 - cursor; 3266 - limit; 3267 - }) 3268 - |> Jsont.Object.opt_mem "cursor" Jsont.string 3269 - ~enc:(fun r -> r.cursor) 3270 - |> Jsont.Object.opt_mem "limit" Jsont.int 3271 - ~enc:(fun r -> r.limit) 3272 |> Jsont.Object.finish 3273 3274 - type output = { 3275 - cursor : string option; 3276 - lists : Jsont.json list; 3277 - } 3278 3279 - let output_jsont = 3280 - Jsont.Object.map ~kind:"Output" 3281 - (fun _typ cursor lists -> { cursor; lists }) 3282 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getListBlocks#output" ~enc:(fun _ -> "app.bsky.graph.getListBlocks#output") 3283 - |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 3284 - |> Jsont.Object.mem "lists" (Jsont.list Jsont.json) ~enc:(fun r -> r.lists) 3285 - |> Jsont.Object.finish 3286 3287 end 3288 - module GetStarterPack = struct 3289 - type params = { 3290 - starter_pack : string; 3291 - } 3292 3293 - let params_jsont = 3294 - Jsont.Object.map ~kind:"Params" 3295 - (fun starter_pack -> { 3296 - starter_pack; 3297 - }) 3298 - |> Jsont.Object.mem "starterPack" Jsont.string 3299 - ~enc:(fun r -> r.starter_pack) 3300 - |> Jsont.Object.finish 3301 3302 type output = { 3303 - starter_pack : Jsont.json; 3304 } 3305 3306 let output_jsont = 3307 Jsont.Object.map ~kind:"Output" 3308 - (fun _typ starter_pack -> { starter_pack }) 3309 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getStarterPack#output" ~enc:(fun _ -> "app.bsky.graph.getStarterPack#output") 3310 - |> Jsont.Object.mem "starterPack" Jsont.json ~enc:(fun r -> r.starter_pack) 3311 |> Jsont.Object.finish 3312 3313 end 3314 - module GetListsWithMembership = struct 3315 - type list_with_membership = { 3316 - list_ : Jsont.json; 3317 - list_item : Jsont.json option; 3318 - } 3319 - 3320 - let list_with_membership_jsont = 3321 - Jsont.Object.map ~kind:"List_with_membership" 3322 - (fun _typ list_ list_item -> { list_; list_item }) 3323 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getListsWithMembership#listWithMembership" ~enc:(fun _ -> "app.bsky.graph.getListsWithMembership#listWithMembership") 3324 - |> Jsont.Object.mem "list" Jsont.json ~enc:(fun r -> r.list_) 3325 - |> Jsont.Object.opt_mem "listItem" Jsont.json ~enc:(fun r -> r.list_item) 3326 - |> Jsont.Object.finish 3327 - 3328 - type params = { 3329 - actor : string; 3330 - cursor : string option; 3331 - limit : int option; 3332 - purposes : string list option; 3333 } 3334 3335 - let params_jsont = 3336 - Jsont.Object.map ~kind:"Params" 3337 - (fun actor cursor limit purposes -> { 3338 - actor; 3339 - cursor; 3340 - limit; 3341 - purposes; 3342 - }) 3343 - |> Jsont.Object.mem "actor" Jsont.string 3344 - ~enc:(fun r -> r.actor) 3345 - |> Jsont.Object.opt_mem "cursor" Jsont.string 3346 - ~enc:(fun r -> r.cursor) 3347 - |> Jsont.Object.opt_mem "limit" Jsont.int 3348 - ~enc:(fun r -> r.limit) 3349 - |> Jsont.Object.opt_mem "purposes" (Jsont.list Jsont.string) 3350 - ~enc:(fun r -> r.purposes) 3351 |> Jsont.Object.finish 3352 3353 type output = { 3354 - cursor : string option; 3355 - lists_with_membership : Jsont.json list; 3356 } 3357 3358 let output_jsont = 3359 Jsont.Object.map ~kind:"Output" 3360 - (fun _typ cursor lists_with_membership -> { cursor; lists_with_membership }) 3361 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getListsWithMembership#output" ~enc:(fun _ -> "app.bsky.graph.getListsWithMembership#output") 3362 - |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 3363 - |> Jsont.Object.mem "listsWithMembership" (Jsont.list Jsont.json) ~enc:(fun r -> r.lists_with_membership) 3364 |> Jsont.Object.finish 3365 3366 end 3367 - module GetListMutes = struct 3368 - type params = { 3369 - cursor : string option; 3370 - limit : int option; 3371 } 3372 3373 - let params_jsont = 3374 - Jsont.Object.map ~kind:"Params" 3375 - (fun cursor limit -> { 3376 - cursor; 3377 - limit; 3378 - }) 3379 - |> Jsont.Object.opt_mem "cursor" Jsont.string 3380 - ~enc:(fun r -> r.cursor) 3381 - |> Jsont.Object.opt_mem "limit" Jsont.int 3382 - ~enc:(fun r -> r.limit) 3383 |> Jsont.Object.finish 3384 3385 - type output = { 3386 - cursor : string option; 3387 - lists : Jsont.json list; 3388 } 3389 3390 - let output_jsont = 3391 - Jsont.Object.map ~kind:"Output" 3392 - (fun _typ cursor lists -> { cursor; lists }) 3393 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getListMutes#output" ~enc:(fun _ -> "app.bsky.graph.getListMutes#output") 3394 - |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 3395 - |> Jsont.Object.mem "lists" (Jsont.list Jsont.json) ~enc:(fun r -> r.lists) 3396 |> Jsont.Object.finish 3397 3398 - end 3399 - module GetStarterPacks = struct 3400 - type params = { 3401 - uris : string list; 3402 } 3403 3404 - let params_jsont = 3405 - Jsont.Object.map ~kind:"Params" 3406 - (fun uris -> { 3407 - uris; 3408 - }) 3409 - |> Jsont.Object.mem "uris" (Jsont.list Jsont.string) 3410 - ~enc:(fun r -> r.uris) 3411 |> Jsont.Object.finish 3412 3413 type output = { 3414 - starter_packs : Jsont.json list; 3415 } 3416 3417 let output_jsont = 3418 Jsont.Object.map ~kind:"Output" 3419 - (fun _typ starter_packs -> { starter_packs }) 3420 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getStarterPacks#output" ~enc:(fun _ -> "app.bsky.graph.getStarterPacks#output") 3421 - |> Jsont.Object.mem "starterPacks" (Jsont.list Jsont.json) ~enc:(fun r -> r.starter_packs) 3422 |> Jsont.Object.finish 3423 3424 end 3425 - module GetLists = struct 3426 - type params = { 3427 - actor : string; 3428 - cursor : string option; 3429 - limit : int option; 3430 - purposes : string list option; 3431 - } 3432 3433 - let params_jsont = 3434 - Jsont.Object.map ~kind:"Params" 3435 - (fun actor cursor limit purposes -> { 3436 - actor; 3437 - cursor; 3438 - limit; 3439 - purposes; 3440 - }) 3441 - |> Jsont.Object.mem "actor" Jsont.string 3442 - ~enc:(fun r -> r.actor) 3443 - |> Jsont.Object.opt_mem "cursor" Jsont.string 3444 - ~enc:(fun r -> r.cursor) 3445 - |> Jsont.Object.opt_mem "limit" Jsont.int 3446 - ~enc:(fun r -> r.limit) 3447 - |> Jsont.Object.opt_mem "purposes" (Jsont.list Jsont.string) 3448 - ~enc:(fun r -> r.purposes) 3449 - |> Jsont.Object.finish 3450 3451 - type output = { 3452 - cursor : string option; 3453 - lists : Jsont.json list; 3454 } 3455 3456 - let output_jsont = 3457 - Jsont.Object.map ~kind:"Output" 3458 - (fun _typ cursor lists -> { cursor; lists }) 3459 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getLists#output" ~enc:(fun _ -> "app.bsky.graph.getLists#output") 3460 - |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 3461 - |> Jsont.Object.mem "lists" (Jsont.list Jsont.json) ~enc:(fun r -> r.lists) 3462 |> Jsont.Object.finish 3463 3464 - end 3465 - end 3466 - module Feed = struct 3467 - module Post = struct 3468 - type text_slice = { 3469 - end_ : int; 3470 - start : int; 3471 - } 3472 3473 - let text_slice_jsont = 3474 - Jsont.Object.map ~kind:"Text_slice" 3475 - (fun _typ end_ start -> { end_; start }) 3476 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.post#textSlice" ~enc:(fun _ -> "app.bsky.feed.post#textSlice") 3477 - |> Jsont.Object.mem "end" Jsont.int ~enc:(fun r -> r.end_) 3478 - |> Jsont.Object.mem "start" Jsont.int ~enc:(fun r -> r.start) 3479 - |> Jsont.Object.finish 3480 3481 - type reply_ref = { 3482 - parent : Com.Atproto.Repo.StrongRef.main; 3483 - root : Com.Atproto.Repo.StrongRef.main; 3484 - } 3485 3486 - let reply_ref_jsont = 3487 - Jsont.Object.map ~kind:"Reply_ref" 3488 - (fun _typ parent root -> { parent; root }) 3489 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.post#replyRef" ~enc:(fun _ -> "app.bsky.feed.post#replyRef") 3490 - |> Jsont.Object.mem "parent" Com.Atproto.Repo.StrongRef.main_jsont ~enc:(fun r -> r.parent) 3491 - |> Jsont.Object.mem "root" Com.Atproto.Repo.StrongRef.main_jsont ~enc:(fun r -> r.root) 3492 - |> Jsont.Object.finish 3493 3494 - type entity = { 3495 - index : Jsont.json; 3496 - type_ : string; 3497 - value : string; 3498 } 3499 3500 - let entity_jsont = 3501 - Jsont.Object.map ~kind:"Entity" 3502 - (fun _typ index type_ value -> { index; type_; value }) 3503 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.post#entity" ~enc:(fun _ -> "app.bsky.feed.post#entity") 3504 - |> Jsont.Object.mem "index" Jsont.json ~enc:(fun r -> r.index) 3505 - |> Jsont.Object.mem "type" Jsont.string ~enc:(fun r -> r.type_) 3506 - |> Jsont.Object.mem "value" Jsont.string ~enc:(fun r -> r.value) 3507 |> Jsont.Object.finish 3508 3509 type main = { 3510 created_at : string; 3511 - embed : Jsont.json option; 3512 - entities : Jsont.json list option; 3513 - facets : Richtext.Facet.main list option; 3514 - labels : Com.Atproto.Label.Defs.self_labels option; 3515 - langs : string list option; 3516 - reply : Jsont.json option; 3517 - tags : string list option; 3518 - text : string; 3519 } 3520 3521 let main_jsont = 3522 Jsont.Object.map ~kind:"Main" 3523 - (fun _typ created_at embed entities facets labels langs reply tags text -> { created_at; embed; entities; facets; labels; langs; reply; tags; text }) 3524 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.post" ~enc:(fun _ -> "app.bsky.feed.post") 3525 |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 3526 - |> Jsont.Object.opt_mem "embed" Jsont.json ~enc:(fun r -> r.embed) 3527 - |> Jsont.Object.opt_mem "entities" (Jsont.list Jsont.json) ~enc:(fun r -> r.entities) 3528 - |> Jsont.Object.opt_mem "facets" (Jsont.list Richtext.Facet.main_jsont) ~enc:(fun r -> r.facets) 3529 - |> Jsont.Object.opt_mem "labels" Com.Atproto.Label.Defs.self_labels_jsont ~enc:(fun r -> r.labels) 3530 - |> Jsont.Object.opt_mem "langs" (Jsont.list Jsont.string) ~enc:(fun r -> r.langs) 3531 - |> Jsont.Object.opt_mem "reply" Jsont.json ~enc:(fun r -> r.reply) 3532 - |> Jsont.Object.opt_mem "tags" (Jsont.list Jsont.string) ~enc:(fun r -> r.tags) 3533 - |> Jsont.Object.mem "text" Jsont.string ~enc:(fun r -> r.text) 3534 |> Jsont.Object.finish 3535 3536 end ··· 3593 |> Jsont.Object.finish 3594 3595 end 3596 - module Postgate = struct 3597 - type disable_rule = unit 3598 - 3599 - let disable_rule_jsont = Jsont.ignore 3600 - 3601 - type main = { 3602 - created_at : string; 3603 - detached_embedding_uris : string list option; 3604 - embedding_rules : Jsont.json list option; 3605 - post : string; 3606 - } 3607 - 3608 - let main_jsont = 3609 - Jsont.Object.map ~kind:"Main" 3610 - (fun _typ created_at detached_embedding_uris embedding_rules post -> { created_at; detached_embedding_uris; embedding_rules; post }) 3611 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.postgate" ~enc:(fun _ -> "app.bsky.feed.postgate") 3612 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 3613 - |> Jsont.Object.opt_mem "detachedEmbeddingUris" (Jsont.list Jsont.string) ~enc:(fun r -> r.detached_embedding_uris) 3614 - |> Jsont.Object.opt_mem "embeddingRules" (Jsont.list Jsont.json) ~enc:(fun r -> r.embedding_rules) 3615 - |> Jsont.Object.mem "post" Jsont.string ~enc:(fun r -> r.post) 3616 - |> Jsont.Object.finish 3617 - 3618 - end 3619 module GetRepostedBy = struct 3620 type params = { 3621 cid : string option; ··· 3660 |> Jsont.Object.finish 3661 3662 end 3663 - module DescribeFeedGenerator = struct 3664 - type links = { 3665 - privacy_policy : string option; 3666 - terms_of_service : string option; 3667 - } 3668 - 3669 - let links_jsont = 3670 - Jsont.Object.map ~kind:"Links" 3671 - (fun _typ privacy_policy terms_of_service -> { privacy_policy; terms_of_service }) 3672 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.describeFeedGenerator#links" ~enc:(fun _ -> "app.bsky.feed.describeFeedGenerator#links") 3673 - |> Jsont.Object.opt_mem "privacyPolicy" Jsont.string ~enc:(fun r -> r.privacy_policy) 3674 - |> Jsont.Object.opt_mem "termsOfService" Jsont.string ~enc:(fun r -> r.terms_of_service) 3675 - |> Jsont.Object.finish 3676 - 3677 - type feed = { 3678 - uri : string; 3679 - } 3680 - 3681 - let feed_jsont = 3682 - Jsont.Object.map ~kind:"Feed" 3683 - (fun _typ uri -> { uri }) 3684 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.describeFeedGenerator#feed" ~enc:(fun _ -> "app.bsky.feed.describeFeedGenerator#feed") 3685 - |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 3686 - |> Jsont.Object.finish 3687 - 3688 - type output = { 3689 did : string; 3690 - feeds : Jsont.json list; 3691 - links : Jsont.json option; 3692 } 3693 3694 - let output_jsont = 3695 - Jsont.Object.map ~kind:"Output" 3696 - (fun _typ did feeds links -> { did; feeds; links }) 3697 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.describeFeedGenerator#output" ~enc:(fun _ -> "app.bsky.feed.describeFeedGenerator#output") 3698 |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 3699 - |> Jsont.Object.mem "feeds" (Jsont.list Jsont.json) ~enc:(fun r -> r.feeds) 3700 - |> Jsont.Object.opt_mem "links" Jsont.json ~enc:(fun r -> r.links) 3701 |> Jsont.Object.finish 3702 3703 end 3704 - module Threadgate = struct 3705 - type mention_rule = unit 3706 - 3707 - let mention_rule_jsont = Jsont.ignore 3708 - 3709 - type list_rule = { 3710 - list_ : string; 3711 - } 3712 - 3713 - let list_rule_jsont = 3714 - Jsont.Object.map ~kind:"List_rule" 3715 - (fun _typ list_ -> { list_ }) 3716 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.threadgate#listRule" ~enc:(fun _ -> "app.bsky.feed.threadgate#listRule") 3717 - |> Jsont.Object.mem "list" Jsont.string ~enc:(fun r -> r.list_) 3718 - |> Jsont.Object.finish 3719 - 3720 - type following_rule = unit 3721 3722 - let following_rule_jsont = Jsont.ignore 3723 - 3724 - type follower_rule = unit 3725 - 3726 - let follower_rule_jsont = Jsont.ignore 3727 3728 type main = { 3729 - allow : Jsont.json list option; 3730 created_at : string; 3731 - hidden_replies : string list option; 3732 post : string; 3733 } 3734 3735 let main_jsont = 3736 Jsont.Object.map ~kind:"Main" 3737 - (fun _typ allow created_at hidden_replies post -> { allow; created_at; hidden_replies; post }) 3738 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.threadgate" ~enc:(fun _ -> "app.bsky.feed.threadgate") 3739 - |> Jsont.Object.opt_mem "allow" (Jsont.list Jsont.json) ~enc:(fun r -> r.allow) 3740 |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 3741 - |> Jsont.Object.opt_mem "hiddenReplies" (Jsont.list Jsont.string) ~enc:(fun r -> r.hidden_replies) 3742 |> Jsont.Object.mem "post" Jsont.string ~enc:(fun r -> r.post) 3743 - |> Jsont.Object.finish 3744 - 3745 - end 3746 - module Like = struct 3747 - type main = { 3748 - created_at : string; 3749 - subject : Com.Atproto.Repo.StrongRef.main; 3750 - via : Com.Atproto.Repo.StrongRef.main option; 3751 - } 3752 - 3753 - let main_jsont = 3754 - Jsont.Object.map ~kind:"Main" 3755 - (fun _typ created_at subject via -> { created_at; subject; via }) 3756 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.like" ~enc:(fun _ -> "app.bsky.feed.like") 3757 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 3758 - |> Jsont.Object.mem "subject" Com.Atproto.Repo.StrongRef.main_jsont ~enc:(fun r -> r.subject) 3759 - |> Jsont.Object.opt_mem "via" Com.Atproto.Repo.StrongRef.main_jsont ~enc:(fun r -> r.via) 3760 |> Jsont.Object.finish 3761 3762 end ··· 4102 |> Jsont.Object.finish 4103 4104 end 4105 - module Repost = struct 4106 - type main = { 4107 - created_at : string; 4108 - subject : Com.Atproto.Repo.StrongRef.main; 4109 - via : Com.Atproto.Repo.StrongRef.main option; 4110 } 4111 4112 - let main_jsont = 4113 - Jsont.Object.map ~kind:"Main" 4114 - (fun _typ created_at subject via -> { created_at; subject; via }) 4115 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.repost" ~enc:(fun _ -> "app.bsky.feed.repost") 4116 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 4117 - |> Jsont.Object.mem "subject" Com.Atproto.Repo.StrongRef.main_jsont ~enc:(fun r -> r.subject) 4118 - |> Jsont.Object.opt_mem "via" Com.Atproto.Repo.StrongRef.main_jsont ~enc:(fun r -> r.via) 4119 |> Jsont.Object.finish 4120 4121 - end 4122 - module Generator = struct 4123 type main = { 4124 - accepts_interactions : bool option; 4125 - avatar : Atp.Blob_ref.t option; 4126 - content_mode : string option; 4127 created_at : string; 4128 - description : string option; 4129 - description_facets : Richtext.Facet.main list option; 4130 - did : string; 4131 - display_name : string; 4132 labels : Com.Atproto.Label.Defs.self_labels option; 4133 } 4134 4135 let main_jsont = 4136 Jsont.Object.map ~kind:"Main" 4137 - (fun _typ accepts_interactions avatar content_mode created_at description description_facets did display_name labels -> { accepts_interactions; avatar; content_mode; created_at; description; description_facets; did; display_name; labels }) 4138 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.generator" ~enc:(fun _ -> "app.bsky.feed.generator") 4139 - |> Jsont.Object.opt_mem "acceptsInteractions" Jsont.bool ~enc:(fun r -> r.accepts_interactions) 4140 - |> Jsont.Object.opt_mem "avatar" Atp.Blob_ref.jsont ~enc:(fun r -> r.avatar) 4141 - |> Jsont.Object.opt_mem "contentMode" Jsont.string ~enc:(fun r -> r.content_mode) 4142 |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 4143 - |> Jsont.Object.opt_mem "description" Jsont.string ~enc:(fun r -> r.description) 4144 - |> Jsont.Object.opt_mem "descriptionFacets" (Jsont.list Richtext.Facet.main_jsont) ~enc:(fun r -> r.description_facets) 4145 - |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 4146 - |> Jsont.Object.mem "displayName" Jsont.string ~enc:(fun r -> r.display_name) 4147 |> Jsont.Object.opt_mem "labels" Com.Atproto.Label.Defs.self_labels_jsont ~enc:(fun r -> r.labels) 4148 |> Jsont.Object.finish 4149 4150 end 4151 - module GetPostThread = struct 4152 type params = { 4153 - depth : int option; 4154 - parent_height : int option; 4155 uri : string; 4156 } 4157 4158 let params_jsont = 4159 Jsont.Object.map ~kind:"Params" 4160 - (fun depth parent_height uri -> { 4161 - depth; 4162 - parent_height; 4163 uri; 4164 }) 4165 - |> Jsont.Object.opt_mem "depth" Jsont.int 4166 - ~enc:(fun r -> r.depth) 4167 - |> Jsont.Object.opt_mem "parentHeight" Jsont.int 4168 - ~enc:(fun r -> r.parent_height) 4169 |> Jsont.Object.mem "uri" Jsont.string 4170 ~enc:(fun r -> r.uri) 4171 |> Jsont.Object.finish 4172 4173 type output = { 4174 - thread : Jsont.json; 4175 - threadgate : Jsont.json option; 4176 } 4177 4178 let output_jsont = 4179 Jsont.Object.map ~kind:"Output" 4180 - (fun _typ thread threadgate -> { thread; threadgate }) 4181 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.getPostThread#output" ~enc:(fun _ -> "app.bsky.feed.getPostThread#output") 4182 - |> Jsont.Object.mem "thread" Jsont.json ~enc:(fun r -> r.thread) 4183 - |> Jsont.Object.opt_mem "threadgate" Jsont.json ~enc:(fun r -> r.threadgate) 4184 |> Jsont.Object.finish 4185 4186 end 4187 - module GetFeed = struct 4188 type params = { 4189 cursor : string option; 4190 - feed : string; 4191 limit : int option; 4192 } 4193 4194 let params_jsont = 4195 Jsont.Object.map ~kind:"Params" 4196 - (fun cursor feed limit -> { 4197 cursor; 4198 - feed; 4199 limit; 4200 }) 4201 |> Jsont.Object.opt_mem "cursor" Jsont.string 4202 ~enc:(fun r -> r.cursor) 4203 - |> Jsont.Object.mem "feed" Jsont.string 4204 - ~enc:(fun r -> r.feed) 4205 |> Jsont.Object.opt_mem "limit" Jsont.int 4206 ~enc:(fun r -> r.limit) 4207 |> Jsont.Object.finish ··· 4214 let output_jsont = 4215 Jsont.Object.map ~kind:"Output" 4216 (fun _typ cursor feed -> { cursor; feed }) 4217 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.getFeed#output" ~enc:(fun _ -> "app.bsky.feed.getFeed#output") 4218 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 4219 |> Jsont.Object.mem "feed" (Jsont.list Jsont.json) ~enc:(fun r -> r.feed) 4220 |> Jsont.Object.finish 4221 4222 end 4223 - module GetQuotes = struct 4224 type params = { 4225 - cid : string option; 4226 cursor : string option; 4227 limit : int option; 4228 - uri : string; 4229 } 4230 4231 let params_jsont = 4232 Jsont.Object.map ~kind:"Params" 4233 - (fun cid cursor limit uri -> { 4234 - cid; 4235 cursor; 4236 limit; 4237 - uri; 4238 }) 4239 - |> Jsont.Object.opt_mem "cid" Jsont.string 4240 - ~enc:(fun r -> r.cid) 4241 |> Jsont.Object.opt_mem "cursor" Jsont.string 4242 ~enc:(fun r -> r.cursor) 4243 |> Jsont.Object.opt_mem "limit" Jsont.int 4244 ~enc:(fun r -> r.limit) 4245 - |> Jsont.Object.mem "uri" Jsont.string 4246 - ~enc:(fun r -> r.uri) 4247 |> Jsont.Object.finish 4248 4249 type output = { 4250 - cid : string option; 4251 cursor : string option; 4252 - posts : Jsont.json list; 4253 - uri : string; 4254 } 4255 4256 let output_jsont = 4257 Jsont.Object.map ~kind:"Output" 4258 - (fun _typ cid cursor posts uri -> { cid; cursor; posts; uri }) 4259 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.getQuotes#output" ~enc:(fun _ -> "app.bsky.feed.getQuotes#output") 4260 - |> Jsont.Object.opt_mem "cid" Jsont.string ~enc:(fun r -> r.cid) 4261 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 4262 - |> Jsont.Object.mem "posts" (Jsont.list Jsont.json) ~enc:(fun r -> r.posts) 4263 - |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 4264 |> Jsont.Object.finish 4265 4266 end ··· 4300 |> Jsont.Object.finish 4301 4302 end 4303 module GetActorLikes = struct 4304 type params = { 4305 actor : string; ··· 4336 |> Jsont.Object.finish 4337 4338 end 4339 - module GetFeedSkeleton = struct 4340 type params = { 4341 cursor : string option; 4342 - feed : string; 4343 limit : int option; 4344 } 4345 4346 let params_jsont = 4347 Jsont.Object.map ~kind:"Params" 4348 - (fun cursor feed limit -> { 4349 cursor; 4350 - feed; 4351 limit; 4352 }) 4353 |> Jsont.Object.opt_mem "cursor" Jsont.string 4354 ~enc:(fun r -> r.cursor) 4355 - |> Jsont.Object.mem "feed" Jsont.string 4356 - ~enc:(fun r -> r.feed) 4357 |> Jsont.Object.opt_mem "limit" Jsont.int 4358 ~enc:(fun r -> r.limit) 4359 |> Jsont.Object.finish 4360 4361 type output = { 4362 cursor : string option; 4363 - feed : Jsont.json list; 4364 - req_id : string option; 4365 } 4366 4367 let output_jsont = 4368 Jsont.Object.map ~kind:"Output" 4369 - (fun _typ cursor feed req_id -> { cursor; feed; req_id }) 4370 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.getFeedSkeleton#output" ~enc:(fun _ -> "app.bsky.feed.getFeedSkeleton#output") 4371 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 4372 - |> Jsont.Object.mem "feed" (Jsont.list Jsont.json) ~enc:(fun r -> r.feed) 4373 - |> Jsont.Object.opt_mem "reqId" Jsont.string ~enc:(fun r -> r.req_id) 4374 |> Jsont.Object.finish 4375 4376 end ··· 4448 |> Jsont.Object.finish 4449 4450 end 4451 module GetFeedGenerators = struct 4452 type params = { 4453 feeds : string list; ··· 4491 let output_jsont = Jsont.ignore 4492 4493 end 4494 - module GetAuthorFeed = struct 4495 type params = { 4496 actor : string; 4497 cursor : string option; 4498 - filter : string option; 4499 - include_pins : bool option; 4500 limit : int option; 4501 } 4502 4503 let params_jsont = 4504 Jsont.Object.map ~kind:"Params" 4505 - (fun actor cursor filter include_pins limit -> { 4506 actor; 4507 cursor; 4508 - filter; 4509 - include_pins; 4510 limit; 4511 }) 4512 |> Jsont.Object.mem "actor" Jsont.string 4513 ~enc:(fun r -> r.actor) 4514 |> Jsont.Object.opt_mem "cursor" Jsont.string 4515 ~enc:(fun r -> r.cursor) 4516 - |> Jsont.Object.opt_mem "filter" Jsont.string 4517 - ~enc:(fun r -> r.filter) 4518 - |> Jsont.Object.opt_mem "includePins" Jsont.bool 4519 - ~enc:(fun r -> r.include_pins) 4520 |> Jsont.Object.opt_mem "limit" Jsont.int 4521 ~enc:(fun r -> r.limit) 4522 |> Jsont.Object.finish 4523 4524 type output = { 4525 cursor : string option; 4526 - feed : Jsont.json list; 4527 } 4528 4529 let output_jsont = 4530 Jsont.Object.map ~kind:"Output" 4531 - (fun _typ cursor feed -> { cursor; feed }) 4532 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.getAuthorFeed#output" ~enc:(fun _ -> "app.bsky.feed.getAuthorFeed#output") 4533 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 4534 - |> Jsont.Object.mem "feed" (Jsont.list Jsont.json) ~enc:(fun r -> r.feed) 4535 |> Jsont.Object.finish 4536 4537 end 4538 - module GetFeedGenerator = struct 4539 type params = { 4540 - feed : string; 4541 } 4542 4543 let params_jsont = 4544 Jsont.Object.map ~kind:"Params" 4545 - (fun feed -> { 4546 - feed; 4547 }) 4548 - |> Jsont.Object.mem "feed" Jsont.string 4549 - ~enc:(fun r -> r.feed) 4550 |> Jsont.Object.finish 4551 4552 type output = { 4553 - is_online : bool; 4554 - is_valid : bool; 4555 - view : Jsont.json; 4556 } 4557 4558 let output_jsont = 4559 Jsont.Object.map ~kind:"Output" 4560 - (fun _typ is_online is_valid view -> { is_online; is_valid; view }) 4561 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.getFeedGenerator#output" ~enc:(fun _ -> "app.bsky.feed.getFeedGenerator#output") 4562 - |> Jsont.Object.mem "isOnline" Jsont.bool ~enc:(fun r -> r.is_online) 4563 - |> Jsont.Object.mem "isValid" Jsont.bool ~enc:(fun r -> r.is_valid) 4564 - |> Jsont.Object.mem "view" Jsont.json ~enc:(fun r -> r.view) 4565 |> Jsont.Object.finish 4566 4567 end 4568 - module GetSuggestedFeeds = struct 4569 type params = { 4570 cursor : string option; 4571 limit : int option; ··· 4585 4586 type output = { 4587 cursor : string option; 4588 - feeds : Jsont.json list; 4589 } 4590 4591 let output_jsont = 4592 Jsont.Object.map ~kind:"Output" 4593 - (fun _typ cursor feeds -> { cursor; feeds }) 4594 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.getSuggestedFeeds#output" ~enc:(fun _ -> "app.bsky.feed.getSuggestedFeeds#output") 4595 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 4596 - |> Jsont.Object.mem "feeds" (Jsont.list Jsont.json) ~enc:(fun r -> r.feeds) 4597 |> Jsont.Object.finish 4598 4599 end 4600 - module GetActorFeeds = struct 4601 type params = { 4602 actor : string; 4603 cursor : string option; ··· 4621 4622 type output = { 4623 cursor : string option; 4624 - feeds : Jsont.json list; 4625 } 4626 4627 let output_jsont = 4628 Jsont.Object.map ~kind:"Output" 4629 - (fun _typ cursor feeds -> { cursor; feeds }) 4630 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.getActorFeeds#output" ~enc:(fun _ -> "app.bsky.feed.getActorFeeds#output") 4631 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 4632 - |> Jsont.Object.mem "feeds" (Jsont.list Jsont.json) ~enc:(fun r -> r.feeds) 4633 |> Jsont.Object.finish 4634 4635 end 4636 - module GetPosts = struct 4637 type params = { 4638 - uris : string list; 4639 } 4640 4641 let params_jsont = 4642 Jsont.Object.map ~kind:"Params" 4643 - (fun uris -> { 4644 - uris; 4645 }) 4646 - |> Jsont.Object.mem "uris" (Jsont.list Jsont.string) 4647 - ~enc:(fun r -> r.uris) 4648 |> Jsont.Object.finish 4649 4650 type output = { 4651 - posts : Jsont.json list; 4652 } 4653 4654 let output_jsont = 4655 Jsont.Object.map ~kind:"Output" 4656 - (fun _typ posts -> { posts }) 4657 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.getPosts#output" ~enc:(fun _ -> "app.bsky.feed.getPosts#output") 4658 - |> Jsont.Object.mem "posts" (Jsont.list Jsont.json) ~enc:(fun r -> r.posts) 4659 |> Jsont.Object.finish 4660 4661 end 4662 - module GetTimeline = struct 4663 type params = { 4664 - algorithm : string option; 4665 cursor : string option; 4666 limit : int option; 4667 } 4668 4669 let params_jsont = 4670 Jsont.Object.map ~kind:"Params" 4671 - (fun algorithm cursor limit -> { 4672 - algorithm; 4673 cursor; 4674 limit; 4675 }) 4676 - |> Jsont.Object.opt_mem "algorithm" Jsont.string 4677 - ~enc:(fun r -> r.algorithm) 4678 |> Jsont.Object.opt_mem "cursor" Jsont.string 4679 ~enc:(fun r -> r.cursor) 4680 |> Jsont.Object.opt_mem "limit" Jsont.int 4681 ~enc:(fun r -> r.limit) 4682 |> Jsont.Object.finish 4683 4684 type output = { 4685 cursor : string option; 4686 - feed : Jsont.json list; 4687 } 4688 4689 let output_jsont = 4690 Jsont.Object.map ~kind:"Output" 4691 - (fun _typ cursor feed -> { cursor; feed }) 4692 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.getTimeline#output" ~enc:(fun _ -> "app.bsky.feed.getTimeline#output") 4693 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 4694 - |> Jsont.Object.mem "feed" (Jsont.list Jsont.json) ~enc:(fun r -> r.feed) 4695 |> Jsont.Object.finish 4696 4697 end 4698 - end 4699 - module Bookmark = struct 4700 - module DeleteBookmark = struct 4701 - type input = { 4702 - uri : string; 4703 } 4704 4705 - let input_jsont = 4706 - Jsont.Object.map ~kind:"Input" 4707 - (fun _typ uri -> { uri }) 4708 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.bookmark.deleteBookmark#input" ~enc:(fun _ -> "app.bsky.bookmark.deleteBookmark#input") 4709 - |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 4710 |> Jsont.Object.finish 4711 4712 end 4713 - module CreateBookmark = struct 4714 - type input = { 4715 - cid : string; 4716 - uri : string; 4717 } 4718 4719 - let input_jsont = 4720 - Jsont.Object.map ~kind:"Input" 4721 - (fun _typ cid uri -> { cid; uri }) 4722 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.bookmark.createBookmark#input" ~enc:(fun _ -> "app.bsky.bookmark.createBookmark#input") 4723 - |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 4724 - |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 4725 |> Jsont.Object.finish 4726 4727 end 4728 - module Defs = struct 4729 - type bookmark_view = { 4730 - created_at : string option; 4731 - item : Jsont.json; 4732 - subject : Com.Atproto.Repo.StrongRef.main; 4733 } 4734 4735 - let bookmark_view_jsont = 4736 - Jsont.Object.map ~kind:"Bookmark_view" 4737 - (fun _typ created_at item subject -> { created_at; item; subject }) 4738 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.bookmark.defs#bookmarkView" ~enc:(fun _ -> "app.bsky.bookmark.defs#bookmarkView") 4739 - |> Jsont.Object.opt_mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 4740 - |> Jsont.Object.mem "item" Jsont.json ~enc:(fun r -> r.item) 4741 - |> Jsont.Object.mem "subject" Com.Atproto.Repo.StrongRef.main_jsont ~enc:(fun r -> r.subject) 4742 |> Jsont.Object.finish 4743 4744 - type bookmark = { 4745 - subject : Com.Atproto.Repo.StrongRef.main; 4746 } 4747 4748 - let bookmark_jsont = 4749 - Jsont.Object.map ~kind:"Bookmark" 4750 - (fun _typ subject -> { subject }) 4751 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.bookmark.defs#bookmark" ~enc:(fun _ -> "app.bsky.bookmark.defs#bookmark") 4752 - |> Jsont.Object.mem "subject" Com.Atproto.Repo.StrongRef.main_jsont ~enc:(fun r -> r.subject) 4753 |> Jsont.Object.finish 4754 4755 end 4756 - module GetBookmarks = struct 4757 type params = { 4758 cursor : string option; 4759 limit : int option; 4760 } 4761 4762 let params_jsont = 4763 Jsont.Object.map ~kind:"Params" 4764 - (fun cursor limit -> { 4765 cursor; 4766 limit; 4767 }) 4768 |> Jsont.Object.opt_mem "cursor" Jsont.string 4769 ~enc:(fun r -> r.cursor) 4770 |> Jsont.Object.opt_mem "limit" Jsont.int ··· 4772 |> Jsont.Object.finish 4773 4774 type output = { 4775 - bookmarks : Defs.bookmark_view list; 4776 cursor : string option; 4777 } 4778 4779 let output_jsont = 4780 Jsont.Object.map ~kind:"Output" 4781 - (fun _typ bookmarks cursor -> { bookmarks; cursor }) 4782 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.bookmark.getBookmarks#output" ~enc:(fun _ -> "app.bsky.bookmark.getBookmarks#output") 4783 - |> Jsont.Object.mem "bookmarks" (Jsont.list Defs.bookmark_view_jsont) ~enc:(fun r -> r.bookmarks) 4784 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 4785 |> Jsont.Object.finish 4786 4787 end 4788 - end 4789 - module Unspecced = struct 4790 - module GetSuggestedUsersSkeleton = struct 4791 type params = { 4792 - category : string option; 4793 limit : int option; 4794 - viewer : string option; 4795 } 4796 4797 let params_jsont = 4798 Jsont.Object.map ~kind:"Params" 4799 - (fun category limit viewer -> { 4800 - category; 4801 limit; 4802 - viewer; 4803 }) 4804 - |> Jsont.Object.opt_mem "category" Jsont.string 4805 - ~enc:(fun r -> r.category) 4806 |> Jsont.Object.opt_mem "limit" Jsont.int 4807 ~enc:(fun r -> r.limit) 4808 - |> Jsont.Object.opt_mem "viewer" Jsont.string 4809 - ~enc:(fun r -> r.viewer) 4810 |> Jsont.Object.finish 4811 4812 type output = { 4813 - dids : string list; 4814 - rec_id : int option; 4815 } 4816 4817 let output_jsont = 4818 Jsont.Object.map ~kind:"Output" 4819 - (fun _typ dids rec_id -> { dids; rec_id }) 4820 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getSuggestedUsersSkeleton#output" ~enc:(fun _ -> "app.bsky.unspecced.getSuggestedUsersSkeleton#output") 4821 - |> Jsont.Object.mem "dids" (Jsont.list Jsont.string) ~enc:(fun r -> r.dids) 4822 - |> Jsont.Object.opt_mem "recId" Jsont.int ~enc:(fun r -> r.rec_id) 4823 |> Jsont.Object.finish 4824 4825 end 4826 - module GetOnboardingSuggestedStarterPacks = struct 4827 type params = { 4828 limit : int option; 4829 } 4830 4831 let params_jsont = 4832 Jsont.Object.map ~kind:"Params" 4833 - (fun limit -> { 4834 limit; 4835 }) 4836 |> Jsont.Object.opt_mem "limit" Jsont.int 4837 ~enc:(fun r -> r.limit) 4838 |> Jsont.Object.finish 4839 4840 type output = { 4841 starter_packs : Jsont.json list; 4842 } 4843 4844 let output_jsont = 4845 Jsont.Object.map ~kind:"Output" 4846 (fun _typ starter_packs -> { starter_packs }) 4847 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getOnboardingSuggestedStarterPacks#output" ~enc:(fun _ -> "app.bsky.unspecced.getOnboardingSuggestedStarterPacks#output") 4848 |> Jsont.Object.mem "starterPacks" (Jsont.list Jsont.json) ~enc:(fun r -> r.starter_packs) 4849 |> Jsont.Object.finish 4850 4851 end 4852 - module GetPopularFeedGenerators = struct 4853 type params = { 4854 cursor : string option; 4855 limit : int option; 4856 - query : string option; 4857 } 4858 4859 let params_jsont = 4860 Jsont.Object.map ~kind:"Params" 4861 - (fun cursor limit query -> { 4862 cursor; 4863 limit; 4864 - query; 4865 }) 4866 |> Jsont.Object.opt_mem "cursor" Jsont.string 4867 ~enc:(fun r -> r.cursor) 4868 |> Jsont.Object.opt_mem "limit" Jsont.int 4869 ~enc:(fun r -> r.limit) 4870 - |> Jsont.Object.opt_mem "query" Jsont.string 4871 - ~enc:(fun r -> r.query) 4872 |> Jsont.Object.finish 4873 4874 type output = { 4875 cursor : string option; 4876 - feeds : Jsont.json list; 4877 } 4878 4879 let output_jsont = 4880 Jsont.Object.map ~kind:"Output" 4881 - (fun _typ cursor feeds -> { cursor; feeds }) 4882 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getPopularFeedGenerators#output" ~enc:(fun _ -> "app.bsky.unspecced.getPopularFeedGenerators#output") 4883 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 4884 - |> Jsont.Object.mem "feeds" (Jsont.list Jsont.json) ~enc:(fun r -> r.feeds) 4885 |> Jsont.Object.finish 4886 4887 end 4888 - module GetSuggestedStarterPacksSkeleton = struct 4889 type params = { 4890 limit : int option; 4891 - viewer : string option; 4892 } 4893 4894 let params_jsont = 4895 Jsont.Object.map ~kind:"Params" 4896 - (fun limit viewer -> { 4897 limit; 4898 - viewer; 4899 }) 4900 |> Jsont.Object.opt_mem "limit" Jsont.int 4901 ~enc:(fun r -> r.limit) 4902 - |> Jsont.Object.opt_mem "viewer" Jsont.string 4903 - ~enc:(fun r -> r.viewer) 4904 |> Jsont.Object.finish 4905 4906 type output = { 4907 - starter_packs : string list; 4908 } 4909 4910 let output_jsont = 4911 Jsont.Object.map ~kind:"Output" 4912 - (fun _typ starter_packs -> { starter_packs }) 4913 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getSuggestedStarterPacksSkeleton#output" ~enc:(fun _ -> "app.bsky.unspecced.getSuggestedStarterPacksSkeleton#output") 4914 - |> Jsont.Object.mem "starterPacks" (Jsont.list Jsont.string) ~enc:(fun r -> r.starter_packs) 4915 |> Jsont.Object.finish 4916 4917 end 4918 module GetSuggestedFeeds = struct 4919 type params = { 4920 limit : int option; ··· 4941 |> Jsont.Object.finish 4942 4943 end 4944 - module GetSuggestedFeedsSkeleton = struct 4945 type params = { 4946 limit : int option; 4947 - viewer : string option; 4948 } 4949 4950 let params_jsont = 4951 Jsont.Object.map ~kind:"Params" 4952 - (fun limit viewer -> { 4953 limit; 4954 - viewer; 4955 }) 4956 |> Jsont.Object.opt_mem "limit" Jsont.int 4957 ~enc:(fun r -> r.limit) 4958 - |> Jsont.Object.opt_mem "viewer" Jsont.string 4959 - ~enc:(fun r -> r.viewer) 4960 |> Jsont.Object.finish 4961 4962 type output = { 4963 - feeds : string list; 4964 } 4965 4966 let output_jsont = 4967 Jsont.Object.map ~kind:"Output" 4968 - (fun _typ feeds -> { feeds }) 4969 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getSuggestedFeedsSkeleton#output" ~enc:(fun _ -> "app.bsky.unspecced.getSuggestedFeedsSkeleton#output") 4970 - |> Jsont.Object.mem "feeds" (Jsont.list Jsont.string) ~enc:(fun r -> r.feeds) 4971 |> Jsont.Object.finish 4972 4973 end 4974 - module GetConfig = struct 4975 - type live_now_config = { 4976 - did : string; 4977 - domains : string list; 4978 } 4979 4980 - let live_now_config_jsont = 4981 - Jsont.Object.map ~kind:"Live_now_config" 4982 - (fun _typ did domains -> { did; domains }) 4983 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getConfig#liveNowConfig" ~enc:(fun _ -> "app.bsky.unspecced.getConfig#liveNowConfig") 4984 - |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 4985 - |> Jsont.Object.mem "domains" (Jsont.list Jsont.string) ~enc:(fun r -> r.domains) 4986 |> Jsont.Object.finish 4987 4988 type output = { 4989 - check_email_confirmed : bool option; 4990 - live_now : live_now_config list option; 4991 } 4992 4993 let output_jsont = 4994 Jsont.Object.map ~kind:"Output" 4995 - (fun _typ check_email_confirmed live_now -> { check_email_confirmed; live_now }) 4996 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getConfig#output" ~enc:(fun _ -> "app.bsky.unspecced.getConfig#output") 4997 - |> Jsont.Object.opt_mem "checkEmailConfirmed" Jsont.bool ~enc:(fun r -> r.check_email_confirmed) 4998 - |> Jsont.Object.opt_mem "liveNow" (Jsont.list live_now_config_jsont) ~enc:(fun r -> r.live_now) 4999 |> Jsont.Object.finish 5000 5001 end ··· 5025 |> Jsont.Object.finish 5026 5027 end 5028 - module GetSuggestedUsers = struct 5029 type params = { 5030 - category : string option; 5031 limit : int option; 5032 } 5033 5034 let params_jsont = 5035 Jsont.Object.map ~kind:"Params" 5036 - (fun category limit -> { 5037 - category; 5038 limit; 5039 }) 5040 - |> Jsont.Object.opt_mem "category" Jsont.string 5041 - ~enc:(fun r -> r.category) 5042 |> Jsont.Object.opt_mem "limit" Jsont.int 5043 ~enc:(fun r -> r.limit) 5044 |> Jsont.Object.finish 5045 5046 type output = { 5047 - actors : Jsont.json list; 5048 - rec_id : int option; 5049 } 5050 5051 let output_jsont = 5052 Jsont.Object.map ~kind:"Output" 5053 - (fun _typ actors rec_id -> { actors; rec_id }) 5054 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getSuggestedUsers#output" ~enc:(fun _ -> "app.bsky.unspecced.getSuggestedUsers#output") 5055 - |> Jsont.Object.mem "actors" (Jsont.list Jsont.json) ~enc:(fun r -> r.actors) 5056 - |> Jsont.Object.opt_mem "recId" Jsont.int ~enc:(fun r -> r.rec_id) 5057 |> Jsont.Object.finish 5058 5059 end 5060 - module GetOnboardingSuggestedStarterPacksSkeleton = struct 5061 type params = { 5062 limit : int option; 5063 viewer : string option; ··· 5076 |> Jsont.Object.finish 5077 5078 type output = { 5079 - starter_packs : string list; 5080 } 5081 5082 let output_jsont = 5083 Jsont.Object.map ~kind:"Output" 5084 (fun _typ starter_packs -> { starter_packs }) 5085 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getOnboardingSuggestedStarterPacksSkeleton#output" ~enc:(fun _ -> "app.bsky.unspecced.getOnboardingSuggestedStarterPacksSkeleton#output") 5086 - |> Jsont.Object.mem "starterPacks" (Jsont.list Jsont.string) ~enc:(fun r -> r.starter_packs) 5087 |> Jsont.Object.finish 5088 5089 end ··· 5267 |> Jsont.Object.finish 5268 5269 end 5270 - module GetTaggedSuggestions = struct 5271 - type suggestion = { 5272 - subject : string; 5273 - subject_type : string; 5274 - tag : string; 5275 } 5276 5277 - let suggestion_jsont = 5278 - Jsont.Object.map ~kind:"Suggestion" 5279 - (fun _typ subject subject_type tag -> { subject; subject_type; tag }) 5280 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getTaggedSuggestions#suggestion" ~enc:(fun _ -> "app.bsky.unspecced.getTaggedSuggestions#suggestion") 5281 - |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 5282 - |> Jsont.Object.mem "subjectType" Jsont.string ~enc:(fun r -> r.subject_type) 5283 - |> Jsont.Object.mem "tag" Jsont.string ~enc:(fun r -> r.tag) 5284 |> Jsont.Object.finish 5285 5286 - type params = unit 5287 - 5288 - let params_jsont = Jsont.ignore 5289 - 5290 type output = { 5291 - suggestions : suggestion list; 5292 } 5293 5294 let output_jsont = 5295 Jsont.Object.map ~kind:"Output" 5296 - (fun _typ suggestions -> { suggestions }) 5297 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getTaggedSuggestions#output" ~enc:(fun _ -> "app.bsky.unspecced.getTaggedSuggestions#output") 5298 - |> Jsont.Object.mem "suggestions" (Jsont.list suggestion_jsont) ~enc:(fun r -> r.suggestions) 5299 |> Jsont.Object.finish 5300 5301 end 5302 - module SearchPostsSkeleton = struct 5303 type params = { 5304 - author : string option; 5305 cursor : string option; 5306 - domain : string option; 5307 - lang : string option; 5308 limit : int option; 5309 - mentions : string option; 5310 - q : string; 5311 - since : string option; 5312 - sort : string option; 5313 - tag : string list option; 5314 - until : string option; 5315 - url : string option; 5316 - viewer : string option; 5317 } 5318 5319 let params_jsont = 5320 Jsont.Object.map ~kind:"Params" 5321 - (fun author cursor domain lang limit mentions q since sort tag until url viewer -> { 5322 - author; 5323 cursor; 5324 - domain; 5325 - lang; 5326 limit; 5327 - mentions; 5328 - q; 5329 - since; 5330 - sort; 5331 - tag; 5332 - until; 5333 - url; 5334 - viewer; 5335 }) 5336 - |> Jsont.Object.opt_mem "author" Jsont.string 5337 - ~enc:(fun r -> r.author) 5338 |> Jsont.Object.opt_mem "cursor" Jsont.string 5339 ~enc:(fun r -> r.cursor) 5340 - |> Jsont.Object.opt_mem "domain" Jsont.string 5341 - ~enc:(fun r -> r.domain) 5342 - |> Jsont.Object.opt_mem "lang" Jsont.string 5343 - ~enc:(fun r -> r.lang) 5344 |> Jsont.Object.opt_mem "limit" Jsont.int 5345 ~enc:(fun r -> r.limit) 5346 - |> Jsont.Object.opt_mem "mentions" Jsont.string 5347 - ~enc:(fun r -> r.mentions) 5348 - |> Jsont.Object.mem "q" Jsont.string 5349 - ~enc:(fun r -> r.q) 5350 - |> Jsont.Object.opt_mem "since" Jsont.string 5351 - ~enc:(fun r -> r.since) 5352 - |> Jsont.Object.opt_mem "sort" Jsont.string 5353 - ~enc:(fun r -> r.sort) 5354 - |> Jsont.Object.opt_mem "tag" (Jsont.list Jsont.string) 5355 - ~enc:(fun r -> r.tag) 5356 - |> Jsont.Object.opt_mem "until" Jsont.string 5357 - ~enc:(fun r -> r.until) 5358 - |> Jsont.Object.opt_mem "url" Jsont.string 5359 - ~enc:(fun r -> r.url) 5360 - |> Jsont.Object.opt_mem "viewer" Jsont.string 5361 - ~enc:(fun r -> r.viewer) 5362 |> Jsont.Object.finish 5363 5364 type output = { 5365 cursor : string option; 5366 - hits_total : int option; 5367 - posts : Defs.skeleton_search_post list; 5368 } 5369 5370 let output_jsont = 5371 Jsont.Object.map ~kind:"Output" 5372 - (fun _typ cursor hits_total posts -> { cursor; hits_total; posts }) 5373 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.searchPostsSkeleton#output" ~enc:(fun _ -> "app.bsky.unspecced.searchPostsSkeleton#output") 5374 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 5375 - |> Jsont.Object.opt_mem "hitsTotal" Jsont.int ~enc:(fun r -> r.hits_total) 5376 - |> Jsont.Object.mem "posts" (Jsont.list Defs.skeleton_search_post_jsont) ~enc:(fun r -> r.posts) 5377 |> Jsont.Object.finish 5378 5379 end 5380 - module GetPostThreadV2 = struct 5381 - type thread_item = { 5382 - depth : int; 5383 - uri : string; 5384 - value : Jsont.json; 5385 } 5386 5387 - let thread_item_jsont = 5388 - Jsont.Object.map ~kind:"Thread_item" 5389 - (fun _typ depth uri value -> { depth; uri; value }) 5390 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getPostThreadV2#threadItem" ~enc:(fun _ -> "app.bsky.unspecced.getPostThreadV2#threadItem") 5391 - |> Jsont.Object.mem "depth" Jsont.int ~enc:(fun r -> r.depth) 5392 - |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 5393 - |> Jsont.Object.mem "value" Jsont.json ~enc:(fun r -> r.value) 5394 |> Jsont.Object.finish 5395 5396 - type params = { 5397 - above : bool option; 5398 - anchor : string; 5399 - below : int option; 5400 - branching_factor : int option; 5401 - sort : string option; 5402 - } 5403 5404 - let params_jsont = 5405 - Jsont.Object.map ~kind:"Params" 5406 - (fun above anchor below branching_factor sort -> { 5407 - above; 5408 - anchor; 5409 - below; 5410 - branching_factor; 5411 - sort; 5412 - }) 5413 - |> Jsont.Object.opt_mem "above" Jsont.bool 5414 - ~enc:(fun r -> r.above) 5415 - |> Jsont.Object.mem "anchor" Jsont.string 5416 - ~enc:(fun r -> r.anchor) 5417 - |> Jsont.Object.opt_mem "below" Jsont.int 5418 - ~enc:(fun r -> r.below) 5419 - |> Jsont.Object.opt_mem "branchingFactor" Jsont.int 5420 - ~enc:(fun r -> r.branching_factor) 5421 - |> Jsont.Object.opt_mem "sort" Jsont.string 5422 - ~enc:(fun r -> r.sort) 5423 - |> Jsont.Object.finish 5424 5425 type output = { 5426 - has_other_replies : bool; 5427 - thread : thread_item list; 5428 - threadgate : Jsont.json option; 5429 } 5430 5431 let output_jsont = 5432 Jsont.Object.map ~kind:"Output" 5433 - (fun _typ has_other_replies thread threadgate -> { has_other_replies; thread; threadgate }) 5434 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getPostThreadV2#output" ~enc:(fun _ -> "app.bsky.unspecced.getPostThreadV2#output") 5435 - |> Jsont.Object.mem "hasOtherReplies" Jsont.bool ~enc:(fun r -> r.has_other_replies) 5436 - |> Jsont.Object.mem "thread" (Jsont.list thread_item_jsont) ~enc:(fun r -> r.thread) 5437 - |> Jsont.Object.opt_mem "threadgate" Jsont.json ~enc:(fun r -> r.threadgate) 5438 |> Jsont.Object.finish 5439 5440 end 5441 - module GetTrendingTopics = struct 5442 type params = { 5443 limit : int option; 5444 viewer : string option; ··· 5457 |> Jsont.Object.finish 5458 5459 type output = { 5460 - suggested : Defs.trending_topic list; 5461 - topics : Defs.trending_topic list; 5462 } 5463 5464 let output_jsont = 5465 Jsont.Object.map ~kind:"Output" 5466 - (fun _typ suggested topics -> { suggested; topics }) 5467 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getTrendingTopics#output" ~enc:(fun _ -> "app.bsky.unspecced.getTrendingTopics#output") 5468 - |> Jsont.Object.mem "suggested" (Jsont.list Defs.trending_topic_jsont) ~enc:(fun r -> r.suggested) 5469 - |> Jsont.Object.mem "topics" (Jsont.list Defs.trending_topic_jsont) ~enc:(fun r -> r.topics) 5470 |> Jsont.Object.finish 5471 5472 end 5473 - module GetTrendsSkeleton = struct 5474 type params = { 5475 limit : int option; 5476 viewer : string option; ··· 5489 |> Jsont.Object.finish 5490 5491 type output = { 5492 - trends : Defs.skeleton_trend list; 5493 } 5494 5495 let output_jsont = 5496 Jsont.Object.map ~kind:"Output" 5497 - (fun _typ trends -> { trends }) 5498 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getTrendsSkeleton#output" ~enc:(fun _ -> "app.bsky.unspecced.getTrendsSkeleton#output") 5499 - |> Jsont.Object.mem "trends" (Jsont.list Defs.skeleton_trend_jsont) ~enc:(fun r -> r.trends) 5500 |> Jsont.Object.finish 5501 5502 end ··· 5541 |> Jsont.Object.finish 5542 5543 end 5544 - module InitAgeAssurance = struct 5545 - type input = { 5546 - country_code : string; 5547 - email : string; 5548 - language : string; 5549 } 5550 5551 - let input_jsont = 5552 - Jsont.Object.map ~kind:"Input" 5553 - (fun _typ country_code email language -> { country_code; email; language }) 5554 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.initAgeAssurance#input" ~enc:(fun _ -> "app.bsky.unspecced.initAgeAssurance#input") 5555 - |> Jsont.Object.mem "countryCode" Jsont.string ~enc:(fun r -> r.country_code) 5556 - |> Jsont.Object.mem "email" Jsont.string ~enc:(fun r -> r.email) 5557 - |> Jsont.Object.mem "language" Jsont.string ~enc:(fun r -> r.language) 5558 |> Jsont.Object.finish 5559 5560 type output = Defs.age_assurance_state 5561 5562 let output_jsont = Defs.age_assurance_state_jsont ··· 5604 |> Jsont.Object.finish 5605 5606 end 5607 - module SearchActorsSkeleton = struct 5608 type params = { 5609 cursor : string option; 5610 limit : int option; 5611 q : string; 5612 - typeahead : bool option; 5613 viewer : string option; 5614 } 5615 5616 let params_jsont = 5617 Jsont.Object.map ~kind:"Params" 5618 - (fun cursor limit q typeahead viewer -> { 5619 cursor; 5620 limit; 5621 q; 5622 - typeahead; 5623 viewer; 5624 }) 5625 |> Jsont.Object.opt_mem "cursor" Jsont.string 5626 ~enc:(fun r -> r.cursor) 5627 |> Jsont.Object.opt_mem "limit" Jsont.int 5628 ~enc:(fun r -> r.limit) 5629 |> Jsont.Object.mem "q" Jsont.string 5630 ~enc:(fun r -> r.q) 5631 - |> Jsont.Object.opt_mem "typeahead" Jsont.bool 5632 - ~enc:(fun r -> r.typeahead) 5633 |> Jsont.Object.opt_mem "viewer" Jsont.string 5634 ~enc:(fun r -> r.viewer) 5635 |> Jsont.Object.finish 5636 5637 type output = { 5638 - actors : Defs.skeleton_search_actor list; 5639 cursor : string option; 5640 hits_total : int option; 5641 } 5642 5643 let output_jsont = 5644 Jsont.Object.map ~kind:"Output" 5645 - (fun _typ actors cursor hits_total -> { actors; cursor; hits_total }) 5646 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.searchActorsSkeleton#output" ~enc:(fun _ -> "app.bsky.unspecced.searchActorsSkeleton#output") 5647 - |> Jsont.Object.mem "actors" (Jsont.list Defs.skeleton_search_actor_jsont) ~enc:(fun r -> r.actors) 5648 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 5649 |> Jsont.Object.opt_mem "hitsTotal" Jsont.int ~enc:(fun r -> r.hits_total) 5650 |> Jsont.Object.finish 5651 5652 end 5653 - module GetAgeAssuranceState = struct 5654 - type output = Defs.age_assurance_state 5655 - 5656 - let output_jsont = Defs.age_assurance_state_jsont 5657 - 5658 - end 5659 - module GetSuggestionsSkeleton = struct 5660 type params = { 5661 cursor : string option; 5662 limit : int option; 5663 - relative_to_did : string option; 5664 viewer : string option; 5665 } 5666 5667 let params_jsont = 5668 Jsont.Object.map ~kind:"Params" 5669 - (fun cursor limit relative_to_did viewer -> { 5670 cursor; 5671 limit; 5672 - relative_to_did; 5673 viewer; 5674 }) 5675 |> Jsont.Object.opt_mem "cursor" Jsont.string 5676 ~enc:(fun r -> r.cursor) 5677 |> Jsont.Object.opt_mem "limit" Jsont.int 5678 ~enc:(fun r -> r.limit) 5679 - |> Jsont.Object.opt_mem "relativeToDid" Jsont.string 5680 - ~enc:(fun r -> r.relative_to_did) 5681 |> Jsont.Object.opt_mem "viewer" Jsont.string 5682 ~enc:(fun r -> r.viewer) 5683 |> Jsont.Object.finish ··· 5685 type output = { 5686 actors : Defs.skeleton_search_actor list; 5687 cursor : string option; 5688 - rec_id : int option; 5689 - relative_to_did : string option; 5690 } 5691 5692 let output_jsont = 5693 Jsont.Object.map ~kind:"Output" 5694 - (fun _typ actors cursor rec_id relative_to_did -> { actors; cursor; rec_id; relative_to_did }) 5695 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getSuggestionsSkeleton#output" ~enc:(fun _ -> "app.bsky.unspecced.getSuggestionsSkeleton#output") 5696 |> Jsont.Object.mem "actors" (Jsont.list Defs.skeleton_search_actor_jsont) ~enc:(fun r -> r.actors) 5697 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 5698 - |> Jsont.Object.opt_mem "recId" Jsont.int ~enc:(fun r -> r.rec_id) 5699 - |> Jsont.Object.opt_mem "relativeToDid" Jsont.string ~enc:(fun r -> r.relative_to_did) 5700 |> Jsont.Object.finish 5701 5702 end ··· 5723 (fun _typ trends -> { trends }) 5724 |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getTrends#output" ~enc:(fun _ -> "app.bsky.unspecced.getTrends#output") 5725 |> Jsont.Object.mem "trends" (Jsont.list Defs.trend_view_jsont) ~enc:(fun r -> r.trends) 5726 |> Jsont.Object.finish 5727 5728 end
··· 15 16 module Com = struct 17 module Atproto = struct 18 + module Moderation = struct 19 + module Defs = struct 20 + type subject_type = string 21 + let subject_type_jsont = Jsont.string 22 + 23 + type reason_violation = string 24 + let reason_violation_jsont = Jsont.string 25 + 26 + type reason_type = string 27 + let reason_type_jsont = Jsont.string 28 + 29 + type reason_spam = string 30 + let reason_spam_jsont = Jsont.string 31 + 32 + type reason_sexual = string 33 + let reason_sexual_jsont = Jsont.string 34 + 35 + type reason_rude = string 36 + let reason_rude_jsont = Jsont.string 37 + 38 + type reason_other = string 39 + let reason_other_jsont = Jsont.string 40 + 41 + type reason_misleading = string 42 + let reason_misleading_jsont = Jsont.string 43 + 44 + type reason_appeal = string 45 + let reason_appeal_jsont = Jsont.string 46 + 47 + end 48 + end 49 module Label = struct 50 module Defs = struct 51 type self_label = { ··· 155 156 end 157 end 158 end 159 end 160 module App = struct 161 module Bsky = struct 162 + module AuthFullApp = struct 163 type main = unit 164 let main_jsont = Jsont.ignore 165 ··· 169 let main_jsont = Jsont.ignore 170 171 end 172 module AuthManageFeedDeclarations = struct 173 type main = unit 174 let main_jsont = Jsont.ignore 175 176 end 177 + module AuthManageNotifications = struct 178 type main = unit 179 let main_jsont = Jsont.ignore 180 181 end 182 + module AuthManageModeration = struct 183 type main = unit 184 let main_jsont = Jsont.ignore 185 ··· 189 let main_jsont = Jsont.ignore 190 191 end 192 + module AuthManageLabelerService = struct 193 type main = unit 194 let main_jsont = Jsont.ignore 195 196 end 197 + module Notification = struct 198 + module GetUnreadCount = struct 199 type params = { 200 + priority : bool option; 201 + seen_at : string option; 202 } 203 204 let params_jsont = 205 Jsont.Object.map ~kind:"Params" 206 + (fun priority seen_at -> { 207 + priority; 208 + seen_at; 209 }) 210 + |> Jsont.Object.opt_mem "priority" Jsont.bool 211 + ~enc:(fun r -> r.priority) 212 + |> Jsont.Object.opt_mem "seenAt" Jsont.string 213 + ~enc:(fun r -> r.seen_at) 214 |> Jsont.Object.finish 215 216 type output = { 217 + count : int; 218 } 219 220 let output_jsont = 221 Jsont.Object.map ~kind:"Output" 222 + (fun _typ count -> { count }) 223 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.notification.getUnreadCount#output" ~enc:(fun _ -> "app.bsky.notification.getUnreadCount#output") 224 + |> Jsont.Object.mem "count" Jsont.int ~enc:(fun r -> r.count) 225 |> Jsont.Object.finish 226 227 end 228 module UpdateSeen = struct 229 type input = { 230 seen_at : string; ··· 235 (fun _typ seen_at -> { seen_at }) 236 |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.notification.updateSeen#input" ~enc:(fun _ -> "app.bsky.notification.updateSeen#input") 237 |> Jsont.Object.mem "seenAt" Jsont.string ~enc:(fun r -> r.seen_at) 238 |> Jsont.Object.finish 239 240 end ··· 313 |> Jsont.Object.finish 314 315 end 316 + module Declaration = struct 317 + type main = { 318 + allow_subscriptions : string; 319 } 320 321 + let main_jsont = 322 + Jsont.Object.map ~kind:"Main" 323 + (fun _typ allow_subscriptions -> { allow_subscriptions }) 324 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.notification.declaration" ~enc:(fun _ -> "app.bsky.notification.declaration") 325 + |> Jsont.Object.mem "allowSubscriptions" Jsont.string ~enc:(fun r -> r.allow_subscriptions) 326 |> Jsont.Object.finish 327 328 + end 329 + module PutPreferences = struct 330 + type input = { 331 + priority : bool; 332 } 333 334 + let input_jsont = 335 + Jsont.Object.map ~kind:"Input" 336 + (fun _typ priority -> { priority }) 337 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.notification.putPreferences#input" ~enc:(fun _ -> "app.bsky.notification.putPreferences#input") 338 + |> Jsont.Object.mem "priority" Jsont.bool ~enc:(fun r -> r.priority) 339 |> Jsont.Object.finish 340 341 end 342 + module RegisterPush = struct 343 type input = { 344 + age_restricted : bool option; 345 app_id : string; 346 platform : string; 347 service_did : string; ··· 350 351 let input_jsont = 352 Jsont.Object.map ~kind:"Input" 353 + (fun _typ age_restricted app_id platform service_did token -> { age_restricted; app_id; platform; service_did; token }) 354 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.notification.registerPush#input" ~enc:(fun _ -> "app.bsky.notification.registerPush#input") 355 + |> Jsont.Object.opt_mem "ageRestricted" Jsont.bool ~enc:(fun r -> r.age_restricted) 356 |> Jsont.Object.mem "appId" Jsont.string ~enc:(fun r -> r.app_id) 357 |> Jsont.Object.mem "platform" Jsont.string ~enc:(fun r -> r.platform) 358 |> Jsont.Object.mem "serviceDid" Jsont.string ~enc:(fun r -> r.service_did) ··· 360 |> Jsont.Object.finish 361 362 end 363 + module UnregisterPush = struct 364 type input = { 365 + app_id : string; 366 + platform : string; 367 + service_did : string; 368 + token : string; 369 } 370 371 let input_jsont = 372 Jsont.Object.map ~kind:"Input" 373 + (fun _typ app_id platform service_did token -> { app_id; platform; service_did; token }) 374 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.notification.unregisterPush#input" ~enc:(fun _ -> "app.bsky.notification.unregisterPush#input") 375 + |> Jsont.Object.mem "appId" Jsont.string ~enc:(fun r -> r.app_id) 376 + |> Jsont.Object.mem "platform" Jsont.string ~enc:(fun r -> r.platform) 377 + |> Jsont.Object.mem "serviceDid" Jsont.string ~enc:(fun r -> r.service_did) 378 + |> Jsont.Object.mem "token" Jsont.string ~enc:(fun r -> r.token) 379 |> Jsont.Object.finish 380 381 end ··· 487 |> Jsont.Object.finish 488 489 end 490 module ListActivitySubscriptions = struct 491 type params = { 492 cursor : string option; ··· 613 614 end 615 end 616 + module Labeler = struct 617 + module Defs = struct 618 + type labeler_viewer_state = { 619 + like : string option; 620 + } 621 + 622 + let labeler_viewer_state_jsont = 623 + Jsont.Object.map ~kind:"Labeler_viewer_state" 624 + (fun _typ like -> { like }) 625 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.labeler.defs#labelerViewerState" ~enc:(fun _ -> "app.bsky.labeler.defs#labelerViewerState") 626 + |> Jsont.Object.opt_mem "like" Jsont.string ~enc:(fun r -> r.like) 627 + |> Jsont.Object.finish 628 + 629 + type labeler_policies = { 630 + label_value_definitions : Com.Atproto.Label.Defs.label_value_definition list option; 631 + label_values : Com.Atproto.Label.Defs.label_value list; 632 + } 633 + 634 + let labeler_policies_jsont = 635 + Jsont.Object.map ~kind:"Labeler_policies" 636 + (fun _typ label_value_definitions label_values -> { label_value_definitions; label_values }) 637 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.labeler.defs#labelerPolicies" ~enc:(fun _ -> "app.bsky.labeler.defs#labelerPolicies") 638 + |> Jsont.Object.opt_mem "labelValueDefinitions" (Jsont.list Com.Atproto.Label.Defs.label_value_definition_jsont) ~enc:(fun r -> r.label_value_definitions) 639 + |> Jsont.Object.mem "labelValues" (Jsont.list Com.Atproto.Label.Defs.label_value_jsont) ~enc:(fun r -> r.label_values) 640 + |> Jsont.Object.finish 641 + 642 + type labeler_view_detailed = { 643 + cid : string; 644 + creator : Jsont.json; 645 + indexed_at : string; 646 + labels : Com.Atproto.Label.Defs.label list option; 647 + like_count : int option; 648 + policies : Jsont.json; 649 + reason_types : Com.Atproto.Moderation.Defs.reason_type list option; 650 + subject_collections : string list option; 651 + subject_types : Com.Atproto.Moderation.Defs.subject_type list option; 652 + uri : string; 653 + viewer : Jsont.json option; 654 + } 655 + 656 + let labeler_view_detailed_jsont = 657 + Jsont.Object.map ~kind:"Labeler_view_detailed" 658 + (fun _typ cid creator indexed_at labels like_count policies reason_types subject_collections subject_types uri viewer -> { cid; creator; indexed_at; labels; like_count; policies; reason_types; subject_collections; subject_types; uri; viewer }) 659 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.labeler.defs#labelerViewDetailed" ~enc:(fun _ -> "app.bsky.labeler.defs#labelerViewDetailed") 660 + |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 661 + |> Jsont.Object.mem "creator" Jsont.json ~enc:(fun r -> r.creator) 662 + |> Jsont.Object.mem "indexedAt" Jsont.string ~enc:(fun r -> r.indexed_at) 663 + |> Jsont.Object.opt_mem "labels" (Jsont.list Com.Atproto.Label.Defs.label_jsont) ~enc:(fun r -> r.labels) 664 + |> Jsont.Object.opt_mem "likeCount" Jsont.int ~enc:(fun r -> r.like_count) 665 + |> Jsont.Object.mem "policies" Jsont.json ~enc:(fun r -> r.policies) 666 + |> Jsont.Object.opt_mem "reasonTypes" (Jsont.list Com.Atproto.Moderation.Defs.reason_type_jsont) ~enc:(fun r -> r.reason_types) 667 + |> Jsont.Object.opt_mem "subjectCollections" (Jsont.list Jsont.string) ~enc:(fun r -> r.subject_collections) 668 + |> Jsont.Object.opt_mem "subjectTypes" (Jsont.list Com.Atproto.Moderation.Defs.subject_type_jsont) ~enc:(fun r -> r.subject_types) 669 + |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 670 + |> Jsont.Object.opt_mem "viewer" Jsont.json ~enc:(fun r -> r.viewer) 671 + |> Jsont.Object.finish 672 + 673 + type labeler_view = { 674 + cid : string; 675 + creator : Jsont.json; 676 + indexed_at : string; 677 + labels : Com.Atproto.Label.Defs.label list option; 678 + like_count : int option; 679 + uri : string; 680 + viewer : Jsont.json option; 681 + } 682 + 683 + let labeler_view_jsont = 684 + Jsont.Object.map ~kind:"Labeler_view" 685 + (fun _typ cid creator indexed_at labels like_count uri viewer -> { cid; creator; indexed_at; labels; like_count; uri; viewer }) 686 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.labeler.defs#labelerView" ~enc:(fun _ -> "app.bsky.labeler.defs#labelerView") 687 + |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 688 + |> Jsont.Object.mem "creator" Jsont.json ~enc:(fun r -> r.creator) 689 + |> Jsont.Object.mem "indexedAt" Jsont.string ~enc:(fun r -> r.indexed_at) 690 + |> Jsont.Object.opt_mem "labels" (Jsont.list Com.Atproto.Label.Defs.label_jsont) ~enc:(fun r -> r.labels) 691 + |> Jsont.Object.opt_mem "likeCount" Jsont.int ~enc:(fun r -> r.like_count) 692 + |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 693 + |> Jsont.Object.opt_mem "viewer" Jsont.json ~enc:(fun r -> r.viewer) 694 + |> Jsont.Object.finish 695 + 696 + end 697 + module Service = struct 698 + type main = { 699 + created_at : string; 700 + labels : Com.Atproto.Label.Defs.self_labels option; 701 + policies : Jsont.json; 702 + reason_types : Com.Atproto.Moderation.Defs.reason_type list option; 703 + subject_collections : string list option; 704 + subject_types : Com.Atproto.Moderation.Defs.subject_type list option; 705 + } 706 + 707 + let main_jsont = 708 + Jsont.Object.map ~kind:"Main" 709 + (fun _typ created_at labels policies reason_types subject_collections subject_types -> { created_at; labels; policies; reason_types; subject_collections; subject_types }) 710 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.labeler.service" ~enc:(fun _ -> "app.bsky.labeler.service") 711 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 712 + |> Jsont.Object.opt_mem "labels" Com.Atproto.Label.Defs.self_labels_jsont ~enc:(fun r -> r.labels) 713 + |> Jsont.Object.mem "policies" Jsont.json ~enc:(fun r -> r.policies) 714 + |> Jsont.Object.opt_mem "reasonTypes" (Jsont.list Com.Atproto.Moderation.Defs.reason_type_jsont) ~enc:(fun r -> r.reason_types) 715 + |> Jsont.Object.opt_mem "subjectCollections" (Jsont.list Jsont.string) ~enc:(fun r -> r.subject_collections) 716 + |> Jsont.Object.opt_mem "subjectTypes" (Jsont.list Com.Atproto.Moderation.Defs.subject_type_jsont) ~enc:(fun r -> r.subject_types) 717 + |> Jsont.Object.finish 718 + 719 + end 720 + module GetServices = struct 721 + type params = { 722 + detailed : bool option; 723 + dids : string list; 724 + } 725 + 726 + let params_jsont = 727 + Jsont.Object.map ~kind:"Params" 728 + (fun detailed dids -> { 729 + detailed; 730 + dids; 731 + }) 732 + |> Jsont.Object.opt_mem "detailed" Jsont.bool 733 + ~enc:(fun r -> r.detailed) 734 + |> Jsont.Object.mem "dids" (Jsont.list Jsont.string) 735 + ~enc:(fun r -> r.dids) 736 + |> Jsont.Object.finish 737 + 738 + type output = { 739 + views : Jsont.json list; 740 + } 741 + 742 + let output_jsont = 743 + Jsont.Object.map ~kind:"Output" 744 + (fun _typ views -> { views }) 745 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.labeler.getServices#output" ~enc:(fun _ -> "app.bsky.labeler.getServices#output") 746 + |> Jsont.Object.mem "views" (Jsont.list Jsont.json) ~enc:(fun r -> r.views) 747 + |> Jsont.Object.finish 748 + 749 + end 750 + end 751 module Actor = struct 752 module Status = struct 753 type live = string ··· 768 |> Jsont.Object.opt_mem "durationMinutes" Jsont.int ~enc:(fun r -> r.duration_minutes) 769 |> Jsont.Object.opt_mem "embed" Jsont.json ~enc:(fun r -> r.embed) 770 |> Jsont.Object.mem "status" Jsont.string ~enc:(fun r -> r.status) 771 |> Jsont.Object.finish 772 773 end ··· 1308 |> Jsont.Object.finish 1309 1310 end 1311 + module Profile = struct 1312 + type main = { 1313 + avatar : Atp.Blob_ref.t option; 1314 + banner : Atp.Blob_ref.t option; 1315 + created_at : string option; 1316 + description : string option; 1317 + display_name : string option; 1318 + joined_via_starter_pack : Com.Atproto.Repo.StrongRef.main option; 1319 + labels : Com.Atproto.Label.Defs.self_labels option; 1320 + pinned_post : Com.Atproto.Repo.StrongRef.main option; 1321 + pronouns : string option; 1322 + website : string option; 1323 + } 1324 + 1325 + let main_jsont = 1326 + Jsont.Object.map ~kind:"Main" 1327 + (fun _typ avatar banner created_at description display_name joined_via_starter_pack labels pinned_post pronouns website -> { avatar; banner; created_at; description; display_name; joined_via_starter_pack; labels; pinned_post; pronouns; website }) 1328 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.actor.profile" ~enc:(fun _ -> "app.bsky.actor.profile") 1329 + |> Jsont.Object.opt_mem "avatar" Atp.Blob_ref.jsont ~enc:(fun r -> r.avatar) 1330 + |> Jsont.Object.opt_mem "banner" Atp.Blob_ref.jsont ~enc:(fun r -> r.banner) 1331 + |> Jsont.Object.opt_mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 1332 + |> Jsont.Object.opt_mem "description" Jsont.string ~enc:(fun r -> r.description) 1333 + |> Jsont.Object.opt_mem "displayName" Jsont.string ~enc:(fun r -> r.display_name) 1334 + |> Jsont.Object.opt_mem "joinedViaStarterPack" Com.Atproto.Repo.StrongRef.main_jsont ~enc:(fun r -> r.joined_via_starter_pack) 1335 + |> Jsont.Object.opt_mem "labels" Com.Atproto.Label.Defs.self_labels_jsont ~enc:(fun r -> r.labels) 1336 + |> Jsont.Object.opt_mem "pinnedPost" Com.Atproto.Repo.StrongRef.main_jsont ~enc:(fun r -> r.pinned_post) 1337 + |> Jsont.Object.opt_mem "pronouns" Jsont.string ~enc:(fun r -> r.pronouns) 1338 + |> Jsont.Object.opt_mem "website" Jsont.string ~enc:(fun r -> r.website) 1339 + |> Jsont.Object.finish 1340 + 1341 + end 1342 + module GetProfiles = struct 1343 + type params = { 1344 + actors : string list; 1345 + } 1346 + 1347 + let params_jsont = 1348 + Jsont.Object.map ~kind:"Params" 1349 + (fun actors -> { 1350 + actors; 1351 + }) 1352 + |> Jsont.Object.mem "actors" (Jsont.list Jsont.string) 1353 + ~enc:(fun r -> r.actors) 1354 + |> Jsont.Object.finish 1355 + 1356 + type output = { 1357 + profiles : Jsont.json list; 1358 + } 1359 + 1360 + let output_jsont = 1361 + Jsont.Object.map ~kind:"Output" 1362 + (fun _typ profiles -> { profiles }) 1363 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.actor.getProfiles#output" ~enc:(fun _ -> "app.bsky.actor.getProfiles#output") 1364 + |> Jsont.Object.mem "profiles" (Jsont.list Jsont.json) ~enc:(fun r -> r.profiles) 1365 + |> Jsont.Object.finish 1366 + 1367 + end 1368 module GetPreferences = struct 1369 type params = unit 1370 ··· 1382 |> Jsont.Object.finish 1383 1384 end 1385 + module GetSuggestions = struct 1386 type params = { 1387 + cursor : string option; 1388 limit : int option; 1389 } 1390 1391 let params_jsont = 1392 Jsont.Object.map ~kind:"Params" 1393 + (fun cursor limit -> { 1394 + cursor; 1395 limit; 1396 }) 1397 + |> Jsont.Object.opt_mem "cursor" Jsont.string 1398 + ~enc:(fun r -> r.cursor) 1399 |> Jsont.Object.opt_mem "limit" Jsont.int 1400 ~enc:(fun r -> r.limit) 1401 |> Jsont.Object.finish 1402 1403 type output = { 1404 actors : Jsont.json list; 1405 + cursor : string option; 1406 + rec_id : int option; 1407 } 1408 1409 let output_jsont = 1410 Jsont.Object.map ~kind:"Output" 1411 + (fun _typ actors cursor rec_id -> { actors; cursor; rec_id }) 1412 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.actor.getSuggestions#output" ~enc:(fun _ -> "app.bsky.actor.getSuggestions#output") 1413 |> Jsont.Object.mem "actors" (Jsont.list Jsont.json) ~enc:(fun r -> r.actors) 1414 + |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 1415 + |> Jsont.Object.opt_mem "recId" Jsont.int ~enc:(fun r -> r.rec_id) 1416 |> Jsont.Object.finish 1417 1418 end ··· 1475 |> Jsont.Object.finish 1476 1477 end 1478 + module PutPreferences = struct 1479 + type input = { 1480 + preferences : Jsont.json; 1481 + } 1482 + 1483 + let input_jsont = 1484 + Jsont.Object.map ~kind:"Input" 1485 + (fun _typ preferences -> { preferences }) 1486 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.actor.putPreferences#input" ~enc:(fun _ -> "app.bsky.actor.putPreferences#input") 1487 + |> Jsont.Object.mem "preferences" Jsont.json ~enc:(fun r -> r.preferences) 1488 + |> Jsont.Object.finish 1489 + 1490 + end 1491 + module SearchActorsTypeahead = struct 1492 type params = { 1493 limit : int option; 1494 + q : string option; 1495 + term : string option; 1496 } 1497 1498 let params_jsont = 1499 Jsont.Object.map ~kind:"Params" 1500 + (fun limit q term -> { 1501 limit; 1502 + q; 1503 + term; 1504 }) 1505 |> Jsont.Object.opt_mem "limit" Jsont.int 1506 ~enc:(fun r -> r.limit) 1507 + |> Jsont.Object.opt_mem "q" Jsont.string 1508 + ~enc:(fun r -> r.q) 1509 + |> Jsont.Object.opt_mem "term" Jsont.string 1510 + ~enc:(fun r -> r.term) 1511 |> Jsont.Object.finish 1512 1513 type output = { 1514 actors : Jsont.json list; 1515 } 1516 1517 let output_jsont = 1518 Jsont.Object.map ~kind:"Output" 1519 + (fun _typ actors -> { actors }) 1520 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.actor.searchActorsTypeahead#output" ~enc:(fun _ -> "app.bsky.actor.searchActorsTypeahead#output") 1521 |> Jsont.Object.mem "actors" (Jsont.list Jsont.json) ~enc:(fun r -> r.actors) 1522 |> Jsont.Object.finish 1523 1524 end 1525 + end 1526 + module Video = struct 1527 + module GetUploadLimits = struct 1528 type output = { 1529 + can_upload : bool; 1530 + error : string option; 1531 + message : string option; 1532 + remaining_daily_bytes : int option; 1533 + remaining_daily_videos : int option; 1534 } 1535 1536 let output_jsont = 1537 Jsont.Object.map ~kind:"Output" 1538 + (fun _typ can_upload error message remaining_daily_bytes remaining_daily_videos -> { can_upload; error; message; remaining_daily_bytes; remaining_daily_videos }) 1539 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.video.getUploadLimits#output" ~enc:(fun _ -> "app.bsky.video.getUploadLimits#output") 1540 + |> Jsont.Object.mem "canUpload" Jsont.bool ~enc:(fun r -> r.can_upload) 1541 + |> Jsont.Object.opt_mem "error" Jsont.string ~enc:(fun r -> r.error) 1542 + |> Jsont.Object.opt_mem "message" Jsont.string ~enc:(fun r -> r.message) 1543 + |> Jsont.Object.opt_mem "remainingDailyBytes" Jsont.int ~enc:(fun r -> r.remaining_daily_bytes) 1544 + |> Jsont.Object.opt_mem "remainingDailyVideos" Jsont.int ~enc:(fun r -> r.remaining_daily_videos) 1545 |> Jsont.Object.finish 1546 1547 end 1548 + module Defs = struct 1549 + type job_status = { 1550 + blob : Atp.Blob_ref.t option; 1551 + did : string; 1552 + error : string option; 1553 + job_id : string; 1554 + message : string option; 1555 + progress : int option; 1556 + state : string; 1557 } 1558 1559 + let job_status_jsont = 1560 + Jsont.Object.map ~kind:"Job_status" 1561 + (fun _typ blob did error job_id message progress state -> { blob; did; error; job_id; message; progress; state }) 1562 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.video.defs#jobStatus" ~enc:(fun _ -> "app.bsky.video.defs#jobStatus") 1563 + |> Jsont.Object.opt_mem "blob" Atp.Blob_ref.jsont ~enc:(fun r -> r.blob) 1564 + |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 1565 + |> Jsont.Object.opt_mem "error" Jsont.string ~enc:(fun r -> r.error) 1566 + |> Jsont.Object.mem "jobId" Jsont.string ~enc:(fun r -> r.job_id) 1567 + |> Jsont.Object.opt_mem "message" Jsont.string ~enc:(fun r -> r.message) 1568 + |> Jsont.Object.opt_mem "progress" Jsont.int ~enc:(fun r -> r.progress) 1569 + |> Jsont.Object.mem "state" Jsont.string ~enc:(fun r -> r.state) 1570 |> Jsont.Object.finish 1571 1572 end 1573 + module GetJobStatus = struct 1574 + type params = { 1575 + job_id : string; 1576 } 1577 1578 + let params_jsont = 1579 + Jsont.Object.map ~kind:"Params" 1580 + (fun job_id -> { 1581 + job_id; 1582 + }) 1583 + |> Jsont.Object.mem "jobId" Jsont.string 1584 + ~enc:(fun r -> r.job_id) 1585 |> Jsont.Object.finish 1586 1587 + type output = { 1588 + job_status : Defs.job_status; 1589 } 1590 1591 + let output_jsont = 1592 + Jsont.Object.map ~kind:"Output" 1593 + (fun _typ job_status -> { job_status }) 1594 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.video.getJobStatus#output" ~enc:(fun _ -> "app.bsky.video.getJobStatus#output") 1595 + |> Jsont.Object.mem "jobStatus" Defs.job_status_jsont ~enc:(fun r -> r.job_status) 1596 |> Jsont.Object.finish 1597 1598 end 1599 + module UploadVideo = struct 1600 type input = unit 1601 let input_jsont = Jsont.ignore 1602 1603 type output = { 1604 + job_status : Defs.job_status; 1605 } 1606 1607 let output_jsont = 1608 Jsont.Object.map ~kind:"Output" 1609 + (fun _typ job_status -> { job_status }) 1610 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.video.uploadVideo#output" ~enc:(fun _ -> "app.bsky.video.uploadVideo#output") 1611 + |> Jsont.Object.mem "jobStatus" Defs.job_status_jsont ~enc:(fun r -> r.job_status) 1612 |> Jsont.Object.finish 1613 1614 end 1615 + end 1616 + module Richtext = struct 1617 + module Facet = struct 1618 + type tag = { 1619 + tag : string; 1620 } 1621 1622 + let tag_jsont = 1623 + Jsont.Object.map ~kind:"Tag" 1624 + (fun _typ tag -> { tag }) 1625 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.richtext.facet#tag" ~enc:(fun _ -> "app.bsky.richtext.facet#tag") 1626 + |> Jsont.Object.mem "tag" Jsont.string ~enc:(fun r -> r.tag) 1627 |> Jsont.Object.finish 1628 1629 + type mention = { 1630 + did : string; 1631 } 1632 1633 + let mention_jsont = 1634 + Jsont.Object.map ~kind:"Mention" 1635 + (fun _typ did -> { did }) 1636 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.richtext.facet#mention" ~enc:(fun _ -> "app.bsky.richtext.facet#mention") 1637 + |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 1638 |> Jsont.Object.finish 1639 1640 + type link = { 1641 + uri : string; 1642 } 1643 1644 + let link_jsont = 1645 + Jsont.Object.map ~kind:"Link" 1646 + (fun _typ uri -> { uri }) 1647 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.richtext.facet#link" ~enc:(fun _ -> "app.bsky.richtext.facet#link") 1648 + |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 1649 |> Jsont.Object.finish 1650 1651 + type byte_slice = { 1652 + byte_end : int; 1653 + byte_start : int; 1654 } 1655 1656 + let byte_slice_jsont = 1657 + Jsont.Object.map ~kind:"Byte_slice" 1658 + (fun _typ byte_end byte_start -> { byte_end; byte_start }) 1659 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.richtext.facet#byteSlice" ~enc:(fun _ -> "app.bsky.richtext.facet#byteSlice") 1660 + |> Jsont.Object.mem "byteEnd" Jsont.int ~enc:(fun r -> r.byte_end) 1661 + |> Jsont.Object.mem "byteStart" Jsont.int ~enc:(fun r -> r.byte_start) 1662 |> Jsont.Object.finish 1663 1664 + type main = { 1665 + features : Jsont.json list; 1666 + index : byte_slice; 1667 + } 1668 1669 + let main_jsont = 1670 + Jsont.Object.map ~kind:"Main" 1671 + (fun _typ features index -> { features; index }) 1672 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.richtext.facet" ~enc:(fun _ -> "app.bsky.richtext.facet") 1673 + |> Jsont.Object.mem "features" (Jsont.list Jsont.json) ~enc:(fun r -> r.features) 1674 + |> Jsont.Object.mem "index" byte_slice_jsont ~enc:(fun r -> r.index) 1675 + |> Jsont.Object.finish 1676 1677 end 1678 + end 1679 + module AuthCreatePosts = struct 1680 + type main = unit 1681 + let main_jsont = Jsont.ignore 1682 1683 + end 1684 + module Ageassurance = struct 1685 + module Defs = struct 1686 + type status = string 1687 + let status_jsont = Jsont.string 1688 1689 + type state_metadata = { 1690 + account_created_at : string option; 1691 } 1692 1693 + let state_metadata_jsont = 1694 + Jsont.Object.map ~kind:"State_metadata" 1695 + (fun _typ account_created_at -> { account_created_at }) 1696 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.defs#stateMetadata" ~enc:(fun _ -> "app.bsky.ageassurance.defs#stateMetadata") 1697 + |> Jsont.Object.opt_mem "accountCreatedAt" Jsont.string ~enc:(fun r -> r.account_created_at) 1698 |> Jsont.Object.finish 1699 1700 + type event = { 1701 + access : string; 1702 + attempt_id : string; 1703 + complete_ip : string option; 1704 + complete_ua : string option; 1705 + country_code : string; 1706 + created_at : string; 1707 + email : string option; 1708 + init_ip : string option; 1709 + init_ua : string option; 1710 + region_code : string option; 1711 + status : string; 1712 } 1713 1714 + let event_jsont = 1715 + Jsont.Object.map ~kind:"Event" 1716 + (fun _typ access attempt_id complete_ip complete_ua country_code created_at email init_ip init_ua region_code status -> { access; attempt_id; complete_ip; complete_ua; country_code; created_at; email; init_ip; init_ua; region_code; status }) 1717 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.defs#event" ~enc:(fun _ -> "app.bsky.ageassurance.defs#event") 1718 + |> Jsont.Object.mem "access" Jsont.string ~enc:(fun r -> r.access) 1719 + |> Jsont.Object.mem "attemptId" Jsont.string ~enc:(fun r -> r.attempt_id) 1720 + |> Jsont.Object.opt_mem "completeIp" Jsont.string ~enc:(fun r -> r.complete_ip) 1721 + |> Jsont.Object.opt_mem "completeUa" Jsont.string ~enc:(fun r -> r.complete_ua) 1722 + |> Jsont.Object.mem "countryCode" Jsont.string ~enc:(fun r -> r.country_code) 1723 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 1724 + |> Jsont.Object.opt_mem "email" Jsont.string ~enc:(fun r -> r.email) 1725 + |> Jsont.Object.opt_mem "initIp" Jsont.string ~enc:(fun r -> r.init_ip) 1726 + |> Jsont.Object.opt_mem "initUa" Jsont.string ~enc:(fun r -> r.init_ua) 1727 + |> Jsont.Object.opt_mem "regionCode" Jsont.string ~enc:(fun r -> r.region_code) 1728 + |> Jsont.Object.mem "status" Jsont.string ~enc:(fun r -> r.status) 1729 |> Jsont.Object.finish 1730 1731 + type config_region = { 1732 + country_code : string; 1733 + min_access_age : int; 1734 + region_code : string option; 1735 + rules : Jsont.json list; 1736 } 1737 1738 + let config_region_jsont = 1739 + Jsont.Object.map ~kind:"Config_region" 1740 + (fun _typ country_code min_access_age region_code rules -> { country_code; min_access_age; region_code; rules }) 1741 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.defs#configRegion" ~enc:(fun _ -> "app.bsky.ageassurance.defs#configRegion") 1742 + |> Jsont.Object.mem "countryCode" Jsont.string ~enc:(fun r -> r.country_code) 1743 + |> Jsont.Object.mem "minAccessAge" Jsont.int ~enc:(fun r -> r.min_access_age) 1744 + |> Jsont.Object.opt_mem "regionCode" Jsont.string ~enc:(fun r -> r.region_code) 1745 + |> Jsont.Object.mem "rules" (Jsont.list Jsont.json) ~enc:(fun r -> r.rules) 1746 |> Jsont.Object.finish 1747 1748 + type access = string 1749 + let access_jsont = Jsont.string 1750 + 1751 + type state = { 1752 + access : access; 1753 + last_initiated_at : string option; 1754 + status : status; 1755 } 1756 1757 + let state_jsont = 1758 + Jsont.Object.map ~kind:"State" 1759 + (fun _typ access last_initiated_at status -> { access; last_initiated_at; status }) 1760 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.defs#state" ~enc:(fun _ -> "app.bsky.ageassurance.defs#state") 1761 + |> Jsont.Object.mem "access" access_jsont ~enc:(fun r -> r.access) 1762 + |> Jsont.Object.opt_mem "lastInitiatedAt" Jsont.string ~enc:(fun r -> r.last_initiated_at) 1763 + |> Jsont.Object.mem "status" status_jsont ~enc:(fun r -> r.status) 1764 |> Jsont.Object.finish 1765 1766 + type config_region_rule_if_declared_under_age = { 1767 + access : access; 1768 + age : int; 1769 } 1770 1771 + let config_region_rule_if_declared_under_age_jsont = 1772 + Jsont.Object.map ~kind:"Config_region_rule_if_declared_under_age" 1773 + (fun _typ access age -> { access; age }) 1774 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.defs#configRegionRuleIfDeclaredUnderAge" ~enc:(fun _ -> "app.bsky.ageassurance.defs#configRegionRuleIfDeclaredUnderAge") 1775 + |> Jsont.Object.mem "access" access_jsont ~enc:(fun r -> r.access) 1776 + |> Jsont.Object.mem "age" Jsont.int ~enc:(fun r -> r.age) 1777 |> Jsont.Object.finish 1778 1779 + type config_region_rule_if_declared_over_age = { 1780 + access : access; 1781 + age : int; 1782 } 1783 1784 + let config_region_rule_if_declared_over_age_jsont = 1785 + Jsont.Object.map ~kind:"Config_region_rule_if_declared_over_age" 1786 + (fun _typ access age -> { access; age }) 1787 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.defs#configRegionRuleIfDeclaredOverAge" ~enc:(fun _ -> "app.bsky.ageassurance.defs#configRegionRuleIfDeclaredOverAge") 1788 + |> Jsont.Object.mem "access" access_jsont ~enc:(fun r -> r.access) 1789 + |> Jsont.Object.mem "age" Jsont.int ~enc:(fun r -> r.age) 1790 |> Jsont.Object.finish 1791 1792 + type config_region_rule_if_assured_under_age = { 1793 + access : access; 1794 + age : int; 1795 } 1796 1797 + let config_region_rule_if_assured_under_age_jsont = 1798 + Jsont.Object.map ~kind:"Config_region_rule_if_assured_under_age" 1799 + (fun _typ access age -> { access; age }) 1800 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.defs#configRegionRuleIfAssuredUnderAge" ~enc:(fun _ -> "app.bsky.ageassurance.defs#configRegionRuleIfAssuredUnderAge") 1801 + |> Jsont.Object.mem "access" access_jsont ~enc:(fun r -> r.access) 1802 + |> Jsont.Object.mem "age" Jsont.int ~enc:(fun r -> r.age) 1803 |> Jsont.Object.finish 1804 1805 + type config_region_rule_if_assured_over_age = { 1806 + access : access; 1807 + age : int; 1808 } 1809 1810 + let config_region_rule_if_assured_over_age_jsont = 1811 + Jsont.Object.map ~kind:"Config_region_rule_if_assured_over_age" 1812 + (fun _typ access age -> { access; age }) 1813 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.defs#configRegionRuleIfAssuredOverAge" ~enc:(fun _ -> "app.bsky.ageassurance.defs#configRegionRuleIfAssuredOverAge") 1814 + |> Jsont.Object.mem "access" access_jsont ~enc:(fun r -> r.access) 1815 + |> Jsont.Object.mem "age" Jsont.int ~enc:(fun r -> r.age) 1816 |> Jsont.Object.finish 1817 1818 + type config_region_rule_if_account_older_than = { 1819 + access : access; 1820 + date : string; 1821 } 1822 1823 + let config_region_rule_if_account_older_than_jsont = 1824 + Jsont.Object.map ~kind:"Config_region_rule_if_account_older_than" 1825 + (fun _typ access date -> { access; date }) 1826 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.defs#configRegionRuleIfAccountOlderThan" ~enc:(fun _ -> "app.bsky.ageassurance.defs#configRegionRuleIfAccountOlderThan") 1827 + |> Jsont.Object.mem "access" access_jsont ~enc:(fun r -> r.access) 1828 + |> Jsont.Object.mem "date" Jsont.string ~enc:(fun r -> r.date) 1829 |> Jsont.Object.finish 1830 1831 + type config_region_rule_if_account_newer_than = { 1832 + access : access; 1833 + date : string; 1834 } 1835 1836 + let config_region_rule_if_account_newer_than_jsont = 1837 + Jsont.Object.map ~kind:"Config_region_rule_if_account_newer_than" 1838 + (fun _typ access date -> { access; date }) 1839 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.defs#configRegionRuleIfAccountNewerThan" ~enc:(fun _ -> "app.bsky.ageassurance.defs#configRegionRuleIfAccountNewerThan") 1840 + |> Jsont.Object.mem "access" access_jsont ~enc:(fun r -> r.access) 1841 + |> Jsont.Object.mem "date" Jsont.string ~enc:(fun r -> r.date) 1842 |> Jsont.Object.finish 1843 1844 + type config_region_rule_default = { 1845 + access : access; 1846 } 1847 1848 + let config_region_rule_default_jsont = 1849 + Jsont.Object.map ~kind:"Config_region_rule_default" 1850 + (fun _typ access -> { access }) 1851 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.defs#configRegionRuleDefault" ~enc:(fun _ -> "app.bsky.ageassurance.defs#configRegionRuleDefault") 1852 + |> Jsont.Object.mem "access" access_jsont ~enc:(fun r -> r.access) 1853 |> Jsont.Object.finish 1854 1855 + type config = { 1856 + regions : config_region list; 1857 } 1858 1859 + let config_jsont = 1860 + Jsont.Object.map ~kind:"Config" 1861 + (fun _typ regions -> { regions }) 1862 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.defs#config" ~enc:(fun _ -> "app.bsky.ageassurance.defs#config") 1863 + |> Jsont.Object.mem "regions" (Jsont.list config_region_jsont) ~enc:(fun r -> r.regions) 1864 |> Jsont.Object.finish 1865 1866 end 1867 + module GetState = struct 1868 type params = { 1869 + country_code : string; 1870 + region_code : string option; 1871 } 1872 1873 let params_jsont = 1874 Jsont.Object.map ~kind:"Params" 1875 + (fun country_code region_code -> { 1876 + country_code; 1877 + region_code; 1878 }) 1879 + |> Jsont.Object.mem "countryCode" Jsont.string 1880 + ~enc:(fun r -> r.country_code) 1881 + |> Jsont.Object.opt_mem "regionCode" Jsont.string 1882 + ~enc:(fun r -> r.region_code) 1883 |> Jsont.Object.finish 1884 1885 type output = { 1886 + metadata : Defs.state_metadata; 1887 + state : Defs.state; 1888 } 1889 1890 let output_jsont = 1891 Jsont.Object.map ~kind:"Output" 1892 + (fun _typ metadata state -> { metadata; state }) 1893 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.getState#output" ~enc:(fun _ -> "app.bsky.ageassurance.getState#output") 1894 + |> Jsont.Object.mem "metadata" Defs.state_metadata_jsont ~enc:(fun r -> r.metadata) 1895 + |> Jsont.Object.mem "state" Defs.state_jsont ~enc:(fun r -> r.state) 1896 |> Jsont.Object.finish 1897 1898 end 1899 + module Begin = struct 1900 type input = { 1901 + country_code : string; 1902 + email : string; 1903 + language : string; 1904 + region_code : string option; 1905 } 1906 1907 let input_jsont = 1908 Jsont.Object.map ~kind:"Input" 1909 + (fun _typ country_code email language region_code -> { country_code; email; language; region_code }) 1910 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.ageassurance.begin#input" ~enc:(fun _ -> "app.bsky.ageassurance.begin#input") 1911 + |> Jsont.Object.mem "countryCode" Jsont.string ~enc:(fun r -> r.country_code) 1912 + |> Jsont.Object.mem "email" Jsont.string ~enc:(fun r -> r.email) 1913 + |> Jsont.Object.mem "language" Jsont.string ~enc:(fun r -> r.language) 1914 + |> Jsont.Object.opt_mem "regionCode" Jsont.string ~enc:(fun r -> r.region_code) 1915 |> Jsont.Object.finish 1916 1917 + type output = Defs.state 1918 + 1919 + let output_jsont = Defs.state_jsont 1920 + 1921 end 1922 + module GetConfig = struct 1923 + type output = Defs.config 1924 + 1925 + let output_jsont = Defs.config_jsont 1926 + 1927 + end 1928 + end 1929 + module Embed = struct 1930 + module Defs = struct 1931 + type aspect_ratio = { 1932 + height : int; 1933 + width : int; 1934 } 1935 1936 + let aspect_ratio_jsont = 1937 + Jsont.Object.map ~kind:"Aspect_ratio" 1938 + (fun _typ height width -> { height; width }) 1939 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.defs#aspectRatio" ~enc:(fun _ -> "app.bsky.embed.defs#aspectRatio") 1940 + |> Jsont.Object.mem "height" Jsont.int ~enc:(fun r -> r.height) 1941 + |> Jsont.Object.mem "width" Jsont.int ~enc:(fun r -> r.width) 1942 |> Jsont.Object.finish 1943 1944 end 1945 + module External = struct 1946 + type view_external = { 1947 + description : string; 1948 + thumb : string option; 1949 + title : string; 1950 + uri : string; 1951 } 1952 1953 + let view_external_jsont = 1954 + Jsont.Object.map ~kind:"View_external" 1955 + (fun _typ description thumb title uri -> { description; thumb; title; uri }) 1956 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.external#viewExternal" ~enc:(fun _ -> "app.bsky.embed.external#viewExternal") 1957 + |> Jsont.Object.mem "description" Jsont.string ~enc:(fun r -> r.description) 1958 + |> Jsont.Object.opt_mem "thumb" Jsont.string ~enc:(fun r -> r.thumb) 1959 + |> Jsont.Object.mem "title" Jsont.string ~enc:(fun r -> r.title) 1960 + |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 1961 |> Jsont.Object.finish 1962 1963 + type external_ = { 1964 + description : string; 1965 + thumb : Atp.Blob_ref.t option; 1966 + title : string; 1967 + uri : string; 1968 } 1969 1970 + let external__jsont = 1971 + Jsont.Object.map ~kind:"External_" 1972 + (fun _typ description thumb title uri -> { description; thumb; title; uri }) 1973 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.external#external" ~enc:(fun _ -> "app.bsky.embed.external#external") 1974 + |> Jsont.Object.mem "description" Jsont.string ~enc:(fun r -> r.description) 1975 + |> Jsont.Object.opt_mem "thumb" Atp.Blob_ref.jsont ~enc:(fun r -> r.thumb) 1976 + |> Jsont.Object.mem "title" Jsont.string ~enc:(fun r -> r.title) 1977 + |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 1978 |> Jsont.Object.finish 1979 1980 + type view = { 1981 + external_ : Jsont.json; 1982 } 1983 1984 + let view_jsont = 1985 + Jsont.Object.map ~kind:"View" 1986 + (fun _typ external_ -> { external_ }) 1987 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.external#view" ~enc:(fun _ -> "app.bsky.embed.external#view") 1988 + |> Jsont.Object.mem "external" Jsont.json ~enc:(fun r -> r.external_) 1989 + |> Jsont.Object.finish 1990 + 1991 + type main = { 1992 + external_ : Jsont.json; 1993 + } 1994 + 1995 + let main_jsont = 1996 + Jsont.Object.map ~kind:"Main" 1997 + (fun _typ external_ -> { external_ }) 1998 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.external" ~enc:(fun _ -> "app.bsky.embed.external") 1999 + |> Jsont.Object.mem "external" Jsont.json ~enc:(fun r -> r.external_) 2000 |> Jsont.Object.finish 2001 2002 end 2003 + module Images = struct 2004 + type view_image = { 2005 + alt : string; 2006 + aspect_ratio : Jsont.json option; 2007 + fullsize : string; 2008 + thumb : string; 2009 } 2010 2011 + let view_image_jsont = 2012 + Jsont.Object.map ~kind:"View_image" 2013 + (fun _typ alt aspect_ratio fullsize thumb -> { alt; aspect_ratio; fullsize; thumb }) 2014 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.images#viewImage" ~enc:(fun _ -> "app.bsky.embed.images#viewImage") 2015 + |> Jsont.Object.mem "alt" Jsont.string ~enc:(fun r -> r.alt) 2016 + |> Jsont.Object.opt_mem "aspectRatio" Jsont.json ~enc:(fun r -> r.aspect_ratio) 2017 + |> Jsont.Object.mem "fullsize" Jsont.string ~enc:(fun r -> r.fullsize) 2018 + |> Jsont.Object.mem "thumb" Jsont.string ~enc:(fun r -> r.thumb) 2019 |> Jsont.Object.finish 2020 2021 + type image = { 2022 + alt : string; 2023 + aspect_ratio : Jsont.json option; 2024 + image : Atp.Blob_ref.t; 2025 } 2026 2027 + let image_jsont = 2028 + Jsont.Object.map ~kind:"Image" 2029 + (fun _typ alt aspect_ratio image -> { alt; aspect_ratio; image }) 2030 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.images#image" ~enc:(fun _ -> "app.bsky.embed.images#image") 2031 + |> Jsont.Object.mem "alt" Jsont.string ~enc:(fun r -> r.alt) 2032 + |> Jsont.Object.opt_mem "aspectRatio" Jsont.json ~enc:(fun r -> r.aspect_ratio) 2033 + |> Jsont.Object.mem "image" Atp.Blob_ref.jsont ~enc:(fun r -> r.image) 2034 |> Jsont.Object.finish 2035 2036 + type view = { 2037 + images : Jsont.json list; 2038 } 2039 2040 + let view_jsont = 2041 + Jsont.Object.map ~kind:"View" 2042 + (fun _typ images -> { images }) 2043 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.images#view" ~enc:(fun _ -> "app.bsky.embed.images#view") 2044 + |> Jsont.Object.mem "images" (Jsont.list Jsont.json) ~enc:(fun r -> r.images) 2045 |> Jsont.Object.finish 2046 2047 type main = { 2048 + images : Jsont.json list; 2049 } 2050 2051 let main_jsont = 2052 Jsont.Object.map ~kind:"Main" 2053 + (fun _typ images -> { images }) 2054 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.images" ~enc:(fun _ -> "app.bsky.embed.images") 2055 + |> Jsont.Object.mem "images" (Jsont.list Jsont.json) ~enc:(fun r -> r.images) 2056 |> Jsont.Object.finish 2057 2058 end 2059 + module Video = struct 2060 + type view = { 2061 + alt : string option; 2062 + aspect_ratio : Jsont.json option; 2063 cid : string; 2064 + playlist : string; 2065 + thumbnail : string option; 2066 } 2067 2068 + let view_jsont = 2069 + Jsont.Object.map ~kind:"View" 2070 + (fun _typ alt aspect_ratio cid playlist thumbnail -> { alt; aspect_ratio; cid; playlist; thumbnail }) 2071 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.video#view" ~enc:(fun _ -> "app.bsky.embed.video#view") 2072 + |> Jsont.Object.opt_mem "alt" Jsont.string ~enc:(fun r -> r.alt) 2073 + |> Jsont.Object.opt_mem "aspectRatio" Jsont.json ~enc:(fun r -> r.aspect_ratio) 2074 |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 2075 + |> Jsont.Object.mem "playlist" Jsont.string ~enc:(fun r -> r.playlist) 2076 + |> Jsont.Object.opt_mem "thumbnail" Jsont.string ~enc:(fun r -> r.thumbnail) 2077 |> Jsont.Object.finish 2078 2079 + type caption = { 2080 + file : Atp.Blob_ref.t; 2081 + lang : string; 2082 } 2083 2084 + let caption_jsont = 2085 + Jsont.Object.map ~kind:"Caption" 2086 + (fun _typ file lang -> { file; lang }) 2087 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.video#caption" ~enc:(fun _ -> "app.bsky.embed.video#caption") 2088 + |> Jsont.Object.mem "file" Atp.Blob_ref.jsont ~enc:(fun r -> r.file) 2089 + |> Jsont.Object.mem "lang" Jsont.string ~enc:(fun r -> r.lang) 2090 |> Jsont.Object.finish 2091 2092 + type main = { 2093 + alt : string option; 2094 + aspect_ratio : Jsont.json option; 2095 + captions : Jsont.json list option; 2096 + video : Atp.Blob_ref.t; 2097 } 2098 2099 + let main_jsont = 2100 + Jsont.Object.map ~kind:"Main" 2101 + (fun _typ alt aspect_ratio captions video -> { alt; aspect_ratio; captions; video }) 2102 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.video" ~enc:(fun _ -> "app.bsky.embed.video") 2103 + |> Jsont.Object.opt_mem "alt" Jsont.string ~enc:(fun r -> r.alt) 2104 + |> Jsont.Object.opt_mem "aspectRatio" Jsont.json ~enc:(fun r -> r.aspect_ratio) 2105 + |> Jsont.Object.opt_mem "captions" (Jsont.list Jsont.json) ~enc:(fun r -> r.captions) 2106 + |> Jsont.Object.mem "video" Atp.Blob_ref.jsont ~enc:(fun r -> r.video) 2107 |> Jsont.Object.finish 2108 2109 + end 2110 + module RecordWithMedia = struct 2111 + type view = { 2112 + media : Jsont.json; 2113 + record : Jsont.json; 2114 } 2115 2116 + let view_jsont = 2117 + Jsont.Object.map ~kind:"View" 2118 + (fun _typ media record -> { media; record }) 2119 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.recordWithMedia#view" ~enc:(fun _ -> "app.bsky.embed.recordWithMedia#view") 2120 + |> Jsont.Object.mem "media" Jsont.json ~enc:(fun r -> r.media) 2121 + |> Jsont.Object.mem "record" Jsont.json ~enc:(fun r -> r.record) 2122 |> Jsont.Object.finish 2123 2124 + type main = { 2125 + media : Jsont.json; 2126 + record : Jsont.json; 2127 } 2128 2129 + let main_jsont = 2130 + Jsont.Object.map ~kind:"Main" 2131 + (fun _typ media record -> { media; record }) 2132 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.recordWithMedia" ~enc:(fun _ -> "app.bsky.embed.recordWithMedia") 2133 + |> Jsont.Object.mem "media" Jsont.json ~enc:(fun r -> r.media) 2134 + |> Jsont.Object.mem "record" Jsont.json ~enc:(fun r -> r.record) 2135 |> Jsont.Object.finish 2136 2137 + end 2138 + module Record = struct 2139 + type view_record = { 2140 + author : Jsont.json; 2141 cid : string; 2142 + embeds : Jsont.json list option; 2143 + indexed_at : string; 2144 labels : Com.Atproto.Label.Defs.label list option; 2145 + like_count : int option; 2146 + quote_count : int option; 2147 + reply_count : int option; 2148 + repost_count : int option; 2149 uri : string; 2150 + value : Jsont.json; 2151 } 2152 2153 + let view_record_jsont = 2154 + Jsont.Object.map ~kind:"View_record" 2155 + (fun _typ author cid embeds indexed_at labels like_count quote_count reply_count repost_count uri value -> { author; cid; embeds; indexed_at; labels; like_count; quote_count; reply_count; repost_count; uri; value }) 2156 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.record#viewRecord" ~enc:(fun _ -> "app.bsky.embed.record#viewRecord") 2157 + |> Jsont.Object.mem "author" Jsont.json ~enc:(fun r -> r.author) 2158 |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 2159 + |> Jsont.Object.opt_mem "embeds" (Jsont.list Jsont.json) ~enc:(fun r -> r.embeds) 2160 + |> Jsont.Object.mem "indexedAt" Jsont.string ~enc:(fun r -> r.indexed_at) 2161 |> Jsont.Object.opt_mem "labels" (Jsont.list Com.Atproto.Label.Defs.label_jsont) ~enc:(fun r -> r.labels) 2162 + |> Jsont.Object.opt_mem "likeCount" Jsont.int ~enc:(fun r -> r.like_count) 2163 + |> Jsont.Object.opt_mem "quoteCount" Jsont.int ~enc:(fun r -> r.quote_count) 2164 + |> Jsont.Object.opt_mem "replyCount" Jsont.int ~enc:(fun r -> r.reply_count) 2165 + |> Jsont.Object.opt_mem "repostCount" Jsont.int ~enc:(fun r -> r.repost_count) 2166 |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 2167 + |> Jsont.Object.mem "value" Jsont.json ~enc:(fun r -> r.value) 2168 |> Jsont.Object.finish 2169 2170 + type view_not_found = { 2171 + not_found : bool; 2172 uri : string; 2173 } 2174 2175 + let view_not_found_jsont = 2176 + Jsont.Object.map ~kind:"View_not_found" 2177 + (fun _typ not_found uri -> { not_found; uri }) 2178 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.record#viewNotFound" ~enc:(fun _ -> "app.bsky.embed.record#viewNotFound") 2179 + |> Jsont.Object.mem "notFound" Jsont.bool ~enc:(fun r -> r.not_found) 2180 |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 2181 |> Jsont.Object.finish 2182 2183 + type view_detached = { 2184 + detached : bool; 2185 uri : string; 2186 } 2187 2188 + let view_detached_jsont = 2189 + Jsont.Object.map ~kind:"View_detached" 2190 + (fun _typ detached uri -> { detached; uri }) 2191 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.record#viewDetached" ~enc:(fun _ -> "app.bsky.embed.record#viewDetached") 2192 + |> Jsont.Object.mem "detached" Jsont.bool ~enc:(fun r -> r.detached) 2193 |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 2194 |> Jsont.Object.finish 2195 2196 + type view_blocked = { 2197 + author : Jsont.json; 2198 + blocked : bool; 2199 + uri : string; 2200 } 2201 2202 + let view_blocked_jsont = 2203 + Jsont.Object.map ~kind:"View_blocked" 2204 + (fun _typ author blocked uri -> { author; blocked; uri }) 2205 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.record#viewBlocked" ~enc:(fun _ -> "app.bsky.embed.record#viewBlocked") 2206 + |> Jsont.Object.mem "author" Jsont.json ~enc:(fun r -> r.author) 2207 + |> Jsont.Object.mem "blocked" Jsont.bool ~enc:(fun r -> r.blocked) 2208 + |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 2209 |> Jsont.Object.finish 2210 2211 + type view = { 2212 + record : Jsont.json; 2213 } 2214 2215 + let view_jsont = 2216 + Jsont.Object.map ~kind:"View" 2217 + (fun _typ record -> { record }) 2218 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.record#view" ~enc:(fun _ -> "app.bsky.embed.record#view") 2219 + |> Jsont.Object.mem "record" Jsont.json ~enc:(fun r -> r.record) 2220 |> Jsont.Object.finish 2221 2222 type main = { 2223 + record : Com.Atproto.Repo.StrongRef.main; 2224 } 2225 2226 let main_jsont = 2227 Jsont.Object.map ~kind:"Main" 2228 + (fun _typ record -> { record }) 2229 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.embed.record" ~enc:(fun _ -> "app.bsky.embed.record") 2230 + |> Jsont.Object.mem "record" Com.Atproto.Repo.StrongRef.main_jsont ~enc:(fun r -> r.record) 2231 |> Jsont.Object.finish 2232 2233 end 2234 + end 2235 + module Contact = struct 2236 + module SendNotification = struct 2237 + type input = { 2238 + from : string; 2239 + to_ : string; 2240 } 2241 2242 + let input_jsont = 2243 + Jsont.Object.map ~kind:"Input" 2244 + (fun _typ from to_ -> { from; to_ }) 2245 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.contact.sendNotification#input" ~enc:(fun _ -> "app.bsky.contact.sendNotification#input") 2246 + |> Jsont.Object.mem "from" Jsont.string ~enc:(fun r -> r.from) 2247 + |> Jsont.Object.mem "to" Jsont.string ~enc:(fun r -> r.to_) 2248 |> Jsont.Object.finish 2249 2250 + type output = unit 2251 2252 + let output_jsont = Jsont.ignore 2253 2254 end 2255 + module StartPhoneVerification = struct 2256 + type input = { 2257 + phone : string; 2258 } 2259 2260 + let input_jsont = 2261 + Jsont.Object.map ~kind:"Input" 2262 + (fun _typ phone -> { phone }) 2263 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.contact.startPhoneVerification#input" ~enc:(fun _ -> "app.bsky.contact.startPhoneVerification#input") 2264 + |> Jsont.Object.mem "phone" Jsont.string ~enc:(fun r -> r.phone) 2265 |> Jsont.Object.finish 2266 2267 + type output = unit 2268 2269 + let output_jsont = Jsont.ignore 2270 2271 end 2272 + module GetMatches = struct 2273 type params = { 2274 cursor : string option; 2275 limit : int option; 2276 } 2277 2278 let params_jsont = 2279 Jsont.Object.map ~kind:"Params" 2280 + (fun cursor limit -> { 2281 cursor; 2282 limit; 2283 }) 2284 |> Jsont.Object.opt_mem "cursor" Jsont.string 2285 ~enc:(fun r -> r.cursor) 2286 |> Jsont.Object.opt_mem "limit" Jsont.int ··· 2289 2290 type output = { 2291 cursor : string option; 2292 + matches : Jsont.json list; 2293 } 2294 2295 let output_jsont = 2296 Jsont.Object.map ~kind:"Output" 2297 + (fun _typ cursor matches -> { cursor; matches }) 2298 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.contact.getMatches#output" ~enc:(fun _ -> "app.bsky.contact.getMatches#output") 2299 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 2300 + |> Jsont.Object.mem "matches" (Jsont.list Jsont.json) ~enc:(fun r -> r.matches) 2301 |> Jsont.Object.finish 2302 2303 end 2304 + module VerifyPhone = struct 2305 + type input = { 2306 + code : string; 2307 + phone : string; 2308 } 2309 2310 + let input_jsont = 2311 + Jsont.Object.map ~kind:"Input" 2312 + (fun _typ code phone -> { code; phone }) 2313 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.contact.verifyPhone#input" ~enc:(fun _ -> "app.bsky.contact.verifyPhone#input") 2314 + |> Jsont.Object.mem "code" Jsont.string ~enc:(fun r -> r.code) 2315 + |> Jsont.Object.mem "phone" Jsont.string ~enc:(fun r -> r.phone) 2316 |> Jsont.Object.finish 2317 2318 type output = { 2319 + token : string; 2320 } 2321 2322 let output_jsont = 2323 Jsont.Object.map ~kind:"Output" 2324 + (fun _typ token -> { token }) 2325 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.contact.verifyPhone#output" ~enc:(fun _ -> "app.bsky.contact.verifyPhone#output") 2326 + |> Jsont.Object.mem "token" Jsont.string ~enc:(fun r -> r.token) 2327 |> Jsont.Object.finish 2328 2329 end 2330 + module RemoveData = struct 2331 + type input = unit 2332 2333 + let input_jsont = Jsont.ignore 2334 2335 + type output = unit 2336 2337 + let output_jsont = Jsont.ignore 2338 2339 + end 2340 + module Defs = struct 2341 + type sync_status = { 2342 + matches_count : int; 2343 + synced_at : string; 2344 } 2345 2346 + let sync_status_jsont = 2347 + Jsont.Object.map ~kind:"Sync_status" 2348 + (fun _typ matches_count synced_at -> { matches_count; synced_at }) 2349 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.contact.defs#syncStatus" ~enc:(fun _ -> "app.bsky.contact.defs#syncStatus") 2350 + |> Jsont.Object.mem "matchesCount" Jsont.int ~enc:(fun r -> r.matches_count) 2351 + |> Jsont.Object.mem "syncedAt" Jsont.string ~enc:(fun r -> r.synced_at) 2352 |> Jsont.Object.finish 2353 2354 + type notification = { 2355 + from : string; 2356 + to_ : string; 2357 } 2358 2359 + let notification_jsont = 2360 + Jsont.Object.map ~kind:"Notification" 2361 + (fun _typ from to_ -> { from; to_ }) 2362 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.contact.defs#notification" ~enc:(fun _ -> "app.bsky.contact.defs#notification") 2363 + |> Jsont.Object.mem "from" Jsont.string ~enc:(fun r -> r.from) 2364 + |> Jsont.Object.mem "to" Jsont.string ~enc:(fun r -> r.to_) 2365 |> Jsont.Object.finish 2366 2367 + type match_and_contact_index = { 2368 + contact_index : int; 2369 + match_ : Jsont.json; 2370 } 2371 2372 + let match_and_contact_index_jsont = 2373 + Jsont.Object.map ~kind:"Match_and_contact_index" 2374 + (fun _typ contact_index match_ -> { contact_index; match_ }) 2375 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.contact.defs#matchAndContactIndex" ~enc:(fun _ -> "app.bsky.contact.defs#matchAndContactIndex") 2376 + |> Jsont.Object.mem "contactIndex" Jsont.int ~enc:(fun r -> r.contact_index) 2377 + |> Jsont.Object.mem "match" Jsont.json ~enc:(fun r -> r.match_) 2378 |> Jsont.Object.finish 2379 2380 end 2381 + module DismissMatch = struct 2382 + type input = { 2383 + subject : string; 2384 } 2385 2386 + let input_jsont = 2387 + Jsont.Object.map ~kind:"Input" 2388 + (fun _typ subject -> { subject }) 2389 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.contact.dismissMatch#input" ~enc:(fun _ -> "app.bsky.contact.dismissMatch#input") 2390 + |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 2391 |> Jsont.Object.finish 2392 2393 + type output = unit 2394 2395 + let output_jsont = Jsont.ignore 2396 2397 end 2398 + module GetSyncStatus = struct 2399 + type params = unit 2400 2401 + let params_jsont = Jsont.ignore 2402 2403 type output = { 2404 + sync_status : Defs.sync_status option; 2405 } 2406 2407 let output_jsont = 2408 Jsont.Object.map ~kind:"Output" 2409 + (fun _typ sync_status -> { sync_status }) 2410 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.contact.getSyncStatus#output" ~enc:(fun _ -> "app.bsky.contact.getSyncStatus#output") 2411 + |> Jsont.Object.opt_mem "syncStatus" Defs.sync_status_jsont ~enc:(fun r -> r.sync_status) 2412 |> Jsont.Object.finish 2413 2414 end 2415 + module ImportContacts = struct 2416 + type input = { 2417 + contacts : string list; 2418 + token : string; 2419 } 2420 2421 + let input_jsont = 2422 + Jsont.Object.map ~kind:"Input" 2423 + (fun _typ contacts token -> { contacts; token }) 2424 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.contact.importContacts#input" ~enc:(fun _ -> "app.bsky.contact.importContacts#input") 2425 + |> Jsont.Object.mem "contacts" (Jsont.list Jsont.string) ~enc:(fun r -> r.contacts) 2426 + |> Jsont.Object.mem "token" Jsont.string ~enc:(fun r -> r.token) 2427 |> Jsont.Object.finish 2428 2429 type output = { 2430 + matches_and_contact_indexes : Defs.match_and_contact_index list; 2431 } 2432 2433 let output_jsont = 2434 Jsont.Object.map ~kind:"Output" 2435 + (fun _typ matches_and_contact_indexes -> { matches_and_contact_indexes }) 2436 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.contact.importContacts#output" ~enc:(fun _ -> "app.bsky.contact.importContacts#output") 2437 + |> Jsont.Object.mem "matchesAndContactIndexes" (Jsont.list Defs.match_and_contact_index_jsont) ~enc:(fun r -> r.matches_and_contact_indexes) 2438 |> Jsont.Object.finish 2439 2440 end 2441 + end 2442 + module Feed = struct 2443 + module Repost = struct 2444 + type main = { 2445 + created_at : string; 2446 + subject : Com.Atproto.Repo.StrongRef.main; 2447 + via : Com.Atproto.Repo.StrongRef.main option; 2448 } 2449 2450 + let main_jsont = 2451 + Jsont.Object.map ~kind:"Main" 2452 + (fun _typ created_at subject via -> { created_at; subject; via }) 2453 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.repost" ~enc:(fun _ -> "app.bsky.feed.repost") 2454 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 2455 + |> Jsont.Object.mem "subject" Com.Atproto.Repo.StrongRef.main_jsont ~enc:(fun r -> r.subject) 2456 + |> Jsont.Object.opt_mem "via" Com.Atproto.Repo.StrongRef.main_jsont ~enc:(fun r -> r.via) 2457 |> Jsont.Object.finish 2458 2459 + end 2460 + module DescribeFeedGenerator = struct 2461 + type links = { 2462 + privacy_policy : string option; 2463 + terms_of_service : string option; 2464 } 2465 2466 + let links_jsont = 2467 + Jsont.Object.map ~kind:"Links" 2468 + (fun _typ privacy_policy terms_of_service -> { privacy_policy; terms_of_service }) 2469 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.describeFeedGenerator#links" ~enc:(fun _ -> "app.bsky.feed.describeFeedGenerator#links") 2470 + |> Jsont.Object.opt_mem "privacyPolicy" Jsont.string ~enc:(fun r -> r.privacy_policy) 2471 + |> Jsont.Object.opt_mem "termsOfService" Jsont.string ~enc:(fun r -> r.terms_of_service) 2472 |> Jsont.Object.finish 2473 2474 + type feed = { 2475 + uri : string; 2476 } 2477 2478 + let feed_jsont = 2479 + Jsont.Object.map ~kind:"Feed" 2480 + (fun _typ uri -> { uri }) 2481 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.describeFeedGenerator#feed" ~enc:(fun _ -> "app.bsky.feed.describeFeedGenerator#feed") 2482 + |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 2483 |> Jsont.Object.finish 2484 2485 type output = { 2486 + did : string; 2487 + feeds : Jsont.json list; 2488 + links : Jsont.json option; 2489 } 2490 2491 let output_jsont = 2492 Jsont.Object.map ~kind:"Output" 2493 + (fun _typ did feeds links -> { did; feeds; links }) 2494 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.describeFeedGenerator#output" ~enc:(fun _ -> "app.bsky.feed.describeFeedGenerator#output") 2495 + |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 2496 + |> Jsont.Object.mem "feeds" (Jsont.list Jsont.json) ~enc:(fun r -> r.feeds) 2497 + |> Jsont.Object.opt_mem "links" Jsont.json ~enc:(fun r -> r.links) 2498 |> Jsont.Object.finish 2499 2500 end 2501 + module Threadgate = struct 2502 + type mention_rule = unit 2503 2504 + let mention_rule_jsont = Jsont.ignore 2505 2506 + type list_rule = { 2507 + list_ : string; 2508 } 2509 2510 + let list_rule_jsont = 2511 + Jsont.Object.map ~kind:"List_rule" 2512 + (fun _typ list_ -> { list_ }) 2513 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.threadgate#listRule" ~enc:(fun _ -> "app.bsky.feed.threadgate#listRule") 2514 + |> Jsont.Object.mem "list" Jsont.string ~enc:(fun r -> r.list_) 2515 |> Jsont.Object.finish 2516 2517 + type following_rule = unit 2518 2519 + let following_rule_jsont = Jsont.ignore 2520 2521 + type follower_rule = unit 2522 2523 + let follower_rule_jsont = Jsont.ignore 2524 2525 + type main = { 2526 + allow : Jsont.json list option; 2527 + created_at : string; 2528 + hidden_replies : string list option; 2529 + post : string; 2530 } 2531 2532 + let main_jsont = 2533 + Jsont.Object.map ~kind:"Main" 2534 + (fun _typ allow created_at hidden_replies post -> { allow; created_at; hidden_replies; post }) 2535 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.threadgate" ~enc:(fun _ -> "app.bsky.feed.threadgate") 2536 + |> Jsont.Object.opt_mem "allow" (Jsont.list Jsont.json) ~enc:(fun r -> r.allow) 2537 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 2538 + |> Jsont.Object.opt_mem "hiddenReplies" (Jsont.list Jsont.string) ~enc:(fun r -> r.hidden_replies) 2539 + |> Jsont.Object.mem "post" Jsont.string ~enc:(fun r -> r.post) 2540 |> Jsont.Object.finish 2541 2542 + end 2543 + module Like = struct 2544 type main = { 2545 created_at : string; 2546 + subject : Com.Atproto.Repo.StrongRef.main; 2547 + via : Com.Atproto.Repo.StrongRef.main option; 2548 } 2549 2550 let main_jsont = 2551 Jsont.Object.map ~kind:"Main" 2552 + (fun _typ created_at subject via -> { created_at; subject; via }) 2553 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.like" ~enc:(fun _ -> "app.bsky.feed.like") 2554 |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 2555 + |> Jsont.Object.mem "subject" Com.Atproto.Repo.StrongRef.main_jsont ~enc:(fun r -> r.subject) 2556 + |> Jsont.Object.opt_mem "via" Com.Atproto.Repo.StrongRef.main_jsont ~enc:(fun r -> r.via) 2557 |> Jsont.Object.finish 2558 2559 end ··· 2616 |> Jsont.Object.finish 2617 2618 end 2619 module GetRepostedBy = struct 2620 type params = { 2621 cid : string option; ··· 2660 |> Jsont.Object.finish 2661 2662 end 2663 + module Generator = struct 2664 + type main = { 2665 + accepts_interactions : bool option; 2666 + avatar : Atp.Blob_ref.t option; 2667 + content_mode : string option; 2668 + created_at : string; 2669 + description : string option; 2670 + description_facets : Richtext.Facet.main list option; 2671 did : string; 2672 + display_name : string; 2673 + labels : Com.Atproto.Label.Defs.self_labels option; 2674 } 2675 2676 + let main_jsont = 2677 + Jsont.Object.map ~kind:"Main" 2678 + (fun _typ accepts_interactions avatar content_mode created_at description description_facets did display_name labels -> { accepts_interactions; avatar; content_mode; created_at; description; description_facets; did; display_name; labels }) 2679 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.generator" ~enc:(fun _ -> "app.bsky.feed.generator") 2680 + |> Jsont.Object.opt_mem "acceptsInteractions" Jsont.bool ~enc:(fun r -> r.accepts_interactions) 2681 + |> Jsont.Object.opt_mem "avatar" Atp.Blob_ref.jsont ~enc:(fun r -> r.avatar) 2682 + |> Jsont.Object.opt_mem "contentMode" Jsont.string ~enc:(fun r -> r.content_mode) 2683 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 2684 + |> Jsont.Object.opt_mem "description" Jsont.string ~enc:(fun r -> r.description) 2685 + |> Jsont.Object.opt_mem "descriptionFacets" (Jsont.list Richtext.Facet.main_jsont) ~enc:(fun r -> r.description_facets) 2686 |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 2687 + |> Jsont.Object.mem "displayName" Jsont.string ~enc:(fun r -> r.display_name) 2688 + |> Jsont.Object.opt_mem "labels" Com.Atproto.Label.Defs.self_labels_jsont ~enc:(fun r -> r.labels) 2689 |> Jsont.Object.finish 2690 2691 end 2692 + module Postgate = struct 2693 + type disable_rule = unit 2694 2695 + let disable_rule_jsont = Jsont.ignore 2696 2697 type main = { 2698 created_at : string; 2699 + detached_embedding_uris : string list option; 2700 + embedding_rules : Jsont.json list option; 2701 post : string; 2702 } 2703 2704 let main_jsont = 2705 Jsont.Object.map ~kind:"Main" 2706 + (fun _typ created_at detached_embedding_uris embedding_rules post -> { created_at; detached_embedding_uris; embedding_rules; post }) 2707 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.postgate" ~enc:(fun _ -> "app.bsky.feed.postgate") 2708 |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 2709 + |> Jsont.Object.opt_mem "detachedEmbeddingUris" (Jsont.list Jsont.string) ~enc:(fun r -> r.detached_embedding_uris) 2710 + |> Jsont.Object.opt_mem "embeddingRules" (Jsont.list Jsont.json) ~enc:(fun r -> r.embedding_rules) 2711 |> Jsont.Object.mem "post" Jsont.string ~enc:(fun r -> r.post) 2712 |> Jsont.Object.finish 2713 2714 end ··· 3054 |> Jsont.Object.finish 3055 3056 end 3057 + module Post = struct 3058 + type text_slice = { 3059 + end_ : int; 3060 + start : int; 3061 } 3062 3063 + let text_slice_jsont = 3064 + Jsont.Object.map ~kind:"Text_slice" 3065 + (fun _typ end_ start -> { end_; start }) 3066 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.post#textSlice" ~enc:(fun _ -> "app.bsky.feed.post#textSlice") 3067 + |> Jsont.Object.mem "end" Jsont.int ~enc:(fun r -> r.end_) 3068 + |> Jsont.Object.mem "start" Jsont.int ~enc:(fun r -> r.start) 3069 |> Jsont.Object.finish 3070 3071 + type reply_ref = { 3072 + parent : Com.Atproto.Repo.StrongRef.main; 3073 + root : Com.Atproto.Repo.StrongRef.main; 3074 + } 3075 + 3076 + let reply_ref_jsont = 3077 + Jsont.Object.map ~kind:"Reply_ref" 3078 + (fun _typ parent root -> { parent; root }) 3079 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.post#replyRef" ~enc:(fun _ -> "app.bsky.feed.post#replyRef") 3080 + |> Jsont.Object.mem "parent" Com.Atproto.Repo.StrongRef.main_jsont ~enc:(fun r -> r.parent) 3081 + |> Jsont.Object.mem "root" Com.Atproto.Repo.StrongRef.main_jsont ~enc:(fun r -> r.root) 3082 + |> Jsont.Object.finish 3083 + 3084 + type entity = { 3085 + index : Jsont.json; 3086 + type_ : string; 3087 + value : string; 3088 + } 3089 + 3090 + let entity_jsont = 3091 + Jsont.Object.map ~kind:"Entity" 3092 + (fun _typ index type_ value -> { index; type_; value }) 3093 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.post#entity" ~enc:(fun _ -> "app.bsky.feed.post#entity") 3094 + |> Jsont.Object.mem "index" Jsont.json ~enc:(fun r -> r.index) 3095 + |> Jsont.Object.mem "type" Jsont.string ~enc:(fun r -> r.type_) 3096 + |> Jsont.Object.mem "value" Jsont.string ~enc:(fun r -> r.value) 3097 + |> Jsont.Object.finish 3098 + 3099 type main = { 3100 created_at : string; 3101 + embed : Jsont.json option; 3102 + entities : Jsont.json list option; 3103 + facets : Richtext.Facet.main list option; 3104 labels : Com.Atproto.Label.Defs.self_labels option; 3105 + langs : string list option; 3106 + reply : Jsont.json option; 3107 + tags : string list option; 3108 + text : string; 3109 } 3110 3111 let main_jsont = 3112 Jsont.Object.map ~kind:"Main" 3113 + (fun _typ created_at embed entities facets labels langs reply tags text -> { created_at; embed; entities; facets; labels; langs; reply; tags; text }) 3114 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.post" ~enc:(fun _ -> "app.bsky.feed.post") 3115 |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 3116 + |> Jsont.Object.opt_mem "embed" Jsont.json ~enc:(fun r -> r.embed) 3117 + |> Jsont.Object.opt_mem "entities" (Jsont.list Jsont.json) ~enc:(fun r -> r.entities) 3118 + |> Jsont.Object.opt_mem "facets" (Jsont.list Richtext.Facet.main_jsont) ~enc:(fun r -> r.facets) 3119 |> Jsont.Object.opt_mem "labels" Com.Atproto.Label.Defs.self_labels_jsont ~enc:(fun r -> r.labels) 3120 + |> Jsont.Object.opt_mem "langs" (Jsont.list Jsont.string) ~enc:(fun r -> r.langs) 3121 + |> Jsont.Object.opt_mem "reply" Jsont.json ~enc:(fun r -> r.reply) 3122 + |> Jsont.Object.opt_mem "tags" (Jsont.list Jsont.string) ~enc:(fun r -> r.tags) 3123 + |> Jsont.Object.mem "text" Jsont.string ~enc:(fun r -> r.text) 3124 |> Jsont.Object.finish 3125 3126 end 3127 + module GetPosts = struct 3128 + type params = { 3129 + uris : string list; 3130 + } 3131 + 3132 + let params_jsont = 3133 + Jsont.Object.map ~kind:"Params" 3134 + (fun uris -> { 3135 + uris; 3136 + }) 3137 + |> Jsont.Object.mem "uris" (Jsont.list Jsont.string) 3138 + ~enc:(fun r -> r.uris) 3139 + |> Jsont.Object.finish 3140 + 3141 + type output = { 3142 + posts : Jsont.json list; 3143 + } 3144 + 3145 + let output_jsont = 3146 + Jsont.Object.map ~kind:"Output" 3147 + (fun _typ posts -> { posts }) 3148 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.getPosts#output" ~enc:(fun _ -> "app.bsky.feed.getPosts#output") 3149 + |> Jsont.Object.mem "posts" (Jsont.list Jsont.json) ~enc:(fun r -> r.posts) 3150 + |> Jsont.Object.finish 3151 + 3152 + end 3153 + module GetQuotes = struct 3154 type params = { 3155 + cid : string option; 3156 + cursor : string option; 3157 + limit : int option; 3158 uri : string; 3159 } 3160 3161 let params_jsont = 3162 Jsont.Object.map ~kind:"Params" 3163 + (fun cid cursor limit uri -> { 3164 + cid; 3165 + cursor; 3166 + limit; 3167 uri; 3168 }) 3169 + |> Jsont.Object.opt_mem "cid" Jsont.string 3170 + ~enc:(fun r -> r.cid) 3171 + |> Jsont.Object.opt_mem "cursor" Jsont.string 3172 + ~enc:(fun r -> r.cursor) 3173 + |> Jsont.Object.opt_mem "limit" Jsont.int 3174 + ~enc:(fun r -> r.limit) 3175 |> Jsont.Object.mem "uri" Jsont.string 3176 ~enc:(fun r -> r.uri) 3177 |> Jsont.Object.finish 3178 3179 type output = { 3180 + cid : string option; 3181 + cursor : string option; 3182 + posts : Jsont.json list; 3183 + uri : string; 3184 } 3185 3186 let output_jsont = 3187 Jsont.Object.map ~kind:"Output" 3188 + (fun _typ cid cursor posts uri -> { cid; cursor; posts; uri }) 3189 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.getQuotes#output" ~enc:(fun _ -> "app.bsky.feed.getQuotes#output") 3190 + |> Jsont.Object.opt_mem "cid" Jsont.string ~enc:(fun r -> r.cid) 3191 + |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 3192 + |> Jsont.Object.mem "posts" (Jsont.list Jsont.json) ~enc:(fun r -> r.posts) 3193 + |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 3194 |> Jsont.Object.finish 3195 3196 end 3197 + module GetAuthorFeed = struct 3198 type params = { 3199 + actor : string; 3200 cursor : string option; 3201 + filter : string option; 3202 + include_pins : bool option; 3203 limit : int option; 3204 } 3205 3206 let params_jsont = 3207 Jsont.Object.map ~kind:"Params" 3208 + (fun actor cursor filter include_pins limit -> { 3209 + actor; 3210 cursor; 3211 + filter; 3212 + include_pins; 3213 limit; 3214 }) 3215 + |> Jsont.Object.mem "actor" Jsont.string 3216 + ~enc:(fun r -> r.actor) 3217 |> Jsont.Object.opt_mem "cursor" Jsont.string 3218 ~enc:(fun r -> r.cursor) 3219 + |> Jsont.Object.opt_mem "filter" Jsont.string 3220 + ~enc:(fun r -> r.filter) 3221 + |> Jsont.Object.opt_mem "includePins" Jsont.bool 3222 + ~enc:(fun r -> r.include_pins) 3223 |> Jsont.Object.opt_mem "limit" Jsont.int 3224 ~enc:(fun r -> r.limit) 3225 |> Jsont.Object.finish ··· 3232 let output_jsont = 3233 Jsont.Object.map ~kind:"Output" 3234 (fun _typ cursor feed -> { cursor; feed }) 3235 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.getAuthorFeed#output" ~enc:(fun _ -> "app.bsky.feed.getAuthorFeed#output") 3236 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 3237 |> Jsont.Object.mem "feed" (Jsont.list Jsont.json) ~enc:(fun r -> r.feed) 3238 |> Jsont.Object.finish 3239 3240 end 3241 + module GetTimeline = struct 3242 type params = { 3243 + algorithm : string option; 3244 cursor : string option; 3245 limit : int option; 3246 } 3247 3248 let params_jsont = 3249 Jsont.Object.map ~kind:"Params" 3250 + (fun algorithm cursor limit -> { 3251 + algorithm; 3252 cursor; 3253 limit; 3254 }) 3255 + |> Jsont.Object.opt_mem "algorithm" Jsont.string 3256 + ~enc:(fun r -> r.algorithm) 3257 |> Jsont.Object.opt_mem "cursor" Jsont.string 3258 ~enc:(fun r -> r.cursor) 3259 |> Jsont.Object.opt_mem "limit" Jsont.int 3260 ~enc:(fun r -> r.limit) 3261 |> Jsont.Object.finish 3262 3263 type output = { 3264 cursor : string option; 3265 + feed : Jsont.json list; 3266 } 3267 3268 let output_jsont = 3269 Jsont.Object.map ~kind:"Output" 3270 + (fun _typ cursor feed -> { cursor; feed }) 3271 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.getTimeline#output" ~enc:(fun _ -> "app.bsky.feed.getTimeline#output") 3272 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 3273 + |> Jsont.Object.mem "feed" (Jsont.list Jsont.json) ~enc:(fun r -> r.feed) 3274 |> Jsont.Object.finish 3275 3276 end ··· 3310 |> Jsont.Object.finish 3311 3312 end 3313 + module GetSuggestedFeeds = struct 3314 + type params = { 3315 + cursor : string option; 3316 + limit : int option; 3317 + } 3318 + 3319 + let params_jsont = 3320 + Jsont.Object.map ~kind:"Params" 3321 + (fun cursor limit -> { 3322 + cursor; 3323 + limit; 3324 + }) 3325 + |> Jsont.Object.opt_mem "cursor" Jsont.string 3326 + ~enc:(fun r -> r.cursor) 3327 + |> Jsont.Object.opt_mem "limit" Jsont.int 3328 + ~enc:(fun r -> r.limit) 3329 + |> Jsont.Object.finish 3330 + 3331 + type output = { 3332 + cursor : string option; 3333 + feeds : Jsont.json list; 3334 + } 3335 + 3336 + let output_jsont = 3337 + Jsont.Object.map ~kind:"Output" 3338 + (fun _typ cursor feeds -> { cursor; feeds }) 3339 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.getSuggestedFeeds#output" ~enc:(fun _ -> "app.bsky.feed.getSuggestedFeeds#output") 3340 + |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 3341 + |> Jsont.Object.mem "feeds" (Jsont.list Jsont.json) ~enc:(fun r -> r.feeds) 3342 + |> Jsont.Object.finish 3343 + 3344 + end 3345 module GetActorLikes = struct 3346 type params = { 3347 actor : string; ··· 3378 |> Jsont.Object.finish 3379 3380 end 3381 + module GetActorFeeds = struct 3382 type params = { 3383 + actor : string; 3384 cursor : string option; 3385 limit : int option; 3386 } 3387 3388 let params_jsont = 3389 Jsont.Object.map ~kind:"Params" 3390 + (fun actor cursor limit -> { 3391 + actor; 3392 cursor; 3393 limit; 3394 }) 3395 + |> Jsont.Object.mem "actor" Jsont.string 3396 + ~enc:(fun r -> r.actor) 3397 |> Jsont.Object.opt_mem "cursor" Jsont.string 3398 ~enc:(fun r -> r.cursor) 3399 |> Jsont.Object.opt_mem "limit" Jsont.int 3400 ~enc:(fun r -> r.limit) 3401 |> Jsont.Object.finish 3402 3403 type output = { 3404 cursor : string option; 3405 + feeds : Jsont.json list; 3406 } 3407 3408 let output_jsont = 3409 Jsont.Object.map ~kind:"Output" 3410 + (fun _typ cursor feeds -> { cursor; feeds }) 3411 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.getActorFeeds#output" ~enc:(fun _ -> "app.bsky.feed.getActorFeeds#output") 3412 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 3413 + |> Jsont.Object.mem "feeds" (Jsont.list Jsont.json) ~enc:(fun r -> r.feeds) 3414 |> Jsont.Object.finish 3415 3416 end ··· 3488 |> Jsont.Object.finish 3489 3490 end 3491 + module GetPostThread = struct 3492 + type params = { 3493 + depth : int option; 3494 + parent_height : int option; 3495 + uri : string; 3496 + } 3497 + 3498 + let params_jsont = 3499 + Jsont.Object.map ~kind:"Params" 3500 + (fun depth parent_height uri -> { 3501 + depth; 3502 + parent_height; 3503 + uri; 3504 + }) 3505 + |> Jsont.Object.opt_mem "depth" Jsont.int 3506 + ~enc:(fun r -> r.depth) 3507 + |> Jsont.Object.opt_mem "parentHeight" Jsont.int 3508 + ~enc:(fun r -> r.parent_height) 3509 + |> Jsont.Object.mem "uri" Jsont.string 3510 + ~enc:(fun r -> r.uri) 3511 + |> Jsont.Object.finish 3512 + 3513 + type output = { 3514 + thread : Jsont.json; 3515 + threadgate : Jsont.json option; 3516 + } 3517 + 3518 + let output_jsont = 3519 + Jsont.Object.map ~kind:"Output" 3520 + (fun _typ thread threadgate -> { thread; threadgate }) 3521 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.getPostThread#output" ~enc:(fun _ -> "app.bsky.feed.getPostThread#output") 3522 + |> Jsont.Object.mem "thread" Jsont.json ~enc:(fun r -> r.thread) 3523 + |> Jsont.Object.opt_mem "threadgate" Jsont.json ~enc:(fun r -> r.threadgate) 3524 + |> Jsont.Object.finish 3525 + 3526 + end 3527 + module GetFeedSkeleton = struct 3528 + type params = { 3529 + cursor : string option; 3530 + feed : string; 3531 + limit : int option; 3532 + } 3533 + 3534 + let params_jsont = 3535 + Jsont.Object.map ~kind:"Params" 3536 + (fun cursor feed limit -> { 3537 + cursor; 3538 + feed; 3539 + limit; 3540 + }) 3541 + |> Jsont.Object.opt_mem "cursor" Jsont.string 3542 + ~enc:(fun r -> r.cursor) 3543 + |> Jsont.Object.mem "feed" Jsont.string 3544 + ~enc:(fun r -> r.feed) 3545 + |> Jsont.Object.opt_mem "limit" Jsont.int 3546 + ~enc:(fun r -> r.limit) 3547 + |> Jsont.Object.finish 3548 + 3549 + type output = { 3550 + cursor : string option; 3551 + feed : Jsont.json list; 3552 + req_id : string option; 3553 + } 3554 + 3555 + let output_jsont = 3556 + Jsont.Object.map ~kind:"Output" 3557 + (fun _typ cursor feed req_id -> { cursor; feed; req_id }) 3558 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.getFeedSkeleton#output" ~enc:(fun _ -> "app.bsky.feed.getFeedSkeleton#output") 3559 + |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 3560 + |> Jsont.Object.mem "feed" (Jsont.list Jsont.json) ~enc:(fun r -> r.feed) 3561 + |> Jsont.Object.opt_mem "reqId" Jsont.string ~enc:(fun r -> r.req_id) 3562 + |> Jsont.Object.finish 3563 + 3564 + end 3565 + module GetFeed = struct 3566 + type params = { 3567 + cursor : string option; 3568 + feed : string; 3569 + limit : int option; 3570 + } 3571 + 3572 + let params_jsont = 3573 + Jsont.Object.map ~kind:"Params" 3574 + (fun cursor feed limit -> { 3575 + cursor; 3576 + feed; 3577 + limit; 3578 + }) 3579 + |> Jsont.Object.opt_mem "cursor" Jsont.string 3580 + ~enc:(fun r -> r.cursor) 3581 + |> Jsont.Object.mem "feed" Jsont.string 3582 + ~enc:(fun r -> r.feed) 3583 + |> Jsont.Object.opt_mem "limit" Jsont.int 3584 + ~enc:(fun r -> r.limit) 3585 + |> Jsont.Object.finish 3586 + 3587 + type output = { 3588 + cursor : string option; 3589 + feed : Jsont.json list; 3590 + } 3591 + 3592 + let output_jsont = 3593 + Jsont.Object.map ~kind:"Output" 3594 + (fun _typ cursor feed -> { cursor; feed }) 3595 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.getFeed#output" ~enc:(fun _ -> "app.bsky.feed.getFeed#output") 3596 + |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 3597 + |> Jsont.Object.mem "feed" (Jsont.list Jsont.json) ~enc:(fun r -> r.feed) 3598 + |> Jsont.Object.finish 3599 + 3600 + end 3601 module GetFeedGenerators = struct 3602 type params = { 3603 feeds : string list; ··· 3641 let output_jsont = Jsont.ignore 3642 3643 end 3644 + module GetFeedGenerator = struct 3645 + type params = { 3646 + feed : string; 3647 + } 3648 + 3649 + let params_jsont = 3650 + Jsont.Object.map ~kind:"Params" 3651 + (fun feed -> { 3652 + feed; 3653 + }) 3654 + |> Jsont.Object.mem "feed" Jsont.string 3655 + ~enc:(fun r -> r.feed) 3656 + |> Jsont.Object.finish 3657 + 3658 + type output = { 3659 + is_online : bool; 3660 + is_valid : bool; 3661 + view : Jsont.json; 3662 + } 3663 + 3664 + let output_jsont = 3665 + Jsont.Object.map ~kind:"Output" 3666 + (fun _typ is_online is_valid view -> { is_online; is_valid; view }) 3667 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.getFeedGenerator#output" ~enc:(fun _ -> "app.bsky.feed.getFeedGenerator#output") 3668 + |> Jsont.Object.mem "isOnline" Jsont.bool ~enc:(fun r -> r.is_online) 3669 + |> Jsont.Object.mem "isValid" Jsont.bool ~enc:(fun r -> r.is_valid) 3670 + |> Jsont.Object.mem "view" Jsont.json ~enc:(fun r -> r.view) 3671 + |> Jsont.Object.finish 3672 + 3673 + end 3674 + end 3675 + module Graph = struct 3676 + module Defs = struct 3677 + type starter_pack_view_basic = { 3678 + cid : string; 3679 + creator : Jsont.json; 3680 + indexed_at : string; 3681 + joined_all_time_count : int option; 3682 + joined_week_count : int option; 3683 + labels : Com.Atproto.Label.Defs.label list option; 3684 + list_item_count : int option; 3685 + record : Jsont.json; 3686 + uri : string; 3687 + } 3688 + 3689 + let starter_pack_view_basic_jsont = 3690 + Jsont.Object.map ~kind:"Starter_pack_view_basic" 3691 + (fun _typ cid creator indexed_at joined_all_time_count joined_week_count labels list_item_count record uri -> { cid; creator; indexed_at; joined_all_time_count; joined_week_count; labels; list_item_count; record; uri }) 3692 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.defs#starterPackViewBasic" ~enc:(fun _ -> "app.bsky.graph.defs#starterPackViewBasic") 3693 + |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 3694 + |> Jsont.Object.mem "creator" Jsont.json ~enc:(fun r -> r.creator) 3695 + |> Jsont.Object.mem "indexedAt" Jsont.string ~enc:(fun r -> r.indexed_at) 3696 + |> Jsont.Object.opt_mem "joinedAllTimeCount" Jsont.int ~enc:(fun r -> r.joined_all_time_count) 3697 + |> Jsont.Object.opt_mem "joinedWeekCount" Jsont.int ~enc:(fun r -> r.joined_week_count) 3698 + |> Jsont.Object.opt_mem "labels" (Jsont.list Com.Atproto.Label.Defs.label_jsont) ~enc:(fun r -> r.labels) 3699 + |> Jsont.Object.opt_mem "listItemCount" Jsont.int ~enc:(fun r -> r.list_item_count) 3700 + |> Jsont.Object.mem "record" Jsont.json ~enc:(fun r -> r.record) 3701 + |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 3702 + |> Jsont.Object.finish 3703 + 3704 + type relationship = { 3705 + blocked_by : string option; 3706 + blocked_by_list : string option; 3707 + blocking : string option; 3708 + blocking_by_list : string option; 3709 + did : string; 3710 + followed_by : string option; 3711 + following : string option; 3712 + } 3713 + 3714 + let relationship_jsont = 3715 + Jsont.Object.map ~kind:"Relationship" 3716 + (fun _typ blocked_by blocked_by_list blocking blocking_by_list did followed_by following -> { blocked_by; blocked_by_list; blocking; blocking_by_list; did; followed_by; following }) 3717 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.defs#relationship" ~enc:(fun _ -> "app.bsky.graph.defs#relationship") 3718 + |> Jsont.Object.opt_mem "blockedBy" Jsont.string ~enc:(fun r -> r.blocked_by) 3719 + |> Jsont.Object.opt_mem "blockedByList" Jsont.string ~enc:(fun r -> r.blocked_by_list) 3720 + |> Jsont.Object.opt_mem "blocking" Jsont.string ~enc:(fun r -> r.blocking) 3721 + |> Jsont.Object.opt_mem "blockingByList" Jsont.string ~enc:(fun r -> r.blocking_by_list) 3722 + |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 3723 + |> Jsont.Object.opt_mem "followedBy" Jsont.string ~enc:(fun r -> r.followed_by) 3724 + |> Jsont.Object.opt_mem "following" Jsont.string ~enc:(fun r -> r.following) 3725 + |> Jsont.Object.finish 3726 + 3727 + type referencelist = string 3728 + let referencelist_jsont = Jsont.string 3729 + 3730 + type not_found_actor = { 3731 + actor : string; 3732 + not_found : bool; 3733 + } 3734 + 3735 + let not_found_actor_jsont = 3736 + Jsont.Object.map ~kind:"Not_found_actor" 3737 + (fun _typ actor not_found -> { actor; not_found }) 3738 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.defs#notFoundActor" ~enc:(fun _ -> "app.bsky.graph.defs#notFoundActor") 3739 + |> Jsont.Object.mem "actor" Jsont.string ~enc:(fun r -> r.actor) 3740 + |> Jsont.Object.mem "notFound" Jsont.bool ~enc:(fun r -> r.not_found) 3741 + |> Jsont.Object.finish 3742 + 3743 + type modlist = string 3744 + let modlist_jsont = Jsont.string 3745 + 3746 + type list_viewer_state = { 3747 + blocked : string option; 3748 + muted : bool option; 3749 + } 3750 + 3751 + let list_viewer_state_jsont = 3752 + Jsont.Object.map ~kind:"List_viewer_state" 3753 + (fun _typ blocked muted -> { blocked; muted }) 3754 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.defs#listViewerState" ~enc:(fun _ -> "app.bsky.graph.defs#listViewerState") 3755 + |> Jsont.Object.opt_mem "blocked" Jsont.string ~enc:(fun r -> r.blocked) 3756 + |> Jsont.Object.opt_mem "muted" Jsont.bool ~enc:(fun r -> r.muted) 3757 + |> Jsont.Object.finish 3758 + 3759 + type list_purpose = string 3760 + let list_purpose_jsont = Jsont.string 3761 + 3762 + type list_item_view = { 3763 + subject : Jsont.json; 3764 + uri : string; 3765 + } 3766 + 3767 + let list_item_view_jsont = 3768 + Jsont.Object.map ~kind:"List_item_view" 3769 + (fun _typ subject uri -> { subject; uri }) 3770 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.defs#listItemView" ~enc:(fun _ -> "app.bsky.graph.defs#listItemView") 3771 + |> Jsont.Object.mem "subject" Jsont.json ~enc:(fun r -> r.subject) 3772 + |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 3773 + |> Jsont.Object.finish 3774 + 3775 + type curatelist = string 3776 + let curatelist_jsont = Jsont.string 3777 + 3778 + type list_view_basic = { 3779 + avatar : string option; 3780 + cid : string; 3781 + indexed_at : string option; 3782 + labels : Com.Atproto.Label.Defs.label list option; 3783 + list_item_count : int option; 3784 + name : string; 3785 + purpose : Jsont.json; 3786 + uri : string; 3787 + viewer : Jsont.json option; 3788 + } 3789 + 3790 + let list_view_basic_jsont = 3791 + Jsont.Object.map ~kind:"List_view_basic" 3792 + (fun _typ avatar cid indexed_at labels list_item_count name purpose uri viewer -> { avatar; cid; indexed_at; labels; list_item_count; name; purpose; uri; viewer }) 3793 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.defs#listViewBasic" ~enc:(fun _ -> "app.bsky.graph.defs#listViewBasic") 3794 + |> Jsont.Object.opt_mem "avatar" Jsont.string ~enc:(fun r -> r.avatar) 3795 + |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 3796 + |> Jsont.Object.opt_mem "indexedAt" Jsont.string ~enc:(fun r -> r.indexed_at) 3797 + |> Jsont.Object.opt_mem "labels" (Jsont.list Com.Atproto.Label.Defs.label_jsont) ~enc:(fun r -> r.labels) 3798 + |> Jsont.Object.opt_mem "listItemCount" Jsont.int ~enc:(fun r -> r.list_item_count) 3799 + |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 3800 + |> Jsont.Object.mem "purpose" Jsont.json ~enc:(fun r -> r.purpose) 3801 + |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 3802 + |> Jsont.Object.opt_mem "viewer" Jsont.json ~enc:(fun r -> r.viewer) 3803 + |> Jsont.Object.finish 3804 + 3805 + type list_view = { 3806 + avatar : string option; 3807 + cid : string; 3808 + creator : Jsont.json; 3809 + description : string option; 3810 + description_facets : Richtext.Facet.main list option; 3811 + indexed_at : string; 3812 + labels : Com.Atproto.Label.Defs.label list option; 3813 + list_item_count : int option; 3814 + name : string; 3815 + purpose : Jsont.json; 3816 + uri : string; 3817 + viewer : Jsont.json option; 3818 + } 3819 + 3820 + let list_view_jsont = 3821 + Jsont.Object.map ~kind:"List_view" 3822 + (fun _typ avatar cid creator description description_facets indexed_at labels list_item_count name purpose uri viewer -> { avatar; cid; creator; description; description_facets; indexed_at; labels; list_item_count; name; purpose; uri; viewer }) 3823 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.defs#listView" ~enc:(fun _ -> "app.bsky.graph.defs#listView") 3824 + |> Jsont.Object.opt_mem "avatar" Jsont.string ~enc:(fun r -> r.avatar) 3825 + |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 3826 + |> Jsont.Object.mem "creator" Jsont.json ~enc:(fun r -> r.creator) 3827 + |> Jsont.Object.opt_mem "description" Jsont.string ~enc:(fun r -> r.description) 3828 + |> Jsont.Object.opt_mem "descriptionFacets" (Jsont.list Richtext.Facet.main_jsont) ~enc:(fun r -> r.description_facets) 3829 + |> Jsont.Object.mem "indexedAt" Jsont.string ~enc:(fun r -> r.indexed_at) 3830 + |> Jsont.Object.opt_mem "labels" (Jsont.list Com.Atproto.Label.Defs.label_jsont) ~enc:(fun r -> r.labels) 3831 + |> Jsont.Object.opt_mem "listItemCount" Jsont.int ~enc:(fun r -> r.list_item_count) 3832 + |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 3833 + |> Jsont.Object.mem "purpose" Jsont.json ~enc:(fun r -> r.purpose) 3834 + |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 3835 + |> Jsont.Object.opt_mem "viewer" Jsont.json ~enc:(fun r -> r.viewer) 3836 + |> Jsont.Object.finish 3837 + 3838 + type starter_pack_view = { 3839 + cid : string; 3840 + creator : Jsont.json; 3841 + feeds : Jsont.json list option; 3842 + indexed_at : string; 3843 + joined_all_time_count : int option; 3844 + joined_week_count : int option; 3845 + labels : Com.Atproto.Label.Defs.label list option; 3846 + list_ : Jsont.json option; 3847 + list_items_sample : Jsont.json list option; 3848 + record : Jsont.json; 3849 + uri : string; 3850 + } 3851 + 3852 + let starter_pack_view_jsont = 3853 + Jsont.Object.map ~kind:"Starter_pack_view" 3854 + (fun _typ cid creator feeds indexed_at joined_all_time_count joined_week_count labels list_ list_items_sample record uri -> { cid; creator; feeds; indexed_at; joined_all_time_count; joined_week_count; labels; list_; list_items_sample; record; uri }) 3855 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.defs#starterPackView" ~enc:(fun _ -> "app.bsky.graph.defs#starterPackView") 3856 + |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 3857 + |> Jsont.Object.mem "creator" Jsont.json ~enc:(fun r -> r.creator) 3858 + |> Jsont.Object.opt_mem "feeds" (Jsont.list Jsont.json) ~enc:(fun r -> r.feeds) 3859 + |> Jsont.Object.mem "indexedAt" Jsont.string ~enc:(fun r -> r.indexed_at) 3860 + |> Jsont.Object.opt_mem "joinedAllTimeCount" Jsont.int ~enc:(fun r -> r.joined_all_time_count) 3861 + |> Jsont.Object.opt_mem "joinedWeekCount" Jsont.int ~enc:(fun r -> r.joined_week_count) 3862 + |> Jsont.Object.opt_mem "labels" (Jsont.list Com.Atproto.Label.Defs.label_jsont) ~enc:(fun r -> r.labels) 3863 + |> Jsont.Object.opt_mem "list" Jsont.json ~enc:(fun r -> r.list_) 3864 + |> Jsont.Object.opt_mem "listItemsSample" (Jsont.list Jsont.json) ~enc:(fun r -> r.list_items_sample) 3865 + |> Jsont.Object.mem "record" Jsont.json ~enc:(fun r -> r.record) 3866 + |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 3867 + |> Jsont.Object.finish 3868 + 3869 + end 3870 + module UnmuteActor = struct 3871 + type input = { 3872 + actor : string; 3873 + } 3874 + 3875 + let input_jsont = 3876 + Jsont.Object.map ~kind:"Input" 3877 + (fun _typ actor -> { actor }) 3878 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.unmuteActor#input" ~enc:(fun _ -> "app.bsky.graph.unmuteActor#input") 3879 + |> Jsont.Object.mem "actor" Jsont.string ~enc:(fun r -> r.actor) 3880 + |> Jsont.Object.finish 3881 + 3882 + end 3883 + module Listitem = struct 3884 + type main = { 3885 + created_at : string; 3886 + list_ : string; 3887 + subject : string; 3888 + } 3889 + 3890 + let main_jsont = 3891 + Jsont.Object.map ~kind:"Main" 3892 + (fun _typ created_at list_ subject -> { created_at; list_; subject }) 3893 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.listitem" ~enc:(fun _ -> "app.bsky.graph.listitem") 3894 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 3895 + |> Jsont.Object.mem "list" Jsont.string ~enc:(fun r -> r.list_) 3896 + |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 3897 + |> Jsont.Object.finish 3898 + 3899 + end 3900 + module GetSuggestedFollowsByActor = struct 3901 + type params = { 3902 + actor : string; 3903 + } 3904 + 3905 + let params_jsont = 3906 + Jsont.Object.map ~kind:"Params" 3907 + (fun actor -> { 3908 + actor; 3909 + }) 3910 + |> Jsont.Object.mem "actor" Jsont.string 3911 + ~enc:(fun r -> r.actor) 3912 + |> Jsont.Object.finish 3913 + 3914 + type output = { 3915 + is_fallback : bool option; 3916 + rec_id : int option; 3917 + suggestions : Jsont.json list; 3918 + } 3919 + 3920 + let output_jsont = 3921 + Jsont.Object.map ~kind:"Output" 3922 + (fun _typ is_fallback rec_id suggestions -> { is_fallback; rec_id; suggestions }) 3923 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getSuggestedFollowsByActor#output" ~enc:(fun _ -> "app.bsky.graph.getSuggestedFollowsByActor#output") 3924 + |> Jsont.Object.opt_mem "isFallback" Jsont.bool ~enc:(fun r -> r.is_fallback) 3925 + |> Jsont.Object.opt_mem "recId" Jsont.int ~enc:(fun r -> r.rec_id) 3926 + |> Jsont.Object.mem "suggestions" (Jsont.list Jsont.json) ~enc:(fun r -> r.suggestions) 3927 + |> Jsont.Object.finish 3928 + 3929 + end 3930 + module MuteActorList = struct 3931 + type input = { 3932 + list_ : string; 3933 + } 3934 + 3935 + let input_jsont = 3936 + Jsont.Object.map ~kind:"Input" 3937 + (fun _typ list_ -> { list_ }) 3938 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.muteActorList#input" ~enc:(fun _ -> "app.bsky.graph.muteActorList#input") 3939 + |> Jsont.Object.mem "list" Jsont.string ~enc:(fun r -> r.list_) 3940 + |> Jsont.Object.finish 3941 + 3942 + end 3943 + module GetFollowers = struct 3944 type params = { 3945 actor : string; 3946 cursor : string option; 3947 limit : int option; 3948 } 3949 3950 let params_jsont = 3951 Jsont.Object.map ~kind:"Params" 3952 + (fun actor cursor limit -> { 3953 actor; 3954 cursor; 3955 limit; 3956 }) 3957 |> Jsont.Object.mem "actor" Jsont.string 3958 ~enc:(fun r -> r.actor) 3959 |> Jsont.Object.opt_mem "cursor" Jsont.string 3960 ~enc:(fun r -> r.cursor) 3961 + |> Jsont.Object.opt_mem "limit" Jsont.int 3962 + ~enc:(fun r -> r.limit) 3963 + |> Jsont.Object.finish 3964 + 3965 + type output = { 3966 + cursor : string option; 3967 + followers : Jsont.json list; 3968 + subject : Jsont.json; 3969 + } 3970 + 3971 + let output_jsont = 3972 + Jsont.Object.map ~kind:"Output" 3973 + (fun _typ cursor followers subject -> { cursor; followers; subject }) 3974 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getFollowers#output" ~enc:(fun _ -> "app.bsky.graph.getFollowers#output") 3975 + |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 3976 + |> Jsont.Object.mem "followers" (Jsont.list Jsont.json) ~enc:(fun r -> r.followers) 3977 + |> Jsont.Object.mem "subject" Jsont.json ~enc:(fun r -> r.subject) 3978 + |> Jsont.Object.finish 3979 + 3980 + end 3981 + module MuteActor = struct 3982 + type input = { 3983 + actor : string; 3984 + } 3985 + 3986 + let input_jsont = 3987 + Jsont.Object.map ~kind:"Input" 3988 + (fun _typ actor -> { actor }) 3989 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.muteActor#input" ~enc:(fun _ -> "app.bsky.graph.muteActor#input") 3990 + |> Jsont.Object.mem "actor" Jsont.string ~enc:(fun r -> r.actor) 3991 + |> Jsont.Object.finish 3992 + 3993 + end 3994 + module UnmuteActorList = struct 3995 + type input = { 3996 + list_ : string; 3997 + } 3998 + 3999 + let input_jsont = 4000 + Jsont.Object.map ~kind:"Input" 4001 + (fun _typ list_ -> { list_ }) 4002 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.unmuteActorList#input" ~enc:(fun _ -> "app.bsky.graph.unmuteActorList#input") 4003 + |> Jsont.Object.mem "list" Jsont.string ~enc:(fun r -> r.list_) 4004 + |> Jsont.Object.finish 4005 + 4006 + end 4007 + module GetBlocks = struct 4008 + type params = { 4009 + cursor : string option; 4010 + limit : int option; 4011 + } 4012 + 4013 + let params_jsont = 4014 + Jsont.Object.map ~kind:"Params" 4015 + (fun cursor limit -> { 4016 + cursor; 4017 + limit; 4018 + }) 4019 + |> Jsont.Object.opt_mem "cursor" Jsont.string 4020 + ~enc:(fun r -> r.cursor) 4021 |> Jsont.Object.opt_mem "limit" Jsont.int 4022 ~enc:(fun r -> r.limit) 4023 |> Jsont.Object.finish 4024 4025 type output = { 4026 + blocks : Jsont.json list; 4027 cursor : string option; 4028 } 4029 4030 let output_jsont = 4031 Jsont.Object.map ~kind:"Output" 4032 + (fun _typ blocks cursor -> { blocks; cursor }) 4033 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getBlocks#output" ~enc:(fun _ -> "app.bsky.graph.getBlocks#output") 4034 + |> Jsont.Object.mem "blocks" (Jsont.list Jsont.json) ~enc:(fun r -> r.blocks) 4035 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 4036 + |> Jsont.Object.finish 4037 + 4038 + end 4039 + module Listblock = struct 4040 + type main = { 4041 + created_at : string; 4042 + subject : string; 4043 + } 4044 + 4045 + let main_jsont = 4046 + Jsont.Object.map ~kind:"Main" 4047 + (fun _typ created_at subject -> { created_at; subject }) 4048 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.listblock" ~enc:(fun _ -> "app.bsky.graph.listblock") 4049 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 4050 + |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 4051 + |> Jsont.Object.finish 4052 + 4053 + end 4054 + module MuteThread = struct 4055 + type input = { 4056 + root : string; 4057 + } 4058 + 4059 + let input_jsont = 4060 + Jsont.Object.map ~kind:"Input" 4061 + (fun _typ root -> { root }) 4062 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.muteThread#input" ~enc:(fun _ -> "app.bsky.graph.muteThread#input") 4063 + |> Jsont.Object.mem "root" Jsont.string ~enc:(fun r -> r.root) 4064 + |> Jsont.Object.finish 4065 + 4066 + end 4067 + module Follow = struct 4068 + type main = { 4069 + created_at : string; 4070 + subject : string; 4071 + via : Com.Atproto.Repo.StrongRef.main option; 4072 + } 4073 + 4074 + let main_jsont = 4075 + Jsont.Object.map ~kind:"Main" 4076 + (fun _typ created_at subject via -> { created_at; subject; via }) 4077 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.follow" ~enc:(fun _ -> "app.bsky.graph.follow") 4078 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 4079 + |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 4080 + |> Jsont.Object.opt_mem "via" Com.Atproto.Repo.StrongRef.main_jsont ~enc:(fun r -> r.via) 4081 |> Jsont.Object.finish 4082 4083 end 4084 + module Starterpack = struct 4085 + type feed_item = { 4086 + uri : string; 4087 + } 4088 + 4089 + let feed_item_jsont = 4090 + Jsont.Object.map ~kind:"Feed_item" 4091 + (fun _typ uri -> { uri }) 4092 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.starterpack#feedItem" ~enc:(fun _ -> "app.bsky.graph.starterpack#feedItem") 4093 + |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 4094 + |> Jsont.Object.finish 4095 + 4096 + type main = { 4097 + created_at : string; 4098 + description : string option; 4099 + description_facets : Richtext.Facet.main list option; 4100 + feeds : Jsont.json list option; 4101 + list_ : string; 4102 + name : string; 4103 + } 4104 + 4105 + let main_jsont = 4106 + Jsont.Object.map ~kind:"Main" 4107 + (fun _typ created_at description description_facets feeds list_ name -> { created_at; description; description_facets; feeds; list_; name }) 4108 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.starterpack" ~enc:(fun _ -> "app.bsky.graph.starterpack") 4109 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 4110 + |> Jsont.Object.opt_mem "description" Jsont.string ~enc:(fun r -> r.description) 4111 + |> Jsont.Object.opt_mem "descriptionFacets" (Jsont.list Richtext.Facet.main_jsont) ~enc:(fun r -> r.description_facets) 4112 + |> Jsont.Object.opt_mem "feeds" (Jsont.list Jsont.json) ~enc:(fun r -> r.feeds) 4113 + |> Jsont.Object.mem "list" Jsont.string ~enc:(fun r -> r.list_) 4114 + |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 4115 + |> Jsont.Object.finish 4116 + 4117 + end 4118 + module GetFollows = struct 4119 type params = { 4120 + actor : string; 4121 + cursor : string option; 4122 + limit : int option; 4123 } 4124 4125 let params_jsont = 4126 Jsont.Object.map ~kind:"Params" 4127 + (fun actor cursor limit -> { 4128 + actor; 4129 + cursor; 4130 + limit; 4131 }) 4132 + |> Jsont.Object.mem "actor" Jsont.string 4133 + ~enc:(fun r -> r.actor) 4134 + |> Jsont.Object.opt_mem "cursor" Jsont.string 4135 + ~enc:(fun r -> r.cursor) 4136 + |> Jsont.Object.opt_mem "limit" Jsont.int 4137 + ~enc:(fun r -> r.limit) 4138 |> Jsont.Object.finish 4139 4140 type output = { 4141 + cursor : string option; 4142 + follows : Jsont.json list; 4143 + subject : Jsont.json; 4144 } 4145 4146 let output_jsont = 4147 Jsont.Object.map ~kind:"Output" 4148 + (fun _typ cursor follows subject -> { cursor; follows; subject }) 4149 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getFollows#output" ~enc:(fun _ -> "app.bsky.graph.getFollows#output") 4150 + |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 4151 + |> Jsont.Object.mem "follows" (Jsont.list Jsont.json) ~enc:(fun r -> r.follows) 4152 + |> Jsont.Object.mem "subject" Jsont.json ~enc:(fun r -> r.subject) 4153 |> Jsont.Object.finish 4154 4155 end 4156 + module Verification = struct 4157 + type main = { 4158 + created_at : string; 4159 + display_name : string; 4160 + handle : string; 4161 + subject : string; 4162 + } 4163 + 4164 + let main_jsont = 4165 + Jsont.Object.map ~kind:"Main" 4166 + (fun _typ created_at display_name handle subject -> { created_at; display_name; handle; subject }) 4167 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.verification" ~enc:(fun _ -> "app.bsky.graph.verification") 4168 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 4169 + |> Jsont.Object.mem "displayName" Jsont.string ~enc:(fun r -> r.display_name) 4170 + |> Jsont.Object.mem "handle" Jsont.string ~enc:(fun r -> r.handle) 4171 + |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 4172 + |> Jsont.Object.finish 4173 + 4174 + end 4175 + module UnmuteThread = struct 4176 + type input = { 4177 + root : string; 4178 + } 4179 + 4180 + let input_jsont = 4181 + Jsont.Object.map ~kind:"Input" 4182 + (fun _typ root -> { root }) 4183 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.unmuteThread#input" ~enc:(fun _ -> "app.bsky.graph.unmuteThread#input") 4184 + |> Jsont.Object.mem "root" Jsont.string ~enc:(fun r -> r.root) 4185 + |> Jsont.Object.finish 4186 + 4187 + end 4188 + module GetMutes = struct 4189 type params = { 4190 cursor : string option; 4191 limit : int option; ··· 4205 4206 type output = { 4207 cursor : string option; 4208 + mutes : Jsont.json list; 4209 } 4210 4211 let output_jsont = 4212 Jsont.Object.map ~kind:"Output" 4213 + (fun _typ cursor mutes -> { cursor; mutes }) 4214 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getMutes#output" ~enc:(fun _ -> "app.bsky.graph.getMutes#output") 4215 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 4216 + |> Jsont.Object.mem "mutes" (Jsont.list Jsont.json) ~enc:(fun r -> r.mutes) 4217 |> Jsont.Object.finish 4218 4219 end 4220 + module GetKnownFollowers = struct 4221 type params = { 4222 actor : string; 4223 cursor : string option; ··· 4241 4242 type output = { 4243 cursor : string option; 4244 + followers : Jsont.json list; 4245 + subject : Jsont.json; 4246 } 4247 4248 let output_jsont = 4249 Jsont.Object.map ~kind:"Output" 4250 + (fun _typ cursor followers subject -> { cursor; followers; subject }) 4251 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getKnownFollowers#output" ~enc:(fun _ -> "app.bsky.graph.getKnownFollowers#output") 4252 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 4253 + |> Jsont.Object.mem "followers" (Jsont.list Jsont.json) ~enc:(fun r -> r.followers) 4254 + |> Jsont.Object.mem "subject" Jsont.json ~enc:(fun r -> r.subject) 4255 |> Jsont.Object.finish 4256 4257 end 4258 + module Block = struct 4259 + type main = { 4260 + created_at : string; 4261 + subject : string; 4262 + } 4263 + 4264 + let main_jsont = 4265 + Jsont.Object.map ~kind:"Main" 4266 + (fun _typ created_at subject -> { created_at; subject }) 4267 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.block" ~enc:(fun _ -> "app.bsky.graph.block") 4268 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 4269 + |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 4270 + |> Jsont.Object.finish 4271 + 4272 + end 4273 + module GetRelationships = struct 4274 type params = { 4275 + actor : string; 4276 + others : string list option; 4277 } 4278 4279 let params_jsont = 4280 Jsont.Object.map ~kind:"Params" 4281 + (fun actor others -> { 4282 + actor; 4283 + others; 4284 }) 4285 + |> Jsont.Object.mem "actor" Jsont.string 4286 + ~enc:(fun r -> r.actor) 4287 + |> Jsont.Object.opt_mem "others" (Jsont.list Jsont.string) 4288 + ~enc:(fun r -> r.others) 4289 |> Jsont.Object.finish 4290 4291 type output = { 4292 + actor : string option; 4293 + relationships : Jsont.json list; 4294 } 4295 4296 let output_jsont = 4297 Jsont.Object.map ~kind:"Output" 4298 + (fun _typ actor relationships -> { actor; relationships }) 4299 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getRelationships#output" ~enc:(fun _ -> "app.bsky.graph.getRelationships#output") 4300 + |> Jsont.Object.opt_mem "actor" Jsont.string ~enc:(fun r -> r.actor) 4301 + |> Jsont.Object.mem "relationships" (Jsont.list Jsont.json) ~enc:(fun r -> r.relationships) 4302 |> Jsont.Object.finish 4303 4304 end 4305 + module GetListsWithMembership = struct 4306 + type list_with_membership = { 4307 + list_ : Jsont.json; 4308 + list_item : Jsont.json option; 4309 + } 4310 + 4311 + let list_with_membership_jsont = 4312 + Jsont.Object.map ~kind:"List_with_membership" 4313 + (fun _typ list_ list_item -> { list_; list_item }) 4314 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getListsWithMembership#listWithMembership" ~enc:(fun _ -> "app.bsky.graph.getListsWithMembership#listWithMembership") 4315 + |> Jsont.Object.mem "list" Jsont.json ~enc:(fun r -> r.list_) 4316 + |> Jsont.Object.opt_mem "listItem" Jsont.json ~enc:(fun r -> r.list_item) 4317 + |> Jsont.Object.finish 4318 + 4319 type params = { 4320 + actor : string; 4321 cursor : string option; 4322 limit : int option; 4323 + purposes : string list option; 4324 } 4325 4326 let params_jsont = 4327 Jsont.Object.map ~kind:"Params" 4328 + (fun actor cursor limit purposes -> { 4329 + actor; 4330 cursor; 4331 limit; 4332 + purposes; 4333 }) 4334 + |> Jsont.Object.mem "actor" Jsont.string 4335 + ~enc:(fun r -> r.actor) 4336 |> Jsont.Object.opt_mem "cursor" Jsont.string 4337 ~enc:(fun r -> r.cursor) 4338 |> Jsont.Object.opt_mem "limit" Jsont.int 4339 ~enc:(fun r -> r.limit) 4340 + |> Jsont.Object.opt_mem "purposes" (Jsont.list Jsont.string) 4341 + ~enc:(fun r -> r.purposes) 4342 |> Jsont.Object.finish 4343 4344 type output = { 4345 cursor : string option; 4346 + lists_with_membership : Jsont.json list; 4347 } 4348 4349 let output_jsont = 4350 Jsont.Object.map ~kind:"Output" 4351 + (fun _typ cursor lists_with_membership -> { cursor; lists_with_membership }) 4352 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getListsWithMembership#output" ~enc:(fun _ -> "app.bsky.graph.getListsWithMembership#output") 4353 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 4354 + |> Jsont.Object.mem "listsWithMembership" (Jsont.list Jsont.json) ~enc:(fun r -> r.lists_with_membership) 4355 |> Jsont.Object.finish 4356 4357 end 4358 + module GetListMutes = struct 4359 + type params = { 4360 + cursor : string option; 4361 + limit : int option; 4362 + } 4363 + 4364 + let params_jsont = 4365 + Jsont.Object.map ~kind:"Params" 4366 + (fun cursor limit -> { 4367 + cursor; 4368 + limit; 4369 + }) 4370 + |> Jsont.Object.opt_mem "cursor" Jsont.string 4371 + ~enc:(fun r -> r.cursor) 4372 + |> Jsont.Object.opt_mem "limit" Jsont.int 4373 + ~enc:(fun r -> r.limit) 4374 + |> Jsont.Object.finish 4375 + 4376 + type output = { 4377 + cursor : string option; 4378 + lists : Jsont.json list; 4379 } 4380 4381 + let output_jsont = 4382 + Jsont.Object.map ~kind:"Output" 4383 + (fun _typ cursor lists -> { cursor; lists }) 4384 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getListMutes#output" ~enc:(fun _ -> "app.bsky.graph.getListMutes#output") 4385 + |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 4386 + |> Jsont.Object.mem "lists" (Jsont.list Jsont.json) ~enc:(fun r -> r.lists) 4387 |> Jsont.Object.finish 4388 4389 end 4390 + module GetActorStarterPacks = struct 4391 + type params = { 4392 + actor : string; 4393 + cursor : string option; 4394 + limit : int option; 4395 } 4396 4397 + let params_jsont = 4398 + Jsont.Object.map ~kind:"Params" 4399 + (fun actor cursor limit -> { 4400 + actor; 4401 + cursor; 4402 + limit; 4403 + }) 4404 + |> Jsont.Object.mem "actor" Jsont.string 4405 + ~enc:(fun r -> r.actor) 4406 + |> Jsont.Object.opt_mem "cursor" Jsont.string 4407 + ~enc:(fun r -> r.cursor) 4408 + |> Jsont.Object.opt_mem "limit" Jsont.int 4409 + ~enc:(fun r -> r.limit) 4410 + |> Jsont.Object.finish 4411 + 4412 + type output = { 4413 + cursor : string option; 4414 + starter_packs : Jsont.json list; 4415 + } 4416 + 4417 + let output_jsont = 4418 + Jsont.Object.map ~kind:"Output" 4419 + (fun _typ cursor starter_packs -> { cursor; starter_packs }) 4420 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getActorStarterPacks#output" ~enc:(fun _ -> "app.bsky.graph.getActorStarterPacks#output") 4421 + |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 4422 + |> Jsont.Object.mem "starterPacks" (Jsont.list Jsont.json) ~enc:(fun r -> r.starter_packs) 4423 |> Jsont.Object.finish 4424 4425 end 4426 + module SearchStarterPacks = struct 4427 + type params = { 4428 + cursor : string option; 4429 + limit : int option; 4430 + q : string; 4431 } 4432 4433 + let params_jsont = 4434 + Jsont.Object.map ~kind:"Params" 4435 + (fun cursor limit q -> { 4436 + cursor; 4437 + limit; 4438 + q; 4439 + }) 4440 + |> Jsont.Object.opt_mem "cursor" Jsont.string 4441 + ~enc:(fun r -> r.cursor) 4442 + |> Jsont.Object.opt_mem "limit" Jsont.int 4443 + ~enc:(fun r -> r.limit) 4444 + |> Jsont.Object.mem "q" Jsont.string 4445 + ~enc:(fun r -> r.q) 4446 |> Jsont.Object.finish 4447 4448 + type output = { 4449 + cursor : string option; 4450 + starter_packs : Jsont.json list; 4451 } 4452 4453 + let output_jsont = 4454 + Jsont.Object.map ~kind:"Output" 4455 + (fun _typ cursor starter_packs -> { cursor; starter_packs }) 4456 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.searchStarterPacks#output" ~enc:(fun _ -> "app.bsky.graph.searchStarterPacks#output") 4457 + |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 4458 + |> Jsont.Object.mem "starterPacks" (Jsont.list Jsont.json) ~enc:(fun r -> r.starter_packs) 4459 |> Jsont.Object.finish 4460 4461 end 4462 + module GetStarterPacksWithMembership = struct 4463 + type starter_pack_with_membership = { 4464 + list_item : Jsont.json option; 4465 + starter_pack : Jsont.json; 4466 + } 4467 + 4468 + let starter_pack_with_membership_jsont = 4469 + Jsont.Object.map ~kind:"Starter_pack_with_membership" 4470 + (fun _typ list_item starter_pack -> { list_item; starter_pack }) 4471 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getStarterPacksWithMembership#starterPackWithMembership" ~enc:(fun _ -> "app.bsky.graph.getStarterPacksWithMembership#starterPackWithMembership") 4472 + |> Jsont.Object.opt_mem "listItem" Jsont.json ~enc:(fun r -> r.list_item) 4473 + |> Jsont.Object.mem "starterPack" Jsont.json ~enc:(fun r -> r.starter_pack) 4474 + |> Jsont.Object.finish 4475 + 4476 type params = { 4477 + actor : string; 4478 cursor : string option; 4479 limit : int option; 4480 } 4481 4482 let params_jsont = 4483 Jsont.Object.map ~kind:"Params" 4484 + (fun actor cursor limit -> { 4485 + actor; 4486 cursor; 4487 limit; 4488 }) 4489 + |> Jsont.Object.mem "actor" Jsont.string 4490 + ~enc:(fun r -> r.actor) 4491 |> Jsont.Object.opt_mem "cursor" Jsont.string 4492 ~enc:(fun r -> r.cursor) 4493 |> Jsont.Object.opt_mem "limit" Jsont.int ··· 4495 |> Jsont.Object.finish 4496 4497 type output = { 4498 cursor : string option; 4499 + starter_packs_with_membership : Jsont.json list; 4500 } 4501 4502 let output_jsont = 4503 Jsont.Object.map ~kind:"Output" 4504 + (fun _typ cursor starter_packs_with_membership -> { cursor; starter_packs_with_membership }) 4505 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getStarterPacksWithMembership#output" ~enc:(fun _ -> "app.bsky.graph.getStarterPacksWithMembership#output") 4506 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 4507 + |> Jsont.Object.mem "starterPacksWithMembership" (Jsont.list Jsont.json) ~enc:(fun r -> r.starter_packs_with_membership) 4508 |> Jsont.Object.finish 4509 4510 end 4511 + module GetLists = struct 4512 type params = { 4513 + actor : string; 4514 + cursor : string option; 4515 limit : int option; 4516 + purposes : string list option; 4517 } 4518 4519 let params_jsont = 4520 Jsont.Object.map ~kind:"Params" 4521 + (fun actor cursor limit purposes -> { 4522 + actor; 4523 + cursor; 4524 limit; 4525 + purposes; 4526 }) 4527 + |> Jsont.Object.mem "actor" Jsont.string 4528 + ~enc:(fun r -> r.actor) 4529 + |> Jsont.Object.opt_mem "cursor" Jsont.string 4530 + ~enc:(fun r -> r.cursor) 4531 |> Jsont.Object.opt_mem "limit" Jsont.int 4532 ~enc:(fun r -> r.limit) 4533 + |> Jsont.Object.opt_mem "purposes" (Jsont.list Jsont.string) 4534 + ~enc:(fun r -> r.purposes) 4535 |> Jsont.Object.finish 4536 4537 type output = { 4538 + cursor : string option; 4539 + lists : Jsont.json list; 4540 } 4541 4542 let output_jsont = 4543 Jsont.Object.map ~kind:"Output" 4544 + (fun _typ cursor lists -> { cursor; lists }) 4545 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getLists#output" ~enc:(fun _ -> "app.bsky.graph.getLists#output") 4546 + |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 4547 + |> Jsont.Object.mem "lists" (Jsont.list Jsont.json) ~enc:(fun r -> r.lists) 4548 |> Jsont.Object.finish 4549 4550 end 4551 + module GetStarterPack = struct 4552 type params = { 4553 + starter_pack : string; 4554 + } 4555 + 4556 + let params_jsont = 4557 + Jsont.Object.map ~kind:"Params" 4558 + (fun starter_pack -> { 4559 + starter_pack; 4560 + }) 4561 + |> Jsont.Object.mem "starterPack" Jsont.string 4562 + ~enc:(fun r -> r.starter_pack) 4563 + |> Jsont.Object.finish 4564 + 4565 + type output = { 4566 + starter_pack : Jsont.json; 4567 + } 4568 + 4569 + let output_jsont = 4570 + Jsont.Object.map ~kind:"Output" 4571 + (fun _typ starter_pack -> { starter_pack }) 4572 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getStarterPack#output" ~enc:(fun _ -> "app.bsky.graph.getStarterPack#output") 4573 + |> Jsont.Object.mem "starterPack" Jsont.json ~enc:(fun r -> r.starter_pack) 4574 + |> Jsont.Object.finish 4575 + 4576 + end 4577 + module GetListBlocks = struct 4578 + type params = { 4579 + cursor : string option; 4580 limit : int option; 4581 } 4582 4583 let params_jsont = 4584 Jsont.Object.map ~kind:"Params" 4585 + (fun cursor limit -> { 4586 + cursor; 4587 limit; 4588 }) 4589 + |> Jsont.Object.opt_mem "cursor" Jsont.string 4590 + ~enc:(fun r -> r.cursor) 4591 |> Jsont.Object.opt_mem "limit" Jsont.int 4592 ~enc:(fun r -> r.limit) 4593 |> Jsont.Object.finish 4594 4595 type output = { 4596 + cursor : string option; 4597 + lists : Jsont.json list; 4598 + } 4599 + 4600 + let output_jsont = 4601 + Jsont.Object.map ~kind:"Output" 4602 + (fun _typ cursor lists -> { cursor; lists }) 4603 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getListBlocks#output" ~enc:(fun _ -> "app.bsky.graph.getListBlocks#output") 4604 + |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 4605 + |> Jsont.Object.mem "lists" (Jsont.list Jsont.json) ~enc:(fun r -> r.lists) 4606 + |> Jsont.Object.finish 4607 + 4608 + end 4609 + module GetStarterPacks = struct 4610 + type params = { 4611 + uris : string list; 4612 + } 4613 + 4614 + let params_jsont = 4615 + Jsont.Object.map ~kind:"Params" 4616 + (fun uris -> { 4617 + uris; 4618 + }) 4619 + |> Jsont.Object.mem "uris" (Jsont.list Jsont.string) 4620 + ~enc:(fun r -> r.uris) 4621 + |> Jsont.Object.finish 4622 + 4623 + type output = { 4624 starter_packs : Jsont.json list; 4625 } 4626 4627 let output_jsont = 4628 Jsont.Object.map ~kind:"Output" 4629 (fun _typ starter_packs -> { starter_packs }) 4630 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getStarterPacks#output" ~enc:(fun _ -> "app.bsky.graph.getStarterPacks#output") 4631 |> Jsont.Object.mem "starterPacks" (Jsont.list Jsont.json) ~enc:(fun r -> r.starter_packs) 4632 |> Jsont.Object.finish 4633 4634 end 4635 + module GetList = struct 4636 type params = { 4637 cursor : string option; 4638 limit : int option; 4639 + list_ : string; 4640 } 4641 4642 let params_jsont = 4643 Jsont.Object.map ~kind:"Params" 4644 + (fun cursor limit list_ -> { 4645 cursor; 4646 limit; 4647 + list_; 4648 }) 4649 |> Jsont.Object.opt_mem "cursor" Jsont.string 4650 ~enc:(fun r -> r.cursor) 4651 |> Jsont.Object.opt_mem "limit" Jsont.int 4652 ~enc:(fun r -> r.limit) 4653 + |> Jsont.Object.mem "list" Jsont.string 4654 + ~enc:(fun r -> r.list_) 4655 |> Jsont.Object.finish 4656 4657 type output = { 4658 cursor : string option; 4659 + items : Jsont.json list; 4660 + list_ : Jsont.json; 4661 } 4662 4663 let output_jsont = 4664 Jsont.Object.map ~kind:"Output" 4665 + (fun _typ cursor items list_ -> { cursor; items; list_ }) 4666 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getList#output" ~enc:(fun _ -> "app.bsky.graph.getList#output") 4667 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 4668 + |> Jsont.Object.mem "items" (Jsont.list Jsont.json) ~enc:(fun r -> r.items) 4669 + |> Jsont.Object.mem "list" Jsont.json ~enc:(fun r -> r.list_) 4670 + |> Jsont.Object.finish 4671 + 4672 + end 4673 + module List = struct 4674 + type main = { 4675 + avatar : Atp.Blob_ref.t option; 4676 + created_at : string; 4677 + description : string option; 4678 + description_facets : Richtext.Facet.main list option; 4679 + labels : Com.Atproto.Label.Defs.self_labels option; 4680 + name : string; 4681 + purpose : Jsont.json; 4682 + } 4683 + 4684 + let main_jsont = 4685 + Jsont.Object.map ~kind:"Main" 4686 + (fun _typ avatar created_at description description_facets labels name purpose -> { avatar; created_at; description; description_facets; labels; name; purpose }) 4687 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.list" ~enc:(fun _ -> "app.bsky.graph.list") 4688 + |> Jsont.Object.opt_mem "avatar" Atp.Blob_ref.jsont ~enc:(fun r -> r.avatar) 4689 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 4690 + |> Jsont.Object.opt_mem "description" Jsont.string ~enc:(fun r -> r.description) 4691 + |> Jsont.Object.opt_mem "descriptionFacets" (Jsont.list Richtext.Facet.main_jsont) ~enc:(fun r -> r.description_facets) 4692 + |> Jsont.Object.opt_mem "labels" Com.Atproto.Label.Defs.self_labels_jsont ~enc:(fun r -> r.labels) 4693 + |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 4694 + |> Jsont.Object.mem "purpose" Jsont.json ~enc:(fun r -> r.purpose) 4695 + |> Jsont.Object.finish 4696 + 4697 + end 4698 + end 4699 + module Bookmark = struct 4700 + module Defs = struct 4701 + type bookmark_view = { 4702 + created_at : string option; 4703 + item : Jsont.json; 4704 + subject : Com.Atproto.Repo.StrongRef.main; 4705 + } 4706 + 4707 + let bookmark_view_jsont = 4708 + Jsont.Object.map ~kind:"Bookmark_view" 4709 + (fun _typ created_at item subject -> { created_at; item; subject }) 4710 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.bookmark.defs#bookmarkView" ~enc:(fun _ -> "app.bsky.bookmark.defs#bookmarkView") 4711 + |> Jsont.Object.opt_mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 4712 + |> Jsont.Object.mem "item" Jsont.json ~enc:(fun r -> r.item) 4713 + |> Jsont.Object.mem "subject" Com.Atproto.Repo.StrongRef.main_jsont ~enc:(fun r -> r.subject) 4714 + |> Jsont.Object.finish 4715 + 4716 + type bookmark = { 4717 + subject : Com.Atproto.Repo.StrongRef.main; 4718 + } 4719 + 4720 + let bookmark_jsont = 4721 + Jsont.Object.map ~kind:"Bookmark" 4722 + (fun _typ subject -> { subject }) 4723 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.bookmark.defs#bookmark" ~enc:(fun _ -> "app.bsky.bookmark.defs#bookmark") 4724 + |> Jsont.Object.mem "subject" Com.Atproto.Repo.StrongRef.main_jsont ~enc:(fun r -> r.subject) 4725 + |> Jsont.Object.finish 4726 + 4727 + end 4728 + module CreateBookmark = struct 4729 + type input = { 4730 + cid : string; 4731 + uri : string; 4732 + } 4733 + 4734 + let input_jsont = 4735 + Jsont.Object.map ~kind:"Input" 4736 + (fun _typ cid uri -> { cid; uri }) 4737 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.bookmark.createBookmark#input" ~enc:(fun _ -> "app.bsky.bookmark.createBookmark#input") 4738 + |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 4739 + |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 4740 |> Jsont.Object.finish 4741 4742 end 4743 + module DeleteBookmark = struct 4744 + type input = { 4745 + uri : string; 4746 + } 4747 + 4748 + let input_jsont = 4749 + Jsont.Object.map ~kind:"Input" 4750 + (fun _typ uri -> { uri }) 4751 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.bookmark.deleteBookmark#input" ~enc:(fun _ -> "app.bsky.bookmark.deleteBookmark#input") 4752 + |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 4753 + |> Jsont.Object.finish 4754 + 4755 + end 4756 + module GetBookmarks = struct 4757 type params = { 4758 + cursor : string option; 4759 limit : int option; 4760 } 4761 4762 let params_jsont = 4763 Jsont.Object.map ~kind:"Params" 4764 + (fun cursor limit -> { 4765 + cursor; 4766 limit; 4767 }) 4768 + |> Jsont.Object.opt_mem "cursor" Jsont.string 4769 + ~enc:(fun r -> r.cursor) 4770 |> Jsont.Object.opt_mem "limit" Jsont.int 4771 ~enc:(fun r -> r.limit) 4772 |> Jsont.Object.finish 4773 4774 type output = { 4775 + bookmarks : Defs.bookmark_view list; 4776 + cursor : string option; 4777 } 4778 4779 let output_jsont = 4780 Jsont.Object.map ~kind:"Output" 4781 + (fun _typ bookmarks cursor -> { bookmarks; cursor }) 4782 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.bookmark.getBookmarks#output" ~enc:(fun _ -> "app.bsky.bookmark.getBookmarks#output") 4783 + |> Jsont.Object.mem "bookmarks" (Jsont.list Defs.bookmark_view_jsont) ~enc:(fun r -> r.bookmarks) 4784 + |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 4785 |> Jsont.Object.finish 4786 4787 end 4788 + end 4789 + module Unspecced = struct 4790 module GetSuggestedFeeds = struct 4791 type params = { 4792 limit : int option; ··· 4813 |> Jsont.Object.finish 4814 4815 end 4816 + module GetSuggestedUsers = struct 4817 type params = { 4818 + category : string option; 4819 limit : int option; 4820 } 4821 4822 let params_jsont = 4823 Jsont.Object.map ~kind:"Params" 4824 + (fun category limit -> { 4825 + category; 4826 limit; 4827 }) 4828 + |> Jsont.Object.opt_mem "category" Jsont.string 4829 + ~enc:(fun r -> r.category) 4830 |> Jsont.Object.opt_mem "limit" Jsont.int 4831 ~enc:(fun r -> r.limit) 4832 |> Jsont.Object.finish 4833 4834 type output = { 4835 + actors : Jsont.json list; 4836 + rec_id : int option; 4837 } 4838 4839 let output_jsont = 4840 Jsont.Object.map ~kind:"Output" 4841 + (fun _typ actors rec_id -> { actors; rec_id }) 4842 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getSuggestedUsers#output" ~enc:(fun _ -> "app.bsky.unspecced.getSuggestedUsers#output") 4843 + |> Jsont.Object.mem "actors" (Jsont.list Jsont.json) ~enc:(fun r -> r.actors) 4844 + |> Jsont.Object.opt_mem "recId" Jsont.int ~enc:(fun r -> r.rec_id) 4845 |> Jsont.Object.finish 4846 4847 end 4848 + module GetSuggestedUsersSkeleton = struct 4849 + type params = { 4850 + category : string option; 4851 + limit : int option; 4852 + viewer : string option; 4853 } 4854 4855 + let params_jsont = 4856 + Jsont.Object.map ~kind:"Params" 4857 + (fun category limit viewer -> { 4858 + category; 4859 + limit; 4860 + viewer; 4861 + }) 4862 + |> Jsont.Object.opt_mem "category" Jsont.string 4863 + ~enc:(fun r -> r.category) 4864 + |> Jsont.Object.opt_mem "limit" Jsont.int 4865 + ~enc:(fun r -> r.limit) 4866 + |> Jsont.Object.opt_mem "viewer" Jsont.string 4867 + ~enc:(fun r -> r.viewer) 4868 |> Jsont.Object.finish 4869 4870 type output = { 4871 + dids : string list; 4872 + rec_id : int option; 4873 } 4874 4875 let output_jsont = 4876 Jsont.Object.map ~kind:"Output" 4877 + (fun _typ dids rec_id -> { dids; rec_id }) 4878 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getSuggestedUsersSkeleton#output" ~enc:(fun _ -> "app.bsky.unspecced.getSuggestedUsersSkeleton#output") 4879 + |> Jsont.Object.mem "dids" (Jsont.list Jsont.string) ~enc:(fun r -> r.dids) 4880 + |> Jsont.Object.opt_mem "recId" Jsont.int ~enc:(fun r -> r.rec_id) 4881 |> Jsont.Object.finish 4882 4883 end ··· 4907 |> Jsont.Object.finish 4908 4909 end 4910 + module GetOnboardingSuggestedStarterPacksSkeleton = struct 4911 type params = { 4912 limit : int option; 4913 + viewer : string option; 4914 } 4915 4916 let params_jsont = 4917 Jsont.Object.map ~kind:"Params" 4918 + (fun limit viewer -> { 4919 limit; 4920 + viewer; 4921 }) 4922 |> Jsont.Object.opt_mem "limit" Jsont.int 4923 ~enc:(fun r -> r.limit) 4924 + |> Jsont.Object.opt_mem "viewer" Jsont.string 4925 + ~enc:(fun r -> r.viewer) 4926 |> Jsont.Object.finish 4927 4928 type output = { 4929 + starter_packs : string list; 4930 } 4931 4932 let output_jsont = 4933 Jsont.Object.map ~kind:"Output" 4934 + (fun _typ starter_packs -> { starter_packs }) 4935 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getOnboardingSuggestedStarterPacksSkeleton#output" ~enc:(fun _ -> "app.bsky.unspecced.getOnboardingSuggestedStarterPacksSkeleton#output") 4936 + |> Jsont.Object.mem "starterPacks" (Jsont.list Jsont.string) ~enc:(fun r -> r.starter_packs) 4937 |> Jsont.Object.finish 4938 4939 end 4940 + module GetSuggestedFeedsSkeleton = struct 4941 type params = { 4942 limit : int option; 4943 viewer : string option; ··· 4956 |> Jsont.Object.finish 4957 4958 type output = { 4959 + feeds : string list; 4960 + } 4961 + 4962 + let output_jsont = 4963 + Jsont.Object.map ~kind:"Output" 4964 + (fun _typ feeds -> { feeds }) 4965 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getSuggestedFeedsSkeleton#output" ~enc:(fun _ -> "app.bsky.unspecced.getSuggestedFeedsSkeleton#output") 4966 + |> Jsont.Object.mem "feeds" (Jsont.list Jsont.string) ~enc:(fun r -> r.feeds) 4967 + |> Jsont.Object.finish 4968 + 4969 + end 4970 + module GetOnboardingSuggestedStarterPacks = struct 4971 + type params = { 4972 + limit : int option; 4973 + } 4974 + 4975 + let params_jsont = 4976 + Jsont.Object.map ~kind:"Params" 4977 + (fun limit -> { 4978 + limit; 4979 + }) 4980 + |> Jsont.Object.opt_mem "limit" Jsont.int 4981 + ~enc:(fun r -> r.limit) 4982 + |> Jsont.Object.finish 4983 + 4984 + type output = { 4985 + starter_packs : Jsont.json list; 4986 } 4987 4988 let output_jsont = 4989 Jsont.Object.map ~kind:"Output" 4990 (fun _typ starter_packs -> { starter_packs }) 4991 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getOnboardingSuggestedStarterPacks#output" ~enc:(fun _ -> "app.bsky.unspecced.getOnboardingSuggestedStarterPacks#output") 4992 + |> Jsont.Object.mem "starterPacks" (Jsont.list Jsont.json) ~enc:(fun r -> r.starter_packs) 4993 |> Jsont.Object.finish 4994 4995 end ··· 5173 |> Jsont.Object.finish 5174 5175 end 5176 + module GetConfig = struct 5177 + type live_now_config = { 5178 + did : string; 5179 + domains : string list; 5180 } 5181 5182 + let live_now_config_jsont = 5183 + Jsont.Object.map ~kind:"Live_now_config" 5184 + (fun _typ did domains -> { did; domains }) 5185 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getConfig#liveNowConfig" ~enc:(fun _ -> "app.bsky.unspecced.getConfig#liveNowConfig") 5186 + |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 5187 + |> Jsont.Object.mem "domains" (Jsont.list Jsont.string) ~enc:(fun r -> r.domains) 5188 |> Jsont.Object.finish 5189 5190 type output = { 5191 + check_email_confirmed : bool option; 5192 + live_now : live_now_config list option; 5193 } 5194 5195 let output_jsont = 5196 Jsont.Object.map ~kind:"Output" 5197 + (fun _typ check_email_confirmed live_now -> { check_email_confirmed; live_now }) 5198 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getConfig#output" ~enc:(fun _ -> "app.bsky.unspecced.getConfig#output") 5199 + |> Jsont.Object.opt_mem "checkEmailConfirmed" Jsont.bool ~enc:(fun r -> r.check_email_confirmed) 5200 + |> Jsont.Object.opt_mem "liveNow" (Jsont.list live_now_config_jsont) ~enc:(fun r -> r.live_now) 5201 |> Jsont.Object.finish 5202 5203 end 5204 + module GetPopularFeedGenerators = struct 5205 type params = { 5206 cursor : string option; 5207 limit : int option; 5208 + query : string option; 5209 } 5210 5211 let params_jsont = 5212 Jsont.Object.map ~kind:"Params" 5213 + (fun cursor limit query -> { 5214 cursor; 5215 limit; 5216 + query; 5217 }) 5218 |> Jsont.Object.opt_mem "cursor" Jsont.string 5219 ~enc:(fun r -> r.cursor) 5220 |> Jsont.Object.opt_mem "limit" Jsont.int 5221 ~enc:(fun r -> r.limit) 5222 + |> Jsont.Object.opt_mem "query" Jsont.string 5223 + ~enc:(fun r -> r.query) 5224 |> Jsont.Object.finish 5225 5226 type output = { 5227 cursor : string option; 5228 + feeds : Jsont.json list; 5229 } 5230 5231 let output_jsont = 5232 Jsont.Object.map ~kind:"Output" 5233 + (fun _typ cursor feeds -> { cursor; feeds }) 5234 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getPopularFeedGenerators#output" ~enc:(fun _ -> "app.bsky.unspecced.getPopularFeedGenerators#output") 5235 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 5236 + |> Jsont.Object.mem "feeds" (Jsont.list Jsont.json) ~enc:(fun r -> r.feeds) 5237 |> Jsont.Object.finish 5238 5239 end 5240 + module GetTaggedSuggestions = struct 5241 + type suggestion = { 5242 + subject : string; 5243 + subject_type : string; 5244 + tag : string; 5245 } 5246 5247 + let suggestion_jsont = 5248 + Jsont.Object.map ~kind:"Suggestion" 5249 + (fun _typ subject subject_type tag -> { subject; subject_type; tag }) 5250 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getTaggedSuggestions#suggestion" ~enc:(fun _ -> "app.bsky.unspecced.getTaggedSuggestions#suggestion") 5251 + |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 5252 + |> Jsont.Object.mem "subjectType" Jsont.string ~enc:(fun r -> r.subject_type) 5253 + |> Jsont.Object.mem "tag" Jsont.string ~enc:(fun r -> r.tag) 5254 |> Jsont.Object.finish 5255 5256 + type params = unit 5257 5258 + let params_jsont = Jsont.ignore 5259 5260 type output = { 5261 + suggestions : suggestion list; 5262 } 5263 5264 let output_jsont = 5265 Jsont.Object.map ~kind:"Output" 5266 + (fun _typ suggestions -> { suggestions }) 5267 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getTaggedSuggestions#output" ~enc:(fun _ -> "app.bsky.unspecced.getTaggedSuggestions#output") 5268 + |> Jsont.Object.mem "suggestions" (Jsont.list suggestion_jsont) ~enc:(fun r -> r.suggestions) 5269 |> Jsont.Object.finish 5270 5271 end 5272 + module GetSuggestedStarterPacksSkeleton = struct 5273 type params = { 5274 limit : int option; 5275 viewer : string option; ··· 5288 |> Jsont.Object.finish 5289 5290 type output = { 5291 + starter_packs : string list; 5292 } 5293 5294 let output_jsont = 5295 Jsont.Object.map ~kind:"Output" 5296 + (fun _typ starter_packs -> { starter_packs }) 5297 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getSuggestedStarterPacksSkeleton#output" ~enc:(fun _ -> "app.bsky.unspecced.getSuggestedStarterPacksSkeleton#output") 5298 + |> Jsont.Object.mem "starterPacks" (Jsont.list Jsont.string) ~enc:(fun r -> r.starter_packs) 5299 + |> Jsont.Object.finish 5300 + 5301 + end 5302 + module InitAgeAssurance = struct 5303 + type input = { 5304 + country_code : string; 5305 + email : string; 5306 + language : string; 5307 + } 5308 + 5309 + let input_jsont = 5310 + Jsont.Object.map ~kind:"Input" 5311 + (fun _typ country_code email language -> { country_code; email; language }) 5312 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.initAgeAssurance#input" ~enc:(fun _ -> "app.bsky.unspecced.initAgeAssurance#input") 5313 + |> Jsont.Object.mem "countryCode" Jsont.string ~enc:(fun r -> r.country_code) 5314 + |> Jsont.Object.mem "email" Jsont.string ~enc:(fun r -> r.email) 5315 + |> Jsont.Object.mem "language" Jsont.string ~enc:(fun r -> r.language) 5316 |> Jsont.Object.finish 5317 5318 + type output = Defs.age_assurance_state 5319 + 5320 + let output_jsont = Defs.age_assurance_state_jsont 5321 + 5322 end 5323 + module GetTrendingTopics = struct 5324 type params = { 5325 limit : int option; 5326 viewer : string option; ··· 5339 |> Jsont.Object.finish 5340 5341 type output = { 5342 + suggested : Defs.trending_topic list; 5343 + topics : Defs.trending_topic list; 5344 } 5345 5346 let output_jsont = 5347 Jsont.Object.map ~kind:"Output" 5348 + (fun _typ suggested topics -> { suggested; topics }) 5349 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getTrendingTopics#output" ~enc:(fun _ -> "app.bsky.unspecced.getTrendingTopics#output") 5350 + |> Jsont.Object.mem "suggested" (Jsont.list Defs.trending_topic_jsont) ~enc:(fun r -> r.suggested) 5351 + |> Jsont.Object.mem "topics" (Jsont.list Defs.trending_topic_jsont) ~enc:(fun r -> r.topics) 5352 |> Jsont.Object.finish 5353 5354 end ··· 5393 |> Jsont.Object.finish 5394 5395 end 5396 + module GetSuggestionsSkeleton = struct 5397 + type params = { 5398 + cursor : string option; 5399 + limit : int option; 5400 + relative_to_did : string option; 5401 + viewer : string option; 5402 } 5403 5404 + let params_jsont = 5405 + Jsont.Object.map ~kind:"Params" 5406 + (fun cursor limit relative_to_did viewer -> { 5407 + cursor; 5408 + limit; 5409 + relative_to_did; 5410 + viewer; 5411 + }) 5412 + |> Jsont.Object.opt_mem "cursor" Jsont.string 5413 + ~enc:(fun r -> r.cursor) 5414 + |> Jsont.Object.opt_mem "limit" Jsont.int 5415 + ~enc:(fun r -> r.limit) 5416 + |> Jsont.Object.opt_mem "relativeToDid" Jsont.string 5417 + ~enc:(fun r -> r.relative_to_did) 5418 + |> Jsont.Object.opt_mem "viewer" Jsont.string 5419 + ~enc:(fun r -> r.viewer) 5420 |> Jsont.Object.finish 5421 5422 + type output = { 5423 + actors : Defs.skeleton_search_actor list; 5424 + cursor : string option; 5425 + rec_id : int option; 5426 + relative_to_did : string option; 5427 + } 5428 + 5429 + let output_jsont = 5430 + Jsont.Object.map ~kind:"Output" 5431 + (fun _typ actors cursor rec_id relative_to_did -> { actors; cursor; rec_id; relative_to_did }) 5432 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getSuggestionsSkeleton#output" ~enc:(fun _ -> "app.bsky.unspecced.getSuggestionsSkeleton#output") 5433 + |> Jsont.Object.mem "actors" (Jsont.list Defs.skeleton_search_actor_jsont) ~enc:(fun r -> r.actors) 5434 + |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 5435 + |> Jsont.Object.opt_mem "recId" Jsont.int ~enc:(fun r -> r.rec_id) 5436 + |> Jsont.Object.opt_mem "relativeToDid" Jsont.string ~enc:(fun r -> r.relative_to_did) 5437 + |> Jsont.Object.finish 5438 + 5439 + end 5440 + module GetAgeAssuranceState = struct 5441 type output = Defs.age_assurance_state 5442 5443 let output_jsont = Defs.age_assurance_state_jsont ··· 5485 |> Jsont.Object.finish 5486 5487 end 5488 + module SearchPostsSkeleton = struct 5489 type params = { 5490 + author : string option; 5491 cursor : string option; 5492 + domain : string option; 5493 + lang : string option; 5494 limit : int option; 5495 + mentions : string option; 5496 q : string; 5497 + since : string option; 5498 + sort : string option; 5499 + tag : string list option; 5500 + until : string option; 5501 + url : string option; 5502 viewer : string option; 5503 } 5504 5505 let params_jsont = 5506 Jsont.Object.map ~kind:"Params" 5507 + (fun author cursor domain lang limit mentions q since sort tag until url viewer -> { 5508 + author; 5509 cursor; 5510 + domain; 5511 + lang; 5512 limit; 5513 + mentions; 5514 q; 5515 + since; 5516 + sort; 5517 + tag; 5518 + until; 5519 + url; 5520 viewer; 5521 }) 5522 + |> Jsont.Object.opt_mem "author" Jsont.string 5523 + ~enc:(fun r -> r.author) 5524 |> Jsont.Object.opt_mem "cursor" Jsont.string 5525 ~enc:(fun r -> r.cursor) 5526 + |> Jsont.Object.opt_mem "domain" Jsont.string 5527 + ~enc:(fun r -> r.domain) 5528 + |> Jsont.Object.opt_mem "lang" Jsont.string 5529 + ~enc:(fun r -> r.lang) 5530 |> Jsont.Object.opt_mem "limit" Jsont.int 5531 ~enc:(fun r -> r.limit) 5532 + |> Jsont.Object.opt_mem "mentions" Jsont.string 5533 + ~enc:(fun r -> r.mentions) 5534 |> Jsont.Object.mem "q" Jsont.string 5535 ~enc:(fun r -> r.q) 5536 + |> Jsont.Object.opt_mem "since" Jsont.string 5537 + ~enc:(fun r -> r.since) 5538 + |> Jsont.Object.opt_mem "sort" Jsont.string 5539 + ~enc:(fun r -> r.sort) 5540 + |> Jsont.Object.opt_mem "tag" (Jsont.list Jsont.string) 5541 + ~enc:(fun r -> r.tag) 5542 + |> Jsont.Object.opt_mem "until" Jsont.string 5543 + ~enc:(fun r -> r.until) 5544 + |> Jsont.Object.opt_mem "url" Jsont.string 5545 + ~enc:(fun r -> r.url) 5546 |> Jsont.Object.opt_mem "viewer" Jsont.string 5547 ~enc:(fun r -> r.viewer) 5548 |> Jsont.Object.finish 5549 5550 type output = { 5551 cursor : string option; 5552 hits_total : int option; 5553 + posts : Defs.skeleton_search_post list; 5554 } 5555 5556 let output_jsont = 5557 Jsont.Object.map ~kind:"Output" 5558 + (fun _typ cursor hits_total posts -> { cursor; hits_total; posts }) 5559 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.searchPostsSkeleton#output" ~enc:(fun _ -> "app.bsky.unspecced.searchPostsSkeleton#output") 5560 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 5561 |> Jsont.Object.opt_mem "hitsTotal" Jsont.int ~enc:(fun r -> r.hits_total) 5562 + |> Jsont.Object.mem "posts" (Jsont.list Defs.skeleton_search_post_jsont) ~enc:(fun r -> r.posts) 5563 |> Jsont.Object.finish 5564 5565 end 5566 + module SearchActorsSkeleton = struct 5567 type params = { 5568 cursor : string option; 5569 limit : int option; 5570 + q : string; 5571 + typeahead : bool option; 5572 viewer : string option; 5573 } 5574 5575 let params_jsont = 5576 Jsont.Object.map ~kind:"Params" 5577 + (fun cursor limit q typeahead viewer -> { 5578 cursor; 5579 limit; 5580 + q; 5581 + typeahead; 5582 viewer; 5583 }) 5584 |> Jsont.Object.opt_mem "cursor" Jsont.string 5585 ~enc:(fun r -> r.cursor) 5586 |> Jsont.Object.opt_mem "limit" Jsont.int 5587 ~enc:(fun r -> r.limit) 5588 + |> Jsont.Object.mem "q" Jsont.string 5589 + ~enc:(fun r -> r.q) 5590 + |> Jsont.Object.opt_mem "typeahead" Jsont.bool 5591 + ~enc:(fun r -> r.typeahead) 5592 |> Jsont.Object.opt_mem "viewer" Jsont.string 5593 ~enc:(fun r -> r.viewer) 5594 |> Jsont.Object.finish ··· 5596 type output = { 5597 actors : Defs.skeleton_search_actor list; 5598 cursor : string option; 5599 + hits_total : int option; 5600 } 5601 5602 let output_jsont = 5603 Jsont.Object.map ~kind:"Output" 5604 + (fun _typ actors cursor hits_total -> { actors; cursor; hits_total }) 5605 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.searchActorsSkeleton#output" ~enc:(fun _ -> "app.bsky.unspecced.searchActorsSkeleton#output") 5606 |> Jsont.Object.mem "actors" (Jsont.list Defs.skeleton_search_actor_jsont) ~enc:(fun r -> r.actors) 5607 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 5608 + |> Jsont.Object.opt_mem "hitsTotal" Jsont.int ~enc:(fun r -> r.hits_total) 5609 |> Jsont.Object.finish 5610 5611 end ··· 5632 (fun _typ trends -> { trends }) 5633 |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getTrends#output" ~enc:(fun _ -> "app.bsky.unspecced.getTrends#output") 5634 |> Jsont.Object.mem "trends" (Jsont.list Defs.trend_view_jsont) ~enc:(fun r -> r.trends) 5635 + |> Jsont.Object.finish 5636 + 5637 + end 5638 + module GetPostThreadV2 = struct 5639 + type thread_item = { 5640 + depth : int; 5641 + uri : string; 5642 + value : Jsont.json; 5643 + } 5644 + 5645 + let thread_item_jsont = 5646 + Jsont.Object.map ~kind:"Thread_item" 5647 + (fun _typ depth uri value -> { depth; uri; value }) 5648 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getPostThreadV2#threadItem" ~enc:(fun _ -> "app.bsky.unspecced.getPostThreadV2#threadItem") 5649 + |> Jsont.Object.mem "depth" Jsont.int ~enc:(fun r -> r.depth) 5650 + |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 5651 + |> Jsont.Object.mem "value" Jsont.json ~enc:(fun r -> r.value) 5652 + |> Jsont.Object.finish 5653 + 5654 + type params = { 5655 + above : bool option; 5656 + anchor : string; 5657 + below : int option; 5658 + branching_factor : int option; 5659 + sort : string option; 5660 + } 5661 + 5662 + let params_jsont = 5663 + Jsont.Object.map ~kind:"Params" 5664 + (fun above anchor below branching_factor sort -> { 5665 + above; 5666 + anchor; 5667 + below; 5668 + branching_factor; 5669 + sort; 5670 + }) 5671 + |> Jsont.Object.opt_mem "above" Jsont.bool 5672 + ~enc:(fun r -> r.above) 5673 + |> Jsont.Object.mem "anchor" Jsont.string 5674 + ~enc:(fun r -> r.anchor) 5675 + |> Jsont.Object.opt_mem "below" Jsont.int 5676 + ~enc:(fun r -> r.below) 5677 + |> Jsont.Object.opt_mem "branchingFactor" Jsont.int 5678 + ~enc:(fun r -> r.branching_factor) 5679 + |> Jsont.Object.opt_mem "sort" Jsont.string 5680 + ~enc:(fun r -> r.sort) 5681 + |> Jsont.Object.finish 5682 + 5683 + type output = { 5684 + has_other_replies : bool; 5685 + thread : thread_item list; 5686 + threadgate : Jsont.json option; 5687 + } 5688 + 5689 + let output_jsont = 5690 + Jsont.Object.map ~kind:"Output" 5691 + (fun _typ has_other_replies thread threadgate -> { has_other_replies; thread; threadgate }) 5692 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getPostThreadV2#output" ~enc:(fun _ -> "app.bsky.unspecced.getPostThreadV2#output") 5693 + |> Jsont.Object.mem "hasOtherReplies" Jsont.bool ~enc:(fun r -> r.has_other_replies) 5694 + |> Jsont.Object.mem "thread" (Jsont.list thread_item_jsont) ~enc:(fun r -> r.thread) 5695 + |> Jsont.Object.opt_mem "threadgate" Jsont.json ~enc:(fun r -> r.threadgate) 5696 + |> Jsont.Object.finish 5697 + 5698 + end 5699 + module GetTrendsSkeleton = struct 5700 + type params = { 5701 + limit : int option; 5702 + viewer : string option; 5703 + } 5704 + 5705 + let params_jsont = 5706 + Jsont.Object.map ~kind:"Params" 5707 + (fun limit viewer -> { 5708 + limit; 5709 + viewer; 5710 + }) 5711 + |> Jsont.Object.opt_mem "limit" Jsont.int 5712 + ~enc:(fun r -> r.limit) 5713 + |> Jsont.Object.opt_mem "viewer" Jsont.string 5714 + ~enc:(fun r -> r.viewer) 5715 + |> Jsont.Object.finish 5716 + 5717 + type output = { 5718 + trends : Defs.skeleton_trend list; 5719 + } 5720 + 5721 + let output_jsont = 5722 + Jsont.Object.map ~kind:"Output" 5723 + (fun _typ trends -> { trends }) 5724 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getTrendsSkeleton#output" ~enc:(fun _ -> "app.bsky.unspecced.getTrendsSkeleton#output") 5725 + |> Jsont.Object.mem "trends" (Jsont.list Defs.skeleton_trend_jsont) ~enc:(fun r -> r.trends) 5726 |> Jsont.Object.finish 5727 5728 end
+1641 -1641
ocaml-atp/lexicons/bsky/atp_lexicon_bsky.mli
··· 12 13 module Com : sig 14 module Atproto : sig 15 module Label : sig 16 module Defs : sig 17 (** Metadata tag on an atproto record, published by the author within the record. Note that schemas should use #selfLabels, not #selfLabel. *) ··· 93 94 end 95 end 96 - module Moderation : sig 97 - module Defs : sig 98 - (** Tag describing a type of subject that might be reported. *) 99 - 100 - type subject_type = string 101 - val subject_type_jsont : subject_type Jsont.t 102 - 103 - (** Direct violation of server rules, laws, terms of service. Prefer new lexicon definition `tools.ozone.report.defs#reasonRuleOther`. *) 104 - 105 - type reason_violation = string 106 - val reason_violation_jsont : reason_violation Jsont.t 107 - 108 - 109 - type reason_type = string 110 - val reason_type_jsont : reason_type Jsont.t 111 - 112 - (** Spam: frequent unwanted promotion, replies, mentions. Prefer new lexicon definition `tools.ozone.report.defs#reasonMisleadingSpam`. *) 113 - 114 - type reason_spam = string 115 - val reason_spam_jsont : reason_spam Jsont.t 116 - 117 - (** Unwanted or mislabeled sexual content. Prefer new lexicon definition `tools.ozone.report.defs#reasonSexualUnlabeled`. *) 118 - 119 - type reason_sexual = string 120 - val reason_sexual_jsont : reason_sexual Jsont.t 121 - 122 - (** Rude, harassing, explicit, or otherwise unwelcoming behavior. Prefer new lexicon definition `tools.ozone.report.defs#reasonHarassmentOther`. *) 123 - 124 - type reason_rude = string 125 - val reason_rude_jsont : reason_rude Jsont.t 126 - 127 - (** Reports not falling under another report category. Prefer new lexicon definition `tools.ozone.report.defs#reasonOther`. *) 128 - 129 - type reason_other = string 130 - val reason_other_jsont : reason_other Jsont.t 131 - 132 - (** Misleading identity, affiliation, or content. Prefer new lexicon definition `tools.ozone.report.defs#reasonMisleadingOther`. *) 133 - 134 - type reason_misleading = string 135 - val reason_misleading_jsont : reason_misleading Jsont.t 136 - 137 - (** Appeal a previously taken moderation action *) 138 - 139 - type reason_appeal = string 140 - val reason_appeal_jsont : reason_appeal Jsont.t 141 - 142 - end 143 - end 144 end 145 end 146 module App : sig 147 module Bsky : sig 148 - module AuthManageLabelerService : sig 149 150 type main = unit 151 val main_jsont : main Jsont.t ··· 157 val main_jsont : main Jsont.t 158 159 end 160 - module AuthManageModeration : sig 161 - 162 - type main = unit 163 - val main_jsont : main Jsont.t 164 - 165 - end 166 - module Richtext : sig 167 - module Facet : sig 168 - (** Facet feature for a hashtag. The text usually includes a '#' prefix, but the facet reference should not (except in the case of 'double hash tags'). *) 169 - 170 - type tag = { 171 - tag : string; 172 - } 173 - 174 - (** Jsont codec for {!type:tag}. *) 175 - val tag_jsont : tag Jsont.t 176 - 177 - (** Facet feature for mention of another account. The text is usually a handle, including a '\@' prefix, but the facet reference is a DID. *) 178 - 179 - type mention = { 180 - did : string; 181 - } 182 - 183 - (** Jsont codec for {!type:mention}. *) 184 - val mention_jsont : mention Jsont.t 185 - 186 - (** Facet feature for a URL. The text URL may have been simplified or truncated, but the facet reference should be a complete URL. *) 187 - 188 - type link = { 189 - uri : string; 190 - } 191 - 192 - (** Jsont codec for {!type:link}. *) 193 - val link_jsont : link Jsont.t 194 - 195 - (** Specifies the sub-string range a facet feature applies to. Start index is inclusive, end index is exclusive. Indices are zero-indexed, counting bytes of the UTF-8 encoded text. NOTE: some languages, like Javascript, use UTF-16 or Unicode codepoints for string slice indexing; in these languages, convert to byte arrays before working with facets. *) 196 - 197 - type byte_slice = { 198 - byte_end : int; 199 - byte_start : int; 200 - } 201 - 202 - (** Jsont codec for {!type:byte_slice}. *) 203 - val byte_slice_jsont : byte_slice Jsont.t 204 - 205 - (** Annotation of a sub-string within rich text. *) 206 - 207 - type main = { 208 - features : Jsont.json list; 209 - index : byte_slice; 210 - } 211 - 212 - (** Jsont codec for {!type:main}. *) 213 - val main_jsont : main Jsont.t 214 - 215 - end 216 - end 217 module AuthManageFeedDeclarations : sig 218 219 type main = unit 220 val main_jsont : main Jsont.t 221 222 end 223 - module AuthFullApp : sig 224 225 type main = unit 226 val main_jsont : main Jsont.t 227 228 end 229 - module AuthManageNotifications : sig 230 231 type main = unit 232 val main_jsont : main Jsont.t ··· 238 val main_jsont : main Jsont.t 239 240 end 241 - module Ageassurance : sig 242 - module Defs : sig 243 - (** The status of the Age Assurance process. *) 244 - 245 - type status = string 246 - val status_jsont : status Jsont.t 247 - 248 - (** Additional metadata needed to compute Age Assurance state client-side. *) 249 - 250 - type state_metadata = { 251 - account_created_at : string option; (** The account creation timestamp. *) 252 - } 253 - 254 - (** Jsont codec for {!type:state_metadata}. *) 255 - val state_metadata_jsont : state_metadata Jsont.t 256 - 257 - (** Object used to store Age Assurance data in stash. *) 258 - 259 - type event = { 260 - access : string; (** The access level granted based on Age Assurance data we've processed. *) 261 - attempt_id : string; (** The unique identifier for this instance of the Age Assurance flow, in UUID format. *) 262 - complete_ip : string option; (** The IP address used when completing the Age Assurance flow. *) 263 - complete_ua : string option; (** The user agent used when completing the Age Assurance flow. *) 264 - country_code : string; (** The ISO 3166-1 alpha-2 country code provided when beginning the Age Assurance flow. *) 265 - created_at : string; (** The date and time of this write operation. *) 266 - email : string option; (** The email used for Age Assurance. *) 267 - init_ip : string option; (** The IP address used when initiating the Age Assurance flow. *) 268 - init_ua : string option; (** The user agent used when initiating the Age Assurance flow. *) 269 - region_code : string option; (** The ISO 3166-2 region code provided when beginning the Age Assurance flow. *) 270 - status : string; (** The status of the Age Assurance process. *) 271 - } 272 - 273 - (** Jsont codec for {!type:event}. *) 274 - val event_jsont : event Jsont.t 275 - 276 - (** The Age Assurance configuration for a specific region. *) 277 - 278 - type config_region = { 279 - country_code : string; (** The ISO 3166-1 alpha-2 country code this configuration applies to. *) 280 - min_access_age : int; (** The minimum age (as a whole integer) required to use Bluesky in this region. *) 281 - region_code : string option; (** The ISO 3166-2 region code this configuration applies to. If omitted, the configuration applies to the entire country. *) 282 - rules : Jsont.json list; (** The ordered list of Age Assurance rules that apply to this region. Rules should be applied in order, and the first matching rule determines the access level granted. The rules array should always include a default rule as the last item. *) 283 - } 284 - 285 - (** Jsont codec for {!type:config_region}. *) 286 - val config_region_jsont : config_region Jsont.t 287 - 288 - (** The access level granted based on Age Assurance data we've processed. *) 289 - 290 - type access = string 291 - val access_jsont : access Jsont.t 292 - 293 - (** The user's computed Age Assurance state. *) 294 - 295 - type state = { 296 - access : access; 297 - last_initiated_at : string option; (** The timestamp when this state was last updated. *) 298 - status : status; 299 - } 300 - 301 - (** Jsont codec for {!type:state}. *) 302 - val state_jsont : state Jsont.t 303 - 304 - (** Age Assurance rule that applies if the user has declared themselves under a certain age. *) 305 - 306 - type config_region_rule_if_declared_under_age = { 307 - access : access; 308 - age : int; (** The age threshold as a whole integer. *) 309 - } 310 - 311 - (** Jsont codec for {!type:config_region_rule_if_declared_under_age}. *) 312 - val config_region_rule_if_declared_under_age_jsont : config_region_rule_if_declared_under_age Jsont.t 313 - 314 - (** Age Assurance rule that applies if the user has declared themselves equal-to or over a certain age. *) 315 - 316 - type config_region_rule_if_declared_over_age = { 317 - access : access; 318 - age : int; (** The age threshold as a whole integer. *) 319 - } 320 - 321 - (** Jsont codec for {!type:config_region_rule_if_declared_over_age}. *) 322 - val config_region_rule_if_declared_over_age_jsont : config_region_rule_if_declared_over_age Jsont.t 323 - 324 - (** Age Assurance rule that applies if the user has been assured to be under a certain age. *) 325 - 326 - type config_region_rule_if_assured_under_age = { 327 - access : access; 328 - age : int; (** The age threshold as a whole integer. *) 329 - } 330 - 331 - (** Jsont codec for {!type:config_region_rule_if_assured_under_age}. *) 332 - val config_region_rule_if_assured_under_age_jsont : config_region_rule_if_assured_under_age Jsont.t 333 - 334 - (** Age Assurance rule that applies if the user has been assured to be equal-to or over a certain age. *) 335 - 336 - type config_region_rule_if_assured_over_age = { 337 - access : access; 338 - age : int; (** The age threshold as a whole integer. *) 339 - } 340 - 341 - (** Jsont codec for {!type:config_region_rule_if_assured_over_age}. *) 342 - val config_region_rule_if_assured_over_age_jsont : config_region_rule_if_assured_over_age Jsont.t 343 - 344 - (** Age Assurance rule that applies if the account is older than a certain date. *) 345 - 346 - type config_region_rule_if_account_older_than = { 347 - access : access; 348 - date : string; (** The date threshold as a datetime string. *) 349 - } 350 - 351 - (** Jsont codec for {!type:config_region_rule_if_account_older_than}. *) 352 - val config_region_rule_if_account_older_than_jsont : config_region_rule_if_account_older_than Jsont.t 353 - 354 - (** Age Assurance rule that applies if the account is equal-to or newer than a certain date. *) 355 - 356 - type config_region_rule_if_account_newer_than = { 357 - access : access; 358 - date : string; (** The date threshold as a datetime string. *) 359 - } 360 - 361 - (** Jsont codec for {!type:config_region_rule_if_account_newer_than}. *) 362 - val config_region_rule_if_account_newer_than_jsont : config_region_rule_if_account_newer_than Jsont.t 363 - 364 - (** Age Assurance rule that applies by default. *) 365 - 366 - type config_region_rule_default = { 367 - access : access; 368 - } 369 - 370 - (** Jsont codec for {!type:config_region_rule_default}. *) 371 - val config_region_rule_default_jsont : config_region_rule_default Jsont.t 372 - 373 - 374 - type config = { 375 - regions : config_region list; (** The per-region Age Assurance configuration. *) 376 - } 377 - 378 - (** Jsont codec for {!type:config}. *) 379 - val config_jsont : config Jsont.t 380 - 381 - end 382 - module Begin : sig 383 - (** Initiate Age Assurance for an account. *) 384 - 385 - 386 - type input = { 387 - country_code : string; (** An ISO 3166-1 alpha-2 code of the user's location. *) 388 - email : string; (** The user's email address to receive Age Assurance instructions. *) 389 - language : string; (** The user's preferred language for communication during the Age Assurance process. *) 390 - region_code : string option; (** An optional ISO 3166-2 code of the user's region or state within the country. *) 391 - } 392 - 393 - (** Jsont codec for {!type:input}. *) 394 - val input_jsont : input Jsont.t 395 - 396 - 397 - type output = Defs.state 398 - 399 - (** Jsont codec for {!type:output}. *) 400 - val output_jsont : output Jsont.t 401 - 402 - end 403 - module GetState : sig 404 - (** Returns server-computed Age Assurance state, if available, and any additional metadata needed to compute Age Assurance state client-side. *) 405 - 406 - (** Query/procedure parameters. *) 407 - type params = { 408 - country_code : string; 409 - region_code : string option; 410 - } 411 - 412 - (** Jsont codec for {!type:params}. *) 413 - val params_jsont : params Jsont.t 414 - 415 - 416 - type output = { 417 - metadata : Defs.state_metadata; 418 - state : Defs.state; 419 - } 420 - 421 - (** Jsont codec for {!type:output}. *) 422 - val output_jsont : output Jsont.t 423 - 424 - end 425 - module GetConfig : sig 426 - (** Returns Age Assurance configuration for use on the client. *) 427 - 428 - 429 - type output = Defs.config 430 - 431 - (** Jsont codec for {!type:output}. *) 432 - val output_jsont : output Jsont.t 433 - 434 - end 435 - end 436 - module Labeler : sig 437 - module Defs : sig 438 - 439 - type labeler_viewer_state = { 440 - like : string option; 441 - } 442 - 443 - (** Jsont codec for {!type:labeler_viewer_state}. *) 444 - val labeler_viewer_state_jsont : labeler_viewer_state Jsont.t 445 - 446 - 447 - type labeler_policies = { 448 - label_value_definitions : Com.Atproto.Label.Defs.label_value_definition list option; (** Label values created by this labeler and scoped exclusively to it. Labels defined here will override global label definitions for this labeler. *) 449 - label_values : Com.Atproto.Label.Defs.label_value list; (** The label values which this labeler publishes. May include global or custom labels. *) 450 - } 451 - 452 - (** Jsont codec for {!type:labeler_policies}. *) 453 - val labeler_policies_jsont : labeler_policies Jsont.t 454 - 455 - 456 - type labeler_view_detailed = { 457 - cid : string; 458 - creator : Jsont.json; 459 - indexed_at : string; 460 - labels : Com.Atproto.Label.Defs.label list option; 461 - like_count : int option; 462 - policies : Jsont.json; 463 - reason_types : Com.Atproto.Moderation.Defs.reason_type list option; (** The set of report reason 'codes' which are in-scope for this service to review and action. These usually align to policy categories. If not defined (distinct from empty array), all reason types are allowed. *) 464 - subject_collections : string list option; (** Set of record types (collection NSIDs) which can be reported to this service. If not defined (distinct from empty array), default is any record type. *) 465 - subject_types : Com.Atproto.Moderation.Defs.subject_type list option; (** The set of subject types (account, record, etc) this service accepts reports on. *) 466 - uri : string; 467 - viewer : Jsont.json option; 468 - } 469 - 470 - (** Jsont codec for {!type:labeler_view_detailed}. *) 471 - val labeler_view_detailed_jsont : labeler_view_detailed Jsont.t 472 - 473 - 474 - type labeler_view = { 475 - cid : string; 476 - creator : Jsont.json; 477 - indexed_at : string; 478 - labels : Com.Atproto.Label.Defs.label list option; 479 - like_count : int option; 480 - uri : string; 481 - viewer : Jsont.json option; 482 - } 483 - 484 - (** Jsont codec for {!type:labeler_view}. *) 485 - val labeler_view_jsont : labeler_view Jsont.t 486 - 487 - end 488 - module Service : sig 489 - (** A declaration of the existence of labeler service. *) 490 - 491 - type main = { 492 - created_at : string; 493 - labels : Com.Atproto.Label.Defs.self_labels option; 494 - policies : Jsont.json; 495 - reason_types : Com.Atproto.Moderation.Defs.reason_type list option; (** The set of report reason 'codes' which are in-scope for this service to review and action. These usually align to policy categories. If not defined (distinct from empty array), all reason types are allowed. *) 496 - subject_collections : string list option; (** Set of record types (collection NSIDs) which can be reported to this service. If not defined (distinct from empty array), default is any record type. *) 497 - subject_types : Com.Atproto.Moderation.Defs.subject_type list option; (** The set of subject types (account, record, etc) this service accepts reports on. *) 498 - } 499 - 500 - (** Jsont codec for {!type:main}. *) 501 - val main_jsont : main Jsont.t 502 - 503 - end 504 - module GetServices : sig 505 - (** Get information about a list of labeler services. *) 506 - 507 - (** Query/procedure parameters. *) 508 - type params = { 509 - detailed : bool option; 510 - dids : string list; 511 - } 512 - 513 - (** Jsont codec for {!type:params}. *) 514 - val params_jsont : params Jsont.t 515 - 516 - 517 - type output = { 518 - views : Jsont.json list; 519 - } 520 - 521 - (** Jsont codec for {!type:output}. *) 522 - val output_jsont : output Jsont.t 523 - 524 - end 525 - end 526 - module AuthCreatePosts : sig 527 528 type main = unit 529 val main_jsont : main Jsont.t 530 531 end 532 - module Video : sig 533 - module GetUploadLimits : sig 534 - (** Get video upload limits for the authenticated user. *) 535 - 536 - 537 - type output = { 538 - can_upload : bool; 539 - error : string option; 540 - message : string option; 541 - remaining_daily_bytes : int option; 542 - remaining_daily_videos : int option; 543 - } 544 - 545 - (** Jsont codec for {!type:output}. *) 546 - val output_jsont : output Jsont.t 547 - 548 - end 549 - module Defs : sig 550 - 551 - type job_status = { 552 - blob : Atp.Blob_ref.t option; 553 - did : string; 554 - error : string option; 555 - job_id : string; 556 - message : string option; 557 - progress : int option; (** Progress within the current processing state. *) 558 - state : string; (** The state of the video processing job. All values not listed as a known value indicate that the job is in process. *) 559 - } 560 - 561 - (** Jsont codec for {!type:job_status}. *) 562 - val job_status_jsont : job_status Jsont.t 563 - 564 - end 565 - module UploadVideo : sig 566 - (** Upload a video to be processed then stored on the PDS. *) 567 - 568 - 569 - type input = unit 570 - val input_jsont : input Jsont.t 571 - 572 - 573 - type output = { 574 - job_status : Defs.job_status; 575 - } 576 - 577 - (** Jsont codec for {!type:output}. *) 578 - val output_jsont : output Jsont.t 579 - 580 - end 581 - module GetJobStatus : sig 582 - (** Get status details for a video processing job. *) 583 584 (** Query/procedure parameters. *) 585 type params = { 586 - job_id : string; 587 } 588 589 (** Jsont codec for {!type:params}. *) ··· 591 592 593 type output = { 594 - job_status : Defs.job_status; 595 } 596 597 (** Jsont codec for {!type:output}. *) 598 val output_jsont : output Jsont.t 599 600 end 601 - end 602 - module Embed : sig 603 - module External : sig 604 - 605 - type view_external = { 606 - description : string; 607 - thumb : string option; 608 - title : string; 609 - uri : string; 610 - } 611 - 612 - (** Jsont codec for {!type:view_external}. *) 613 - val view_external_jsont : view_external Jsont.t 614 - 615 - 616 - type external_ = { 617 - description : string; 618 - thumb : Atp.Blob_ref.t option; 619 - title : string; 620 - uri : string; 621 - } 622 - 623 - (** Jsont codec for {!type:external_}. *) 624 - val external__jsont : external_ Jsont.t 625 - 626 - 627 - type view = { 628 - external_ : Jsont.json; 629 - } 630 - 631 - (** Jsont codec for {!type:view}. *) 632 - val view_jsont : view Jsont.t 633 - 634 - (** A representation of some externally linked content (eg, a URL and 'card'), embedded in a Bluesky record (eg, a post). *) 635 - 636 - type main = { 637 - external_ : Jsont.json; 638 - } 639 - 640 - (** Jsont codec for {!type:main}. *) 641 - val main_jsont : main Jsont.t 642 - 643 - end 644 - module Defs : sig 645 - (** width:height represents an aspect ratio. It may be approximate, and may not correspond to absolute dimensions in any given unit. *) 646 - 647 - type aspect_ratio = { 648 - height : int; 649 - width : int; 650 - } 651 - 652 - (** Jsont codec for {!type:aspect_ratio}. *) 653 - val aspect_ratio_jsont : aspect_ratio Jsont.t 654 - 655 - end 656 - module Images : sig 657 - 658 - type view_image = { 659 - alt : string; (** Alt text description of the image, for accessibility. *) 660 - aspect_ratio : Jsont.json option; 661 - fullsize : string; (** Fully-qualified URL where a large version of the image can be fetched. May or may not be the exact original blob. For example, CDN location provided by the App View. *) 662 - thumb : string; (** Fully-qualified URL where a thumbnail of the image can be fetched. For example, CDN location provided by the App View. *) 663 - } 664 - 665 - (** Jsont codec for {!type:view_image}. *) 666 - val view_image_jsont : view_image Jsont.t 667 - 668 - 669 - type image = { 670 - alt : string; (** Alt text description of the image, for accessibility. *) 671 - aspect_ratio : Jsont.json option; 672 - image : Atp.Blob_ref.t; 673 - } 674 - 675 - (** Jsont codec for {!type:image}. *) 676 - val image_jsont : image Jsont.t 677 - 678 - 679 - type view = { 680 - images : Jsont.json list; 681 - } 682 - 683 - (** Jsont codec for {!type:view}. *) 684 - val view_jsont : view Jsont.t 685 - 686 - 687 - type main = { 688 - images : Jsont.json list; 689 - } 690 - 691 - (** Jsont codec for {!type:main}. *) 692 - val main_jsont : main Jsont.t 693 - 694 - end 695 - module Video : sig 696 - 697 - type view = { 698 - alt : string option; 699 - aspect_ratio : Jsont.json option; 700 - cid : string; 701 - playlist : string; 702 - thumbnail : string option; 703 - } 704 - 705 - (** Jsont codec for {!type:view}. *) 706 - val view_jsont : view Jsont.t 707 - 708 - 709 - type caption = { 710 - file : Atp.Blob_ref.t; 711 - lang : string; 712 - } 713 - 714 - (** Jsont codec for {!type:caption}. *) 715 - val caption_jsont : caption Jsont.t 716 - 717 - 718 - type main = { 719 - alt : string option; (** Alt text description of the video, for accessibility. *) 720 - aspect_ratio : Jsont.json option; 721 - captions : Jsont.json list option; 722 - video : Atp.Blob_ref.t; (** The mp4 video file. May be up to 100mb, formerly limited to 50mb. *) 723 - } 724 - 725 - (** Jsont codec for {!type:main}. *) 726 - val main_jsont : main Jsont.t 727 - 728 - end 729 - module RecordWithMedia : sig 730 - 731 - type view = { 732 - media : Jsont.json; 733 - record : Jsont.json; 734 - } 735 - 736 - (** Jsont codec for {!type:view}. *) 737 - val view_jsont : view Jsont.t 738 - 739 - 740 - type main = { 741 - media : Jsont.json; 742 - record : Jsont.json; 743 - } 744 - 745 - (** Jsont codec for {!type:main}. *) 746 - val main_jsont : main Jsont.t 747 - 748 - end 749 - module Record : sig 750 - 751 - type view_record = { 752 - author : Jsont.json; 753 - cid : string; 754 - embeds : Jsont.json list option; 755 - indexed_at : string; 756 - labels : Com.Atproto.Label.Defs.label list option; 757 - like_count : int option; 758 - quote_count : int option; 759 - reply_count : int option; 760 - repost_count : int option; 761 - uri : string; 762 - value : Jsont.json; (** The record data itself. *) 763 - } 764 - 765 - (** Jsont codec for {!type:view_record}. *) 766 - val view_record_jsont : view_record Jsont.t 767 - 768 - 769 - type view_not_found = { 770 - not_found : bool; 771 - uri : string; 772 - } 773 - 774 - (** Jsont codec for {!type:view_not_found}. *) 775 - val view_not_found_jsont : view_not_found Jsont.t 776 - 777 - 778 - type view_detached = { 779 - detached : bool; 780 - uri : string; 781 - } 782 - 783 - (** Jsont codec for {!type:view_detached}. *) 784 - val view_detached_jsont : view_detached Jsont.t 785 - 786 - 787 - type view_blocked = { 788 - author : Jsont.json; 789 - blocked : bool; 790 - uri : string; 791 - } 792 - 793 - (** Jsont codec for {!type:view_blocked}. *) 794 - val view_blocked_jsont : view_blocked Jsont.t 795 - 796 - 797 - type view = { 798 - record : Jsont.json; 799 - } 800 - 801 - (** Jsont codec for {!type:view}. *) 802 - val view_jsont : view Jsont.t 803 - 804 - 805 - type main = { 806 - record : Com.Atproto.Repo.StrongRef.main; 807 - } 808 - 809 - (** Jsont codec for {!type:main}. *) 810 - val main_jsont : main Jsont.t 811 - 812 - end 813 - end 814 - module Notification : sig 815 module UpdateSeen : sig 816 (** Notify server that the requesting account has seen notifications. Requires auth. *) 817 ··· 824 val input_jsont : input Jsont.t 825 826 end 827 - module RegisterPush : sig 828 - (** Register to receive push notifications, via a specified service, for the requesting account. Requires auth. *) 829 - 830 - 831 - type input = { 832 - age_restricted : bool option; (** Set to true when the actor is age restricted *) 833 - app_id : string; 834 - platform : string; 835 - service_did : string; 836 - token : string; 837 - } 838 - 839 - (** Jsont codec for {!type:input}. *) 840 - val input_jsont : input Jsont.t 841 - 842 - end 843 module ListNotifications : sig 844 845 type notification = { ··· 883 val output_jsont : output Jsont.t 884 885 end 886 - module GetUnreadCount : sig 887 - (** Count the number of unread notifications for the requesting account. Requires auth. *) 888 889 - (** Query/procedure parameters. *) 890 - type params = { 891 - priority : bool option; 892 - seen_at : string option; 893 } 894 895 - (** Jsont codec for {!type:params}. *) 896 - val params_jsont : params Jsont.t 897 898 899 - type output = { 900 - count : int; 901 } 902 903 - (** Jsont codec for {!type:output}. *) 904 - val output_jsont : output Jsont.t 905 906 end 907 - module UnregisterPush : sig 908 - (** The inverse of registerPush - inform a specified service that push notifications should no longer be sent to the given token for the requesting account. Requires auth. *) 909 910 911 type input = { 912 app_id : string; 913 platform : string; 914 service_did : string; ··· 919 val input_jsont : input Jsont.t 920 921 end 922 - module PutPreferences : sig 923 - (** Set notification-related preferences for an account. Requires auth. *) 924 925 926 type input = { 927 - priority : bool; 928 } 929 930 (** Jsont codec for {!type:input}. *) ··· 1004 1005 (** Jsont codec for {!type:preferences}. *) 1006 val preferences_jsont : preferences Jsont.t 1007 - 1008 - end 1009 - module Declaration : sig 1010 - (** A declaration of the user's choices related to notifications that can be produced by them. *) 1011 - 1012 - type main = { 1013 - allow_subscriptions : string; (** A declaration of the user's preference for allowing activity subscriptions from other users. Absence of a record implies 'followers'. *) 1014 - } 1015 - 1016 - (** Jsont codec for {!type:main}. *) 1017 - val main_jsont : main Jsont.t 1018 1019 end 1020 module ListActivitySubscriptions : sig ··· 1112 1113 end 1114 end 1115 module Actor : sig 1116 module Status : sig 1117 (** Advertises an account as currently offering live content. *) ··· 1126 duration_minutes : int option; (** The duration of the status in minutes. Applications can choose to impose minimum and maximum limits. *) 1127 embed : Jsont.json option; (** An optional embed associated with the status. *) 1128 status : string; (** The status for the account. *) 1129 - } 1130 - 1131 - (** Jsont codec for {!type:main}. *) 1132 - val main_jsont : main Jsont.t 1133 - 1134 - end 1135 - module Profile : sig 1136 - (** A declaration of a Bluesky account profile. *) 1137 - 1138 - type main = { 1139 - avatar : Atp.Blob_ref.t option; (** Small image to be displayed next to posts from account. AKA, 'profile picture' *) 1140 - banner : Atp.Blob_ref.t option; (** Larger horizontal image to display behind profile view. *) 1141 - created_at : string option; 1142 - description : string option; (** Free-form profile description text. *) 1143 - display_name : string option; 1144 - joined_via_starter_pack : Com.Atproto.Repo.StrongRef.main option; 1145 - labels : Com.Atproto.Label.Defs.self_labels option; (** Self-label values, specific to the Bluesky application, on the overall account. *) 1146 - pinned_post : Com.Atproto.Repo.StrongRef.main option; 1147 - pronouns : string option; (** Free-form pronouns text. *) 1148 - website : string option; 1149 } 1150 1151 (** Jsont codec for {!type:main}. *) ··· 1515 val known_followers_jsont : known_followers Jsont.t 1516 1517 end 1518 - module GetPreferences : sig 1519 - (** Get private preferences attached to the current account. Expected use is synchronization between multiple devices, and import/export during account migration. Requires auth. *) 1520 1521 - (** Query/procedure parameters. *) 1522 - type params = unit 1523 - 1524 - (** Jsont codec for {!type:params}. *) 1525 - val params_jsont : params Jsont.t 1526 - 1527 - 1528 - type output = { 1529 - preferences : Jsont.json; 1530 } 1531 1532 - (** Jsont codec for {!type:output}. *) 1533 - val output_jsont : output Jsont.t 1534 1535 end 1536 - module SearchActorsTypeahead : sig 1537 - (** Find actor suggestions for a prefix search term. Expected use is for auto-completion during text field entry. Does not require auth. *) 1538 1539 (** Query/procedure parameters. *) 1540 type params = { 1541 - limit : int option; 1542 - q : string option; (** Search query prefix; not a full query string. *) 1543 - term : string option; (** DEPRECATED: use 'q' instead. *) 1544 } 1545 1546 (** Jsont codec for {!type:params}. *) ··· 1548 1549 1550 type output = { 1551 - actors : Jsont.json list; 1552 } 1553 1554 (** Jsont codec for {!type:output}. *) 1555 val output_jsont : output Jsont.t 1556 1557 end 1558 - module GetProfile : sig 1559 - (** Get detailed profile view of an actor. Does not require auth, but contains relevant metadata with auth. *) 1560 1561 (** Query/procedure parameters. *) 1562 - type params = { 1563 - actor : string; (** Handle or DID of account to fetch profile of. *) 1564 - } 1565 1566 (** Jsont codec for {!type:params}. *) 1567 val params_jsont : params Jsont.t 1568 1569 1570 - type output = Jsont.json 1571 1572 (** Jsont codec for {!type:output}. *) 1573 val output_jsont : output Jsont.t 1574 1575 end 1576 - module SearchActors : sig 1577 - (** Find actors (profiles) matching search criteria. Does not require auth. *) 1578 1579 (** Query/procedure parameters. *) 1580 type params = { 1581 cursor : string option; 1582 limit : int option; 1583 - q : string option; (** Search query string. Syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended. *) 1584 - term : string option; (** DEPRECATED: use 'q' instead. *) 1585 } 1586 1587 (** Jsont codec for {!type:params}. *) ··· 1591 type output = { 1592 actors : Jsont.json list; 1593 cursor : string option; 1594 } 1595 1596 (** Jsont codec for {!type:output}. *) 1597 val output_jsont : output Jsont.t 1598 1599 end 1600 - module GetSuggestions : sig 1601 - (** Get a list of suggested actors. Expected use is discovery of accounts to follow during new account onboarding. *) 1602 1603 (** Query/procedure parameters. *) 1604 type params = { 1605 - cursor : string option; 1606 - limit : int option; 1607 } 1608 1609 (** Jsont codec for {!type:params}. *) 1610 val params_jsont : params Jsont.t 1611 1612 1613 - type output = { 1614 - actors : Jsont.json list; 1615 - cursor : string option; 1616 - rec_id : int option; (** Snowflake for this recommendation, use when submitting recommendation events. *) 1617 - } 1618 1619 (** Jsont codec for {!type:output}. *) 1620 val output_jsont : output Jsont.t 1621 1622 end 1623 - module GetProfiles : sig 1624 - (** Get detailed profile views of multiple actors. *) 1625 1626 (** Query/procedure parameters. *) 1627 type params = { 1628 - actors : string list; 1629 } 1630 1631 (** Jsont codec for {!type:params}. *) ··· 1633 1634 1635 type output = { 1636 - profiles : Jsont.json list; 1637 } 1638 1639 (** Jsont codec for {!type:output}. *) ··· 1652 val input_jsont : input Jsont.t 1653 1654 end 1655 - end 1656 - module Contact : sig 1657 - module Defs : sig 1658 1659 - type sync_status = { 1660 - matches_count : int; (** Number of existing contact matches resulting of the user imports and of their imported contacts having imported the user. Matches stop being counted when the user either follows the matched contact or dismisses the match. *) 1661 - synced_at : string; (** Last date when contacts where imported. *) 1662 } 1663 1664 - (** Jsont codec for {!type:sync_status}. *) 1665 - val sync_status_jsont : sync_status Jsont.t 1666 1667 - (** A stash object to be sent via bsync representing a notification to be created. *) 1668 1669 - type notification = { 1670 - from : string; (** The DID of who this notification comes from. *) 1671 - to_ : string; (** The DID of who this notification should go to. *) 1672 - } 1673 - 1674 - (** Jsont codec for {!type:notification}. *) 1675 - val notification_jsont : notification Jsont.t 1676 - 1677 - (** Associates a profile with the positional index of the contact import input in the call to `app.bsky.contact.importContacts`, so clients can know which phone caused a particular match. *) 1678 - 1679 - type match_and_contact_index = { 1680 - contact_index : int; (** The index of this match in the import contact input. *) 1681 - match_ : Jsont.json; (** Profile of the matched user. *) 1682 } 1683 1684 - (** Jsont codec for {!type:match_and_contact_index}. *) 1685 - val match_and_contact_index_jsont : match_and_contact_index Jsont.t 1686 1687 end 1688 - module RemoveData : sig 1689 - (** Removes all stored hashes used for contact matching, existing matches, and sync status. Requires authentication. *) 1690 - 1691 - 1692 - type input = unit 1693 - 1694 - (** Jsont codec for {!type:input}. *) 1695 - val input_jsont : input Jsont.t 1696 1697 1698 - type output = unit 1699 1700 (** Jsont codec for {!type:output}. *) 1701 val output_jsont : output Jsont.t 1702 1703 end 1704 - module DismissMatch : sig 1705 - (** Removes a match that was found via contact import. It shouldn't appear again if the same contact is re-imported. Requires authentication. *) 1706 - 1707 1708 - type input = { 1709 - subject : string; (** The subject's DID to dismiss the match with. *) 1710 } 1711 1712 - (** Jsont codec for {!type:input}. *) 1713 - val input_jsont : input Jsont.t 1714 - 1715 - 1716 - type output = unit 1717 - 1718 - (** Jsont codec for {!type:output}. *) 1719 - val output_jsont : output Jsont.t 1720 1721 end 1722 - module GetMatches : sig 1723 - (** Returns the matched contacts (contacts that were mutually imported). Excludes dismissed matches. Requires authentication. *) 1724 1725 (** Query/procedure parameters. *) 1726 type params = { 1727 - cursor : string option; 1728 - limit : int option; 1729 } 1730 1731 (** Jsont codec for {!type:params}. *) ··· 1733 1734 1735 type output = { 1736 - cursor : string option; 1737 - matches : Jsont.json list; 1738 } 1739 1740 (** Jsont codec for {!type:output}. *) 1741 val output_jsont : output Jsont.t 1742 1743 end 1744 - module VerifyPhone : sig 1745 - (** Verifies control over a phone number with a code received via SMS and starts a contact import session. Requires authentication. *) 1746 1747 1748 - type input = { 1749 - code : string; (** The code received via SMS as a result of the call to `app.bsky.contact.startPhoneVerification`. *) 1750 - phone : string; (** The phone number to verify. Should be the same as the one passed to `app.bsky.contact.startPhoneVerification`. *) 1751 - } 1752 - 1753 - (** Jsont codec for {!type:input}. *) 1754 val input_jsont : input Jsont.t 1755 1756 1757 type output = { 1758 - token : string; (** JWT to be used in a call to `app.bsky.contact.importContacts`. It is only valid for a single call. *) 1759 } 1760 1761 (** Jsont codec for {!type:output}. *) 1762 val output_jsont : output Jsont.t 1763 1764 end 1765 - module StartPhoneVerification : sig 1766 - (** Starts a phone verification flow. The phone passed will receive a code via SMS that should be passed to `app.bsky.contact.verifyPhone`. Requires authentication. *) 1767 1768 1769 - type input = { 1770 - phone : string; (** The phone number to receive the code via SMS. *) 1771 } 1772 1773 - (** Jsont codec for {!type:input}. *) 1774 - val input_jsont : input Jsont.t 1775 1776 1777 - type output = unit 1778 1779 - (** Jsont codec for {!type:output}. *) 1780 - val output_jsont : output Jsont.t 1781 1782 - end 1783 - module SendNotification : sig 1784 - (** System endpoint to send notifications related to contact imports. Requires role authentication. *) 1785 1786 - 1787 - type input = { 1788 - from : string; (** The DID of who this notification comes from. *) 1789 - to_ : string; (** The DID of who this notification should go to. *) 1790 } 1791 1792 - (** Jsont codec for {!type:input}. *) 1793 - val input_jsont : input Jsont.t 1794 1795 1796 - type output = unit 1797 1798 - (** Jsont codec for {!type:output}. *) 1799 - val output_jsont : output Jsont.t 1800 1801 end 1802 - module GetSyncStatus : sig 1803 - (** Gets the user's current contact import status. Requires authentication. *) 1804 1805 - (** Query/procedure parameters. *) 1806 - type params = unit 1807 1808 - (** Jsont codec for {!type:params}. *) 1809 - val params_jsont : params Jsont.t 1810 1811 1812 - type output = { 1813 - sync_status : Defs.sync_status option; (** If present, indicates the user has imported their contacts. If not present, indicates the user never used the feature or called `app.bsky.contact.removeData` and didn't import again since. *) 1814 } 1815 1816 - (** Jsont codec for {!type:output}. *) 1817 - val output_jsont : output Jsont.t 1818 1819 - end 1820 - module ImportContacts : sig 1821 - (** Import contacts for securely matching with other users. This follows the protocol explained in https://docs.bsky.app/blog/contact-import-rfc. Requires authentication. *) 1822 1823 - 1824 - type input = { 1825 - contacts : string list; (** List of phone numbers in global E.164 format (e.g., '+12125550123'). Phone numbers that cannot be normalized into a valid phone number will be discarded. Should not repeat the 'phone' input used in `app.bsky.contact.verifyPhone`. *) 1826 - token : string; (** JWT to authenticate the call. Use the JWT received as a response to the call to `app.bsky.contact.verifyPhone`. *) 1827 } 1828 1829 - (** Jsont codec for {!type:input}. *) 1830 - val input_jsont : input Jsont.t 1831 1832 1833 - type output = { 1834 - matches_and_contact_indexes : Defs.match_and_contact_index list; (** The users that matched during import and their indexes on the input contacts, so the client can correlate with its local list. *) 1835 } 1836 1837 - (** Jsont codec for {!type:output}. *) 1838 - val output_jsont : output Jsont.t 1839 1840 - end 1841 - end 1842 - module Graph : sig 1843 - module Starterpack : sig 1844 1845 - type feed_item = { 1846 - uri : string; 1847 } 1848 1849 - (** Jsont codec for {!type:feed_item}. *) 1850 - val feed_item_jsont : feed_item Jsont.t 1851 1852 - (** Record defining a starter pack of actors and feeds for new users. *) 1853 1854 - type main = { 1855 - created_at : string; 1856 - description : string option; 1857 - description_facets : Richtext.Facet.main list option; 1858 - feeds : Jsont.json list option; 1859 - list_ : string; (** Reference (AT-URI) to the list record. *) 1860 - name : string; (** Display name for starter pack; can not be empty. *) 1861 } 1862 1863 - (** Jsont codec for {!type:main}. *) 1864 - val main_jsont : main Jsont.t 1865 1866 - end 1867 - module GetFollows : sig 1868 - (** Enumerates accounts which a specified account (actor) follows. *) 1869 1870 - (** Query/procedure parameters. *) 1871 - type params = { 1872 - actor : string; 1873 - cursor : string option; 1874 - limit : int option; 1875 } 1876 1877 - (** Jsont codec for {!type:params}. *) 1878 - val params_jsont : params Jsont.t 1879 1880 1881 - type output = { 1882 - cursor : string option; 1883 - follows : Jsont.json list; 1884 - subject : Jsont.json; 1885 } 1886 1887 - (** Jsont codec for {!type:output}. *) 1888 - val output_jsont : output Jsont.t 1889 1890 - end 1891 - module GetSuggestedFollowsByActor : sig 1892 - (** Enumerates follows similar to a given account (actor). Expected use is to recommend additional accounts immediately after following one account. *) 1893 1894 - (** Query/procedure parameters. *) 1895 - type params = { 1896 - actor : string; 1897 } 1898 1899 - (** Jsont codec for {!type:params}. *) 1900 - val params_jsont : params Jsont.t 1901 1902 1903 - type output = { 1904 - is_fallback : bool option; (** If true, response has fallen-back to generic results, and is not scoped using relativeToDid *) 1905 - rec_id : int option; (** Snowflake for this recommendation, use when submitting recommendation events. *) 1906 - suggestions : Jsont.json list; 1907 } 1908 1909 - (** Jsont codec for {!type:output}. *) 1910 - val output_jsont : output Jsont.t 1911 1912 - end 1913 - module Block : sig 1914 - (** Record declaring a 'block' relationship against another account. NOTE: blocks are public in Bluesky; see blog posts for details. *) 1915 1916 - type main = { 1917 - created_at : string; 1918 - subject : string; (** DID of the account to be blocked. *) 1919 } 1920 1921 - (** Jsont codec for {!type:main}. *) 1922 - val main_jsont : main Jsont.t 1923 1924 - end 1925 - module Listblock : sig 1926 - (** Record representing a block relationship against an entire an entire list of accounts (actors). *) 1927 1928 - type main = { 1929 - created_at : string; 1930 - subject : string; (** Reference (AT-URI) to the mod list record. *) 1931 } 1932 1933 - (** Jsont codec for {!type:main}. *) 1934 - val main_jsont : main Jsont.t 1935 1936 - end 1937 - module MuteThread : sig 1938 - (** Mutes a thread preventing notifications from the thread and any of its children. Mutes are private in Bluesky. Requires auth. *) 1939 1940 - 1941 - type input = { 1942 - root : string; 1943 } 1944 1945 - (** Jsont codec for {!type:input}. *) 1946 - val input_jsont : input Jsont.t 1947 1948 end 1949 - module GetFollowers : sig 1950 - (** Enumerates accounts which follow a specified account (actor). *) 1951 1952 (** Query/procedure parameters. *) 1953 type params = { 1954 - actor : string; 1955 - cursor : string option; 1956 - limit : int option; 1957 } 1958 1959 (** Jsont codec for {!type:params}. *) ··· 1961 1962 1963 type output = { 1964 - cursor : string option; 1965 - followers : Jsont.json list; 1966 - subject : Jsont.json; 1967 } 1968 1969 (** Jsont codec for {!type:output}. *) 1970 val output_jsont : output Jsont.t 1971 1972 end 1973 - module UnmuteThread : sig 1974 - (** Unmutes the specified thread. Requires auth. *) 1975 1976 1977 type input = { 1978 - root : string; 1979 } 1980 1981 (** Jsont codec for {!type:input}. *) 1982 val input_jsont : input Jsont.t 1983 1984 - end 1985 - module Follow : sig 1986 - (** Record declaring a social 'follow' relationship of another account. Duplicate follows will be ignored by the AppView. *) 1987 1988 - type main = { 1989 - created_at : string; 1990 - subject : string; 1991 - via : Com.Atproto.Repo.StrongRef.main option; 1992 - } 1993 1994 - (** Jsont codec for {!type:main}. *) 1995 - val main_jsont : main Jsont.t 1996 1997 end 1998 - module UnmuteActor : sig 1999 - (** Unmutes the specified account. Requires auth. *) 2000 2001 2002 - type input = { 2003 - actor : string; 2004 - } 2005 - 2006 - (** Jsont codec for {!type:input}. *) 2007 - val input_jsont : input Jsont.t 2008 - 2009 - end 2010 - module MuteActorList : sig 2011 - (** Creates a mute relationship for the specified list of accounts. Mutes are private in Bluesky. Requires auth. *) 2012 - 2013 - 2014 - type input = { 2015 - list_ : string; 2016 - } 2017 2018 - (** Jsont codec for {!type:input}. *) 2019 - val input_jsont : input Jsont.t 2020 2021 end 2022 - module UnmuteActorList : sig 2023 - (** Unmutes the specified list of accounts. Requires auth. *) 2024 - 2025 2026 - type input = { 2027 - list_ : string; 2028 } 2029 2030 - (** Jsont codec for {!type:input}. *) 2031 - val input_jsont : input Jsont.t 2032 2033 end 2034 - module GetKnownFollowers : sig 2035 - (** Enumerates accounts which follow a specified account (actor) and are followed by the viewer. *) 2036 2037 - (** Query/procedure parameters. *) 2038 - type params = { 2039 - actor : string; 2040 - cursor : string option; 2041 - limit : int option; 2042 } 2043 2044 - (** Jsont codec for {!type:params}. *) 2045 - val params_jsont : params Jsont.t 2046 2047 2048 - type output = { 2049 - cursor : string option; 2050 - followers : Jsont.json list; 2051 - subject : Jsont.json; 2052 } 2053 2054 - (** Jsont codec for {!type:output}. *) 2055 - val output_jsont : output Jsont.t 2056 - 2057 - end 2058 - module MuteActor : sig 2059 - (** Creates a mute relationship for the specified account. Mutes are private in Bluesky. Requires auth. *) 2060 2061 2062 - type input = { 2063 - actor : string; 2064 } 2065 2066 - (** Jsont codec for {!type:input}. *) 2067 - val input_jsont : input Jsont.t 2068 2069 - end 2070 - module Listitem : sig 2071 - (** Record representing an account's inclusion on a specific list. The AppView will ignore duplicate listitem records. *) 2072 2073 type main = { 2074 - created_at : string; 2075 - list_ : string; (** Reference (AT-URI) to the list record (app.bsky.graph.list). *) 2076 - subject : string; (** The account which is included on the list. *) 2077 } 2078 2079 (** Jsont codec for {!type:main}. *) 2080 val main_jsont : main Jsont.t 2081 2082 end 2083 - module Defs : sig 2084 2085 - type starter_pack_view_basic = { 2086 - cid : string; 2087 - creator : Jsont.json; 2088 - indexed_at : string; 2089 - joined_all_time_count : int option; 2090 - joined_week_count : int option; 2091 - labels : Com.Atproto.Label.Defs.label list option; 2092 - list_item_count : int option; 2093 - record : Jsont.json; 2094 - uri : string; 2095 } 2096 2097 - (** Jsont codec for {!type:starter_pack_view_basic}. *) 2098 - val starter_pack_view_basic_jsont : starter_pack_view_basic Jsont.t 2099 2100 - (** lists the bi-directional graph relationships between one actor (not indicated in the object), and the target actors (the DID included in the object) *) 2101 2102 - type relationship = { 2103 - blocked_by : string option; (** if the actor is blocked by this DID, contains the AT-URI of the block record *) 2104 - blocked_by_list : string option; (** if the actor is blocked by this DID via a block list, contains the AT-URI of the listblock record *) 2105 - blocking : string option; (** if the actor blocks this DID, this is the AT-URI of the block record *) 2106 - blocking_by_list : string option; (** if the actor blocks this DID via a block list, this is the AT-URI of the listblock record *) 2107 - did : string; 2108 - followed_by : string option; (** if the actor is followed by this DID, contains the AT-URI of the follow record *) 2109 - following : string option; (** if the actor follows this DID, this is the AT-URI of the follow record *) 2110 } 2111 2112 - (** Jsont codec for {!type:relationship}. *) 2113 - val relationship_jsont : relationship Jsont.t 2114 2115 - (** A list of actors used for only for reference purposes such as within a starter pack. *) 2116 2117 - type referencelist = string 2118 - val referencelist_jsont : referencelist Jsont.t 2119 2120 - (** indicates that a handle or DID could not be resolved *) 2121 2122 - type not_found_actor = { 2123 - actor : string; 2124 - not_found : bool; 2125 } 2126 2127 - (** Jsont codec for {!type:not_found_actor}. *) 2128 - val not_found_actor_jsont : not_found_actor Jsont.t 2129 2130 - (** A list of actors to apply an aggregate moderation action (mute/block) on. *) 2131 2132 - type modlist = string 2133 - val modlist_jsont : modlist Jsont.t 2134 2135 2136 - type list_viewer_state = { 2137 - blocked : string option; 2138 - muted : bool option; 2139 } 2140 2141 - (** Jsont codec for {!type:list_viewer_state}. *) 2142 - val list_viewer_state_jsont : list_viewer_state Jsont.t 2143 2144 2145 - type list_purpose = string 2146 - val list_purpose_jsont : list_purpose Jsont.t 2147 2148 2149 - type list_item_view = { 2150 - subject : Jsont.json; 2151 - uri : string; 2152 } 2153 2154 - (** Jsont codec for {!type:list_item_view}. *) 2155 - val list_item_view_jsont : list_item_view Jsont.t 2156 2157 - (** A list of actors used for curation purposes such as list feeds or interaction gating. *) 2158 2159 - type curatelist = string 2160 - val curatelist_jsont : curatelist Jsont.t 2161 2162 2163 - type list_view_basic = { 2164 - avatar : string option; 2165 cid : string; 2166 - indexed_at : string option; 2167 labels : Com.Atproto.Label.Defs.label list option; 2168 - list_item_count : int option; 2169 - name : string; 2170 - purpose : Jsont.json; 2171 uri : string; 2172 - viewer : Jsont.json option; 2173 } 2174 2175 - (** Jsont codec for {!type:list_view_basic}. *) 2176 - val list_view_basic_jsont : list_view_basic Jsont.t 2177 2178 2179 - type list_view = { 2180 - avatar : string option; 2181 - cid : string; 2182 - creator : Jsont.json; 2183 - description : string option; 2184 - description_facets : Richtext.Facet.main list option; 2185 - indexed_at : string; 2186 - labels : Com.Atproto.Label.Defs.label list option; 2187 - list_item_count : int option; 2188 - name : string; 2189 - purpose : Jsont.json; 2190 uri : string; 2191 - viewer : Jsont.json option; 2192 } 2193 2194 - (** Jsont codec for {!type:list_view}. *) 2195 - val list_view_jsont : list_view Jsont.t 2196 2197 2198 - type starter_pack_view = { 2199 - cid : string; 2200 - creator : Jsont.json; 2201 - feeds : Jsont.json list option; 2202 - indexed_at : string; 2203 - joined_all_time_count : int option; 2204 - joined_week_count : int option; 2205 - labels : Com.Atproto.Label.Defs.label list option; 2206 - list_ : Jsont.json option; 2207 - list_items_sample : Jsont.json list option; 2208 - record : Jsont.json; 2209 uri : string; 2210 } 2211 2212 - (** Jsont codec for {!type:starter_pack_view}. *) 2213 - val starter_pack_view_jsont : starter_pack_view Jsont.t 2214 2215 - end 2216 - module GetBlocks : sig 2217 - (** Enumerates which accounts the requesting account is currently blocking. Requires auth. *) 2218 2219 - (** Query/procedure parameters. *) 2220 - type params = { 2221 - cursor : string option; 2222 - limit : int option; 2223 } 2224 2225 - (** Jsont codec for {!type:params}. *) 2226 - val params_jsont : params Jsont.t 2227 2228 2229 - type output = { 2230 - blocks : Jsont.json list; 2231 - cursor : string option; 2232 } 2233 2234 - (** Jsont codec for {!type:output}. *) 2235 - val output_jsont : output Jsont.t 2236 2237 - end 2238 - module Verification : sig 2239 - (** Record declaring a verification relationship between two accounts. Verifications are only considered valid by an app if issued by an account the app considers trusted. *) 2240 2241 type main = { 2242 - created_at : string; (** Date of when the verification was created. *) 2243 - display_name : string; (** Display name of the subject the verification applies to at the moment of verifying, which might not be the same at the time of viewing. The verification is only valid if the current displayName matches the one at the time of verifying. *) 2244 - handle : string; (** Handle of the subject the verification applies to at the moment of verifying, which might not be the same at the time of viewing. The verification is only valid if the current handle matches the one at the time of verifying. *) 2245 - subject : string; (** DID of the subject the verification applies to. *) 2246 } 2247 2248 (** Jsont codec for {!type:main}. *) 2249 val main_jsont : main Jsont.t 2250 2251 end 2252 - module GetMutes : sig 2253 - (** Enumerates accounts that the requesting account (actor) currently has muted. Requires auth. *) 2254 2255 - (** Query/procedure parameters. *) 2256 - type params = { 2257 - cursor : string option; 2258 - limit : int option; 2259 } 2260 2261 - (** Jsont codec for {!type:params}. *) 2262 - val params_jsont : params Jsont.t 2263 2264 2265 - type output = { 2266 - cursor : string option; 2267 - mutes : Jsont.json list; 2268 - } 2269 2270 (** Jsont codec for {!type:output}. *) 2271 val output_jsont : output Jsont.t 2272 2273 end 2274 - module GetRelationships : sig 2275 - (** Enumerates public relationships between one account, and a list of other accounts. Does not require auth. *) 2276 2277 - (** Query/procedure parameters. *) 2278 - type params = { 2279 - actor : string; (** Primary account requesting relationships for. *) 2280 - others : string list option; (** List of 'other' accounts to be related back to the primary. *) 2281 } 2282 2283 - (** Jsont codec for {!type:params}. *) 2284 - val params_jsont : params Jsont.t 2285 2286 2287 - type output = { 2288 - actor : string option; 2289 - relationships : Jsont.json list; 2290 - } 2291 2292 (** Jsont codec for {!type:output}. *) 2293 val output_jsont : output Jsont.t 2294 2295 end 2296 - module GetStarterPacksWithMembership : sig 2297 - (** A starter pack and an optional list item indicating membership of a target user to that starter pack. *) 2298 - 2299 - type starter_pack_with_membership = { 2300 - list_item : Jsont.json option; 2301 - starter_pack : Jsont.json; 2302 - } 2303 - 2304 - (** Jsont codec for {!type:starter_pack_with_membership}. *) 2305 - val starter_pack_with_membership_jsont : starter_pack_with_membership Jsont.t 2306 - 2307 - (** Enumerates the starter packs created by the session user, and includes membership information about `actor` in those starter packs. Requires auth. *) 2308 2309 (** Query/procedure parameters. *) 2310 type params = { 2311 - actor : string; (** The account (actor) to check for membership. *) 2312 cursor : string option; 2313 limit : int option; 2314 } ··· 2319 2320 type output = { 2321 cursor : string option; 2322 - starter_packs_with_membership : Jsont.json list; 2323 } 2324 2325 (** Jsont codec for {!type:output}. *) 2326 val output_jsont : output Jsont.t 2327 2328 end 2329 - module GetActorStarterPacks : sig 2330 - (** Get a list of starter packs created by the actor. *) 2331 2332 - (** Query/procedure parameters. *) 2333 - type params = { 2334 - actor : string; 2335 - cursor : string option; 2336 - limit : int option; 2337 } 2338 2339 - (** Jsont codec for {!type:params}. *) 2340 - val params_jsont : params Jsont.t 2341 2342 2343 type output = { 2344 - cursor : string option; 2345 - starter_packs : Jsont.json list; 2346 } 2347 2348 (** Jsont codec for {!type:output}. *) 2349 val output_jsont : output Jsont.t 2350 2351 end 2352 - module List : sig 2353 - (** Record representing a list of accounts (actors). Scope includes both moderation-oriented lists and curration-oriented lists. *) 2354 - 2355 - type main = { 2356 - avatar : Atp.Blob_ref.t option; 2357 - created_at : string; 2358 - description : string option; 2359 - description_facets : Richtext.Facet.main list option; 2360 - labels : Com.Atproto.Label.Defs.self_labels option; 2361 - name : string; (** Display name for list; can not be empty. *) 2362 - purpose : Jsont.json; (** Defines the purpose of the list (aka, moderation-oriented or curration-oriented) *) 2363 - } 2364 2365 - (** Jsont codec for {!type:main}. *) 2366 - val main_jsont : main Jsont.t 2367 2368 - end 2369 - module SearchStarterPacks : sig 2370 - (** Find starter packs matching search criteria. Does not require auth. *) 2371 2372 - (** Query/procedure parameters. *) 2373 - type params = { 2374 - cursor : string option; 2375 - limit : int option; 2376 - q : string; (** Search query string. Syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended. *) 2377 - } 2378 - 2379 - (** Jsont codec for {!type:params}. *) 2380 - val params_jsont : params Jsont.t 2381 2382 2383 - type output = { 2384 - cursor : string option; 2385 - starter_packs : Jsont.json list; 2386 - } 2387 2388 (** Jsont codec for {!type:output}. *) 2389 val output_jsont : output Jsont.t 2390 2391 end 2392 - module GetList : sig 2393 - (** Gets a 'view' (with additional context) of a specified list. *) 2394 2395 - (** Query/procedure parameters. *) 2396 - type params = { 2397 - cursor : string option; 2398 - limit : int option; 2399 - list_ : string; (** Reference (AT-URI) of the list record to hydrate. *) 2400 } 2401 2402 - (** Jsont codec for {!type:params}. *) 2403 - val params_jsont : params Jsont.t 2404 2405 2406 - type output = { 2407 - cursor : string option; 2408 - items : Jsont.json list; 2409 - list_ : Jsont.json; 2410 } 2411 2412 - (** Jsont codec for {!type:output}. *) 2413 - val output_jsont : output Jsont.t 2414 2415 end 2416 - module GetListBlocks : sig 2417 - (** Get mod lists that the requesting account (actor) is blocking. Requires auth. *) 2418 2419 - (** Query/procedure parameters. *) 2420 - type params = { 2421 - cursor : string option; 2422 - limit : int option; 2423 } 2424 2425 - (** Jsont codec for {!type:params}. *) 2426 - val params_jsont : params Jsont.t 2427 2428 2429 - type output = { 2430 - cursor : string option; 2431 - lists : Jsont.json list; 2432 - } 2433 2434 (** Jsont codec for {!type:output}. *) 2435 val output_jsont : output Jsont.t 2436 2437 end 2438 - module GetStarterPack : sig 2439 - (** Gets a view of a starter pack. *) 2440 2441 (** Query/procedure parameters. *) 2442 - type params = { 2443 - starter_pack : string; (** Reference (AT-URI) of the starter pack record. *) 2444 - } 2445 2446 (** Jsont codec for {!type:params}. *) 2447 val params_jsont : params Jsont.t 2448 2449 2450 type output = { 2451 - starter_pack : Jsont.json; 2452 } 2453 2454 (** Jsont codec for {!type:output}. *) 2455 val output_jsont : output Jsont.t 2456 2457 end 2458 - module GetListsWithMembership : sig 2459 - (** A list and an optional list item indicating membership of a target user to that list. *) 2460 2461 - type list_with_membership = { 2462 - list_ : Jsont.json; 2463 - list_item : Jsont.json option; 2464 - } 2465 2466 - (** Jsont codec for {!type:list_with_membership}. *) 2467 - val list_with_membership_jsont : list_with_membership Jsont.t 2468 - 2469 - (** Enumerates the lists created by the session user, and includes membership information about `actor` in those lists. Only supports curation and moderation lists (no reference lists, used in starter packs). Requires auth. *) 2470 - 2471 - (** Query/procedure parameters. *) 2472 - type params = { 2473 - actor : string; (** The account (actor) to check for membership. *) 2474 - cursor : string option; 2475 - limit : int option; 2476 - purposes : string list option; (** Optional filter by list purpose. If not specified, all supported types are returned. *) 2477 } 2478 2479 - (** Jsont codec for {!type:params}. *) 2480 - val params_jsont : params Jsont.t 2481 2482 2483 type output = { 2484 - cursor : string option; 2485 - lists_with_membership : Jsont.json list; 2486 } 2487 2488 (** Jsont codec for {!type:output}. *) 2489 val output_jsont : output Jsont.t 2490 2491 end 2492 - module GetListMutes : sig 2493 - (** Enumerates mod lists that the requesting account (actor) currently has muted. Requires auth. *) 2494 2495 - (** Query/procedure parameters. *) 2496 - type params = { 2497 - cursor : string option; 2498 - limit : int option; 2499 } 2500 2501 - (** Jsont codec for {!type:params}. *) 2502 - val params_jsont : params Jsont.t 2503 2504 2505 - type output = { 2506 - cursor : string option; 2507 - lists : Jsont.json list; 2508 } 2509 2510 - (** Jsont codec for {!type:output}. *) 2511 - val output_jsont : output Jsont.t 2512 2513 - end 2514 - module GetStarterPacks : sig 2515 - (** Get views for a list of starter packs. *) 2516 2517 - (** Query/procedure parameters. *) 2518 - type params = { 2519 - uris : string list; 2520 } 2521 2522 - (** Jsont codec for {!type:params}. *) 2523 - val params_jsont : params Jsont.t 2524 2525 2526 type output = { 2527 - starter_packs : Jsont.json list; 2528 } 2529 2530 (** Jsont codec for {!type:output}. *) 2531 val output_jsont : output Jsont.t 2532 2533 end 2534 - module GetLists : sig 2535 - (** Enumerates the lists created by a specified account (actor). *) 2536 2537 - (** Query/procedure parameters. *) 2538 - type params = { 2539 - actor : string; (** The account (actor) to enumerate lists from. *) 2540 - cursor : string option; 2541 - limit : int option; 2542 - purposes : string list option; (** Optional filter by list purpose. If not specified, all supported types are returned. *) 2543 - } 2544 2545 - (** Jsont codec for {!type:params}. *) 2546 - val params_jsont : params Jsont.t 2547 2548 2549 - type output = { 2550 - cursor : string option; 2551 - lists : Jsont.json list; 2552 } 2553 2554 - (** Jsont codec for {!type:output}. *) 2555 - val output_jsont : output Jsont.t 2556 2557 - end 2558 - end 2559 - module Feed : sig 2560 - module Post : sig 2561 - (** Deprecated. Use app.bsky.richtext instead -- A text segment. Start is inclusive, end is exclusive. Indices are for utf16-encoded strings. *) 2562 2563 - type text_slice = { 2564 - end_ : int; 2565 - start : int; 2566 - } 2567 2568 - (** Jsont codec for {!type:text_slice}. *) 2569 - val text_slice_jsont : text_slice Jsont.t 2570 2571 2572 - type reply_ref = { 2573 - parent : Com.Atproto.Repo.StrongRef.main; 2574 - root : Com.Atproto.Repo.StrongRef.main; 2575 - } 2576 2577 - (** Jsont codec for {!type:reply_ref}. *) 2578 - val reply_ref_jsont : reply_ref Jsont.t 2579 2580 - (** Deprecated: use facets instead. *) 2581 2582 - type entity = { 2583 - index : Jsont.json; 2584 - type_ : string; (** Expected values are 'mention' and 'link'. *) 2585 - value : string; 2586 } 2587 2588 - (** Jsont codec for {!type:entity}. *) 2589 - val entity_jsont : entity Jsont.t 2590 2591 - (** Record containing a Bluesky post. *) 2592 2593 type main = { 2594 - created_at : string; (** Client-declared timestamp when this post was originally created. *) 2595 - embed : Jsont.json option; 2596 - entities : Jsont.json list option; (** DEPRECATED: replaced by app.bsky.richtext.facet. *) 2597 - facets : Richtext.Facet.main list option; (** Annotations of text (mentions, URLs, hashtags, etc) *) 2598 - labels : Com.Atproto.Label.Defs.self_labels option; (** Self-label values for this post. Effectively content warnings. *) 2599 - langs : string list option; (** Indicates human language of post primary text content. *) 2600 - reply : Jsont.json option; 2601 - tags : string list option; (** Additional hashtags, in addition to any included in post text and facets. *) 2602 - text : string; (** The primary post content. May be an empty string, if there are embeds. *) 2603 } 2604 2605 (** Jsont codec for {!type:main}. *) ··· 2642 val output_jsont : output Jsont.t 2643 2644 end 2645 - module Postgate : sig 2646 - (** Disables embedding of this post. *) 2647 - 2648 - type disable_rule = unit 2649 - 2650 - (** Jsont codec for {!type:disable_rule}. *) 2651 - val disable_rule_jsont : disable_rule Jsont.t 2652 - 2653 - (** Record defining interaction rules for a post. The record key (rkey) of the postgate record must match the record key of the post, and that record must be in the same repository. *) 2654 - 2655 - type main = { 2656 - created_at : string; 2657 - detached_embedding_uris : string list option; (** List of AT-URIs embedding this post that the author has detached from. *) 2658 - embedding_rules : Jsont.json list option; (** List of rules defining who can embed this post. If value is an empty array or is undefined, no particular rules apply and anyone can embed. *) 2659 - post : string; (** Reference (AT-URI) to the post record. *) 2660 - } 2661 - 2662 - (** Jsont codec for {!type:main}. *) 2663 - val main_jsont : main Jsont.t 2664 - 2665 - end 2666 module GetRepostedBy : sig 2667 (** Get a list of reposts for a given post. *) 2668 ··· 2689 val output_jsont : output Jsont.t 2690 2691 end 2692 - module DescribeFeedGenerator : sig 2693 2694 - type links = { 2695 - privacy_policy : string option; 2696 - terms_of_service : string option; 2697 - } 2698 - 2699 - (** Jsont codec for {!type:links}. *) 2700 - val links_jsont : links Jsont.t 2701 - 2702 - 2703 - type feed = { 2704 - uri : string; 2705 - } 2706 - 2707 - (** Jsont codec for {!type:feed}. *) 2708 - val feed_jsont : feed Jsont.t 2709 - 2710 - (** Get information about a feed generator, including policies and offered feed URIs. Does not require auth; implemented by Feed Generator services (not App View). *) 2711 - 2712 - 2713 - type output = { 2714 did : string; 2715 - feeds : Jsont.json list; 2716 - links : Jsont.json option; 2717 } 2718 2719 - (** Jsont codec for {!type:output}. *) 2720 - val output_jsont : output Jsont.t 2721 2722 end 2723 - module Threadgate : sig 2724 - (** Allow replies from actors mentioned in your post. *) 2725 - 2726 - type mention_rule = unit 2727 - 2728 - (** Jsont codec for {!type:mention_rule}. *) 2729 - val mention_rule_jsont : mention_rule Jsont.t 2730 - 2731 - (** Allow replies from actors on a list. *) 2732 - 2733 - type list_rule = { 2734 - list_ : string; 2735 - } 2736 - 2737 - (** Jsont codec for {!type:list_rule}. *) 2738 - val list_rule_jsont : list_rule Jsont.t 2739 - 2740 - (** Allow replies from actors you follow. *) 2741 - 2742 - type following_rule = unit 2743 - 2744 - (** Jsont codec for {!type:following_rule}. *) 2745 - val following_rule_jsont : following_rule Jsont.t 2746 2747 - (** Allow replies from actors who follow you. *) 2748 2749 - type follower_rule = unit 2750 2751 - (** Jsont codec for {!type:follower_rule}. *) 2752 - val follower_rule_jsont : follower_rule Jsont.t 2753 - 2754 - (** Record defining interaction gating rules for a thread (aka, reply controls). The record key (rkey) of the threadgate record must match the record key of the thread's root post, and that record must be in the same repository. *) 2755 2756 type main = { 2757 - allow : Jsont.json list option; (** List of rules defining who can reply to this post. If value is an empty array, no one can reply. If value is undefined, anyone can reply. *) 2758 created_at : string; 2759 - hidden_replies : string list option; (** List of hidden reply URIs. *) 2760 post : string; (** Reference (AT-URI) to the post record. *) 2761 - } 2762 - 2763 - (** Jsont codec for {!type:main}. *) 2764 - val main_jsont : main Jsont.t 2765 - 2766 - end 2767 - module Like : sig 2768 - (** Record declaring a 'like' of a piece of subject content. *) 2769 - 2770 - type main = { 2771 - created_at : string; 2772 - subject : Com.Atproto.Repo.StrongRef.main; 2773 - via : Com.Atproto.Repo.StrongRef.main option; 2774 } 2775 2776 (** Jsont codec for {!type:main}. *) ··· 3048 val feed_view_post_jsont : feed_view_post Jsont.t 3049 3050 end 3051 - module Repost : sig 3052 - (** Record representing a 'repost' of an existing Bluesky post. *) 3053 3054 type main = { 3055 - created_at : string; 3056 - subject : Com.Atproto.Repo.StrongRef.main; 3057 - via : Com.Atproto.Repo.StrongRef.main option; 3058 } 3059 3060 (** Jsont codec for {!type:main}. *) 3061 val main_jsont : main Jsont.t 3062 3063 end 3064 - module Generator : sig 3065 - (** Record declaring of the existence of a feed generator, and containing metadata about it. The record can exist in any repository. *) 3066 3067 - type main = { 3068 - accepts_interactions : bool option; (** Declaration that a feed accepts feedback interactions from a client through app.bsky.feed.sendInteractions *) 3069 - avatar : Atp.Blob_ref.t option; 3070 - content_mode : string option; 3071 - created_at : string; 3072 - description : string option; 3073 - description_facets : Richtext.Facet.main list option; 3074 - did : string; 3075 - display_name : string; 3076 - labels : Com.Atproto.Label.Defs.self_labels option; (** Self-label values *) 3077 } 3078 3079 - (** Jsont codec for {!type:main}. *) 3080 - val main_jsont : main Jsont.t 3081 3082 end 3083 - module GetPostThread : sig 3084 - (** Get posts in a thread. Does not require auth, but additional metadata and filtering will be applied for authed requests. *) 3085 3086 (** Query/procedure parameters. *) 3087 type params = { 3088 - depth : int option; (** How many levels of reply depth should be included in response. *) 3089 - parent_height : int option; (** How many levels of parent (and grandparent, etc) post to include. *) 3090 - uri : string; (** Reference (AT-URI) to post record. *) 3091 } 3092 3093 (** Jsont codec for {!type:params}. *) ··· 3095 3096 3097 type output = { 3098 - thread : Jsont.json; 3099 - threadgate : Jsont.json option; 3100 } 3101 3102 (** Jsont codec for {!type:output}. *) 3103 val output_jsont : output Jsont.t 3104 3105 end 3106 - module GetFeed : sig 3107 - (** Get a hydrated feed from an actor's selected feed generator. Implemented by App View. *) 3108 3109 (** Query/procedure parameters. *) 3110 type params = { 3111 cursor : string option; 3112 - feed : string; 3113 limit : int option; 3114 } 3115 ··· 3126 val output_jsont : output Jsont.t 3127 3128 end 3129 - module GetQuotes : sig 3130 - (** Get a list of quotes for a given post. *) 3131 3132 (** Query/procedure parameters. *) 3133 type params = { 3134 - cid : string option; (** If supplied, filters to quotes of specific version (by CID) of the post record. *) 3135 cursor : string option; 3136 limit : int option; 3137 - uri : string; (** Reference (AT-URI) of post record *) 3138 } 3139 3140 (** Jsont codec for {!type:params}. *) ··· 3142 3143 3144 type output = { 3145 - cid : string option; 3146 cursor : string option; 3147 - posts : Jsont.json list; 3148 - uri : string; 3149 } 3150 3151 (** Jsont codec for {!type:output}. *) ··· 3175 val output_jsont : output Jsont.t 3176 3177 end 3178 module GetActorLikes : sig 3179 (** Get a list of posts liked by an actor. Requires auth, actor must be the requesting account. *) 3180 ··· 3198 val output_jsont : output Jsont.t 3199 3200 end 3201 - module GetFeedSkeleton : sig 3202 - (** Get a skeleton of a feed provided by a feed generator. Auth is optional, depending on provider requirements, and provides the DID of the requester. Implemented by Feed Generator Service. *) 3203 3204 (** Query/procedure parameters. *) 3205 type params = { 3206 cursor : string option; 3207 - feed : string; (** Reference to feed generator record describing the specific feed being requested. *) 3208 limit : int option; 3209 } 3210 ··· 3214 3215 type output = { 3216 cursor : string option; 3217 - feed : Jsont.json list; 3218 - req_id : string option; (** Unique identifier per request that may be passed back alongside interactions. *) 3219 } 3220 3221 (** Jsont codec for {!type:output}. *) ··· 3255 val output_jsont : output Jsont.t 3256 3257 end 3258 module GetFeedGenerators : sig 3259 (** Get information about a list of feed generators. *) 3260 ··· 3293 val output_jsont : output Jsont.t 3294 3295 end 3296 - module GetAuthorFeed : sig 3297 - (** Get a view of an actor's 'author feed' (post and reposts by the author). Does not require auth. *) 3298 3299 (** Query/procedure parameters. *) 3300 type params = { 3301 actor : string; 3302 cursor : string option; 3303 - filter : string option; (** Combinations of post/repost types to include in response. *) 3304 - include_pins : bool option; 3305 limit : int option; 3306 } 3307 ··· 3311 3312 type output = { 3313 cursor : string option; 3314 - feed : Jsont.json list; 3315 } 3316 3317 (** Jsont codec for {!type:output}. *) 3318 val output_jsont : output Jsont.t 3319 3320 end 3321 - module GetFeedGenerator : sig 3322 - (** Get information about a feed generator. Implemented by AppView. *) 3323 3324 (** Query/procedure parameters. *) 3325 type params = { 3326 - feed : string; (** AT-URI of the feed generator record. *) 3327 } 3328 3329 (** Jsont codec for {!type:params}. *) ··· 3331 3332 3333 type output = { 3334 - is_online : bool; (** Indicates whether the feed generator service has been online recently, or else seems to be inactive. *) 3335 - is_valid : bool; (** Indicates whether the feed generator service is compatible with the record declaration. *) 3336 - view : Jsont.json; 3337 } 3338 3339 (** Jsont codec for {!type:output}. *) 3340 val output_jsont : output Jsont.t 3341 3342 end 3343 - module GetSuggestedFeeds : sig 3344 - (** Get a list of suggested feeds (feed generators) for the requesting account. *) 3345 3346 (** Query/procedure parameters. *) 3347 type params = { 3348 cursor : string option; 3349 limit : int option; 3350 } ··· 3355 3356 type output = { 3357 cursor : string option; 3358 - feeds : Jsont.json list; 3359 } 3360 3361 (** Jsont codec for {!type:output}. *) 3362 val output_jsont : output Jsont.t 3363 3364 end 3365 - module GetActorFeeds : sig 3366 - (** Get a list of feeds (feed generator records) created by the actor (in the actor's repo). *) 3367 3368 (** Query/procedure parameters. *) 3369 type params = { ··· 3378 3379 type output = { 3380 cursor : string option; 3381 - feeds : Jsont.json list; 3382 } 3383 3384 (** Jsont codec for {!type:output}. *) 3385 val output_jsont : output Jsont.t 3386 3387 end 3388 - module GetPosts : sig 3389 - (** Gets post views for a specified list of posts (by AT-URI). This is sometimes referred to as 'hydrating' a 'feed skeleton'. *) 3390 3391 (** Query/procedure parameters. *) 3392 type params = { 3393 - uris : string list; (** List of post AT-URIs to return hydrated views for. *) 3394 } 3395 3396 (** Jsont codec for {!type:params}. *) ··· 3398 3399 3400 type output = { 3401 - posts : Jsont.json list; 3402 } 3403 3404 (** Jsont codec for {!type:output}. *) 3405 val output_jsont : output Jsont.t 3406 3407 end 3408 - module GetTimeline : sig 3409 - (** Get a view of the requesting account's home timeline. This is expected to be some form of reverse-chronological feed. *) 3410 3411 (** Query/procedure parameters. *) 3412 type params = { 3413 - algorithm : string option; (** Variant 'algorithm' for timeline. Implementation-specific. NOTE: most feed flexibility has been moved to feed generator mechanism. *) 3414 cursor : string option; 3415 limit : int option; 3416 } 3417 3418 (** Jsont codec for {!type:params}. *) ··· 3421 3422 type output = { 3423 cursor : string option; 3424 - feed : Jsont.json list; 3425 } 3426 3427 (** Jsont codec for {!type:output}. *) 3428 val output_jsont : output Jsont.t 3429 3430 end 3431 - end 3432 - module Bookmark : sig 3433 - module DeleteBookmark : sig 3434 - (** Deletes a private bookmark for the specified record. Currently, only `app.bsky.feed.post` records are supported. Requires authentication. *) 3435 3436 3437 - type input = { 3438 - uri : string; 3439 } 3440 3441 - (** Jsont codec for {!type:input}. *) 3442 - val input_jsont : input Jsont.t 3443 3444 end 3445 - module CreateBookmark : sig 3446 - (** Creates a private bookmark for the specified record. Currently, only `app.bsky.feed.post` records are supported. Requires authentication. *) 3447 3448 3449 - type input = { 3450 - cid : string; 3451 - uri : string; 3452 } 3453 3454 - (** Jsont codec for {!type:input}. *) 3455 - val input_jsont : input Jsont.t 3456 3457 end 3458 - module Defs : sig 3459 3460 - type bookmark_view = { 3461 - created_at : string option; 3462 - item : Jsont.json; 3463 - subject : Com.Atproto.Repo.StrongRef.main; (** A strong ref to the bookmarked record. *) 3464 } 3465 3466 - (** Jsont codec for {!type:bookmark_view}. *) 3467 - val bookmark_view_jsont : bookmark_view Jsont.t 3468 3469 - (** Object used to store bookmark data in stash. *) 3470 3471 - type bookmark = { 3472 - subject : Com.Atproto.Repo.StrongRef.main; (** A strong ref to the record to be bookmarked. Currently, only `app.bsky.feed.post` records are supported. *) 3473 } 3474 3475 - (** Jsont codec for {!type:bookmark}. *) 3476 - val bookmark_jsont : bookmark Jsont.t 3477 3478 end 3479 - module GetBookmarks : sig 3480 - (** Gets views of records bookmarked by the authenticated user. Requires authentication. *) 3481 3482 (** Query/procedure parameters. *) 3483 type params = { 3484 cursor : string option; 3485 limit : int option; 3486 } ··· 3490 3491 3492 type output = { 3493 - bookmarks : Defs.bookmark_view list; 3494 cursor : string option; 3495 } 3496 3497 (** Jsont codec for {!type:output}. *) 3498 val output_jsont : output Jsont.t 3499 3500 end 3501 - end 3502 - module Unspecced : sig 3503 - module GetSuggestedUsersSkeleton : sig 3504 - (** Get a skeleton of suggested users. Intended to be called and hydrated by app.bsky.unspecced.getSuggestedUsers *) 3505 3506 (** Query/procedure parameters. *) 3507 type params = { 3508 - category : string option; (** Category of users to get suggestions for. *) 3509 limit : int option; 3510 - viewer : string option; (** DID of the account making the request (not included for public/unauthenticated queries). *) 3511 } 3512 3513 (** Jsont codec for {!type:params}. *) ··· 3515 3516 3517 type output = { 3518 - dids : string list; 3519 - rec_id : int option; (** Snowflake for this recommendation, use when submitting recommendation events. *) 3520 } 3521 3522 (** Jsont codec for {!type:output}. *) 3523 val output_jsont : output Jsont.t 3524 3525 end 3526 - module GetOnboardingSuggestedStarterPacks : sig 3527 - (** Get a list of suggested starterpacks for onboarding *) 3528 3529 (** Query/procedure parameters. *) 3530 type params = { 3531 limit : int option; 3532 } 3533 ··· 3536 3537 3538 type output = { 3539 starter_packs : Jsont.json list; 3540 } 3541 ··· 3543 val output_jsont : output Jsont.t 3544 3545 end 3546 - module GetPopularFeedGenerators : sig 3547 - (** An unspecced view of globally popular feed generators. *) 3548 3549 (** Query/procedure parameters. *) 3550 type params = { 3551 cursor : string option; 3552 limit : int option; 3553 - query : string option; 3554 } 3555 3556 (** Jsont codec for {!type:params}. *) ··· 3559 3560 type output = { 3561 cursor : string option; 3562 - feeds : Jsont.json list; 3563 } 3564 3565 (** Jsont codec for {!type:output}. *) 3566 val output_jsont : output Jsont.t 3567 3568 end 3569 - module GetSuggestedStarterPacksSkeleton : sig 3570 - (** Get a skeleton of suggested starterpacks. Intended to be called and hydrated by app.bsky.unspecced.getSuggestedStarterpacks *) 3571 3572 (** Query/procedure parameters. *) 3573 type params = { 3574 limit : int option; 3575 - viewer : string option; (** DID of the account making the request (not included for public/unauthenticated queries). *) 3576 } 3577 3578 (** Jsont codec for {!type:params}. *) ··· 3580 3581 3582 type output = { 3583 - starter_packs : string list; 3584 } 3585 3586 (** Jsont codec for {!type:output}. *) 3587 val output_jsont : output Jsont.t 3588 3589 end 3590 module GetSuggestedFeeds : sig 3591 (** Get a list of suggested feeds *) 3592 ··· 3607 val output_jsont : output Jsont.t 3608 3609 end 3610 - module GetSuggestedFeedsSkeleton : sig 3611 - (** Get a skeleton of suggested feeds. Intended to be called and hydrated by app.bsky.unspecced.getSuggestedFeeds *) 3612 3613 (** Query/procedure parameters. *) 3614 type params = { 3615 limit : int option; 3616 - viewer : string option; (** DID of the account making the request (not included for public/unauthenticated queries). *) 3617 } 3618 3619 (** Jsont codec for {!type:params}. *) ··· 3621 3622 3623 type output = { 3624 - feeds : string list; 3625 } 3626 3627 (** Jsont codec for {!type:output}. *) 3628 val output_jsont : output Jsont.t 3629 3630 end 3631 - module GetConfig : sig 3632 3633 - type live_now_config = { 3634 - did : string; 3635 - domains : string list; 3636 } 3637 3638 - (** Jsont codec for {!type:live_now_config}. *) 3639 - val live_now_config_jsont : live_now_config Jsont.t 3640 - 3641 - (** Get miscellaneous runtime configuration. *) 3642 3643 3644 type output = { 3645 - check_email_confirmed : bool option; 3646 - live_now : live_now_config list option; 3647 } 3648 3649 (** Jsont codec for {!type:output}. *) ··· 3670 val output_jsont : output Jsont.t 3671 3672 end 3673 - module GetSuggestedUsers : sig 3674 - (** Get a list of suggested users *) 3675 3676 (** Query/procedure parameters. *) 3677 type params = { 3678 - category : string option; (** Category of users to get suggestions for. *) 3679 limit : int option; 3680 } 3681 3682 (** Jsont codec for {!type:params}. *) ··· 3684 3685 3686 type output = { 3687 - actors : Jsont.json list; 3688 - rec_id : int option; (** Snowflake for this recommendation, use when submitting recommendation events. *) 3689 } 3690 3691 (** Jsont codec for {!type:output}. *) 3692 val output_jsont : output Jsont.t 3693 3694 end 3695 - module GetOnboardingSuggestedStarterPacksSkeleton : sig 3696 - (** Get a skeleton of suggested starterpacks for onboarding. Intended to be called and hydrated by app.bsky.unspecced.getOnboardingSuggestedStarterPacks *) 3697 3698 (** Query/procedure parameters. *) 3699 type params = { ··· 3706 3707 3708 type output = { 3709 - starter_packs : string list; 3710 } 3711 3712 (** Jsont codec for {!type:output}. *) ··· 3839 val age_assurance_event_jsont : age_assurance_event Jsont.t 3840 3841 end 3842 - module GetTaggedSuggestions : sig 3843 3844 - type suggestion = { 3845 - subject : string; 3846 - subject_type : string; 3847 - tag : string; 3848 } 3849 3850 - (** Jsont codec for {!type:suggestion}. *) 3851 - val suggestion_jsont : suggestion Jsont.t 3852 3853 - (** Get a list of suggestions (feeds and users) tagged with categories *) 3854 - 3855 - (** Query/procedure parameters. *) 3856 - type params = unit 3857 - 3858 - (** Jsont codec for {!type:params}. *) 3859 - val params_jsont : params Jsont.t 3860 3861 3862 type output = { 3863 - suggestions : suggestion list; 3864 } 3865 3866 (** Jsont codec for {!type:output}. *) 3867 val output_jsont : output Jsont.t 3868 3869 end 3870 - module SearchPostsSkeleton : sig 3871 - (** Backend Posts search, returns only skeleton *) 3872 3873 (** Query/procedure parameters. *) 3874 type params = { 3875 - author : string option; (** Filter to posts by the given account. Handles are resolved to DID before query-time. *) 3876 - cursor : string option; (** Optional pagination mechanism; may not necessarily allow scrolling through entire result set. *) 3877 - domain : string option; (** Filter to posts with URLs (facet links or embeds) linking to the given domain (hostname). Server may apply hostname normalization. *) 3878 - lang : string option; (** Filter to posts in the given language. Expected to be based on post language field, though server may override language detection. *) 3879 limit : int option; 3880 - mentions : string option; (** Filter to posts which mention the given account. Handles are resolved to DID before query-time. Only matches rich-text facet mentions. *) 3881 - q : string; (** Search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended. *) 3882 - since : string option; (** Filter results for posts after the indicated datetime (inclusive). Expected to use 'sortAt' timestamp, which may not match 'createdAt'. Can be a datetime, or just an ISO date (YYYY-MM-DD). *) 3883 - sort : string option; (** Specifies the ranking order of results. *) 3884 - tag : string list option; (** Filter to posts with the given tag (hashtag), based on rich-text facet or tag field. Do not include the hash (#) prefix. Multiple tags can be specified, with 'AND' matching. *) 3885 - until : string option; (** Filter results for posts before the indicated datetime (not inclusive). Expected to use 'sortAt' timestamp, which may not match 'createdAt'. Can be a datetime, or just an ISO date (YYY-MM-DD). *) 3886 - url : string option; (** Filter to posts with links (facet links or embeds) pointing to this URL. Server may apply URL normalization or fuzzy matching. *) 3887 - viewer : string option; (** DID of the account making the request (not included for public/unauthenticated queries). Used for 'from:me' queries. *) 3888 } 3889 3890 (** Jsont codec for {!type:params}. *) ··· 3893 3894 type output = { 3895 cursor : string option; 3896 - hits_total : int option; (** Count of search hits. Optional, may be rounded/truncated, and may not be possible to paginate through all hits. *) 3897 - posts : Defs.skeleton_search_post list; 3898 } 3899 3900 (** Jsont codec for {!type:output}. *) 3901 val output_jsont : output Jsont.t 3902 3903 end 3904 - module GetPostThreadV2 : sig 3905 3906 - type thread_item = { 3907 - depth : int; (** The nesting level of this item in the thread. Depth 0 means the anchor item. Items above have negative depths, items below have positive depths. *) 3908 - uri : string; 3909 - value : Jsont.json; 3910 } 3911 3912 - (** Jsont codec for {!type:thread_item}. *) 3913 - val thread_item_jsont : thread_item Jsont.t 3914 3915 - (** (NOTE: this endpoint is under development and WILL change without notice. Don't use it until it is moved out of `unspecced` or your application WILL break) Get posts in a thread. It is based in an anchor post at any depth of the tree, and returns posts above it (recursively resolving the parent, without further branching to their replies) and below it (recursive replies, with branching to their replies). Does not require auth, but additional metadata and filtering will be applied for authed requests. *) 3916 3917 (** Query/procedure parameters. *) 3918 - type params = { 3919 - above : bool option; (** Whether to include parents above the anchor. *) 3920 - anchor : string; (** Reference (AT-URI) to post record. This is the anchor post, and the thread will be built around it. It can be any post in the tree, not necessarily a root post. *) 3921 - below : int option; (** How many levels of replies to include below the anchor. *) 3922 - branching_factor : int option; (** Maximum of replies to include at each level of the thread, except for the direct replies to the anchor, which are (NOTE: currently, during unspecced phase) all returned (NOTE: later they might be paginated). *) 3923 - sort : string option; (** Sorting for the thread replies. *) 3924 - } 3925 3926 (** Jsont codec for {!type:params}. *) 3927 val params_jsont : params Jsont.t 3928 3929 3930 type output = { 3931 - has_other_replies : bool; (** Whether this thread has additional replies. If true, a call can be made to the `getPostThreadOtherV2` endpoint to retrieve them. *) 3932 - thread : thread_item list; (** A flat list of thread items. The depth of each item is indicated by the depth property inside the item. *) 3933 - threadgate : Jsont.json option; 3934 } 3935 3936 (** Jsont codec for {!type:output}. *) 3937 val output_jsont : output Jsont.t 3938 3939 end 3940 - module GetTrendingTopics : sig 3941 - (** Get a list of trending topics *) 3942 3943 (** Query/procedure parameters. *) 3944 type params = { 3945 limit : int option; 3946 - viewer : string option; (** DID of the account making the request (not included for public/unauthenticated queries). Used to boost followed accounts in ranking. *) 3947 } 3948 3949 (** Jsont codec for {!type:params}. *) ··· 3951 3952 3953 type output = { 3954 - suggested : Defs.trending_topic list; 3955 - topics : Defs.trending_topic list; 3956 } 3957 3958 (** Jsont codec for {!type:output}. *) 3959 val output_jsont : output Jsont.t 3960 3961 end 3962 - module GetTrendsSkeleton : sig 3963 - (** Get the skeleton of trends on the network. Intended to be called and then hydrated through app.bsky.unspecced.getTrends *) 3964 3965 (** Query/procedure parameters. *) 3966 type params = { 3967 limit : int option; 3968 - viewer : string option; (** DID of the account making the request (not included for public/unauthenticated queries). *) 3969 } 3970 3971 (** Jsont codec for {!type:params}. *) ··· 3973 3974 3975 type output = { 3976 - trends : Defs.skeleton_trend list; 3977 } 3978 3979 (** Jsont codec for {!type:output}. *) ··· 4010 val output_jsont : output Jsont.t 4011 4012 end 4013 - module InitAgeAssurance : sig 4014 - (** Initiate age assurance for an account. This is a one-time action that will start the process of verifying the user's age. *) 4015 4016 4017 - type input = { 4018 - country_code : string; (** An ISO 3166-1 alpha-2 code of the user's location. *) 4019 - email : string; (** The user's email address to receive assurance instructions. *) 4020 - language : string; (** The user's preferred language for communication during the assurance process. *) 4021 } 4022 4023 - (** Jsont codec for {!type:input}. *) 4024 - val input_jsont : input Jsont.t 4025 4026 4027 type output = Defs.age_assurance_state ··· 4055 val output_jsont : output Jsont.t 4056 4057 end 4058 module SearchActorsSkeleton : sig 4059 (** Backend Actors (profile) search, returns only skeleton. *) 4060 ··· 4081 val output_jsont : output Jsont.t 4082 4083 end 4084 - module GetAgeAssuranceState : sig 4085 - (** Returns the current state of the age assurance process for an account. This is used to check if the user has completed age assurance or if further action is required. *) 4086 4087 4088 - type output = Defs.age_assurance_state 4089 4090 (** Jsont codec for {!type:output}. *) 4091 val output_jsont : output Jsont.t 4092 4093 end 4094 - module GetSuggestionsSkeleton : sig 4095 - (** Get a skeleton of suggested actors. Intended to be called and then hydrated through app.bsky.actor.getSuggestions *) 4096 4097 (** Query/procedure parameters. *) 4098 type params = { 4099 - cursor : string option; 4100 - limit : int option; 4101 - relative_to_did : string option; (** DID of the account to get suggestions relative to. If not provided, suggestions will be based on the viewer. *) 4102 - viewer : string option; (** DID of the account making the request (not included for public/unauthenticated queries). Used to boost followed accounts in ranking. *) 4103 } 4104 4105 (** Jsont codec for {!type:params}. *) ··· 4107 4108 4109 type output = { 4110 - actors : Defs.skeleton_search_actor list; 4111 - cursor : string option; 4112 - rec_id : int option; (** Snowflake for this recommendation, use when submitting recommendation events. *) 4113 - relative_to_did : string option; (** DID of the account these suggestions are relative to. If this is returned undefined, suggestions are based on the viewer. *) 4114 } 4115 4116 (** Jsont codec for {!type:output}. *) 4117 val output_jsont : output Jsont.t 4118 4119 end 4120 - module GetTrends : sig 4121 - (** Get the current trends on the network *) 4122 4123 (** Query/procedure parameters. *) 4124 type params = { 4125 limit : int option; 4126 } 4127 4128 (** Jsont codec for {!type:params}. *) ··· 4130 4131 4132 type output = { 4133 - trends : Defs.trend_view list; 4134 } 4135 4136 (** Jsont codec for {!type:output}. *)
··· 12 13 module Com : sig 14 module Atproto : sig 15 + module Moderation : sig 16 + module Defs : sig 17 + (** Tag describing a type of subject that might be reported. *) 18 + 19 + type subject_type = string 20 + val subject_type_jsont : subject_type Jsont.t 21 + 22 + (** Direct violation of server rules, laws, terms of service. Prefer new lexicon definition `tools.ozone.report.defs#reasonRuleOther`. *) 23 + 24 + type reason_violation = string 25 + val reason_violation_jsont : reason_violation Jsont.t 26 + 27 + 28 + type reason_type = string 29 + val reason_type_jsont : reason_type Jsont.t 30 + 31 + (** Spam: frequent unwanted promotion, replies, mentions. Prefer new lexicon definition `tools.ozone.report.defs#reasonMisleadingSpam`. *) 32 + 33 + type reason_spam = string 34 + val reason_spam_jsont : reason_spam Jsont.t 35 + 36 + (** Unwanted or mislabeled sexual content. Prefer new lexicon definition `tools.ozone.report.defs#reasonSexualUnlabeled`. *) 37 + 38 + type reason_sexual = string 39 + val reason_sexual_jsont : reason_sexual Jsont.t 40 + 41 + (** Rude, harassing, explicit, or otherwise unwelcoming behavior. Prefer new lexicon definition `tools.ozone.report.defs#reasonHarassmentOther`. *) 42 + 43 + type reason_rude = string 44 + val reason_rude_jsont : reason_rude Jsont.t 45 + 46 + (** Reports not falling under another report category. Prefer new lexicon definition `tools.ozone.report.defs#reasonOther`. *) 47 + 48 + type reason_other = string 49 + val reason_other_jsont : reason_other Jsont.t 50 + 51 + (** Misleading identity, affiliation, or content. Prefer new lexicon definition `tools.ozone.report.defs#reasonMisleadingOther`. *) 52 + 53 + type reason_misleading = string 54 + val reason_misleading_jsont : reason_misleading Jsont.t 55 + 56 + (** Appeal a previously taken moderation action *) 57 + 58 + type reason_appeal = string 59 + val reason_appeal_jsont : reason_appeal Jsont.t 60 + 61 + end 62 + end 63 module Label : sig 64 module Defs : sig 65 (** Metadata tag on an atproto record, published by the author within the record. Note that schemas should use #selfLabels, not #selfLabel. *) ··· 141 142 end 143 end 144 end 145 end 146 module App : sig 147 module Bsky : sig 148 + module AuthFullApp : sig 149 150 type main = unit 151 val main_jsont : main Jsont.t ··· 157 val main_jsont : main Jsont.t 158 159 end 160 module AuthManageFeedDeclarations : sig 161 162 type main = unit 163 val main_jsont : main Jsont.t 164 165 end 166 + module AuthManageNotifications : sig 167 168 type main = unit 169 val main_jsont : main Jsont.t 170 171 end 172 + module AuthManageModeration : sig 173 174 type main = unit 175 val main_jsont : main Jsont.t ··· 181 val main_jsont : main Jsont.t 182 183 end 184 + module AuthManageLabelerService : sig 185 186 type main = unit 187 val main_jsont : main Jsont.t 188 189 end 190 + module Notification : sig 191 + module GetUnreadCount : sig 192 + (** Count the number of unread notifications for the requesting account. Requires auth. *) 193 194 (** Query/procedure parameters. *) 195 type params = { 196 + priority : bool option; 197 + seen_at : string option; 198 } 199 200 (** Jsont codec for {!type:params}. *) ··· 202 203 204 type output = { 205 + count : int; 206 } 207 208 (** Jsont codec for {!type:output}. *) 209 val output_jsont : output Jsont.t 210 211 end 212 module UpdateSeen : sig 213 (** Notify server that the requesting account has seen notifications. Requires auth. *) 214 ··· 221 val input_jsont : input Jsont.t 222 223 end 224 module ListNotifications : sig 225 226 type notification = { ··· 264 val output_jsont : output Jsont.t 265 266 end 267 + module Declaration : sig 268 + (** A declaration of the user's choices related to notifications that can be produced by them. *) 269 270 + type main = { 271 + allow_subscriptions : string; (** A declaration of the user's preference for allowing activity subscriptions from other users. Absence of a record implies 'followers'. *) 272 } 273 274 + (** Jsont codec for {!type:main}. *) 275 + val main_jsont : main Jsont.t 276 + 277 + end 278 + module PutPreferences : sig 279 + (** Set notification-related preferences for an account. Requires auth. *) 280 281 282 + type input = { 283 + priority : bool; 284 } 285 286 + (** Jsont codec for {!type:input}. *) 287 + val input_jsont : input Jsont.t 288 289 end 290 + module RegisterPush : sig 291 + (** Register to receive push notifications, via a specified service, for the requesting account. Requires auth. *) 292 293 294 type input = { 295 + age_restricted : bool option; (** Set to true when the actor is age restricted *) 296 app_id : string; 297 platform : string; 298 service_did : string; ··· 303 val input_jsont : input Jsont.t 304 305 end 306 + module UnregisterPush : sig 307 + (** The inverse of registerPush - inform a specified service that push notifications should no longer be sent to the given token for the requesting account. Requires auth. *) 308 309 310 type input = { 311 + app_id : string; 312 + platform : string; 313 + service_did : string; 314 + token : string; 315 } 316 317 (** Jsont codec for {!type:input}. *) ··· 391 392 (** Jsont codec for {!type:preferences}. *) 393 val preferences_jsont : preferences Jsont.t 394 395 end 396 module ListActivitySubscriptions : sig ··· 488 489 end 490 end 491 + module Labeler : sig 492 + module Defs : sig 493 + 494 + type labeler_viewer_state = { 495 + like : string option; 496 + } 497 + 498 + (** Jsont codec for {!type:labeler_viewer_state}. *) 499 + val labeler_viewer_state_jsont : labeler_viewer_state Jsont.t 500 + 501 + 502 + type labeler_policies = { 503 + label_value_definitions : Com.Atproto.Label.Defs.label_value_definition list option; (** Label values created by this labeler and scoped exclusively to it. Labels defined here will override global label definitions for this labeler. *) 504 + label_values : Com.Atproto.Label.Defs.label_value list; (** The label values which this labeler publishes. May include global or custom labels. *) 505 + } 506 + 507 + (** Jsont codec for {!type:labeler_policies}. *) 508 + val labeler_policies_jsont : labeler_policies Jsont.t 509 + 510 + 511 + type labeler_view_detailed = { 512 + cid : string; 513 + creator : Jsont.json; 514 + indexed_at : string; 515 + labels : Com.Atproto.Label.Defs.label list option; 516 + like_count : int option; 517 + policies : Jsont.json; 518 + reason_types : Com.Atproto.Moderation.Defs.reason_type list option; (** The set of report reason 'codes' which are in-scope for this service to review and action. These usually align to policy categories. If not defined (distinct from empty array), all reason types are allowed. *) 519 + subject_collections : string list option; (** Set of record types (collection NSIDs) which can be reported to this service. If not defined (distinct from empty array), default is any record type. *) 520 + subject_types : Com.Atproto.Moderation.Defs.subject_type list option; (** The set of subject types (account, record, etc) this service accepts reports on. *) 521 + uri : string; 522 + viewer : Jsont.json option; 523 + } 524 + 525 + (** Jsont codec for {!type:labeler_view_detailed}. *) 526 + val labeler_view_detailed_jsont : labeler_view_detailed Jsont.t 527 + 528 + 529 + type labeler_view = { 530 + cid : string; 531 + creator : Jsont.json; 532 + indexed_at : string; 533 + labels : Com.Atproto.Label.Defs.label list option; 534 + like_count : int option; 535 + uri : string; 536 + viewer : Jsont.json option; 537 + } 538 + 539 + (** Jsont codec for {!type:labeler_view}. *) 540 + val labeler_view_jsont : labeler_view Jsont.t 541 + 542 + end 543 + module Service : sig 544 + (** A declaration of the existence of labeler service. *) 545 + 546 + type main = { 547 + created_at : string; 548 + labels : Com.Atproto.Label.Defs.self_labels option; 549 + policies : Jsont.json; 550 + reason_types : Com.Atproto.Moderation.Defs.reason_type list option; (** The set of report reason 'codes' which are in-scope for this service to review and action. These usually align to policy categories. If not defined (distinct from empty array), all reason types are allowed. *) 551 + subject_collections : string list option; (** Set of record types (collection NSIDs) which can be reported to this service. If not defined (distinct from empty array), default is any record type. *) 552 + subject_types : Com.Atproto.Moderation.Defs.subject_type list option; (** The set of subject types (account, record, etc) this service accepts reports on. *) 553 + } 554 + 555 + (** Jsont codec for {!type:main}. *) 556 + val main_jsont : main Jsont.t 557 + 558 + end 559 + module GetServices : sig 560 + (** Get information about a list of labeler services. *) 561 + 562 + (** Query/procedure parameters. *) 563 + type params = { 564 + detailed : bool option; 565 + dids : string list; 566 + } 567 + 568 + (** Jsont codec for {!type:params}. *) 569 + val params_jsont : params Jsont.t 570 + 571 + 572 + type output = { 573 + views : Jsont.json list; 574 + } 575 + 576 + (** Jsont codec for {!type:output}. *) 577 + val output_jsont : output Jsont.t 578 + 579 + end 580 + end 581 module Actor : sig 582 module Status : sig 583 (** Advertises an account as currently offering live content. *) ··· 592 duration_minutes : int option; (** The duration of the status in minutes. Applications can choose to impose minimum and maximum limits. *) 593 embed : Jsont.json option; (** An optional embed associated with the status. *) 594 status : string; (** The status for the account. *) 595 } 596 597 (** Jsont codec for {!type:main}. *) ··· 961 val known_followers_jsont : known_followers Jsont.t 962 963 end 964 + module Profile : sig 965 + (** A declaration of a Bluesky account profile. *) 966 967 + type main = { 968 + avatar : Atp.Blob_ref.t option; (** Small image to be displayed next to posts from account. AKA, 'profile picture' *) 969 + banner : Atp.Blob_ref.t option; (** Larger horizontal image to display behind profile view. *) 970 + created_at : string option; 971 + description : string option; (** Free-form profile description text. *) 972 + display_name : string option; 973 + joined_via_starter_pack : Com.Atproto.Repo.StrongRef.main option; 974 + labels : Com.Atproto.Label.Defs.self_labels option; (** Self-label values, specific to the Bluesky application, on the overall account. *) 975 + pinned_post : Com.Atproto.Repo.StrongRef.main option; 976 + pronouns : string option; (** Free-form pronouns text. *) 977 + website : string option; 978 } 979 980 + (** Jsont codec for {!type:main}. *) 981 + val main_jsont : main Jsont.t 982 983 end 984 + module GetProfiles : sig 985 + (** Get detailed profile views of multiple actors. *) 986 987 (** Query/procedure parameters. *) 988 type params = { 989 + actors : string list; 990 } 991 992 (** Jsont codec for {!type:params}. *) ··· 994 995 996 type output = { 997 + profiles : Jsont.json list; 998 } 999 1000 (** Jsont codec for {!type:output}. *) 1001 val output_jsont : output Jsont.t 1002 1003 end 1004 + module GetPreferences : sig 1005 + (** Get private preferences attached to the current account. Expected use is synchronization between multiple devices, and import/export during account migration. Requires auth. *) 1006 1007 (** Query/procedure parameters. *) 1008 + type params = unit 1009 1010 (** Jsont codec for {!type:params}. *) 1011 val params_jsont : params Jsont.t 1012 1013 1014 + type output = { 1015 + preferences : Jsont.json; 1016 + } 1017 1018 (** Jsont codec for {!type:output}. *) 1019 val output_jsont : output Jsont.t 1020 1021 end 1022 + module GetSuggestions : sig 1023 + (** Get a list of suggested actors. Expected use is discovery of accounts to follow during new account onboarding. *) 1024 1025 (** Query/procedure parameters. *) 1026 type params = { 1027 cursor : string option; 1028 limit : int option; 1029 } 1030 1031 (** Jsont codec for {!type:params}. *) ··· 1035 type output = { 1036 actors : Jsont.json list; 1037 cursor : string option; 1038 + rec_id : int option; (** Snowflake for this recommendation, use when submitting recommendation events. *) 1039 } 1040 1041 (** Jsont codec for {!type:output}. *) 1042 val output_jsont : output Jsont.t 1043 1044 end 1045 + module GetProfile : sig 1046 + (** Get detailed profile view of an actor. Does not require auth, but contains relevant metadata with auth. *) 1047 1048 (** Query/procedure parameters. *) 1049 type params = { 1050 + actor : string; (** Handle or DID of account to fetch profile of. *) 1051 } 1052 1053 (** Jsont codec for {!type:params}. *) 1054 val params_jsont : params Jsont.t 1055 1056 1057 + type output = Jsont.json 1058 1059 (** Jsont codec for {!type:output}. *) 1060 val output_jsont : output Jsont.t 1061 1062 end 1063 + module SearchActors : sig 1064 + (** Find actors (profiles) matching search criteria. Does not require auth. *) 1065 1066 (** Query/procedure parameters. *) 1067 type params = { 1068 + cursor : string option; 1069 + limit : int option; 1070 + q : string option; (** Search query string. Syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended. *) 1071 + term : string option; (** DEPRECATED: use 'q' instead. *) 1072 } 1073 1074 (** Jsont codec for {!type:params}. *) ··· 1076 1077 1078 type output = { 1079 + actors : Jsont.json list; 1080 + cursor : string option; 1081 } 1082 1083 (** Jsont codec for {!type:output}. *) ··· 1096 val input_jsont : input Jsont.t 1097 1098 end 1099 + module SearchActorsTypeahead : sig 1100 + (** Find actor suggestions for a prefix search term. Expected use is for auto-completion during text field entry. Does not require auth. *) 1101 1102 + (** Query/procedure parameters. *) 1103 + type params = { 1104 + limit : int option; 1105 + q : string option; (** Search query prefix; not a full query string. *) 1106 + term : string option; (** DEPRECATED: use 'q' instead. *) 1107 } 1108 1109 + (** Jsont codec for {!type:params}. *) 1110 + val params_jsont : params Jsont.t 1111 1112 1113 + type output = { 1114 + actors : Jsont.json list; 1115 } 1116 1117 + (** Jsont codec for {!type:output}. *) 1118 + val output_jsont : output Jsont.t 1119 1120 end 1121 + end 1122 + module Video : sig 1123 + module GetUploadLimits : sig 1124 + (** Get video upload limits for the authenticated user. *) 1125 1126 1127 + type output = { 1128 + can_upload : bool; 1129 + error : string option; 1130 + message : string option; 1131 + remaining_daily_bytes : int option; 1132 + remaining_daily_videos : int option; 1133 + } 1134 1135 (** Jsont codec for {!type:output}. *) 1136 val output_jsont : output Jsont.t 1137 1138 end 1139 + module Defs : sig 1140 1141 + type job_status = { 1142 + blob : Atp.Blob_ref.t option; 1143 + did : string; 1144 + error : string option; 1145 + job_id : string; 1146 + message : string option; 1147 + progress : int option; (** Progress within the current processing state. *) 1148 + state : string; (** The state of the video processing job. All values not listed as a known value indicate that the job is in process. *) 1149 } 1150 1151 + (** Jsont codec for {!type:job_status}. *) 1152 + val job_status_jsont : job_status Jsont.t 1153 1154 end 1155 + module GetJobStatus : sig 1156 + (** Get status details for a video processing job. *) 1157 1158 (** Query/procedure parameters. *) 1159 type params = { 1160 + job_id : string; 1161 } 1162 1163 (** Jsont codec for {!type:params}. *) ··· 1165 1166 1167 type output = { 1168 + job_status : Defs.job_status; 1169 } 1170 1171 (** Jsont codec for {!type:output}. *) 1172 val output_jsont : output Jsont.t 1173 1174 end 1175 + module UploadVideo : sig 1176 + (** Upload a video to be processed then stored on the PDS. *) 1177 1178 1179 + type input = unit 1180 val input_jsont : input Jsont.t 1181 1182 1183 type output = { 1184 + job_status : Defs.job_status; 1185 } 1186 1187 (** Jsont codec for {!type:output}. *) 1188 val output_jsont : output Jsont.t 1189 1190 end 1191 + end 1192 + module Richtext : sig 1193 + module Facet : sig 1194 + (** Facet feature for a hashtag. The text usually includes a '#' prefix, but the facet reference should not (except in the case of 'double hash tags'). *) 1195 1196 + type tag = { 1197 + tag : string; 1198 + } 1199 1200 + (** Jsont codec for {!type:tag}. *) 1201 + val tag_jsont : tag Jsont.t 1202 + 1203 + (** Facet feature for mention of another account. The text is usually a handle, including a '\@' prefix, but the facet reference is a DID. *) 1204 + 1205 + type mention = { 1206 + did : string; 1207 } 1208 1209 + (** Jsont codec for {!type:mention}. *) 1210 + val mention_jsont : mention Jsont.t 1211 1212 + (** Facet feature for a URL. The text URL may have been simplified or truncated, but the facet reference should be a complete URL. *) 1213 1214 + type link = { 1215 + uri : string; 1216 + } 1217 1218 + (** Jsont codec for {!type:link}. *) 1219 + val link_jsont : link Jsont.t 1220 1221 + (** Specifies the sub-string range a facet feature applies to. Start index is inclusive, end index is exclusive. Indices are zero-indexed, counting bytes of the UTF-8 encoded text. NOTE: some languages, like Javascript, use UTF-16 or Unicode codepoints for string slice indexing; in these languages, convert to byte arrays before working with facets. *) 1222 1223 + type byte_slice = { 1224 + byte_end : int; 1225 + byte_start : int; 1226 } 1227 1228 + (** Jsont codec for {!type:byte_slice}. *) 1229 + val byte_slice_jsont : byte_slice Jsont.t 1230 1231 + (** Annotation of a sub-string within rich text. *) 1232 1233 + type main = { 1234 + features : Jsont.json list; 1235 + index : byte_slice; 1236 + } 1237 1238 + (** Jsont codec for {!type:main}. *) 1239 + val main_jsont : main Jsont.t 1240 1241 end 1242 + end 1243 + module AuthCreatePosts : sig 1244 1245 + type main = unit 1246 + val main_jsont : main Jsont.t 1247 1248 + end 1249 + module Ageassurance : sig 1250 + module Defs : sig 1251 + (** The status of the Age Assurance process. *) 1252 1253 + type status = string 1254 + val status_jsont : status Jsont.t 1255 1256 + (** Additional metadata needed to compute Age Assurance state client-side. *) 1257 + 1258 + type state_metadata = { 1259 + account_created_at : string option; (** The account creation timestamp. *) 1260 } 1261 1262 + (** Jsont codec for {!type:state_metadata}. *) 1263 + val state_metadata_jsont : state_metadata Jsont.t 1264 1265 + (** Object used to store Age Assurance data in stash. *) 1266 1267 + type event = { 1268 + access : string; (** The access level granted based on Age Assurance data we've processed. *) 1269 + attempt_id : string; (** The unique identifier for this instance of the Age Assurance flow, in UUID format. *) 1270 + complete_ip : string option; (** The IP address used when completing the Age Assurance flow. *) 1271 + complete_ua : string option; (** The user agent used when completing the Age Assurance flow. *) 1272 + country_code : string; (** The ISO 3166-1 alpha-2 country code provided when beginning the Age Assurance flow. *) 1273 + created_at : string; (** The date and time of this write operation. *) 1274 + email : string option; (** The email used for Age Assurance. *) 1275 + init_ip : string option; (** The IP address used when initiating the Age Assurance flow. *) 1276 + init_ua : string option; (** The user agent used when initiating the Age Assurance flow. *) 1277 + region_code : string option; (** The ISO 3166-2 region code provided when beginning the Age Assurance flow. *) 1278 + status : string; (** The status of the Age Assurance process. *) 1279 } 1280 1281 + (** Jsont codec for {!type:event}. *) 1282 + val event_jsont : event Jsont.t 1283 1284 + (** The Age Assurance configuration for a specific region. *) 1285 1286 + type config_region = { 1287 + country_code : string; (** The ISO 3166-1 alpha-2 country code this configuration applies to. *) 1288 + min_access_age : int; (** The minimum age (as a whole integer) required to use Bluesky in this region. *) 1289 + region_code : string option; (** The ISO 3166-2 region code this configuration applies to. If omitted, the configuration applies to the entire country. *) 1290 + rules : Jsont.json list; (** The ordered list of Age Assurance rules that apply to this region. Rules should be applied in order, and the first matching rule determines the access level granted. The rules array should always include a default rule as the last item. *) 1291 } 1292 1293 + (** Jsont codec for {!type:config_region}. *) 1294 + val config_region_jsont : config_region Jsont.t 1295 + 1296 + (** The access level granted based on Age Assurance data we've processed. *) 1297 1298 + type access = string 1299 + val access_jsont : access Jsont.t 1300 + 1301 + (** The user's computed Age Assurance state. *) 1302 1303 + type state = { 1304 + access : access; 1305 + last_initiated_at : string option; (** The timestamp when this state was last updated. *) 1306 + status : status; 1307 } 1308 1309 + (** Jsont codec for {!type:state}. *) 1310 + val state_jsont : state Jsont.t 1311 1312 + (** Age Assurance rule that applies if the user has declared themselves under a certain age. *) 1313 1314 + type config_region_rule_if_declared_under_age = { 1315 + access : access; 1316 + age : int; (** The age threshold as a whole integer. *) 1317 } 1318 1319 + (** Jsont codec for {!type:config_region_rule_if_declared_under_age}. *) 1320 + val config_region_rule_if_declared_under_age_jsont : config_region_rule_if_declared_under_age Jsont.t 1321 1322 + (** Age Assurance rule that applies if the user has declared themselves equal-to or over a certain age. *) 1323 1324 + type config_region_rule_if_declared_over_age = { 1325 + access : access; 1326 + age : int; (** The age threshold as a whole integer. *) 1327 } 1328 1329 + (** Jsont codec for {!type:config_region_rule_if_declared_over_age}. *) 1330 + val config_region_rule_if_declared_over_age_jsont : config_region_rule_if_declared_over_age Jsont.t 1331 1332 + (** Age Assurance rule that applies if the user has been assured to be under a certain age. *) 1333 1334 + type config_region_rule_if_assured_under_age = { 1335 + access : access; 1336 + age : int; (** The age threshold as a whole integer. *) 1337 } 1338 1339 + (** Jsont codec for {!type:config_region_rule_if_assured_under_age}. *) 1340 + val config_region_rule_if_assured_under_age_jsont : config_region_rule_if_assured_under_age Jsont.t 1341 1342 + (** Age Assurance rule that applies if the user has been assured to be equal-to or over a certain age. *) 1343 1344 + type config_region_rule_if_assured_over_age = { 1345 + access : access; 1346 + age : int; (** The age threshold as a whole integer. *) 1347 } 1348 1349 + (** Jsont codec for {!type:config_region_rule_if_assured_over_age}. *) 1350 + val config_region_rule_if_assured_over_age_jsont : config_region_rule_if_assured_over_age Jsont.t 1351 1352 + (** Age Assurance rule that applies if the account is older than a certain date. *) 1353 1354 + type config_region_rule_if_account_older_than = { 1355 + access : access; 1356 + date : string; (** The date threshold as a datetime string. *) 1357 } 1358 1359 + (** Jsont codec for {!type:config_region_rule_if_account_older_than}. *) 1360 + val config_region_rule_if_account_older_than_jsont : config_region_rule_if_account_older_than Jsont.t 1361 1362 + (** Age Assurance rule that applies if the account is equal-to or newer than a certain date. *) 1363 1364 + type config_region_rule_if_account_newer_than = { 1365 + access : access; 1366 + date : string; (** The date threshold as a datetime string. *) 1367 } 1368 1369 + (** Jsont codec for {!type:config_region_rule_if_account_newer_than}. *) 1370 + val config_region_rule_if_account_newer_than_jsont : config_region_rule_if_account_newer_than Jsont.t 1371 1372 + (** Age Assurance rule that applies by default. *) 1373 1374 + type config_region_rule_default = { 1375 + access : access; 1376 } 1377 1378 + (** Jsont codec for {!type:config_region_rule_default}. *) 1379 + val config_region_rule_default_jsont : config_region_rule_default Jsont.t 1380 1381 1382 + type config = { 1383 + regions : config_region list; (** The per-region Age Assurance configuration. *) 1384 } 1385 1386 + (** Jsont codec for {!type:config}. *) 1387 + val config_jsont : config Jsont.t 1388 1389 end 1390 + module GetState : sig 1391 + (** Returns server-computed Age Assurance state, if available, and any additional metadata needed to compute Age Assurance state client-side. *) 1392 1393 (** Query/procedure parameters. *) 1394 type params = { 1395 + country_code : string; 1396 + region_code : string option; 1397 } 1398 1399 (** Jsont codec for {!type:params}. *) ··· 1401 1402 1403 type output = { 1404 + metadata : Defs.state_metadata; 1405 + state : Defs.state; 1406 } 1407 1408 (** Jsont codec for {!type:output}. *) 1409 val output_jsont : output Jsont.t 1410 1411 end 1412 + module Begin : sig 1413 + (** Initiate Age Assurance for an account. *) 1414 1415 1416 type input = { 1417 + country_code : string; (** An ISO 3166-1 alpha-2 code of the user's location. *) 1418 + email : string; (** The user's email address to receive Age Assurance instructions. *) 1419 + language : string; (** The user's preferred language for communication during the Age Assurance process. *) 1420 + region_code : string option; (** An optional ISO 3166-2 code of the user's region or state within the country. *) 1421 } 1422 1423 (** Jsont codec for {!type:input}. *) 1424 val input_jsont : input Jsont.t 1425 1426 1427 + type output = Defs.state 1428 1429 + (** Jsont codec for {!type:output}. *) 1430 + val output_jsont : output Jsont.t 1431 1432 end 1433 + module GetConfig : sig 1434 + (** Returns Age Assurance configuration for use on the client. *) 1435 1436 1437 + type output = Defs.config 1438 1439 + (** Jsont codec for {!type:output}. *) 1440 + val output_jsont : output Jsont.t 1441 1442 end 1443 + end 1444 + module Embed : sig 1445 + module Defs : sig 1446 + (** width:height represents an aspect ratio. It may be approximate, and may not correspond to absolute dimensions in any given unit. *) 1447 1448 + type aspect_ratio = { 1449 + height : int; 1450 + width : int; 1451 } 1452 1453 + (** Jsont codec for {!type:aspect_ratio}. *) 1454 + val aspect_ratio_jsont : aspect_ratio Jsont.t 1455 1456 end 1457 + module External : sig 1458 1459 + type view_external = { 1460 + description : string; 1461 + thumb : string option; 1462 + title : string; 1463 + uri : string; 1464 } 1465 1466 + (** Jsont codec for {!type:view_external}. *) 1467 + val view_external_jsont : view_external Jsont.t 1468 1469 1470 + type external_ = { 1471 + description : string; 1472 + thumb : Atp.Blob_ref.t option; 1473 + title : string; 1474 + uri : string; 1475 } 1476 1477 + (** Jsont codec for {!type:external_}. *) 1478 + val external__jsont : external_ Jsont.t 1479 1480 1481 + type view = { 1482 + external_ : Jsont.json; 1483 } 1484 1485 + (** Jsont codec for {!type:view}. *) 1486 + val view_jsont : view Jsont.t 1487 1488 + (** A representation of some externally linked content (eg, a URL and 'card'), embedded in a Bluesky record (eg, a post). *) 1489 1490 type main = { 1491 + external_ : Jsont.json; 1492 } 1493 1494 (** Jsont codec for {!type:main}. *) 1495 val main_jsont : main Jsont.t 1496 1497 end 1498 + module Images : sig 1499 1500 + type view_image = { 1501 + alt : string; (** Alt text description of the image, for accessibility. *) 1502 + aspect_ratio : Jsont.json option; 1503 + fullsize : string; (** Fully-qualified URL where a large version of the image can be fetched. May or may not be the exact original blob. For example, CDN location provided by the App View. *) 1504 + thumb : string; (** Fully-qualified URL where a thumbnail of the image can be fetched. For example, CDN location provided by the App View. *) 1505 } 1506 1507 + (** Jsont codec for {!type:view_image}. *) 1508 + val view_image_jsont : view_image Jsont.t 1509 1510 1511 + type image = { 1512 + alt : string; (** Alt text description of the image, for accessibility. *) 1513 + aspect_ratio : Jsont.json option; 1514 + image : Atp.Blob_ref.t; 1515 } 1516 1517 + (** Jsont codec for {!type:image}. *) 1518 + val image_jsont : image Jsont.t 1519 1520 1521 + type view = { 1522 + images : Jsont.json list; 1523 + } 1524 1525 + (** Jsont codec for {!type:view}. *) 1526 + val view_jsont : view Jsont.t 1527 1528 + 1529 + type main = { 1530 + images : Jsont.json list; 1531 } 1532 1533 + (** Jsont codec for {!type:main}. *) 1534 + val main_jsont : main Jsont.t 1535 + 1536 + end 1537 + module Video : sig 1538 1539 + type view = { 1540 + alt : string option; 1541 + aspect_ratio : Jsont.json option; 1542 + cid : string; 1543 + playlist : string; 1544 + thumbnail : string option; 1545 + } 1546 1547 + (** Jsont codec for {!type:view}. *) 1548 + val view_jsont : view Jsont.t 1549 1550 1551 + type caption = { 1552 + file : Atp.Blob_ref.t; 1553 + lang : string; 1554 } 1555 1556 + (** Jsont codec for {!type:caption}. *) 1557 + val caption_jsont : caption Jsont.t 1558 1559 1560 + type main = { 1561 + alt : string option; (** Alt text description of the video, for accessibility. *) 1562 + aspect_ratio : Jsont.json option; 1563 + captions : Jsont.json list option; 1564 + video : Atp.Blob_ref.t; (** The mp4 video file. May be up to 100mb, formerly limited to 50mb. *) 1565 + } 1566 1567 + (** Jsont codec for {!type:main}. *) 1568 + val main_jsont : main Jsont.t 1569 1570 + end 1571 + module RecordWithMedia : sig 1572 + 1573 + type view = { 1574 + media : Jsont.json; 1575 + record : Jsont.json; 1576 } 1577 1578 + (** Jsont codec for {!type:view}. *) 1579 + val view_jsont : view Jsont.t 1580 + 1581 1582 + type main = { 1583 + media : Jsont.json; 1584 + record : Jsont.json; 1585 + } 1586 1587 + (** Jsont codec for {!type:main}. *) 1588 + val main_jsont : main Jsont.t 1589 1590 + end 1591 + module Record : sig 1592 1593 + type view_record = { 1594 + author : Jsont.json; 1595 cid : string; 1596 + embeds : Jsont.json list option; 1597 + indexed_at : string; 1598 labels : Com.Atproto.Label.Defs.label list option; 1599 + like_count : int option; 1600 + quote_count : int option; 1601 + reply_count : int option; 1602 + repost_count : int option; 1603 uri : string; 1604 + value : Jsont.json; (** The record data itself. *) 1605 } 1606 1607 + (** Jsont codec for {!type:view_record}. *) 1608 + val view_record_jsont : view_record Jsont.t 1609 1610 1611 + type view_not_found = { 1612 + not_found : bool; 1613 uri : string; 1614 } 1615 1616 + (** Jsont codec for {!type:view_not_found}. *) 1617 + val view_not_found_jsont : view_not_found Jsont.t 1618 1619 1620 + type view_detached = { 1621 + detached : bool; 1622 uri : string; 1623 } 1624 1625 + (** Jsont codec for {!type:view_detached}. *) 1626 + val view_detached_jsont : view_detached Jsont.t 1627 1628 1629 + type view_blocked = { 1630 + author : Jsont.json; 1631 + blocked : bool; 1632 + uri : string; 1633 } 1634 1635 + (** Jsont codec for {!type:view_blocked}. *) 1636 + val view_blocked_jsont : view_blocked Jsont.t 1637 1638 1639 + type view = { 1640 + record : Jsont.json; 1641 } 1642 1643 + (** Jsont codec for {!type:view}. *) 1644 + val view_jsont : view Jsont.t 1645 1646 1647 type main = { 1648 + record : Com.Atproto.Repo.StrongRef.main; 1649 } 1650 1651 (** Jsont codec for {!type:main}. *) 1652 val main_jsont : main Jsont.t 1653 1654 end 1655 + end 1656 + module Contact : sig 1657 + module SendNotification : sig 1658 + (** System endpoint to send notifications related to contact imports. Requires role authentication. *) 1659 1660 + 1661 + type input = { 1662 + from : string; (** The DID of who this notification comes from. *) 1663 + to_ : string; (** The DID of who this notification should go to. *) 1664 } 1665 1666 + (** Jsont codec for {!type:input}. *) 1667 + val input_jsont : input Jsont.t 1668 1669 1670 + type output = unit 1671 1672 (** Jsont codec for {!type:output}. *) 1673 val output_jsont : output Jsont.t 1674 1675 end 1676 + module StartPhoneVerification : sig 1677 + (** Starts a phone verification flow. The phone passed will receive a code via SMS that should be passed to `app.bsky.contact.verifyPhone`. Requires authentication. *) 1678 + 1679 1680 + type input = { 1681 + phone : string; (** The phone number to receive the code via SMS. *) 1682 } 1683 1684 + (** Jsont codec for {!type:input}. *) 1685 + val input_jsont : input Jsont.t 1686 1687 1688 + type output = unit 1689 1690 (** Jsont codec for {!type:output}. *) 1691 val output_jsont : output Jsont.t 1692 1693 end 1694 + module GetMatches : sig 1695 + (** Returns the matched contacts (contacts that were mutually imported). Excludes dismissed matches. Requires authentication. *) 1696 1697 (** Query/procedure parameters. *) 1698 type params = { 1699 cursor : string option; 1700 limit : int option; 1701 } ··· 1706 1707 type output = { 1708 cursor : string option; 1709 + matches : Jsont.json list; 1710 } 1711 1712 (** Jsont codec for {!type:output}. *) 1713 val output_jsont : output Jsont.t 1714 1715 end 1716 + module VerifyPhone : sig 1717 + (** Verifies control over a phone number with a code received via SMS and starts a contact import session. Requires authentication. *) 1718 + 1719 1720 + type input = { 1721 + code : string; (** The code received via SMS as a result of the call to `app.bsky.contact.startPhoneVerification`. *) 1722 + phone : string; (** The phone number to verify. Should be the same as the one passed to `app.bsky.contact.startPhoneVerification`. *) 1723 } 1724 1725 + (** Jsont codec for {!type:input}. *) 1726 + val input_jsont : input Jsont.t 1727 1728 1729 type output = { 1730 + token : string; (** JWT to be used in a call to `app.bsky.contact.importContacts`. It is only valid for a single call. *) 1731 } 1732 1733 (** Jsont codec for {!type:output}. *) 1734 val output_jsont : output Jsont.t 1735 1736 end 1737 + module RemoveData : sig 1738 + (** Removes all stored hashes used for contact matching, existing matches, and sync status. Requires authentication. *) 1739 1740 1741 + type input = unit 1742 1743 + (** Jsont codec for {!type:input}. *) 1744 + val input_jsont : input Jsont.t 1745 1746 1747 + type output = unit 1748 1749 (** Jsont codec for {!type:output}. *) 1750 val output_jsont : output Jsont.t 1751 1752 end 1753 + module Defs : sig 1754 1755 + type sync_status = { 1756 + matches_count : int; (** Number of existing contact matches resulting of the user imports and of their imported contacts having imported the user. Matches stop being counted when the user either follows the matched contact or dismisses the match. *) 1757 + synced_at : string; (** Last date when contacts where imported. *) 1758 + } 1759 + 1760 + (** Jsont codec for {!type:sync_status}. *) 1761 + val sync_status_jsont : sync_status Jsont.t 1762 + 1763 + (** A stash object to be sent via bsync representing a notification to be created. *) 1764 + 1765 + type notification = { 1766 + from : string; (** The DID of who this notification comes from. *) 1767 + to_ : string; (** The DID of who this notification should go to. *) 1768 } 1769 1770 + (** Jsont codec for {!type:notification}. *) 1771 + val notification_jsont : notification Jsont.t 1772 1773 + (** Associates a profile with the positional index of the contact import input in the call to `app.bsky.contact.importContacts`, so clients can know which phone caused a particular match. *) 1774 1775 + type match_and_contact_index = { 1776 + contact_index : int; (** The index of this match in the import contact input. *) 1777 + match_ : Jsont.json; (** Profile of the matched user. *) 1778 } 1779 1780 + (** Jsont codec for {!type:match_and_contact_index}. *) 1781 + val match_and_contact_index_jsont : match_and_contact_index Jsont.t 1782 1783 end 1784 + module DismissMatch : sig 1785 + (** Removes a match that was found via contact import. It shouldn't appear again if the same contact is re-imported. Requires authentication. *) 1786 + 1787 1788 + type input = { 1789 + subject : string; (** The subject's DID to dismiss the match with. *) 1790 } 1791 1792 + (** Jsont codec for {!type:input}. *) 1793 + val input_jsont : input Jsont.t 1794 1795 1796 + type output = unit 1797 1798 (** Jsont codec for {!type:output}. *) 1799 val output_jsont : output Jsont.t 1800 1801 end 1802 + module GetSyncStatus : sig 1803 + (** Gets the user's current contact import status. Requires authentication. *) 1804 1805 (** Query/procedure parameters. *) 1806 + type params = unit 1807 1808 (** Jsont codec for {!type:params}. *) 1809 val params_jsont : params Jsont.t 1810 1811 1812 type output = { 1813 + sync_status : Defs.sync_status option; (** If present, indicates the user has imported their contacts. If not present, indicates the user never used the feature or called `app.bsky.contact.removeData` and didn't import again since. *) 1814 } 1815 1816 (** Jsont codec for {!type:output}. *) 1817 val output_jsont : output Jsont.t 1818 1819 end 1820 + module ImportContacts : sig 1821 + (** Import contacts for securely matching with other users. This follows the protocol explained in https://docs.bsky.app/blog/contact-import-rfc. Requires authentication. *) 1822 1823 1824 + type input = { 1825 + contacts : string list; (** List of phone numbers in global E.164 format (e.g., '+12125550123'). Phone numbers that cannot be normalized into a valid phone number will be discarded. Should not repeat the 'phone' input used in `app.bsky.contact.verifyPhone`. *) 1826 + token : string; (** JWT to authenticate the call. Use the JWT received as a response to the call to `app.bsky.contact.verifyPhone`. *) 1827 } 1828 1829 + (** Jsont codec for {!type:input}. *) 1830 + val input_jsont : input Jsont.t 1831 1832 1833 type output = { 1834 + matches_and_contact_indexes : Defs.match_and_contact_index list; (** The users that matched during import and their indexes on the input contacts, so the client can correlate with its local list. *) 1835 } 1836 1837 (** Jsont codec for {!type:output}. *) 1838 val output_jsont : output Jsont.t 1839 1840 end 1841 + end 1842 + module Feed : sig 1843 + module Repost : sig 1844 + (** Record representing a 'repost' of an existing Bluesky post. *) 1845 1846 + type main = { 1847 + created_at : string; 1848 + subject : Com.Atproto.Repo.StrongRef.main; 1849 + via : Com.Atproto.Repo.StrongRef.main option; 1850 } 1851 1852 + (** Jsont codec for {!type:main}. *) 1853 + val main_jsont : main Jsont.t 1854 1855 + end 1856 + module DescribeFeedGenerator : sig 1857 1858 + type links = { 1859 + privacy_policy : string option; 1860 + terms_of_service : string option; 1861 } 1862 1863 + (** Jsont codec for {!type:links}. *) 1864 + val links_jsont : links Jsont.t 1865 1866 1867 + type feed = { 1868 + uri : string; 1869 } 1870 1871 + (** Jsont codec for {!type:feed}. *) 1872 + val feed_jsont : feed Jsont.t 1873 + 1874 + (** Get information about a feed generator, including policies and offered feed URIs. Does not require auth; implemented by Feed Generator services (not App View). *) 1875 1876 1877 type output = { 1878 + did : string; 1879 + feeds : Jsont.json list; 1880 + links : Jsont.json option; 1881 } 1882 1883 (** Jsont codec for {!type:output}. *) 1884 val output_jsont : output Jsont.t 1885 1886 end 1887 + module Threadgate : sig 1888 + (** Allow replies from actors mentioned in your post. *) 1889 1890 + type mention_rule = unit 1891 1892 + (** Jsont codec for {!type:mention_rule}. *) 1893 + val mention_rule_jsont : mention_rule Jsont.t 1894 1895 + (** Allow replies from actors on a list. *) 1896 1897 + type list_rule = { 1898 + list_ : string; 1899 } 1900 1901 + (** Jsont codec for {!type:list_rule}. *) 1902 + val list_rule_jsont : list_rule Jsont.t 1903 1904 + (** Allow replies from actors you follow. *) 1905 1906 + type following_rule = unit 1907 1908 + (** Jsont codec for {!type:following_rule}. *) 1909 + val following_rule_jsont : following_rule Jsont.t 1910 1911 + (** Allow replies from actors who follow you. *) 1912 1913 + type follower_rule = unit 1914 1915 + (** Jsont codec for {!type:follower_rule}. *) 1916 + val follower_rule_jsont : follower_rule Jsont.t 1917 1918 + (** Record defining interaction gating rules for a thread (aka, reply controls). The record key (rkey) of the threadgate record must match the record key of the thread's root post, and that record must be in the same repository. *) 1919 1920 + type main = { 1921 + allow : Jsont.json list option; (** List of rules defining who can reply to this post. If value is an empty array, no one can reply. If value is undefined, anyone can reply. *) 1922 + created_at : string; 1923 + hidden_replies : string list option; (** List of hidden reply URIs. *) 1924 + post : string; (** Reference (AT-URI) to the post record. *) 1925 } 1926 1927 + (** Jsont codec for {!type:main}. *) 1928 + val main_jsont : main Jsont.t 1929 1930 + end 1931 + module Like : sig 1932 + (** Record declaring a 'like' of a piece of subject content. *) 1933 1934 type main = { 1935 + created_at : string; 1936 + subject : Com.Atproto.Repo.StrongRef.main; 1937 + via : Com.Atproto.Repo.StrongRef.main option; 1938 } 1939 1940 (** Jsont codec for {!type:main}. *) ··· 1977 val output_jsont : output Jsont.t 1978 1979 end 1980 module GetRepostedBy : sig 1981 (** Get a list of reposts for a given post. *) 1982 ··· 2003 val output_jsont : output Jsont.t 2004 2005 end 2006 + module Generator : sig 2007 + (** Record declaring of the existence of a feed generator, and containing metadata about it. The record can exist in any repository. *) 2008 2009 + type main = { 2010 + accepts_interactions : bool option; (** Declaration that a feed accepts feedback interactions from a client through app.bsky.feed.sendInteractions *) 2011 + avatar : Atp.Blob_ref.t option; 2012 + content_mode : string option; 2013 + created_at : string; 2014 + description : string option; 2015 + description_facets : Richtext.Facet.main list option; 2016 did : string; 2017 + display_name : string; 2018 + labels : Com.Atproto.Label.Defs.self_labels option; (** Self-label values *) 2019 } 2020 2021 + (** Jsont codec for {!type:main}. *) 2022 + val main_jsont : main Jsont.t 2023 2024 end 2025 + module Postgate : sig 2026 + (** Disables embedding of this post. *) 2027 2028 + type disable_rule = unit 2029 2030 + (** Jsont codec for {!type:disable_rule}. *) 2031 + val disable_rule_jsont : disable_rule Jsont.t 2032 2033 + (** Record defining interaction rules for a post. The record key (rkey) of the postgate record must match the record key of the post, and that record must be in the same repository. *) 2034 2035 type main = { 2036 created_at : string; 2037 + detached_embedding_uris : string list option; (** List of AT-URIs embedding this post that the author has detached from. *) 2038 + embedding_rules : Jsont.json list option; (** List of rules defining who can embed this post. If value is an empty array or is undefined, no particular rules apply and anyone can embed. *) 2039 post : string; (** Reference (AT-URI) to the post record. *) 2040 } 2041 2042 (** Jsont codec for {!type:main}. *) ··· 2314 val feed_view_post_jsont : feed_view_post Jsont.t 2315 2316 end 2317 + module Post : sig 2318 + (** Deprecated. Use app.bsky.richtext instead -- A text segment. Start is inclusive, end is exclusive. Indices are for utf16-encoded strings. *) 2319 + 2320 + type text_slice = { 2321 + end_ : int; 2322 + start : int; 2323 + } 2324 + 2325 + (** Jsont codec for {!type:text_slice}. *) 2326 + val text_slice_jsont : text_slice Jsont.t 2327 + 2328 + 2329 + type reply_ref = { 2330 + parent : Com.Atproto.Repo.StrongRef.main; 2331 + root : Com.Atproto.Repo.StrongRef.main; 2332 + } 2333 + 2334 + (** Jsont codec for {!type:reply_ref}. *) 2335 + val reply_ref_jsont : reply_ref Jsont.t 2336 + 2337 + (** Deprecated: use facets instead. *) 2338 + 2339 + type entity = { 2340 + index : Jsont.json; 2341 + type_ : string; (** Expected values are 'mention' and 'link'. *) 2342 + value : string; 2343 + } 2344 + 2345 + (** Jsont codec for {!type:entity}. *) 2346 + val entity_jsont : entity Jsont.t 2347 + 2348 + (** Record containing a Bluesky post. *) 2349 2350 type main = { 2351 + created_at : string; (** Client-declared timestamp when this post was originally created. *) 2352 + embed : Jsont.json option; 2353 + entities : Jsont.json list option; (** DEPRECATED: replaced by app.bsky.richtext.facet. *) 2354 + facets : Richtext.Facet.main list option; (** Annotations of text (mentions, URLs, hashtags, etc) *) 2355 + labels : Com.Atproto.Label.Defs.self_labels option; (** Self-label values for this post. Effectively content warnings. *) 2356 + langs : string list option; (** Indicates human language of post primary text content. *) 2357 + reply : Jsont.json option; 2358 + tags : string list option; (** Additional hashtags, in addition to any included in post text and facets. *) 2359 + text : string; (** The primary post content. May be an empty string, if there are embeds. *) 2360 } 2361 2362 (** Jsont codec for {!type:main}. *) 2363 val main_jsont : main Jsont.t 2364 2365 end 2366 + module GetPosts : sig 2367 + (** Gets post views for a specified list of posts (by AT-URI). This is sometimes referred to as 'hydrating' a 'feed skeleton'. *) 2368 2369 + (** Query/procedure parameters. *) 2370 + type params = { 2371 + uris : string list; (** List of post AT-URIs to return hydrated views for. *) 2372 + } 2373 + 2374 + (** Jsont codec for {!type:params}. *) 2375 + val params_jsont : params Jsont.t 2376 + 2377 + 2378 + type output = { 2379 + posts : Jsont.json list; 2380 } 2381 2382 + (** Jsont codec for {!type:output}. *) 2383 + val output_jsont : output Jsont.t 2384 2385 end 2386 + module GetQuotes : sig 2387 + (** Get a list of quotes for a given post. *) 2388 2389 (** Query/procedure parameters. *) 2390 type params = { 2391 + cid : string option; (** If supplied, filters to quotes of specific version (by CID) of the post record. *) 2392 + cursor : string option; 2393 + limit : int option; 2394 + uri : string; (** Reference (AT-URI) of post record *) 2395 } 2396 2397 (** Jsont codec for {!type:params}. *) ··· 2399 2400 2401 type output = { 2402 + cid : string option; 2403 + cursor : string option; 2404 + posts : Jsont.json list; 2405 + uri : string; 2406 } 2407 2408 (** Jsont codec for {!type:output}. *) 2409 val output_jsont : output Jsont.t 2410 2411 end 2412 + module GetAuthorFeed : sig 2413 + (** Get a view of an actor's 'author feed' (post and reposts by the author). Does not require auth. *) 2414 2415 (** Query/procedure parameters. *) 2416 type params = { 2417 + actor : string; 2418 cursor : string option; 2419 + filter : string option; (** Combinations of post/repost types to include in response. *) 2420 + include_pins : bool option; 2421 limit : int option; 2422 } 2423 ··· 2434 val output_jsont : output Jsont.t 2435 2436 end 2437 + module GetTimeline : sig 2438 + (** Get a view of the requesting account's home timeline. This is expected to be some form of reverse-chronological feed. *) 2439 2440 (** Query/procedure parameters. *) 2441 type params = { 2442 + algorithm : string option; (** Variant 'algorithm' for timeline. Implementation-specific. NOTE: most feed flexibility has been moved to feed generator mechanism. *) 2443 cursor : string option; 2444 limit : int option; 2445 } 2446 2447 (** Jsont codec for {!type:params}. *) ··· 2449 2450 2451 type output = { 2452 cursor : string option; 2453 + feed : Jsont.json list; 2454 } 2455 2456 (** Jsont codec for {!type:output}. *) ··· 2480 val output_jsont : output Jsont.t 2481 2482 end 2483 + module GetSuggestedFeeds : sig 2484 + (** Get a list of suggested feeds (feed generators) for the requesting account. *) 2485 + 2486 + (** Query/procedure parameters. *) 2487 + type params = { 2488 + cursor : string option; 2489 + limit : int option; 2490 + } 2491 + 2492 + (** Jsont codec for {!type:params}. *) 2493 + val params_jsont : params Jsont.t 2494 + 2495 + 2496 + type output = { 2497 + cursor : string option; 2498 + feeds : Jsont.json list; 2499 + } 2500 + 2501 + (** Jsont codec for {!type:output}. *) 2502 + val output_jsont : output Jsont.t 2503 + 2504 + end 2505 module GetActorLikes : sig 2506 (** Get a list of posts liked by an actor. Requires auth, actor must be the requesting account. *) 2507 ··· 2525 val output_jsont : output Jsont.t 2526 2527 end 2528 + module GetActorFeeds : sig 2529 + (** Get a list of feeds (feed generator records) created by the actor (in the actor's repo). *) 2530 2531 (** Query/procedure parameters. *) 2532 type params = { 2533 + actor : string; 2534 cursor : string option; 2535 limit : int option; 2536 } 2537 ··· 2541 2542 type output = { 2543 cursor : string option; 2544 + feeds : Jsont.json list; 2545 } 2546 2547 (** Jsont codec for {!type:output}. *) ··· 2581 val output_jsont : output Jsont.t 2582 2583 end 2584 + module GetPostThread : sig 2585 + (** Get posts in a thread. Does not require auth, but additional metadata and filtering will be applied for authed requests. *) 2586 + 2587 + (** Query/procedure parameters. *) 2588 + type params = { 2589 + depth : int option; (** How many levels of reply depth should be included in response. *) 2590 + parent_height : int option; (** How many levels of parent (and grandparent, etc) post to include. *) 2591 + uri : string; (** Reference (AT-URI) to post record. *) 2592 + } 2593 + 2594 + (** Jsont codec for {!type:params}. *) 2595 + val params_jsont : params Jsont.t 2596 + 2597 + 2598 + type output = { 2599 + thread : Jsont.json; 2600 + threadgate : Jsont.json option; 2601 + } 2602 + 2603 + (** Jsont codec for {!type:output}. *) 2604 + val output_jsont : output Jsont.t 2605 + 2606 + end 2607 + module GetFeedSkeleton : sig 2608 + (** Get a skeleton of a feed provided by a feed generator. Auth is optional, depending on provider requirements, and provides the DID of the requester. Implemented by Feed Generator Service. *) 2609 + 2610 + (** Query/procedure parameters. *) 2611 + type params = { 2612 + cursor : string option; 2613 + feed : string; (** Reference to feed generator record describing the specific feed being requested. *) 2614 + limit : int option; 2615 + } 2616 + 2617 + (** Jsont codec for {!type:params}. *) 2618 + val params_jsont : params Jsont.t 2619 + 2620 + 2621 + type output = { 2622 + cursor : string option; 2623 + feed : Jsont.json list; 2624 + req_id : string option; (** Unique identifier per request that may be passed back alongside interactions. *) 2625 + } 2626 + 2627 + (** Jsont codec for {!type:output}. *) 2628 + val output_jsont : output Jsont.t 2629 + 2630 + end 2631 + module GetFeed : sig 2632 + (** Get a hydrated feed from an actor's selected feed generator. Implemented by App View. *) 2633 + 2634 + (** Query/procedure parameters. *) 2635 + type params = { 2636 + cursor : string option; 2637 + feed : string; 2638 + limit : int option; 2639 + } 2640 + 2641 + (** Jsont codec for {!type:params}. *) 2642 + val params_jsont : params Jsont.t 2643 + 2644 + 2645 + type output = { 2646 + cursor : string option; 2647 + feed : Jsont.json list; 2648 + } 2649 + 2650 + (** Jsont codec for {!type:output}. *) 2651 + val output_jsont : output Jsont.t 2652 + 2653 + end 2654 module GetFeedGenerators : sig 2655 (** Get information about a list of feed generators. *) 2656 ··· 2689 val output_jsont : output Jsont.t 2690 2691 end 2692 + module GetFeedGenerator : sig 2693 + (** Get information about a feed generator. Implemented by AppView. *) 2694 + 2695 + (** Query/procedure parameters. *) 2696 + type params = { 2697 + feed : string; (** AT-URI of the feed generator record. *) 2698 + } 2699 + 2700 + (** Jsont codec for {!type:params}. *) 2701 + val params_jsont : params Jsont.t 2702 + 2703 + 2704 + type output = { 2705 + is_online : bool; (** Indicates whether the feed generator service has been online recently, or else seems to be inactive. *) 2706 + is_valid : bool; (** Indicates whether the feed generator service is compatible with the record declaration. *) 2707 + view : Jsont.json; 2708 + } 2709 + 2710 + (** Jsont codec for {!type:output}. *) 2711 + val output_jsont : output Jsont.t 2712 + 2713 + end 2714 + end 2715 + module Graph : sig 2716 + module Defs : sig 2717 + 2718 + type starter_pack_view_basic = { 2719 + cid : string; 2720 + creator : Jsont.json; 2721 + indexed_at : string; 2722 + joined_all_time_count : int option; 2723 + joined_week_count : int option; 2724 + labels : Com.Atproto.Label.Defs.label list option; 2725 + list_item_count : int option; 2726 + record : Jsont.json; 2727 + uri : string; 2728 + } 2729 + 2730 + (** Jsont codec for {!type:starter_pack_view_basic}. *) 2731 + val starter_pack_view_basic_jsont : starter_pack_view_basic Jsont.t 2732 + 2733 + (** lists the bi-directional graph relationships between one actor (not indicated in the object), and the target actors (the DID included in the object) *) 2734 + 2735 + type relationship = { 2736 + blocked_by : string option; (** if the actor is blocked by this DID, contains the AT-URI of the block record *) 2737 + blocked_by_list : string option; (** if the actor is blocked by this DID via a block list, contains the AT-URI of the listblock record *) 2738 + blocking : string option; (** if the actor blocks this DID, this is the AT-URI of the block record *) 2739 + blocking_by_list : string option; (** if the actor blocks this DID via a block list, this is the AT-URI of the listblock record *) 2740 + did : string; 2741 + followed_by : string option; (** if the actor is followed by this DID, contains the AT-URI of the follow record *) 2742 + following : string option; (** if the actor follows this DID, this is the AT-URI of the follow record *) 2743 + } 2744 + 2745 + (** Jsont codec for {!type:relationship}. *) 2746 + val relationship_jsont : relationship Jsont.t 2747 + 2748 + (** A list of actors used for only for reference purposes such as within a starter pack. *) 2749 + 2750 + type referencelist = string 2751 + val referencelist_jsont : referencelist Jsont.t 2752 + 2753 + (** indicates that a handle or DID could not be resolved *) 2754 + 2755 + type not_found_actor = { 2756 + actor : string; 2757 + not_found : bool; 2758 + } 2759 + 2760 + (** Jsont codec for {!type:not_found_actor}. *) 2761 + val not_found_actor_jsont : not_found_actor Jsont.t 2762 + 2763 + (** A list of actors to apply an aggregate moderation action (mute/block) on. *) 2764 + 2765 + type modlist = string 2766 + val modlist_jsont : modlist Jsont.t 2767 + 2768 + 2769 + type list_viewer_state = { 2770 + blocked : string option; 2771 + muted : bool option; 2772 + } 2773 + 2774 + (** Jsont codec for {!type:list_viewer_state}. *) 2775 + val list_viewer_state_jsont : list_viewer_state Jsont.t 2776 + 2777 + 2778 + type list_purpose = string 2779 + val list_purpose_jsont : list_purpose Jsont.t 2780 + 2781 + 2782 + type list_item_view = { 2783 + subject : Jsont.json; 2784 + uri : string; 2785 + } 2786 + 2787 + (** Jsont codec for {!type:list_item_view}. *) 2788 + val list_item_view_jsont : list_item_view Jsont.t 2789 + 2790 + (** A list of actors used for curation purposes such as list feeds or interaction gating. *) 2791 + 2792 + type curatelist = string 2793 + val curatelist_jsont : curatelist Jsont.t 2794 + 2795 + 2796 + type list_view_basic = { 2797 + avatar : string option; 2798 + cid : string; 2799 + indexed_at : string option; 2800 + labels : Com.Atproto.Label.Defs.label list option; 2801 + list_item_count : int option; 2802 + name : string; 2803 + purpose : Jsont.json; 2804 + uri : string; 2805 + viewer : Jsont.json option; 2806 + } 2807 + 2808 + (** Jsont codec for {!type:list_view_basic}. *) 2809 + val list_view_basic_jsont : list_view_basic Jsont.t 2810 + 2811 + 2812 + type list_view = { 2813 + avatar : string option; 2814 + cid : string; 2815 + creator : Jsont.json; 2816 + description : string option; 2817 + description_facets : Richtext.Facet.main list option; 2818 + indexed_at : string; 2819 + labels : Com.Atproto.Label.Defs.label list option; 2820 + list_item_count : int option; 2821 + name : string; 2822 + purpose : Jsont.json; 2823 + uri : string; 2824 + viewer : Jsont.json option; 2825 + } 2826 + 2827 + (** Jsont codec for {!type:list_view}. *) 2828 + val list_view_jsont : list_view Jsont.t 2829 + 2830 + 2831 + type starter_pack_view = { 2832 + cid : string; 2833 + creator : Jsont.json; 2834 + feeds : Jsont.json list option; 2835 + indexed_at : string; 2836 + joined_all_time_count : int option; 2837 + joined_week_count : int option; 2838 + labels : Com.Atproto.Label.Defs.label list option; 2839 + list_ : Jsont.json option; 2840 + list_items_sample : Jsont.json list option; 2841 + record : Jsont.json; 2842 + uri : string; 2843 + } 2844 + 2845 + (** Jsont codec for {!type:starter_pack_view}. *) 2846 + val starter_pack_view_jsont : starter_pack_view Jsont.t 2847 + 2848 + end 2849 + module UnmuteActor : sig 2850 + (** Unmutes the specified account. Requires auth. *) 2851 + 2852 + 2853 + type input = { 2854 + actor : string; 2855 + } 2856 + 2857 + (** Jsont codec for {!type:input}. *) 2858 + val input_jsont : input Jsont.t 2859 + 2860 + end 2861 + module Listitem : sig 2862 + (** Record representing an account's inclusion on a specific list. The AppView will ignore duplicate listitem records. *) 2863 + 2864 + type main = { 2865 + created_at : string; 2866 + list_ : string; (** Reference (AT-URI) to the list record (app.bsky.graph.list). *) 2867 + subject : string; (** The account which is included on the list. *) 2868 + } 2869 + 2870 + (** Jsont codec for {!type:main}. *) 2871 + val main_jsont : main Jsont.t 2872 + 2873 + end 2874 + module GetSuggestedFollowsByActor : sig 2875 + (** Enumerates follows similar to a given account (actor). Expected use is to recommend additional accounts immediately after following one account. *) 2876 + 2877 + (** Query/procedure parameters. *) 2878 + type params = { 2879 + actor : string; 2880 + } 2881 + 2882 + (** Jsont codec for {!type:params}. *) 2883 + val params_jsont : params Jsont.t 2884 + 2885 + 2886 + type output = { 2887 + is_fallback : bool option; (** If true, response has fallen-back to generic results, and is not scoped using relativeToDid *) 2888 + rec_id : int option; (** Snowflake for this recommendation, use when submitting recommendation events. *) 2889 + suggestions : Jsont.json list; 2890 + } 2891 + 2892 + (** Jsont codec for {!type:output}. *) 2893 + val output_jsont : output Jsont.t 2894 + 2895 + end 2896 + module MuteActorList : sig 2897 + (** Creates a mute relationship for the specified list of accounts. Mutes are private in Bluesky. Requires auth. *) 2898 + 2899 + 2900 + type input = { 2901 + list_ : string; 2902 + } 2903 + 2904 + (** Jsont codec for {!type:input}. *) 2905 + val input_jsont : input Jsont.t 2906 + 2907 + end 2908 + module GetFollowers : sig 2909 + (** Enumerates accounts which follow a specified account (actor). *) 2910 2911 (** Query/procedure parameters. *) 2912 type params = { 2913 actor : string; 2914 cursor : string option; 2915 limit : int option; 2916 } 2917 ··· 2921 2922 type output = { 2923 cursor : string option; 2924 + followers : Jsont.json list; 2925 + subject : Jsont.json; 2926 } 2927 2928 (** Jsont codec for {!type:output}. *) 2929 val output_jsont : output Jsont.t 2930 2931 end 2932 + module MuteActor : sig 2933 + (** Creates a mute relationship for the specified account. Mutes are private in Bluesky. Requires auth. *) 2934 + 2935 + 2936 + type input = { 2937 + actor : string; 2938 + } 2939 + 2940 + (** Jsont codec for {!type:input}. *) 2941 + val input_jsont : input Jsont.t 2942 + 2943 + end 2944 + module UnmuteActorList : sig 2945 + (** Unmutes the specified list of accounts. Requires auth. *) 2946 + 2947 + 2948 + type input = { 2949 + list_ : string; 2950 + } 2951 + 2952 + (** Jsont codec for {!type:input}. *) 2953 + val input_jsont : input Jsont.t 2954 + 2955 + end 2956 + module GetBlocks : sig 2957 + (** Enumerates which accounts the requesting account is currently blocking. Requires auth. *) 2958 2959 (** Query/procedure parameters. *) 2960 type params = { 2961 + cursor : string option; 2962 + limit : int option; 2963 } 2964 2965 (** Jsont codec for {!type:params}. *) ··· 2967 2968 2969 type output = { 2970 + blocks : Jsont.json list; 2971 + cursor : string option; 2972 } 2973 2974 (** Jsont codec for {!type:output}. *) 2975 val output_jsont : output Jsont.t 2976 2977 end 2978 + module Listblock : sig 2979 + (** Record representing a block relationship against an entire an entire list of accounts (actors). *) 2980 + 2981 + type main = { 2982 + created_at : string; 2983 + subject : string; (** Reference (AT-URI) to the mod list record. *) 2984 + } 2985 + 2986 + (** Jsont codec for {!type:main}. *) 2987 + val main_jsont : main Jsont.t 2988 + 2989 + end 2990 + module MuteThread : sig 2991 + (** Mutes a thread preventing notifications from the thread and any of its children. Mutes are private in Bluesky. Requires auth. *) 2992 + 2993 + 2994 + type input = { 2995 + root : string; 2996 + } 2997 + 2998 + (** Jsont codec for {!type:input}. *) 2999 + val input_jsont : input Jsont.t 3000 + 3001 + end 3002 + module Follow : sig 3003 + (** Record declaring a social 'follow' relationship of another account. Duplicate follows will be ignored by the AppView. *) 3004 + 3005 + type main = { 3006 + created_at : string; 3007 + subject : string; 3008 + via : Com.Atproto.Repo.StrongRef.main option; 3009 + } 3010 + 3011 + (** Jsont codec for {!type:main}. *) 3012 + val main_jsont : main Jsont.t 3013 + 3014 + end 3015 + module Starterpack : sig 3016 + 3017 + type feed_item = { 3018 + uri : string; 3019 + } 3020 + 3021 + (** Jsont codec for {!type:feed_item}. *) 3022 + val feed_item_jsont : feed_item Jsont.t 3023 + 3024 + (** Record defining a starter pack of actors and feeds for new users. *) 3025 + 3026 + type main = { 3027 + created_at : string; 3028 + description : string option; 3029 + description_facets : Richtext.Facet.main list option; 3030 + feeds : Jsont.json list option; 3031 + list_ : string; (** Reference (AT-URI) to the list record. *) 3032 + name : string; (** Display name for starter pack; can not be empty. *) 3033 + } 3034 + 3035 + (** Jsont codec for {!type:main}. *) 3036 + val main_jsont : main Jsont.t 3037 + 3038 + end 3039 + module GetFollows : sig 3040 + (** Enumerates accounts which a specified account (actor) follows. *) 3041 3042 (** Query/procedure parameters. *) 3043 type params = { 3044 + actor : string; 3045 cursor : string option; 3046 limit : int option; 3047 } ··· 3052 3053 type output = { 3054 cursor : string option; 3055 + follows : Jsont.json list; 3056 + subject : Jsont.json; 3057 } 3058 3059 (** Jsont codec for {!type:output}. *) 3060 val output_jsont : output Jsont.t 3061 3062 end 3063 + module Verification : sig 3064 + (** Record declaring a verification relationship between two accounts. Verifications are only considered valid by an app if issued by an account the app considers trusted. *) 3065 + 3066 + type main = { 3067 + created_at : string; (** Date of when the verification was created. *) 3068 + display_name : string; (** Display name of the subject the verification applies to at the moment of verifying, which might not be the same at the time of viewing. The verification is only valid if the current displayName matches the one at the time of verifying. *) 3069 + handle : string; (** Handle of the subject the verification applies to at the moment of verifying, which might not be the same at the time of viewing. The verification is only valid if the current handle matches the one at the time of verifying. *) 3070 + subject : string; (** DID of the subject the verification applies to. *) 3071 + } 3072 + 3073 + (** Jsont codec for {!type:main}. *) 3074 + val main_jsont : main Jsont.t 3075 + 3076 + end 3077 + module UnmuteThread : sig 3078 + (** Unmutes the specified thread. Requires auth. *) 3079 + 3080 + 3081 + type input = { 3082 + root : string; 3083 + } 3084 + 3085 + (** Jsont codec for {!type:input}. *) 3086 + val input_jsont : input Jsont.t 3087 + 3088 + end 3089 + module GetMutes : sig 3090 + (** Enumerates accounts that the requesting account (actor) currently has muted. Requires auth. *) 3091 + 3092 + (** Query/procedure parameters. *) 3093 + type params = { 3094 + cursor : string option; 3095 + limit : int option; 3096 + } 3097 + 3098 + (** Jsont codec for {!type:params}. *) 3099 + val params_jsont : params Jsont.t 3100 + 3101 + 3102 + type output = { 3103 + cursor : string option; 3104 + mutes : Jsont.json list; 3105 + } 3106 + 3107 + (** Jsont codec for {!type:output}. *) 3108 + val output_jsont : output Jsont.t 3109 + 3110 + end 3111 + module GetKnownFollowers : sig 3112 + (** Enumerates accounts which follow a specified account (actor) and are followed by the viewer. *) 3113 3114 (** Query/procedure parameters. *) 3115 type params = { ··· 3124 3125 type output = { 3126 cursor : string option; 3127 + followers : Jsont.json list; 3128 + subject : Jsont.json; 3129 } 3130 3131 (** Jsont codec for {!type:output}. *) 3132 val output_jsont : output Jsont.t 3133 3134 end 3135 + module Block : sig 3136 + (** Record declaring a 'block' relationship against another account. NOTE: blocks are public in Bluesky; see blog posts for details. *) 3137 + 3138 + type main = { 3139 + created_at : string; 3140 + subject : string; (** DID of the account to be blocked. *) 3141 + } 3142 + 3143 + (** Jsont codec for {!type:main}. *) 3144 + val main_jsont : main Jsont.t 3145 + 3146 + end 3147 + module GetRelationships : sig 3148 + (** Enumerates public relationships between one account, and a list of other accounts. Does not require auth. *) 3149 3150 (** Query/procedure parameters. *) 3151 type params = { 3152 + actor : string; (** Primary account requesting relationships for. *) 3153 + others : string list option; (** List of 'other' accounts to be related back to the primary. *) 3154 } 3155 3156 (** Jsont codec for {!type:params}. *) ··· 3158 3159 3160 type output = { 3161 + actor : string option; 3162 + relationships : Jsont.json list; 3163 } 3164 3165 (** Jsont codec for {!type:output}. *) 3166 val output_jsont : output Jsont.t 3167 3168 end 3169 + module GetListsWithMembership : sig 3170 + (** A list and an optional list item indicating membership of a target user to that list. *) 3171 + 3172 + type list_with_membership = { 3173 + list_ : Jsont.json; 3174 + list_item : Jsont.json option; 3175 + } 3176 + 3177 + (** Jsont codec for {!type:list_with_membership}. *) 3178 + val list_with_membership_jsont : list_with_membership Jsont.t 3179 + 3180 + (** Enumerates the lists created by the session user, and includes membership information about `actor` in those lists. Only supports curation and moderation lists (no reference lists, used in starter packs). Requires auth. *) 3181 3182 (** Query/procedure parameters. *) 3183 type params = { 3184 + actor : string; (** The account (actor) to check for membership. *) 3185 cursor : string option; 3186 limit : int option; 3187 + purposes : string list option; (** Optional filter by list purpose. If not specified, all supported types are returned. *) 3188 } 3189 3190 (** Jsont codec for {!type:params}. *) ··· 3193 3194 type output = { 3195 cursor : string option; 3196 + lists_with_membership : Jsont.json list; 3197 } 3198 3199 (** Jsont codec for {!type:output}. *) 3200 val output_jsont : output Jsont.t 3201 3202 end 3203 + module GetListMutes : sig 3204 + (** Enumerates mod lists that the requesting account (actor) currently has muted. Requires auth. *) 3205 + 3206 + (** Query/procedure parameters. *) 3207 + type params = { 3208 + cursor : string option; 3209 + limit : int option; 3210 + } 3211 3212 + (** Jsont codec for {!type:params}. *) 3213 + val params_jsont : params Jsont.t 3214 3215 + 3216 + type output = { 3217 + cursor : string option; 3218 + lists : Jsont.json list; 3219 } 3220 3221 + (** Jsont codec for {!type:output}. *) 3222 + val output_jsont : output Jsont.t 3223 3224 end 3225 + module GetActorStarterPacks : sig 3226 + (** Get a list of starter packs created by the actor. *) 3227 3228 + (** Query/procedure parameters. *) 3229 + type params = { 3230 + actor : string; 3231 + cursor : string option; 3232 + limit : int option; 3233 + } 3234 3235 + (** Jsont codec for {!type:params}. *) 3236 + val params_jsont : params Jsont.t 3237 + 3238 + 3239 + type output = { 3240 + cursor : string option; 3241 + starter_packs : Jsont.json list; 3242 } 3243 3244 + (** Jsont codec for {!type:output}. *) 3245 + val output_jsont : output Jsont.t 3246 3247 end 3248 + module SearchStarterPacks : sig 3249 + (** Find starter packs matching search criteria. Does not require auth. *) 3250 3251 + (** Query/procedure parameters. *) 3252 + type params = { 3253 + cursor : string option; 3254 + limit : int option; 3255 + q : string; (** Search query string. Syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended. *) 3256 } 3257 3258 + (** Jsont codec for {!type:params}. *) 3259 + val params_jsont : params Jsont.t 3260 3261 3262 + type output = { 3263 + cursor : string option; 3264 + starter_packs : Jsont.json list; 3265 } 3266 3267 + (** Jsont codec for {!type:output}. *) 3268 + val output_jsont : output Jsont.t 3269 3270 end 3271 + module GetStarterPacksWithMembership : sig 3272 + (** A starter pack and an optional list item indicating membership of a target user to that starter pack. *) 3273 + 3274 + type starter_pack_with_membership = { 3275 + list_item : Jsont.json option; 3276 + starter_pack : Jsont.json; 3277 + } 3278 + 3279 + (** Jsont codec for {!type:starter_pack_with_membership}. *) 3280 + val starter_pack_with_membership_jsont : starter_pack_with_membership Jsont.t 3281 + 3282 + (** Enumerates the starter packs created by the session user, and includes membership information about `actor` in those starter packs. Requires auth. *) 3283 3284 (** Query/procedure parameters. *) 3285 type params = { 3286 + actor : string; (** The account (actor) to check for membership. *) 3287 cursor : string option; 3288 limit : int option; 3289 } ··· 3293 3294 3295 type output = { 3296 cursor : string option; 3297 + starter_packs_with_membership : Jsont.json list; 3298 } 3299 3300 (** Jsont codec for {!type:output}. *) 3301 val output_jsont : output Jsont.t 3302 3303 end 3304 + module GetLists : sig 3305 + (** Enumerates the lists created by a specified account (actor). *) 3306 3307 (** Query/procedure parameters. *) 3308 type params = { 3309 + actor : string; (** The account (actor) to enumerate lists from. *) 3310 + cursor : string option; 3311 limit : int option; 3312 + purposes : string list option; (** Optional filter by list purpose. If not specified, all supported types are returned. *) 3313 } 3314 3315 (** Jsont codec for {!type:params}. *) ··· 3317 3318 3319 type output = { 3320 + cursor : string option; 3321 + lists : Jsont.json list; 3322 } 3323 3324 (** Jsont codec for {!type:output}. *) 3325 val output_jsont : output Jsont.t 3326 3327 end 3328 + module GetStarterPack : sig 3329 + (** Gets a view of a starter pack. *) 3330 3331 (** Query/procedure parameters. *) 3332 type params = { 3333 + starter_pack : string; (** Reference (AT-URI) of the starter pack record. *) 3334 + } 3335 + 3336 + (** Jsont codec for {!type:params}. *) 3337 + val params_jsont : params Jsont.t 3338 + 3339 + 3340 + type output = { 3341 + starter_pack : Jsont.json; 3342 + } 3343 + 3344 + (** Jsont codec for {!type:output}. *) 3345 + val output_jsont : output Jsont.t 3346 + 3347 + end 3348 + module GetListBlocks : sig 3349 + (** Get mod lists that the requesting account (actor) is blocking. Requires auth. *) 3350 + 3351 + (** Query/procedure parameters. *) 3352 + type params = { 3353 + cursor : string option; 3354 limit : int option; 3355 } 3356 ··· 3359 3360 3361 type output = { 3362 + cursor : string option; 3363 + lists : Jsont.json list; 3364 + } 3365 + 3366 + (** Jsont codec for {!type:output}. *) 3367 + val output_jsont : output Jsont.t 3368 + 3369 + end 3370 + module GetStarterPacks : sig 3371 + (** Get views for a list of starter packs. *) 3372 + 3373 + (** Query/procedure parameters. *) 3374 + type params = { 3375 + uris : string list; 3376 + } 3377 + 3378 + (** Jsont codec for {!type:params}. *) 3379 + val params_jsont : params Jsont.t 3380 + 3381 + 3382 + type output = { 3383 starter_packs : Jsont.json list; 3384 } 3385 ··· 3387 val output_jsont : output Jsont.t 3388 3389 end 3390 + module GetList : sig 3391 + (** Gets a 'view' (with additional context) of a specified list. *) 3392 3393 (** Query/procedure parameters. *) 3394 type params = { 3395 cursor : string option; 3396 limit : int option; 3397 + list_ : string; (** Reference (AT-URI) of the list record to hydrate. *) 3398 } 3399 3400 (** Jsont codec for {!type:params}. *) ··· 3403 3404 type output = { 3405 cursor : string option; 3406 + items : Jsont.json list; 3407 + list_ : Jsont.json; 3408 } 3409 3410 (** Jsont codec for {!type:output}. *) 3411 val output_jsont : output Jsont.t 3412 3413 end 3414 + module List : sig 3415 + (** Record representing a list of accounts (actors). Scope includes both moderation-oriented lists and curration-oriented lists. *) 3416 + 3417 + type main = { 3418 + avatar : Atp.Blob_ref.t option; 3419 + created_at : string; 3420 + description : string option; 3421 + description_facets : Richtext.Facet.main list option; 3422 + labels : Com.Atproto.Label.Defs.self_labels option; 3423 + name : string; (** Display name for list; can not be empty. *) 3424 + purpose : Jsont.json; (** Defines the purpose of the list (aka, moderation-oriented or curration-oriented) *) 3425 + } 3426 + 3427 + (** Jsont codec for {!type:main}. *) 3428 + val main_jsont : main Jsont.t 3429 + 3430 + end 3431 + end 3432 + module Bookmark : sig 3433 + module Defs : sig 3434 + 3435 + type bookmark_view = { 3436 + created_at : string option; 3437 + item : Jsont.json; 3438 + subject : Com.Atproto.Repo.StrongRef.main; (** A strong ref to the bookmarked record. *) 3439 + } 3440 + 3441 + (** Jsont codec for {!type:bookmark_view}. *) 3442 + val bookmark_view_jsont : bookmark_view Jsont.t 3443 + 3444 + (** Object used to store bookmark data in stash. *) 3445 + 3446 + type bookmark = { 3447 + subject : Com.Atproto.Repo.StrongRef.main; (** A strong ref to the record to be bookmarked. Currently, only `app.bsky.feed.post` records are supported. *) 3448 + } 3449 + 3450 + (** Jsont codec for {!type:bookmark}. *) 3451 + val bookmark_jsont : bookmark Jsont.t 3452 + 3453 + end 3454 + module CreateBookmark : sig 3455 + (** Creates a private bookmark for the specified record. Currently, only `app.bsky.feed.post` records are supported. Requires authentication. *) 3456 + 3457 + 3458 + type input = { 3459 + cid : string; 3460 + uri : string; 3461 + } 3462 + 3463 + (** Jsont codec for {!type:input}. *) 3464 + val input_jsont : input Jsont.t 3465 + 3466 + end 3467 + module DeleteBookmark : sig 3468 + (** Deletes a private bookmark for the specified record. Currently, only `app.bsky.feed.post` records are supported. Requires authentication. *) 3469 + 3470 + 3471 + type input = { 3472 + uri : string; 3473 + } 3474 + 3475 + (** Jsont codec for {!type:input}. *) 3476 + val input_jsont : input Jsont.t 3477 + 3478 + end 3479 + module GetBookmarks : sig 3480 + (** Gets views of records bookmarked by the authenticated user. Requires authentication. *) 3481 3482 (** Query/procedure parameters. *) 3483 type params = { 3484 + cursor : string option; 3485 limit : int option; 3486 } 3487 3488 (** Jsont codec for {!type:params}. *) ··· 3490 3491 3492 type output = { 3493 + bookmarks : Defs.bookmark_view list; 3494 + cursor : string option; 3495 } 3496 3497 (** Jsont codec for {!type:output}. *) 3498 val output_jsont : output Jsont.t 3499 3500 end 3501 + end 3502 + module Unspecced : sig 3503 module GetSuggestedFeeds : sig 3504 (** Get a list of suggested feeds *) 3505 ··· 3520 val output_jsont : output Jsont.t 3521 3522 end 3523 + module GetSuggestedUsers : sig 3524 + (** Get a list of suggested users *) 3525 3526 (** Query/procedure parameters. *) 3527 type params = { 3528 + category : string option; (** Category of users to get suggestions for. *) 3529 limit : int option; 3530 } 3531 3532 (** Jsont codec for {!type:params}. *) ··· 3534 3535 3536 type output = { 3537 + actors : Jsont.json list; 3538 + rec_id : int option; (** Snowflake for this recommendation, use when submitting recommendation events. *) 3539 } 3540 3541 (** Jsont codec for {!type:output}. *) 3542 val output_jsont : output Jsont.t 3543 3544 end 3545 + module GetSuggestedUsersSkeleton : sig 3546 + (** Get a skeleton of suggested users. Intended to be called and hydrated by app.bsky.unspecced.getSuggestedUsers *) 3547 3548 + (** Query/procedure parameters. *) 3549 + type params = { 3550 + category : string option; (** Category of users to get suggestions for. *) 3551 + limit : int option; 3552 + viewer : string option; (** DID of the account making the request (not included for public/unauthenticated queries). *) 3553 } 3554 3555 + (** Jsont codec for {!type:params}. *) 3556 + val params_jsont : params Jsont.t 3557 3558 3559 type output = { 3560 + dids : string list; 3561 + rec_id : int option; (** Snowflake for this recommendation, use when submitting recommendation events. *) 3562 } 3563 3564 (** Jsont codec for {!type:output}. *) ··· 3585 val output_jsont : output Jsont.t 3586 3587 end 3588 + module GetOnboardingSuggestedStarterPacksSkeleton : sig 3589 + (** Get a skeleton of suggested starterpacks for onboarding. Intended to be called and hydrated by app.bsky.unspecced.getOnboardingSuggestedStarterPacks *) 3590 3591 (** Query/procedure parameters. *) 3592 type params = { 3593 limit : int option; 3594 + viewer : string option; (** DID of the account making the request (not included for public/unauthenticated queries). *) 3595 } 3596 3597 (** Jsont codec for {!type:params}. *) ··· 3599 3600 3601 type output = { 3602 + starter_packs : string list; 3603 } 3604 3605 (** Jsont codec for {!type:output}. *) 3606 val output_jsont : output Jsont.t 3607 3608 end 3609 + module GetSuggestedFeedsSkeleton : sig 3610 + (** Get a skeleton of suggested feeds. Intended to be called and hydrated by app.bsky.unspecced.getSuggestedFeeds *) 3611 3612 (** Query/procedure parameters. *) 3613 type params = { ··· 3620 3621 3622 type output = { 3623 + feeds : string list; 3624 + } 3625 + 3626 + (** Jsont codec for {!type:output}. *) 3627 + val output_jsont : output Jsont.t 3628 + 3629 + end 3630 + module GetOnboardingSuggestedStarterPacks : sig 3631 + (** Get a list of suggested starterpacks for onboarding *) 3632 + 3633 + (** Query/procedure parameters. *) 3634 + type params = { 3635 + limit : int option; 3636 + } 3637 + 3638 + (** Jsont codec for {!type:params}. *) 3639 + val params_jsont : params Jsont.t 3640 + 3641 + 3642 + type output = { 3643 + starter_packs : Jsont.json list; 3644 } 3645 3646 (** Jsont codec for {!type:output}. *) ··· 3773 val age_assurance_event_jsont : age_assurance_event Jsont.t 3774 3775 end 3776 + module GetConfig : sig 3777 3778 + type live_now_config = { 3779 + did : string; 3780 + domains : string list; 3781 } 3782 3783 + (** Jsont codec for {!type:live_now_config}. *) 3784 + val live_now_config_jsont : live_now_config Jsont.t 3785 3786 + (** Get miscellaneous runtime configuration. *) 3787 3788 3789 type output = { 3790 + check_email_confirmed : bool option; 3791 + live_now : live_now_config list option; 3792 } 3793 3794 (** Jsont codec for {!type:output}. *) 3795 val output_jsont : output Jsont.t 3796 3797 end 3798 + module GetPopularFeedGenerators : sig 3799 + (** An unspecced view of globally popular feed generators. *) 3800 3801 (** Query/procedure parameters. *) 3802 type params = { 3803 + cursor : string option; 3804 limit : int option; 3805 + query : string option; 3806 } 3807 3808 (** Jsont codec for {!type:params}. *) ··· 3811 3812 type output = { 3813 cursor : string option; 3814 + feeds : Jsont.json list; 3815 } 3816 3817 (** Jsont codec for {!type:output}. *) 3818 val output_jsont : output Jsont.t 3819 3820 end 3821 + module GetTaggedSuggestions : sig 3822 3823 + type suggestion = { 3824 + subject : string; 3825 + subject_type : string; 3826 + tag : string; 3827 } 3828 3829 + (** Jsont codec for {!type:suggestion}. *) 3830 + val suggestion_jsont : suggestion Jsont.t 3831 3832 + (** Get a list of suggestions (feeds and users) tagged with categories *) 3833 3834 (** Query/procedure parameters. *) 3835 + type params = unit 3836 3837 (** Jsont codec for {!type:params}. *) 3838 val params_jsont : params Jsont.t 3839 3840 3841 type output = { 3842 + suggestions : suggestion list; 3843 } 3844 3845 (** Jsont codec for {!type:output}. *) 3846 val output_jsont : output Jsont.t 3847 3848 end 3849 + module GetSuggestedStarterPacksSkeleton : sig 3850 + (** Get a skeleton of suggested starterpacks. Intended to be called and hydrated by app.bsky.unspecced.getSuggestedStarterpacks *) 3851 3852 (** Query/procedure parameters. *) 3853 type params = { 3854 limit : int option; 3855 + viewer : string option; (** DID of the account making the request (not included for public/unauthenticated queries). *) 3856 } 3857 3858 (** Jsont codec for {!type:params}. *) ··· 3860 3861 3862 type output = { 3863 + starter_packs : string list; 3864 } 3865 3866 (** Jsont codec for {!type:output}. *) 3867 val output_jsont : output Jsont.t 3868 3869 end 3870 + module InitAgeAssurance : sig 3871 + (** Initiate age assurance for an account. This is a one-time action that will start the process of verifying the user's age. *) 3872 + 3873 + 3874 + type input = { 3875 + country_code : string; (** An ISO 3166-1 alpha-2 code of the user's location. *) 3876 + email : string; (** The user's email address to receive assurance instructions. *) 3877 + language : string; (** The user's preferred language for communication during the assurance process. *) 3878 + } 3879 + 3880 + (** Jsont codec for {!type:input}. *) 3881 + val input_jsont : input Jsont.t 3882 + 3883 + 3884 + type output = Defs.age_assurance_state 3885 + 3886 + (** Jsont codec for {!type:output}. *) 3887 + val output_jsont : output Jsont.t 3888 + 3889 + end 3890 + module GetTrendingTopics : sig 3891 + (** Get a list of trending topics *) 3892 3893 (** Query/procedure parameters. *) 3894 type params = { 3895 limit : int option; 3896 + viewer : string option; (** DID of the account making the request (not included for public/unauthenticated queries). Used to boost followed accounts in ranking. *) 3897 } 3898 3899 (** Jsont codec for {!type:params}. *) ··· 3901 3902 3903 type output = { 3904 + suggested : Defs.trending_topic list; 3905 + topics : Defs.trending_topic list; 3906 } 3907 3908 (** Jsont codec for {!type:output}. *) ··· 3939 val output_jsont : output Jsont.t 3940 3941 end 3942 + module GetSuggestionsSkeleton : sig 3943 + (** Get a skeleton of suggested actors. Intended to be called and then hydrated through app.bsky.actor.getSuggestions *) 3944 + 3945 + (** Query/procedure parameters. *) 3946 + type params = { 3947 + cursor : string option; 3948 + limit : int option; 3949 + relative_to_did : string option; (** DID of the account to get suggestions relative to. If not provided, suggestions will be based on the viewer. *) 3950 + viewer : string option; (** DID of the account making the request (not included for public/unauthenticated queries). Used to boost followed accounts in ranking. *) 3951 + } 3952 3953 + (** Jsont codec for {!type:params}. *) 3954 + val params_jsont : params Jsont.t 3955 3956 + 3957 + type output = { 3958 + actors : Defs.skeleton_search_actor list; 3959 + cursor : string option; 3960 + rec_id : int option; (** Snowflake for this recommendation, use when submitting recommendation events. *) 3961 + relative_to_did : string option; (** DID of the account these suggestions are relative to. If this is returned undefined, suggestions are based on the viewer. *) 3962 } 3963 3964 + (** Jsont codec for {!type:output}. *) 3965 + val output_jsont : output Jsont.t 3966 + 3967 + end 3968 + module GetAgeAssuranceState : sig 3969 + (** Returns the current state of the age assurance process for an account. This is used to check if the user has completed age assurance or if further action is required. *) 3970 3971 3972 type output = Defs.age_assurance_state ··· 4000 val output_jsont : output Jsont.t 4001 4002 end 4003 + module SearchPostsSkeleton : sig 4004 + (** Backend Posts search, returns only skeleton *) 4005 + 4006 + (** Query/procedure parameters. *) 4007 + type params = { 4008 + author : string option; (** Filter to posts by the given account. Handles are resolved to DID before query-time. *) 4009 + cursor : string option; (** Optional pagination mechanism; may not necessarily allow scrolling through entire result set. *) 4010 + domain : string option; (** Filter to posts with URLs (facet links or embeds) linking to the given domain (hostname). Server may apply hostname normalization. *) 4011 + lang : string option; (** Filter to posts in the given language. Expected to be based on post language field, though server may override language detection. *) 4012 + limit : int option; 4013 + mentions : string option; (** Filter to posts which mention the given account. Handles are resolved to DID before query-time. Only matches rich-text facet mentions. *) 4014 + q : string; (** Search query string; syntax, phrase, boolean, and faceting is unspecified, but Lucene query syntax is recommended. *) 4015 + since : string option; (** Filter results for posts after the indicated datetime (inclusive). Expected to use 'sortAt' timestamp, which may not match 'createdAt'. Can be a datetime, or just an ISO date (YYYY-MM-DD). *) 4016 + sort : string option; (** Specifies the ranking order of results. *) 4017 + tag : string list option; (** Filter to posts with the given tag (hashtag), based on rich-text facet or tag field. Do not include the hash (#) prefix. Multiple tags can be specified, with 'AND' matching. *) 4018 + until : string option; (** Filter results for posts before the indicated datetime (not inclusive). Expected to use 'sortAt' timestamp, which may not match 'createdAt'. Can be a datetime, or just an ISO date (YYY-MM-DD). *) 4019 + url : string option; (** Filter to posts with links (facet links or embeds) pointing to this URL. Server may apply URL normalization or fuzzy matching. *) 4020 + viewer : string option; (** DID of the account making the request (not included for public/unauthenticated queries). Used for 'from:me' queries. *) 4021 + } 4022 + 4023 + (** Jsont codec for {!type:params}. *) 4024 + val params_jsont : params Jsont.t 4025 + 4026 + 4027 + type output = { 4028 + cursor : string option; 4029 + hits_total : int option; (** Count of search hits. Optional, may be rounded/truncated, and may not be possible to paginate through all hits. *) 4030 + posts : Defs.skeleton_search_post list; 4031 + } 4032 + 4033 + (** Jsont codec for {!type:output}. *) 4034 + val output_jsont : output Jsont.t 4035 + 4036 + end 4037 module SearchActorsSkeleton : sig 4038 (** Backend Actors (profile) search, returns only skeleton. *) 4039 ··· 4060 val output_jsont : output Jsont.t 4061 4062 end 4063 + module GetTrends : sig 4064 + (** Get the current trends on the network *) 4065 4066 + (** Query/procedure parameters. *) 4067 + type params = { 4068 + limit : int option; 4069 + } 4070 4071 + (** Jsont codec for {!type:params}. *) 4072 + val params_jsont : params Jsont.t 4073 + 4074 + 4075 + type output = { 4076 + trends : Defs.trend_view list; 4077 + } 4078 4079 (** Jsont codec for {!type:output}. *) 4080 val output_jsont : output Jsont.t 4081 4082 end 4083 + module GetPostThreadV2 : sig 4084 + 4085 + type thread_item = { 4086 + depth : int; (** The nesting level of this item in the thread. Depth 0 means the anchor item. Items above have negative depths, items below have positive depths. *) 4087 + uri : string; 4088 + value : Jsont.json; 4089 + } 4090 + 4091 + (** Jsont codec for {!type:thread_item}. *) 4092 + val thread_item_jsont : thread_item Jsont.t 4093 + 4094 + (** (NOTE: this endpoint is under development and WILL change without notice. Don't use it until it is moved out of `unspecced` or your application WILL break) Get posts in a thread. It is based in an anchor post at any depth of the tree, and returns posts above it (recursively resolving the parent, without further branching to their replies) and below it (recursive replies, with branching to their replies). Does not require auth, but additional metadata and filtering will be applied for authed requests. *) 4095 4096 (** Query/procedure parameters. *) 4097 type params = { 4098 + above : bool option; (** Whether to include parents above the anchor. *) 4099 + anchor : string; (** Reference (AT-URI) to post record. This is the anchor post, and the thread will be built around it. It can be any post in the tree, not necessarily a root post. *) 4100 + below : int option; (** How many levels of replies to include below the anchor. *) 4101 + branching_factor : int option; (** Maximum of replies to include at each level of the thread, except for the direct replies to the anchor, which are (NOTE: currently, during unspecced phase) all returned (NOTE: later they might be paginated). *) 4102 + sort : string option; (** Sorting for the thread replies. *) 4103 } 4104 4105 (** Jsont codec for {!type:params}. *) ··· 4107 4108 4109 type output = { 4110 + has_other_replies : bool; (** Whether this thread has additional replies. If true, a call can be made to the `getPostThreadOtherV2` endpoint to retrieve them. *) 4111 + thread : thread_item list; (** A flat list of thread items. The depth of each item is indicated by the depth property inside the item. *) 4112 + threadgate : Jsont.json option; 4113 } 4114 4115 (** Jsont codec for {!type:output}. *) 4116 val output_jsont : output Jsont.t 4117 4118 end 4119 + module GetTrendsSkeleton : sig 4120 + (** Get the skeleton of trends on the network. Intended to be called and then hydrated through app.bsky.unspecced.getTrends *) 4121 4122 (** Query/procedure parameters. *) 4123 type params = { 4124 limit : int option; 4125 + viewer : string option; (** DID of the account making the request (not included for public/unauthenticated queries). *) 4126 } 4127 4128 (** Jsont codec for {!type:params}. *) ··· 4130 4131 4132 type output = { 4133 + trends : Defs.skeleton_trend list; 4134 } 4135 4136 (** Jsont codec for {!type:output}. *)
+15 -15
ocaml-atp/lexicons/standard-site/atp_lexicon_standard_site.ml
··· 36 end 37 module Site = struct 38 module Standard = struct 39 - module Graph = struct 40 - module Subscription = struct 41 - type main = { 42 - publication : string; 43 - } 44 - 45 - let main_jsont = 46 - Jsont.Object.map ~kind:"Main" 47 - (fun _typ publication -> { publication }) 48 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"site.standard.graph.subscription" ~enc:(fun _ -> "site.standard.graph.subscription") 49 - |> Jsont.Object.mem "publication" Jsont.string ~enc:(fun r -> r.publication) 50 - |> Jsont.Object.finish 51 - 52 - end 53 - end 54 module Document = struct 55 type main = { 56 bsky_post_ref : Com.Atproto.Repo.StrongRef.main option; ··· 135 |> Jsont.Object.mem "accentForeground" Color.rgb_jsont ~enc:(fun r -> r.accent_foreground) 136 |> Jsont.Object.mem "background" Color.rgb_jsont ~enc:(fun r -> r.background) 137 |> Jsont.Object.mem "foreground" Color.rgb_jsont ~enc:(fun r -> r.foreground) 138 |> Jsont.Object.finish 139 140 end
··· 36 end 37 module Site = struct 38 module Standard = struct 39 module Document = struct 40 type main = { 41 bsky_post_ref : Com.Atproto.Repo.StrongRef.main option; ··· 120 |> Jsont.Object.mem "accentForeground" Color.rgb_jsont ~enc:(fun r -> r.accent_foreground) 121 |> Jsont.Object.mem "background" Color.rgb_jsont ~enc:(fun r -> r.background) 122 |> Jsont.Object.mem "foreground" Color.rgb_jsont ~enc:(fun r -> r.foreground) 123 + |> Jsont.Object.finish 124 + 125 + end 126 + end 127 + module Graph = struct 128 + module Subscription = struct 129 + type main = { 130 + publication : string; 131 + } 132 + 133 + let main_jsont = 134 + Jsont.Object.map ~kind:"Main" 135 + (fun _typ publication -> { publication }) 136 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"site.standard.graph.subscription" ~enc:(fun _ -> "site.standard.graph.subscription") 137 + |> Jsont.Object.mem "publication" Jsont.string ~enc:(fun r -> r.publication) 138 |> Jsont.Object.finish 139 140 end
+13 -13
ocaml-atp/lexicons/standard-site/atp_lexicon_standard_site.mli
··· 30 end 31 module Site : sig 32 module Standard : sig 33 - module Graph : sig 34 - module Subscription : sig 35 - (** Record declaring a subscription to a publication. *) 36 - 37 - type main = { 38 - publication : string; (** AT-URI reference to the publication record being subscribed to (ex: at://did:plc:abc123/site.standard.publication/xyz789). *) 39 - } 40 - 41 - (** Jsont codec for {!type:main}. *) 42 - val main_jsont : main Jsont.t 43 - 44 - end 45 - end 46 module Document : sig 47 (** A document record representing a published article, blog post, or other content. Documents can belong to a publication or exist independently. *) 48 ··· 96 accent_foreground : Color.rgb; (** Color used for button text. *) 97 background : Color.rgb; (** Color used for content background. *) 98 foreground : Color.rgb; (** Color used for content text. *) 99 } 100 101 (** Jsont codec for {!type:main}. *)
··· 30 end 31 module Site : sig 32 module Standard : sig 33 module Document : sig 34 (** A document record representing a published article, blog post, or other content. Documents can belong to a publication or exist independently. *) 35 ··· 83 accent_foreground : Color.rgb; (** Color used for button text. *) 84 background : Color.rgb; (** Color used for content background. *) 85 foreground : Color.rgb; (** Color used for content text. *) 86 + } 87 + 88 + (** Jsont codec for {!type:main}. *) 89 + val main_jsont : main Jsont.t 90 + 91 + end 92 + end 93 + module Graph : sig 94 + module Subscription : sig 95 + (** Record declaring a subscription to a publication. *) 96 + 97 + type main = { 98 + publication : string; (** AT-URI reference to the publication record being subscribed to (ex: at://did:plc:abc123/site.standard.publication/xyz789). *) 99 } 100 101 (** Jsont codec for {!type:main}. *)
+963 -963
ocaml-atp/lexicons/tangled/atp_lexicon_tangled.ml
··· 15 16 module Sh = struct 17 module Tangled = struct 18 module Spindle = struct 19 type main = { 20 created_at : string; ··· 45 46 end 47 end 48 module Git = struct 49 module RefUpdate = struct 50 type individual_language_size = { ··· 135 136 end 137 end 138 - module Actor = struct 139 - module Profile = struct 140 - type main = { 141 - bluesky : bool; 142 - description : string option; 143 - links : string list option; 144 - location : string option; 145 - pinned_repositories : string list option; 146 - pronouns : string option; 147 - stats : string list option; 148 - } 149 - 150 - let main_jsont = 151 - Jsont.Object.map ~kind:"Main" 152 - (fun _typ bluesky description links location pinned_repositories pronouns stats -> { bluesky; description; links; location; pinned_repositories; pronouns; stats }) 153 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.actor.profile" ~enc:(fun _ -> "sh.tangled.actor.profile") 154 - |> Jsont.Object.mem "bluesky" Jsont.bool ~enc:(fun r -> r.bluesky) 155 - |> Jsont.Object.opt_mem "description" Jsont.string ~enc:(fun r -> r.description) 156 - |> Jsont.Object.opt_mem "links" (Jsont.list Jsont.string) ~enc:(fun r -> r.links) 157 - |> Jsont.Object.opt_mem "location" Jsont.string ~enc:(fun r -> r.location) 158 - |> Jsont.Object.opt_mem "pinnedRepositories" (Jsont.list Jsont.string) ~enc:(fun r -> r.pinned_repositories) 159 - |> Jsont.Object.opt_mem "pronouns" Jsont.string ~enc:(fun r -> r.pronouns) 160 - |> Jsont.Object.opt_mem "stats" (Jsont.list Jsont.string) ~enc:(fun r -> r.stats) 161 - |> Jsont.Object.finish 162 - 163 - end 164 - end 165 module String = struct 166 type main = { 167 contents : string; ··· 181 |> Jsont.Object.finish 182 183 end 184 - module Feed = struct 185 - module Star = struct 186 - type main = { 187 - created_at : string; 188 - subject : string; 189 - } 190 - 191 - let main_jsont = 192 - Jsont.Object.map ~kind:"Main" 193 - (fun _typ created_at subject -> { created_at; subject }) 194 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.feed.star" ~enc:(fun _ -> "sh.tangled.feed.star") 195 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 196 - |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 197 - |> Jsont.Object.finish 198 - 199 - end 200 - module Reaction = struct 201 - type main = { 202 - created_at : string; 203 - reaction : string; 204 - subject : string; 205 - } 206 - 207 - let main_jsont = 208 - Jsont.Object.map ~kind:"Main" 209 - (fun _typ created_at reaction subject -> { created_at; reaction; subject }) 210 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.feed.reaction" ~enc:(fun _ -> "sh.tangled.feed.reaction") 211 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 212 - |> Jsont.Object.mem "reaction" Jsont.string ~enc:(fun r -> r.reaction) 213 - |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 214 - |> Jsont.Object.finish 215 - 216 - end 217 - end 218 module Repo = struct 219 type main = { 220 created_at : string; ··· 243 |> Jsont.Object.opt_mem "website" Jsont.string ~enc:(fun r -> r.website) 244 |> Jsont.Object.finish 245 246 - module Artifact = struct 247 type main = { 248 - artifact : Atp.Blob_ref.t; 249 created_at : string; 250 - name : string; 251 repo : string; 252 - tag : string; 253 } 254 255 let main_jsont = 256 Jsont.Object.map ~kind:"Main" 257 - (fun _typ artifact created_at name repo tag -> { artifact; created_at; name; repo; tag }) 258 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.artifact" ~enc:(fun _ -> "sh.tangled.repo.artifact") 259 - |> Jsont.Object.mem "artifact" Atp.Blob_ref.jsont ~enc:(fun r -> r.artifact) 260 |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 261 - |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 262 |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 263 - |> Jsont.Object.mem "tag" Jsont.binary_string ~enc:(fun r -> r.tag) 264 |> Jsont.Object.finish 265 266 end 267 - module MergeCheck = struct 268 - type conflict_info = { 269 - filename : string; 270 - reason : string; 271 } 272 273 - let conflict_info_jsont = 274 - Jsont.Object.map ~kind:"Conflict_info" 275 - (fun _typ filename reason -> { filename; reason }) 276 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.mergeCheck#conflictInfo" ~enc:(fun _ -> "sh.tangled.repo.mergeCheck#conflictInfo") 277 - |> Jsont.Object.mem "filename" Jsont.string ~enc:(fun r -> r.filename) 278 - |> Jsont.Object.mem "reason" Jsont.string ~enc:(fun r -> r.reason) 279 |> Jsont.Object.finish 280 281 type input = { 282 - branch : string; 283 - did : string; 284 - name : string; 285 - patch : string; 286 } 287 288 let input_jsont = 289 Jsont.Object.map ~kind:"Input" 290 - (fun _typ branch did name patch -> { branch; did; name; patch }) 291 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.mergeCheck#input" ~enc:(fun _ -> "sh.tangled.repo.mergeCheck#input") 292 - |> Jsont.Object.mem "branch" Jsont.string ~enc:(fun r -> r.branch) 293 - |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 294 |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 295 - |> Jsont.Object.mem "patch" Jsont.string ~enc:(fun r -> r.patch) 296 |> Jsont.Object.finish 297 298 type output = { 299 - conflicts : conflict_info list option; 300 - error : string option; 301 - is_conflicted : bool; 302 message : string option; 303 } 304 305 let output_jsont = 306 Jsont.Object.map ~kind:"Output" 307 - (fun _typ conflicts error is_conflicted message -> { conflicts; error; is_conflicted; message }) 308 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.mergeCheck#output" ~enc:(fun _ -> "sh.tangled.repo.mergeCheck#output") 309 - |> Jsont.Object.opt_mem "conflicts" (Jsont.list conflict_info_jsont) ~enc:(fun r -> r.conflicts) 310 - |> Jsont.Object.opt_mem "error" Jsont.string ~enc:(fun r -> r.error) 311 - |> Jsont.Object.mem "is_conflicted" Jsont.bool ~enc:(fun r -> r.is_conflicted) 312 |> Jsont.Object.opt_mem "message" Jsont.string ~enc:(fun r -> r.message) 313 |> Jsont.Object.finish 314 315 end ··· 400 |> Jsont.Object.finish 401 402 end 403 - module SetDefaultBranch = struct 404 type input = { 405 - default_branch : string; 406 repo : string; 407 } 408 409 let input_jsont = 410 Jsont.Object.map ~kind:"Input" 411 - (fun _typ default_branch repo -> { default_branch; repo }) 412 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.setDefaultBranch#input" ~enc:(fun _ -> "sh.tangled.repo.setDefaultBranch#input") 413 - |> Jsont.Object.mem "defaultBranch" Jsont.string ~enc:(fun r -> r.default_branch) 414 |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 415 |> Jsont.Object.finish 416 417 end 418 - module Compare = struct 419 type params = { 420 repo : string; 421 - rev1 : string; 422 - rev2 : string; 423 } 424 425 let params_jsont = 426 Jsont.Object.map ~kind:"Params" 427 - (fun repo rev1 rev2 -> { 428 repo; 429 - rev1; 430 - rev2; 431 }) 432 |> Jsont.Object.mem "repo" Jsont.string 433 ~enc:(fun r -> r.repo) 434 - |> Jsont.Object.mem "rev1" Jsont.string 435 - ~enc:(fun r -> r.rev1) 436 - |> Jsont.Object.mem "rev2" Jsont.string 437 - ~enc:(fun r -> r.rev2) 438 |> Jsont.Object.finish 439 440 - type output = unit 441 - let output_jsont = Jsont.ignore 442 - 443 - end 444 - module Merge = struct 445 - type input = { 446 - author_email : string option; 447 - author_name : string option; 448 - branch : string; 449 - commit_body : string option; 450 - commit_message : string option; 451 - did : string; 452 name : string; 453 - patch : string; 454 } 455 456 - let input_jsont = 457 - Jsont.Object.map ~kind:"Input" 458 - (fun _typ author_email author_name branch commit_body commit_message did name patch -> { author_email; author_name; branch; commit_body; commit_message; did; name; patch }) 459 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.merge#input" ~enc:(fun _ -> "sh.tangled.repo.merge#input") 460 - |> Jsont.Object.opt_mem "authorEmail" Jsont.string ~enc:(fun r -> r.author_email) 461 - |> Jsont.Object.opt_mem "authorName" Jsont.string ~enc:(fun r -> r.author_name) 462 - |> Jsont.Object.mem "branch" Jsont.string ~enc:(fun r -> r.branch) 463 - |> Jsont.Object.opt_mem "commitBody" Jsont.string ~enc:(fun r -> r.commit_body) 464 - |> Jsont.Object.opt_mem "commitMessage" Jsont.string ~enc:(fun r -> r.commit_message) 465 - |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 466 |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 467 - |> Jsont.Object.mem "patch" Jsont.string ~enc:(fun r -> r.patch) 468 |> Jsont.Object.finish 469 470 end 471 - module Tags = struct 472 type params = { 473 cursor : string option; 474 limit : int option; 475 repo : string; 476 } 477 478 let params_jsont = 479 Jsont.Object.map ~kind:"Params" 480 - (fun cursor limit repo -> { 481 cursor; 482 limit; 483 repo; 484 }) 485 |> Jsont.Object.opt_mem "cursor" Jsont.string 486 ~enc:(fun r -> r.cursor) 487 |> Jsont.Object.opt_mem "limit" Jsont.int 488 ~enc:(fun r -> r.limit) 489 |> Jsont.Object.mem "repo" Jsont.string 490 ~enc:(fun r -> r.repo) 491 |> Jsont.Object.finish ··· 494 let output_jsont = Jsont.ignore 495 496 end 497 - module Collaborator = struct 498 - type main = { 499 created_at : string; 500 repo : string; 501 - subject : string; 502 } 503 504 - let main_jsont = 505 - Jsont.Object.map ~kind:"Main" 506 - (fun _typ created_at repo subject -> { created_at; repo; subject }) 507 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.collaborator" ~enc:(fun _ -> "sh.tangled.repo.collaborator") 508 |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 509 |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 510 - |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 511 |> Jsont.Object.finish 512 513 end 514 - module Branches = struct 515 type params = { 516 cursor : string option; 517 limit : int option; ··· 537 let output_jsont = Jsont.ignore 538 539 end 540 - module GetDefaultBranch = struct 541 - type signature = { 542 - email : string; 543 - name : string; 544 - when_ : string; 545 - } 546 - 547 - let signature_jsont = 548 - Jsont.Object.map ~kind:"Signature" 549 - (fun _typ email name when_ -> { email; name; when_ }) 550 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.getDefaultBranch#signature" ~enc:(fun _ -> "sh.tangled.repo.getDefaultBranch#signature") 551 - |> Jsont.Object.mem "email" Jsont.string ~enc:(fun r -> r.email) 552 - |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 553 - |> Jsont.Object.mem "when" Jsont.string ~enc:(fun r -> r.when_) 554 - |> Jsont.Object.finish 555 - 556 type params = { 557 repo : string; 558 } 559 560 let params_jsont = 561 Jsont.Object.map ~kind:"Params" 562 - (fun repo -> { 563 repo; 564 }) 565 |> Jsont.Object.mem "repo" Jsont.string 566 ~enc:(fun r -> r.repo) 567 |> Jsont.Object.finish 568 569 - type output = { 570 - author : signature option; 571 - hash : string; 572 - message : string option; 573 - name : string; 574 - short_hash : string option; 575 - when_ : string; 576 } 577 578 - let output_jsont = 579 - Jsont.Object.map ~kind:"Output" 580 - (fun _typ author hash message name short_hash when_ -> { author; hash; message; name; short_hash; when_ }) 581 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.getDefaultBranch#output" ~enc:(fun _ -> "sh.tangled.repo.getDefaultBranch#output") 582 - |> Jsont.Object.opt_mem "author" signature_jsont ~enc:(fun r -> r.author) 583 - |> Jsont.Object.mem "hash" Jsont.string ~enc:(fun r -> r.hash) 584 - |> Jsont.Object.opt_mem "message" Jsont.string ~enc:(fun r -> r.message) 585 - |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 586 - |> Jsont.Object.opt_mem "shortHash" Jsont.string ~enc:(fun r -> r.short_hash) 587 - |> Jsont.Object.mem "when" Jsont.string ~enc:(fun r -> r.when_) 588 |> Jsont.Object.finish 589 590 end ··· 605 |> Jsont.Object.finish 606 607 end 608 - module ForkStatus = struct 609 - type input = { 610 - branch : string; 611 - did : string; 612 - hidden_ref : string; 613 name : string; 614 - source : string; 615 } 616 617 - let input_jsont = 618 - Jsont.Object.map ~kind:"Input" 619 - (fun _typ branch did hidden_ref name source -> { branch; did; hidden_ref; name; source }) 620 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.forkStatus#input" ~enc:(fun _ -> "sh.tangled.repo.forkStatus#input") 621 - |> Jsont.Object.mem "branch" Jsont.string ~enc:(fun r -> r.branch) 622 - |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 623 - |> Jsont.Object.mem "hiddenRef" Jsont.string ~enc:(fun r -> r.hidden_ref) 624 |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 625 - |> Jsont.Object.mem "source" Jsont.string ~enc:(fun r -> r.source) 626 - |> Jsont.Object.finish 627 - 628 - type output = { 629 - status : int; 630 - } 631 - 632 - let output_jsont = 633 - Jsont.Object.map ~kind:"Output" 634 - (fun _typ status -> { status }) 635 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.forkStatus#output" ~enc:(fun _ -> "sh.tangled.repo.forkStatus#output") 636 - |> Jsont.Object.mem "status" Jsont.int ~enc:(fun r -> r.status) 637 |> Jsont.Object.finish 638 639 end 640 - module Branch = struct 641 - type signature = { 642 - email : string; 643 - name : string; 644 - when_ : string; 645 - } 646 - 647 - let signature_jsont = 648 - Jsont.Object.map ~kind:"Signature" 649 - (fun _typ email name when_ -> { email; name; when_ }) 650 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.branch#signature" ~enc:(fun _ -> "sh.tangled.repo.branch#signature") 651 - |> Jsont.Object.mem "email" Jsont.string ~enc:(fun r -> r.email) 652 - |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 653 - |> Jsont.Object.mem "when" Jsont.string ~enc:(fun r -> r.when_) 654 - |> Jsont.Object.finish 655 - 656 type params = { 657 - name : string; 658 repo : string; 659 } 660 661 let params_jsont = 662 Jsont.Object.map ~kind:"Params" 663 - (fun name repo -> { 664 - name; 665 repo; 666 }) 667 - |> Jsont.Object.mem "name" Jsont.string 668 - ~enc:(fun r -> r.name) 669 |> Jsont.Object.mem "repo" Jsont.string 670 ~enc:(fun r -> r.repo) 671 |> Jsont.Object.finish 672 673 - type output = { 674 - author : signature option; 675 - hash : string; 676 - is_default : bool option; 677 - message : string option; 678 - name : string; 679 - short_hash : string option; 680 - when_ : string; 681 - } 682 - 683 - let output_jsont = 684 - Jsont.Object.map ~kind:"Output" 685 - (fun _typ author hash is_default message name short_hash when_ -> { author; hash; is_default; message; name; short_hash; when_ }) 686 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.branch#output" ~enc:(fun _ -> "sh.tangled.repo.branch#output") 687 - |> Jsont.Object.opt_mem "author" signature_jsont ~enc:(fun r -> r.author) 688 - |> Jsont.Object.mem "hash" Jsont.string ~enc:(fun r -> r.hash) 689 - |> Jsont.Object.opt_mem "isDefault" Jsont.bool ~enc:(fun r -> r.is_default) 690 - |> Jsont.Object.opt_mem "message" Jsont.string ~enc:(fun r -> r.message) 691 - |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 692 - |> Jsont.Object.opt_mem "shortHash" Jsont.string ~enc:(fun r -> r.short_hash) 693 - |> Jsont.Object.mem "when" Jsont.string ~enc:(fun r -> r.when_) 694 - |> Jsont.Object.finish 695 696 end 697 - module DeleteBranch = struct 698 type input = { 699 - branch : string; 700 repo : string; 701 } 702 703 let input_jsont = 704 Jsont.Object.map ~kind:"Input" 705 - (fun _typ branch repo -> { branch; repo }) 706 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.deleteBranch#input" ~enc:(fun _ -> "sh.tangled.repo.deleteBranch#input") 707 - |> Jsont.Object.mem "branch" Jsont.string ~enc:(fun r -> r.branch) 708 |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 709 |> Jsont.Object.finish 710 711 end 712 - module Log = struct 713 - type params = { 714 - cursor : string option; 715 - limit : int option; 716 - path : string option; 717 - ref_ : string; 718 - repo : string; 719 } 720 721 - let params_jsont = 722 - Jsont.Object.map ~kind:"Params" 723 - (fun cursor limit path ref_ repo -> { 724 - cursor; 725 - limit; 726 - path; 727 - ref_; 728 - repo; 729 - }) 730 - |> Jsont.Object.opt_mem "cursor" Jsont.string 731 - ~enc:(fun r -> r.cursor) 732 - |> Jsont.Object.opt_mem "limit" Jsont.int 733 - ~enc:(fun r -> r.limit) 734 - |> Jsont.Object.opt_mem "path" Jsont.string 735 - ~enc:(fun r -> r.path) 736 - |> Jsont.Object.mem "ref" Jsont.string 737 - ~enc:(fun r -> r.ref_) 738 - |> Jsont.Object.mem "repo" Jsont.string 739 - ~enc:(fun r -> r.repo) 740 |> Jsont.Object.finish 741 - 742 - type output = unit 743 - let output_jsont = Jsont.ignore 744 745 end 746 module Blob = struct ··· 846 |> Jsont.Object.finish 847 848 end 849 - module RemoveSecret = struct 850 type input = { 851 - key : string; 852 repo : string; 853 } 854 855 let input_jsont = 856 Jsont.Object.map ~kind:"Input" 857 - (fun _typ key repo -> { key; repo }) 858 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.removeSecret#input" ~enc:(fun _ -> "sh.tangled.repo.removeSecret#input") 859 - |> Jsont.Object.mem "key" Jsont.string ~enc:(fun r -> r.key) 860 |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 861 |> Jsont.Object.finish 862 863 - end 864 - module Languages = struct 865 - type language = { 866 - color : string option; 867 - extensions : string list option; 868 - file_count : int option; 869 - name : string; 870 - percentage : int; 871 - size : int; 872 - } 873 - 874 - let language_jsont = 875 - Jsont.Object.map ~kind:"Language" 876 - (fun _typ color extensions file_count name percentage size -> { color; extensions; file_count; name; percentage; size }) 877 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.languages#language" ~enc:(fun _ -> "sh.tangled.repo.languages#language") 878 - |> Jsont.Object.opt_mem "color" Jsont.string ~enc:(fun r -> r.color) 879 - |> Jsont.Object.opt_mem "extensions" (Jsont.list Jsont.string) ~enc:(fun r -> r.extensions) 880 - |> Jsont.Object.opt_mem "fileCount" Jsont.int ~enc:(fun r -> r.file_count) 881 - |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 882 - |> Jsont.Object.mem "percentage" Jsont.int ~enc:(fun r -> r.percentage) 883 - |> Jsont.Object.mem "size" Jsont.int ~enc:(fun r -> r.size) 884 - |> Jsont.Object.finish 885 - 886 - type params = { 887 - ref_ : string option; 888 - repo : string; 889 - } 890 - 891 - let params_jsont = 892 - Jsont.Object.map ~kind:"Params" 893 - (fun ref_ repo -> { 894 - ref_; 895 - repo; 896 - }) 897 - |> Jsont.Object.opt_mem "ref" Jsont.string 898 - ~enc:(fun r -> r.ref_) 899 - |> Jsont.Object.mem "repo" Jsont.string 900 - ~enc:(fun r -> r.repo) 901 - |> Jsont.Object.finish 902 - 903 type output = { 904 - languages : language list; 905 - ref_ : string; 906 - total_files : int option; 907 - total_size : int option; 908 } 909 910 let output_jsont = 911 Jsont.Object.map ~kind:"Output" 912 - (fun _typ languages ref_ total_files total_size -> { languages; ref_; total_files; total_size }) 913 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.languages#output" ~enc:(fun _ -> "sh.tangled.repo.languages#output") 914 - |> Jsont.Object.mem "languages" (Jsont.list language_jsont) ~enc:(fun r -> r.languages) 915 - |> Jsont.Object.mem "ref" Jsont.string ~enc:(fun r -> r.ref_) 916 - |> Jsont.Object.opt_mem "totalFiles" Jsont.int ~enc:(fun r -> r.total_files) 917 - |> Jsont.Object.opt_mem "totalSize" Jsont.int ~enc:(fun r -> r.total_size) 918 |> Jsont.Object.finish 919 920 end 921 - module Diff = struct 922 type params = { 923 - ref_ : string; 924 repo : string; 925 } 926 927 let params_jsont = 928 Jsont.Object.map ~kind:"Params" 929 - (fun ref_ repo -> { 930 - ref_; 931 repo; 932 }) 933 - |> Jsont.Object.mem "ref" Jsont.string 934 - ~enc:(fun r -> r.ref_) 935 |> Jsont.Object.mem "repo" Jsont.string 936 ~enc:(fun r -> r.repo) 937 |> Jsont.Object.finish 938 939 type output = unit 940 let output_jsont = Jsont.ignore 941 942 end 943 - module ForkSync = struct 944 type input = { 945 branch : string; 946 did : string; 947 name : string; 948 source : string; 949 } 950 951 let input_jsont = 952 Jsont.Object.map ~kind:"Input" 953 - (fun _typ branch did name source -> { branch; did; name; source }) 954 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.forkSync#input" ~enc:(fun _ -> "sh.tangled.repo.forkSync#input") 955 |> Jsont.Object.mem "branch" Jsont.string ~enc:(fun r -> r.branch) 956 |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 957 |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 958 |> Jsont.Object.mem "source" Jsont.string ~enc:(fun r -> r.source) 959 |> Jsont.Object.finish 960 961 end 962 - module AddSecret = struct 963 - type input = { 964 - key : string; 965 - repo : string; 966 - value : string; 967 } 968 969 - let input_jsont = 970 - Jsont.Object.map ~kind:"Input" 971 - (fun _typ key repo value -> { key; repo; value }) 972 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.addSecret#input" ~enc:(fun _ -> "sh.tangled.repo.addSecret#input") 973 - |> Jsont.Object.mem "key" Jsont.string ~enc:(fun r -> r.key) 974 - |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 975 - |> Jsont.Object.mem "value" Jsont.string ~enc:(fun r -> r.value) 976 |> Jsont.Object.finish 977 978 - end 979 - module Delete = struct 980 type input = { 981 did : string; 982 name : string; 983 - rkey : string; 984 } 985 986 let input_jsont = 987 Jsont.Object.map ~kind:"Input" 988 - (fun _typ did name rkey -> { did; name; rkey }) 989 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.delete#input" ~enc:(fun _ -> "sh.tangled.repo.delete#input") 990 |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 991 |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 992 - |> Jsont.Object.mem "rkey" Jsont.string ~enc:(fun r -> r.rkey) 993 - |> Jsont.Object.finish 994 - 995 - end 996 - module ListSecrets = struct 997 - type secret = { 998 - created_at : string; 999 - created_by : string; 1000 - key : string; 1001 - repo : string; 1002 - } 1003 - 1004 - let secret_jsont = 1005 - Jsont.Object.map ~kind:"Secret" 1006 - (fun _typ created_at created_by key repo -> { created_at; created_by; key; repo }) 1007 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.listSecrets#secret" ~enc:(fun _ -> "sh.tangled.repo.listSecrets#secret") 1008 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 1009 - |> Jsont.Object.mem "createdBy" Jsont.string ~enc:(fun r -> r.created_by) 1010 - |> Jsont.Object.mem "key" Jsont.string ~enc:(fun r -> r.key) 1011 - |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 1012 - |> Jsont.Object.finish 1013 - 1014 - type params = { 1015 - repo : string; 1016 - } 1017 - 1018 - let params_jsont = 1019 - Jsont.Object.map ~kind:"Params" 1020 - (fun repo -> { 1021 - repo; 1022 - }) 1023 - |> Jsont.Object.mem "repo" Jsont.string 1024 - ~enc:(fun r -> r.repo) 1025 |> Jsont.Object.finish 1026 1027 type output = { 1028 - secrets : secret list; 1029 } 1030 1031 let output_jsont = 1032 Jsont.Object.map ~kind:"Output" 1033 - (fun _typ secrets -> { secrets }) 1034 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.listSecrets#output" ~enc:(fun _ -> "sh.tangled.repo.listSecrets#output") 1035 - |> Jsont.Object.mem "secrets" (Jsont.list secret_jsont) ~enc:(fun r -> r.secrets) 1036 |> Jsont.Object.finish 1037 1038 end 1039 - module Archive = struct 1040 type params = { 1041 - format : string option; 1042 - prefix : string option; 1043 - ref_ : string; 1044 repo : string; 1045 } 1046 1047 let params_jsont = 1048 Jsont.Object.map ~kind:"Params" 1049 - (fun format prefix ref_ repo -> { 1050 - format; 1051 - prefix; 1052 - ref_; 1053 repo; 1054 }) 1055 - |> Jsont.Object.opt_mem "format" Jsont.string 1056 - ~enc:(fun r -> r.format) 1057 - |> Jsont.Object.opt_mem "prefix" Jsont.string 1058 - ~enc:(fun r -> r.prefix) 1059 - |> Jsont.Object.mem "ref" Jsont.string 1060 - ~enc:(fun r -> r.ref_) 1061 |> Jsont.Object.mem "repo" Jsont.string 1062 ~enc:(fun r -> r.repo) 1063 |> Jsont.Object.finish ··· 1066 let output_jsont = Jsont.ignore 1067 1068 end 1069 - module HiddenRef = struct 1070 type input = { 1071 - fork_ref : string; 1072 - remote_ref : string; 1073 - repo : string; 1074 } 1075 1076 let input_jsont = 1077 Jsont.Object.map ~kind:"Input" 1078 - (fun _typ fork_ref remote_ref repo -> { fork_ref; remote_ref; repo }) 1079 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.hiddenRef#input" ~enc:(fun _ -> "sh.tangled.repo.hiddenRef#input") 1080 - |> Jsont.Object.mem "forkRef" Jsont.string ~enc:(fun r -> r.fork_ref) 1081 - |> Jsont.Object.mem "remoteRef" Jsont.string ~enc:(fun r -> r.remote_ref) 1082 - |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 1083 - |> Jsont.Object.finish 1084 - 1085 - type output = { 1086 - error : string option; 1087 - ref_ : string option; 1088 - success : bool; 1089 - } 1090 - 1091 - let output_jsont = 1092 - Jsont.Object.map ~kind:"Output" 1093 - (fun _typ error ref_ success -> { error; ref_; success }) 1094 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.hiddenRef#output" ~enc:(fun _ -> "sh.tangled.repo.hiddenRef#output") 1095 - |> Jsont.Object.opt_mem "error" Jsont.string ~enc:(fun r -> r.error) 1096 - |> Jsont.Object.opt_mem "ref" Jsont.string ~enc:(fun r -> r.ref_) 1097 - |> Jsont.Object.mem "success" Jsont.bool ~enc:(fun r -> r.success) 1098 - |> Jsont.Object.finish 1099 - 1100 - end 1101 - module Pull = struct 1102 - type target = { 1103 - branch : string; 1104 - repo : string; 1105 - } 1106 - 1107 - let target_jsont = 1108 - Jsont.Object.map ~kind:"Target" 1109 - (fun _typ branch repo -> { branch; repo }) 1110 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.pull#target" ~enc:(fun _ -> "sh.tangled.repo.pull#target") 1111 - |> Jsont.Object.mem "branch" Jsont.string ~enc:(fun r -> r.branch) 1112 - |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 1113 - |> Jsont.Object.finish 1114 - 1115 - type source = { 1116 - branch : string; 1117 - repo : string option; 1118 - sha : string; 1119 - } 1120 - 1121 - let source_jsont = 1122 - Jsont.Object.map ~kind:"Source" 1123 - (fun _typ branch repo sha -> { branch; repo; sha }) 1124 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.pull#source" ~enc:(fun _ -> "sh.tangled.repo.pull#source") 1125 |> Jsont.Object.mem "branch" Jsont.string ~enc:(fun r -> r.branch) 1126 - |> Jsont.Object.opt_mem "repo" Jsont.string ~enc:(fun r -> r.repo) 1127 - |> Jsont.Object.mem "sha" Jsont.string ~enc:(fun r -> r.sha) 1128 - |> Jsont.Object.finish 1129 - 1130 - type main = { 1131 - body : string option; 1132 - created_at : string; 1133 - mentions : string list option; 1134 - patch : string option; 1135 - patch_blob : Atp.Blob_ref.t; 1136 - references : string list option; 1137 - source : source option; 1138 - target : target; 1139 - title : string; 1140 - } 1141 - 1142 - let main_jsont = 1143 - Jsont.Object.map ~kind:"Main" 1144 - (fun _typ body created_at mentions patch patch_blob references source target title -> { body; created_at; mentions; patch; patch_blob; references; source; target; title }) 1145 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.pull" ~enc:(fun _ -> "sh.tangled.repo.pull") 1146 - |> Jsont.Object.opt_mem "body" Jsont.string ~enc:(fun r -> r.body) 1147 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 1148 - |> Jsont.Object.opt_mem "mentions" (Jsont.list Jsont.string) ~enc:(fun r -> r.mentions) 1149 - |> Jsont.Object.opt_mem "patch" Jsont.string ~enc:(fun r -> r.patch) 1150 - |> Jsont.Object.mem "patchBlob" Atp.Blob_ref.jsont ~enc:(fun r -> r.patch_blob) 1151 - |> Jsont.Object.opt_mem "references" (Jsont.list Jsont.string) ~enc:(fun r -> r.references) 1152 - |> Jsont.Object.opt_mem "source" source_jsont ~enc:(fun r -> r.source) 1153 - |> Jsont.Object.mem "target" target_jsont ~enc:(fun r -> r.target) 1154 - |> Jsont.Object.mem "title" Jsont.string ~enc:(fun r -> r.title) 1155 |> Jsont.Object.finish 1156 1157 - module Comment = struct 1158 - type main = { 1159 - body : string; 1160 - created_at : string; 1161 - mentions : string list option; 1162 - pull : string; 1163 - references : string list option; 1164 - } 1165 - 1166 - let main_jsont = 1167 - Jsont.Object.map ~kind:"Main" 1168 - (fun _typ body created_at mentions pull references -> { body; created_at; mentions; pull; references }) 1169 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.pull.comment" ~enc:(fun _ -> "sh.tangled.repo.pull.comment") 1170 - |> Jsont.Object.mem "body" Jsont.string ~enc:(fun r -> r.body) 1171 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 1172 - |> Jsont.Object.opt_mem "mentions" (Jsont.list Jsont.string) ~enc:(fun r -> r.mentions) 1173 - |> Jsont.Object.mem "pull" Jsont.string ~enc:(fun r -> r.pull) 1174 - |> Jsont.Object.opt_mem "references" (Jsont.list Jsont.string) ~enc:(fun r -> r.references) 1175 - |> Jsont.Object.finish 1176 - 1177 - end 1178 - module Status = struct 1179 - type main = { 1180 - pull : string; 1181 - status : string; 1182 - } 1183 - 1184 - let main_jsont = 1185 - Jsont.Object.map ~kind:"Main" 1186 - (fun _typ pull status -> { pull; status }) 1187 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.pull.status" ~enc:(fun _ -> "sh.tangled.repo.pull.status") 1188 - |> Jsont.Object.mem "pull" Jsont.string ~enc:(fun r -> r.pull) 1189 - |> Jsont.Object.mem "status" Jsont.string ~enc:(fun r -> r.status) 1190 - |> Jsont.Object.finish 1191 - 1192 - module Closed = struct 1193 - type main = string 1194 - let main_jsont = Jsont.string 1195 - 1196 - end 1197 - module Open = struct 1198 - type main = string 1199 - let main_jsont = Jsont.string 1200 - 1201 - end 1202 - module Merged = struct 1203 - type main = string 1204 - let main_jsont = Jsont.string 1205 - 1206 - end 1207 - end 1208 end 1209 - module Issue = struct 1210 - type main = { 1211 - body : string option; 1212 - created_at : string; 1213 - mentions : string list option; 1214 - references : string list option; 1215 - repo : string; 1216 - title : string; 1217 - } 1218 - 1219 - let main_jsont = 1220 - Jsont.Object.map ~kind:"Main" 1221 - (fun _typ body created_at mentions references repo title -> { body; created_at; mentions; references; repo; title }) 1222 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.issue" ~enc:(fun _ -> "sh.tangled.repo.issue") 1223 - |> Jsont.Object.opt_mem "body" Jsont.string ~enc:(fun r -> r.body) 1224 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 1225 - |> Jsont.Object.opt_mem "mentions" (Jsont.list Jsont.string) ~enc:(fun r -> r.mentions) 1226 - |> Jsont.Object.opt_mem "references" (Jsont.list Jsont.string) ~enc:(fun r -> r.references) 1227 - |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 1228 - |> Jsont.Object.mem "title" Jsont.string ~enc:(fun r -> r.title) 1229 - |> Jsont.Object.finish 1230 - 1231 - module Comment = struct 1232 - type main = { 1233 - body : string; 1234 - created_at : string; 1235 - issue : string; 1236 - mentions : string list option; 1237 - references : string list option; 1238 - reply_to : string option; 1239 - } 1240 - 1241 - let main_jsont = 1242 - Jsont.Object.map ~kind:"Main" 1243 - (fun _typ body created_at issue mentions references reply_to -> { body; created_at; issue; mentions; references; reply_to }) 1244 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.issue.comment" ~enc:(fun _ -> "sh.tangled.repo.issue.comment") 1245 - |> Jsont.Object.mem "body" Jsont.string ~enc:(fun r -> r.body) 1246 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 1247 - |> Jsont.Object.mem "issue" Jsont.string ~enc:(fun r -> r.issue) 1248 - |> Jsont.Object.opt_mem "mentions" (Jsont.list Jsont.string) ~enc:(fun r -> r.mentions) 1249 - |> Jsont.Object.opt_mem "references" (Jsont.list Jsont.string) ~enc:(fun r -> r.references) 1250 - |> Jsont.Object.opt_mem "replyTo" Jsont.string ~enc:(fun r -> r.reply_to) 1251 - |> Jsont.Object.finish 1252 - 1253 - end 1254 - module State = struct 1255 - type main = { 1256 - issue : string; 1257 - state : string; 1258 - } 1259 - 1260 - let main_jsont = 1261 - Jsont.Object.map ~kind:"Main" 1262 - (fun _typ issue state -> { issue; state }) 1263 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.issue.state" ~enc:(fun _ -> "sh.tangled.repo.issue.state") 1264 - |> Jsont.Object.mem "issue" Jsont.string ~enc:(fun r -> r.issue) 1265 - |> Jsont.Object.mem "state" Jsont.string ~enc:(fun r -> r.state) 1266 - |> Jsont.Object.finish 1267 - 1268 - module Closed = struct 1269 - type main = string 1270 - let main_jsont = Jsont.string 1271 - 1272 - end 1273 - module Open = struct 1274 - type main = string 1275 - let main_jsont = Jsont.string 1276 - 1277 - end 1278 - end 1279 - end 1280 - end 1281 - module Label = struct 1282 - module Definition = struct 1283 - type value_type = { 1284 - enum : string list option; 1285 - format : string; 1286 - type_ : string; 1287 - } 1288 - 1289 - let value_type_jsont = 1290 - Jsont.Object.map ~kind:"Value_type" 1291 - (fun _typ enum format type_ -> { enum; format; type_ }) 1292 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.label.definition#valueType" ~enc:(fun _ -> "sh.tangled.label.definition#valueType") 1293 - |> Jsont.Object.opt_mem "enum" (Jsont.list Jsont.string) ~enc:(fun r -> r.enum) 1294 - |> Jsont.Object.mem "format" Jsont.string ~enc:(fun r -> r.format) 1295 - |> Jsont.Object.mem "type" Jsont.string ~enc:(fun r -> r.type_) 1296 - |> Jsont.Object.finish 1297 - 1298 - type main = { 1299 color : string option; 1300 - created_at : string; 1301 - multiple : bool option; 1302 name : string; 1303 - scope : string list; 1304 - value_type : value_type; 1305 } 1306 1307 - let main_jsont = 1308 - Jsont.Object.map ~kind:"Main" 1309 - (fun _typ color created_at multiple name scope value_type -> { color; created_at; multiple; name; scope; value_type }) 1310 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.label.definition" ~enc:(fun _ -> "sh.tangled.label.definition") 1311 |> Jsont.Object.opt_mem "color" Jsont.string ~enc:(fun r -> r.color) 1312 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 1313 - |> Jsont.Object.opt_mem "multiple" Jsont.bool ~enc:(fun r -> r.multiple) 1314 |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 1315 - |> Jsont.Object.mem "scope" (Jsont.list Jsont.string) ~enc:(fun r -> r.scope) 1316 - |> Jsont.Object.mem "valueType" value_type_jsont ~enc:(fun r -> r.value_type) 1317 - |> Jsont.Object.finish 1318 - 1319 - end 1320 - module Op = struct 1321 - type operand = { 1322 - key : string; 1323 - value : string; 1324 - } 1325 - 1326 - let operand_jsont = 1327 - Jsont.Object.map ~kind:"Operand" 1328 - (fun _typ key value -> { key; value }) 1329 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.label.op#operand" ~enc:(fun _ -> "sh.tangled.label.op#operand") 1330 - |> Jsont.Object.mem "key" Jsont.string ~enc:(fun r -> r.key) 1331 - |> Jsont.Object.mem "value" Jsont.string ~enc:(fun r -> r.value) 1332 - |> Jsont.Object.finish 1333 - 1334 - type main = { 1335 - add : operand list; 1336 - delete : operand list; 1337 - performed_at : string; 1338 - subject : string; 1339 - } 1340 - 1341 - let main_jsont = 1342 - Jsont.Object.map ~kind:"Main" 1343 - (fun _typ add delete performed_at subject -> { add; delete; performed_at; subject }) 1344 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.label.op" ~enc:(fun _ -> "sh.tangled.label.op") 1345 - |> Jsont.Object.mem "add" (Jsont.list operand_jsont) ~enc:(fun r -> r.add) 1346 - |> Jsont.Object.mem "delete" (Jsont.list operand_jsont) ~enc:(fun r -> r.delete) 1347 - |> Jsont.Object.mem "performedAt" Jsont.string ~enc:(fun r -> r.performed_at) 1348 - |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 1349 - |> Jsont.Object.finish 1350 - 1351 - end 1352 - end 1353 - module Graph = struct 1354 - module Follow = struct 1355 - type main = { 1356 - created_at : string; 1357 - subject : string; 1358 - } 1359 - 1360 - let main_jsont = 1361 - Jsont.Object.map ~kind:"Main" 1362 - (fun _typ created_at subject -> { created_at; subject }) 1363 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.graph.follow" ~enc:(fun _ -> "sh.tangled.graph.follow") 1364 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 1365 - |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 1366 - |> Jsont.Object.finish 1367 - 1368 - end 1369 - end 1370 - module Knot = struct 1371 - type main = { 1372 - created_at : string; 1373 - } 1374 - 1375 - let main_jsont = 1376 - Jsont.Object.map ~kind:"Main" 1377 - (fun _typ created_at -> { created_at }) 1378 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.knot" ~enc:(fun _ -> "sh.tangled.knot") 1379 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 1380 - |> Jsont.Object.finish 1381 - 1382 - module Member = struct 1383 - type main = { 1384 - created_at : string; 1385 - domain : string; 1386 - subject : string; 1387 - } 1388 - 1389 - let main_jsont = 1390 - Jsont.Object.map ~kind:"Main" 1391 - (fun _typ created_at domain subject -> { created_at; domain; subject }) 1392 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.knot.member" ~enc:(fun _ -> "sh.tangled.knot.member") 1393 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 1394 - |> Jsont.Object.mem "domain" Jsont.string ~enc:(fun r -> r.domain) 1395 - |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 1396 - |> Jsont.Object.finish 1397 - 1398 - end 1399 - module ListKeys = struct 1400 - type public_key = { 1401 - created_at : string; 1402 - did : string; 1403 - key : string; 1404 - } 1405 - 1406 - let public_key_jsont = 1407 - Jsont.Object.map ~kind:"Public_key" 1408 - (fun _typ created_at did key -> { created_at; did; key }) 1409 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.knot.listKeys#publicKey" ~enc:(fun _ -> "sh.tangled.knot.listKeys#publicKey") 1410 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 1411 - |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 1412 - |> Jsont.Object.mem "key" Jsont.string ~enc:(fun r -> r.key) 1413 |> Jsont.Object.finish 1414 1415 type params = { 1416 - cursor : string option; 1417 - limit : int option; 1418 } 1419 1420 let params_jsont = 1421 Jsont.Object.map ~kind:"Params" 1422 - (fun cursor limit -> { 1423 - cursor; 1424 - limit; 1425 }) 1426 - |> Jsont.Object.opt_mem "cursor" Jsont.string 1427 - ~enc:(fun r -> r.cursor) 1428 - |> Jsont.Object.opt_mem "limit" Jsont.int 1429 - ~enc:(fun r -> r.limit) 1430 - |> Jsont.Object.finish 1431 - 1432 - type output = { 1433 - cursor : string option; 1434 - keys : public_key list; 1435 - } 1436 - 1437 - let output_jsont = 1438 - Jsont.Object.map ~kind:"Output" 1439 - (fun _typ cursor keys -> { cursor; keys }) 1440 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.knot.listKeys#output" ~enc:(fun _ -> "sh.tangled.knot.listKeys#output") 1441 - |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 1442 - |> Jsont.Object.mem "keys" (Jsont.list public_key_jsont) ~enc:(fun r -> r.keys) 1443 - |> Jsont.Object.finish 1444 - 1445 - end 1446 - module Version = struct 1447 - type output = { 1448 - version : string; 1449 - } 1450 - 1451 - let output_jsont = 1452 - Jsont.Object.map ~kind:"Output" 1453 - (fun _typ version -> { version }) 1454 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.knot.version#output" ~enc:(fun _ -> "sh.tangled.knot.version#output") 1455 - |> Jsont.Object.mem "version" Jsont.string ~enc:(fun r -> r.version) 1456 |> Jsont.Object.finish 1457 1458 - end 1459 - end 1460 - module Owner = struct 1461 type output = { 1462 - owner : string; 1463 } 1464 1465 let output_jsont = 1466 Jsont.Object.map ~kind:"Output" 1467 - (fun _typ owner -> { owner }) 1468 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.owner#output" ~enc:(fun _ -> "sh.tangled.owner#output") 1469 - |> Jsont.Object.mem "owner" Jsont.string ~enc:(fun r -> r.owner) 1470 - |> Jsont.Object.finish 1471 - 1472 - end 1473 - module PublicKey = struct 1474 - type main = { 1475 - created_at : string; 1476 - key : string; 1477 - name : string; 1478 - } 1479 - 1480 - let main_jsont = 1481 - Jsont.Object.map ~kind:"Main" 1482 - (fun _typ created_at key name -> { created_at; key; name }) 1483 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.publicKey" ~enc:(fun _ -> "sh.tangled.publicKey") 1484 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 1485 - |> Jsont.Object.mem "key" Jsont.string ~enc:(fun r -> r.key) 1486 - |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 1487 - |> Jsont.Object.finish 1488 - 1489 - end 1490 - module Pipeline = struct 1491 - type trigger_repo = { 1492 - default_branch : string; 1493 - did : string; 1494 - knot : string; 1495 - repo : string; 1496 - } 1497 - 1498 - let trigger_repo_jsont = 1499 - Jsont.Object.map ~kind:"Trigger_repo" 1500 - (fun _typ default_branch did knot repo -> { default_branch; did; knot; repo }) 1501 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.pipeline#triggerRepo" ~enc:(fun _ -> "sh.tangled.pipeline#triggerRepo") 1502 - |> Jsont.Object.mem "defaultBranch" Jsont.string ~enc:(fun r -> r.default_branch) 1503 - |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 1504 - |> Jsont.Object.mem "knot" Jsont.string ~enc:(fun r -> r.knot) 1505 - |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 1506 - |> Jsont.Object.finish 1507 - 1508 - type push_trigger_data = { 1509 - new_sha : string; 1510 - old_sha : string; 1511 - ref_ : string; 1512 - } 1513 - 1514 - let push_trigger_data_jsont = 1515 - Jsont.Object.map ~kind:"Push_trigger_data" 1516 - (fun _typ new_sha old_sha ref_ -> { new_sha; old_sha; ref_ }) 1517 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.pipeline#pushTriggerData" ~enc:(fun _ -> "sh.tangled.pipeline#pushTriggerData") 1518 - |> Jsont.Object.mem "newSha" Jsont.string ~enc:(fun r -> r.new_sha) 1519 - |> Jsont.Object.mem "oldSha" Jsont.string ~enc:(fun r -> r.old_sha) 1520 |> Jsont.Object.mem "ref" Jsont.string ~enc:(fun r -> r.ref_) 1521 - |> Jsont.Object.finish 1522 - 1523 - type pull_request_trigger_data = { 1524 - action : string; 1525 - source_branch : string; 1526 - source_sha : string; 1527 - target_branch : string; 1528 - } 1529 - 1530 - let pull_request_trigger_data_jsont = 1531 - Jsont.Object.map ~kind:"Pull_request_trigger_data" 1532 - (fun _typ action source_branch source_sha target_branch -> { action; source_branch; source_sha; target_branch }) 1533 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.pipeline#pullRequestTriggerData" ~enc:(fun _ -> "sh.tangled.pipeline#pullRequestTriggerData") 1534 - |> Jsont.Object.mem "action" Jsont.string ~enc:(fun r -> r.action) 1535 - |> Jsont.Object.mem "sourceBranch" Jsont.string ~enc:(fun r -> r.source_branch) 1536 - |> Jsont.Object.mem "sourceSha" Jsont.string ~enc:(fun r -> r.source_sha) 1537 - |> Jsont.Object.mem "targetBranch" Jsont.string ~enc:(fun r -> r.target_branch) 1538 - |> Jsont.Object.finish 1539 - 1540 - type pair = { 1541 - key : string; 1542 - value : string; 1543 - } 1544 - 1545 - let pair_jsont = 1546 - Jsont.Object.map ~kind:"Pair" 1547 - (fun _typ key value -> { key; value }) 1548 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.pipeline#pair" ~enc:(fun _ -> "sh.tangled.pipeline#pair") 1549 - |> Jsont.Object.mem "key" Jsont.string ~enc:(fun r -> r.key) 1550 - |> Jsont.Object.mem "value" Jsont.string ~enc:(fun r -> r.value) 1551 - |> Jsont.Object.finish 1552 - 1553 - type clone_opts = { 1554 - depth : int; 1555 - skip : bool; 1556 - submodules : bool; 1557 - } 1558 - 1559 - let clone_opts_jsont = 1560 - Jsont.Object.map ~kind:"Clone_opts" 1561 - (fun _typ depth skip submodules -> { depth; skip; submodules }) 1562 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.pipeline#cloneOpts" ~enc:(fun _ -> "sh.tangled.pipeline#cloneOpts") 1563 - |> Jsont.Object.mem "depth" Jsont.int ~enc:(fun r -> r.depth) 1564 - |> Jsont.Object.mem "skip" Jsont.bool ~enc:(fun r -> r.skip) 1565 - |> Jsont.Object.mem "submodules" Jsont.bool ~enc:(fun r -> r.submodules) 1566 - |> Jsont.Object.finish 1567 - 1568 - type workflow = { 1569 - clone : clone_opts; 1570 - engine : string; 1571 - name : string; 1572 - raw : string; 1573 - } 1574 - 1575 - let workflow_jsont = 1576 - Jsont.Object.map ~kind:"Workflow" 1577 - (fun _typ clone engine name raw -> { clone; engine; name; raw }) 1578 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.pipeline#workflow" ~enc:(fun _ -> "sh.tangled.pipeline#workflow") 1579 - |> Jsont.Object.mem "clone" clone_opts_jsont ~enc:(fun r -> r.clone) 1580 - |> Jsont.Object.mem "engine" Jsont.string ~enc:(fun r -> r.engine) 1581 - |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 1582 - |> Jsont.Object.mem "raw" Jsont.string ~enc:(fun r -> r.raw) 1583 - |> Jsont.Object.finish 1584 - 1585 - type manual_trigger_data = { 1586 - inputs : pair list option; 1587 - } 1588 - 1589 - let manual_trigger_data_jsont = 1590 - Jsont.Object.map ~kind:"Manual_trigger_data" 1591 - (fun _typ inputs -> { inputs }) 1592 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.pipeline#manualTriggerData" ~enc:(fun _ -> "sh.tangled.pipeline#manualTriggerData") 1593 - |> Jsont.Object.opt_mem "inputs" (Jsont.list pair_jsont) ~enc:(fun r -> r.inputs) 1594 - |> Jsont.Object.finish 1595 - 1596 - type trigger_metadata = { 1597 - kind : string; 1598 - manual : manual_trigger_data option; 1599 - pull_request : pull_request_trigger_data option; 1600 - push : push_trigger_data option; 1601 - repo : trigger_repo; 1602 - } 1603 - 1604 - let trigger_metadata_jsont = 1605 - Jsont.Object.map ~kind:"Trigger_metadata" 1606 - (fun _typ kind manual pull_request push repo -> { kind; manual; pull_request; push; repo }) 1607 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.pipeline#triggerMetadata" ~enc:(fun _ -> "sh.tangled.pipeline#triggerMetadata") 1608 - |> Jsont.Object.mem "kind" Jsont.string ~enc:(fun r -> r.kind) 1609 - |> Jsont.Object.opt_mem "manual" manual_trigger_data_jsont ~enc:(fun r -> r.manual) 1610 - |> Jsont.Object.opt_mem "pullRequest" pull_request_trigger_data_jsont ~enc:(fun r -> r.pull_request) 1611 - |> Jsont.Object.opt_mem "push" push_trigger_data_jsont ~enc:(fun r -> r.push) 1612 - |> Jsont.Object.mem "repo" trigger_repo_jsont ~enc:(fun r -> r.repo) 1613 - |> Jsont.Object.finish 1614 - 1615 - type main = { 1616 - trigger_metadata : trigger_metadata; 1617 - workflows : workflow list; 1618 - } 1619 - 1620 - let main_jsont = 1621 - Jsont.Object.map ~kind:"Main" 1622 - (fun _typ trigger_metadata workflows -> { trigger_metadata; workflows }) 1623 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.pipeline" ~enc:(fun _ -> "sh.tangled.pipeline") 1624 - |> Jsont.Object.mem "triggerMetadata" trigger_metadata_jsont ~enc:(fun r -> r.trigger_metadata) 1625 - |> Jsont.Object.mem "workflows" (Jsont.list workflow_jsont) ~enc:(fun r -> r.workflows) 1626 - |> Jsont.Object.finish 1627 - 1628 - module Status = struct 1629 - type main = { 1630 - created_at : string; 1631 - error : string option; 1632 - exit_code : int option; 1633 - pipeline : string; 1634 - status : string; 1635 - workflow : string; 1636 - } 1637 - 1638 - let main_jsont = 1639 - Jsont.Object.map ~kind:"Main" 1640 - (fun _typ created_at error exit_code pipeline status workflow -> { created_at; error; exit_code; pipeline; status; workflow }) 1641 - |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.pipeline.status" ~enc:(fun _ -> "sh.tangled.pipeline.status") 1642 - |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 1643 - |> Jsont.Object.opt_mem "error" Jsont.string ~enc:(fun r -> r.error) 1644 - |> Jsont.Object.opt_mem "exitCode" Jsont.int ~enc:(fun r -> r.exit_code) 1645 - |> Jsont.Object.mem "pipeline" Jsont.string ~enc:(fun r -> r.pipeline) 1646 - |> Jsont.Object.mem "status" Jsont.string ~enc:(fun r -> r.status) 1647 - |> Jsont.Object.mem "workflow" Jsont.string ~enc:(fun r -> r.workflow) 1648 |> Jsont.Object.finish 1649 1650 end
··· 15 16 module Sh = struct 17 module Tangled = struct 18 + module Actor = struct 19 + module Profile = struct 20 + type main = { 21 + bluesky : bool; 22 + description : string option; 23 + links : string list option; 24 + location : string option; 25 + pinned_repositories : string list option; 26 + pronouns : string option; 27 + stats : string list option; 28 + } 29 + 30 + let main_jsont = 31 + Jsont.Object.map ~kind:"Main" 32 + (fun _typ bluesky description links location pinned_repositories pronouns stats -> { bluesky; description; links; location; pinned_repositories; pronouns; stats }) 33 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.actor.profile" ~enc:(fun _ -> "sh.tangled.actor.profile") 34 + |> Jsont.Object.mem "bluesky" Jsont.bool ~enc:(fun r -> r.bluesky) 35 + |> Jsont.Object.opt_mem "description" Jsont.string ~enc:(fun r -> r.description) 36 + |> Jsont.Object.opt_mem "links" (Jsont.list Jsont.string) ~enc:(fun r -> r.links) 37 + |> Jsont.Object.opt_mem "location" Jsont.string ~enc:(fun r -> r.location) 38 + |> Jsont.Object.opt_mem "pinnedRepositories" (Jsont.list Jsont.string) ~enc:(fun r -> r.pinned_repositories) 39 + |> Jsont.Object.opt_mem "pronouns" Jsont.string ~enc:(fun r -> r.pronouns) 40 + |> Jsont.Object.opt_mem "stats" (Jsont.list Jsont.string) ~enc:(fun r -> r.stats) 41 + |> Jsont.Object.finish 42 + 43 + end 44 + end 45 + module Owner = struct 46 + type output = { 47 + owner : string; 48 + } 49 + 50 + let output_jsont = 51 + Jsont.Object.map ~kind:"Output" 52 + (fun _typ owner -> { owner }) 53 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.owner#output" ~enc:(fun _ -> "sh.tangled.owner#output") 54 + |> Jsont.Object.mem "owner" Jsont.string ~enc:(fun r -> r.owner) 55 + |> Jsont.Object.finish 56 + 57 + end 58 module Spindle = struct 59 type main = { 60 created_at : string; ··· 85 86 end 87 end 88 + module Pipeline = struct 89 + type trigger_repo = { 90 + default_branch : string; 91 + did : string; 92 + knot : string; 93 + repo : string; 94 + } 95 + 96 + let trigger_repo_jsont = 97 + Jsont.Object.map ~kind:"Trigger_repo" 98 + (fun _typ default_branch did knot repo -> { default_branch; did; knot; repo }) 99 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.pipeline#triggerRepo" ~enc:(fun _ -> "sh.tangled.pipeline#triggerRepo") 100 + |> Jsont.Object.mem "defaultBranch" Jsont.string ~enc:(fun r -> r.default_branch) 101 + |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 102 + |> Jsont.Object.mem "knot" Jsont.string ~enc:(fun r -> r.knot) 103 + |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 104 + |> Jsont.Object.finish 105 + 106 + type push_trigger_data = { 107 + new_sha : string; 108 + old_sha : string; 109 + ref_ : string; 110 + } 111 + 112 + let push_trigger_data_jsont = 113 + Jsont.Object.map ~kind:"Push_trigger_data" 114 + (fun _typ new_sha old_sha ref_ -> { new_sha; old_sha; ref_ }) 115 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.pipeline#pushTriggerData" ~enc:(fun _ -> "sh.tangled.pipeline#pushTriggerData") 116 + |> Jsont.Object.mem "newSha" Jsont.string ~enc:(fun r -> r.new_sha) 117 + |> Jsont.Object.mem "oldSha" Jsont.string ~enc:(fun r -> r.old_sha) 118 + |> Jsont.Object.mem "ref" Jsont.string ~enc:(fun r -> r.ref_) 119 + |> Jsont.Object.finish 120 + 121 + type pull_request_trigger_data = { 122 + action : string; 123 + source_branch : string; 124 + source_sha : string; 125 + target_branch : string; 126 + } 127 + 128 + let pull_request_trigger_data_jsont = 129 + Jsont.Object.map ~kind:"Pull_request_trigger_data" 130 + (fun _typ action source_branch source_sha target_branch -> { action; source_branch; source_sha; target_branch }) 131 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.pipeline#pullRequestTriggerData" ~enc:(fun _ -> "sh.tangled.pipeline#pullRequestTriggerData") 132 + |> Jsont.Object.mem "action" Jsont.string ~enc:(fun r -> r.action) 133 + |> Jsont.Object.mem "sourceBranch" Jsont.string ~enc:(fun r -> r.source_branch) 134 + |> Jsont.Object.mem "sourceSha" Jsont.string ~enc:(fun r -> r.source_sha) 135 + |> Jsont.Object.mem "targetBranch" Jsont.string ~enc:(fun r -> r.target_branch) 136 + |> Jsont.Object.finish 137 + 138 + type pair = { 139 + key : string; 140 + value : string; 141 + } 142 + 143 + let pair_jsont = 144 + Jsont.Object.map ~kind:"Pair" 145 + (fun _typ key value -> { key; value }) 146 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.pipeline#pair" ~enc:(fun _ -> "sh.tangled.pipeline#pair") 147 + |> Jsont.Object.mem "key" Jsont.string ~enc:(fun r -> r.key) 148 + |> Jsont.Object.mem "value" Jsont.string ~enc:(fun r -> r.value) 149 + |> Jsont.Object.finish 150 + 151 + type clone_opts = { 152 + depth : int; 153 + skip : bool; 154 + submodules : bool; 155 + } 156 + 157 + let clone_opts_jsont = 158 + Jsont.Object.map ~kind:"Clone_opts" 159 + (fun _typ depth skip submodules -> { depth; skip; submodules }) 160 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.pipeline#cloneOpts" ~enc:(fun _ -> "sh.tangled.pipeline#cloneOpts") 161 + |> Jsont.Object.mem "depth" Jsont.int ~enc:(fun r -> r.depth) 162 + |> Jsont.Object.mem "skip" Jsont.bool ~enc:(fun r -> r.skip) 163 + |> Jsont.Object.mem "submodules" Jsont.bool ~enc:(fun r -> r.submodules) 164 + |> Jsont.Object.finish 165 + 166 + type workflow = { 167 + clone : clone_opts; 168 + engine : string; 169 + name : string; 170 + raw : string; 171 + } 172 + 173 + let workflow_jsont = 174 + Jsont.Object.map ~kind:"Workflow" 175 + (fun _typ clone engine name raw -> { clone; engine; name; raw }) 176 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.pipeline#workflow" ~enc:(fun _ -> "sh.tangled.pipeline#workflow") 177 + |> Jsont.Object.mem "clone" clone_opts_jsont ~enc:(fun r -> r.clone) 178 + |> Jsont.Object.mem "engine" Jsont.string ~enc:(fun r -> r.engine) 179 + |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 180 + |> Jsont.Object.mem "raw" Jsont.string ~enc:(fun r -> r.raw) 181 + |> Jsont.Object.finish 182 + 183 + type manual_trigger_data = { 184 + inputs : pair list option; 185 + } 186 + 187 + let manual_trigger_data_jsont = 188 + Jsont.Object.map ~kind:"Manual_trigger_data" 189 + (fun _typ inputs -> { inputs }) 190 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.pipeline#manualTriggerData" ~enc:(fun _ -> "sh.tangled.pipeline#manualTriggerData") 191 + |> Jsont.Object.opt_mem "inputs" (Jsont.list pair_jsont) ~enc:(fun r -> r.inputs) 192 + |> Jsont.Object.finish 193 + 194 + type trigger_metadata = { 195 + kind : string; 196 + manual : manual_trigger_data option; 197 + pull_request : pull_request_trigger_data option; 198 + push : push_trigger_data option; 199 + repo : trigger_repo; 200 + } 201 + 202 + let trigger_metadata_jsont = 203 + Jsont.Object.map ~kind:"Trigger_metadata" 204 + (fun _typ kind manual pull_request push repo -> { kind; manual; pull_request; push; repo }) 205 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.pipeline#triggerMetadata" ~enc:(fun _ -> "sh.tangled.pipeline#triggerMetadata") 206 + |> Jsont.Object.mem "kind" Jsont.string ~enc:(fun r -> r.kind) 207 + |> Jsont.Object.opt_mem "manual" manual_trigger_data_jsont ~enc:(fun r -> r.manual) 208 + |> Jsont.Object.opt_mem "pullRequest" pull_request_trigger_data_jsont ~enc:(fun r -> r.pull_request) 209 + |> Jsont.Object.opt_mem "push" push_trigger_data_jsont ~enc:(fun r -> r.push) 210 + |> Jsont.Object.mem "repo" trigger_repo_jsont ~enc:(fun r -> r.repo) 211 + |> Jsont.Object.finish 212 + 213 + type main = { 214 + trigger_metadata : trigger_metadata; 215 + workflows : workflow list; 216 + } 217 + 218 + let main_jsont = 219 + Jsont.Object.map ~kind:"Main" 220 + (fun _typ trigger_metadata workflows -> { trigger_metadata; workflows }) 221 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.pipeline" ~enc:(fun _ -> "sh.tangled.pipeline") 222 + |> Jsont.Object.mem "triggerMetadata" trigger_metadata_jsont ~enc:(fun r -> r.trigger_metadata) 223 + |> Jsont.Object.mem "workflows" (Jsont.list workflow_jsont) ~enc:(fun r -> r.workflows) 224 + |> Jsont.Object.finish 225 + 226 + module Status = struct 227 + type main = { 228 + created_at : string; 229 + error : string option; 230 + exit_code : int option; 231 + pipeline : string; 232 + status : string; 233 + workflow : string; 234 + } 235 + 236 + let main_jsont = 237 + Jsont.Object.map ~kind:"Main" 238 + (fun _typ created_at error exit_code pipeline status workflow -> { created_at; error; exit_code; pipeline; status; workflow }) 239 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.pipeline.status" ~enc:(fun _ -> "sh.tangled.pipeline.status") 240 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 241 + |> Jsont.Object.opt_mem "error" Jsont.string ~enc:(fun r -> r.error) 242 + |> Jsont.Object.opt_mem "exitCode" Jsont.int ~enc:(fun r -> r.exit_code) 243 + |> Jsont.Object.mem "pipeline" Jsont.string ~enc:(fun r -> r.pipeline) 244 + |> Jsont.Object.mem "status" Jsont.string ~enc:(fun r -> r.status) 245 + |> Jsont.Object.mem "workflow" Jsont.string ~enc:(fun r -> r.workflow) 246 + |> Jsont.Object.finish 247 + 248 + end 249 + end 250 + module Knot = struct 251 + type main = { 252 + created_at : string; 253 + } 254 + 255 + let main_jsont = 256 + Jsont.Object.map ~kind:"Main" 257 + (fun _typ created_at -> { created_at }) 258 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.knot" ~enc:(fun _ -> "sh.tangled.knot") 259 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 260 + |> Jsont.Object.finish 261 + 262 + module Version = struct 263 + type output = { 264 + version : string; 265 + } 266 + 267 + let output_jsont = 268 + Jsont.Object.map ~kind:"Output" 269 + (fun _typ version -> { version }) 270 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.knot.version#output" ~enc:(fun _ -> "sh.tangled.knot.version#output") 271 + |> Jsont.Object.mem "version" Jsont.string ~enc:(fun r -> r.version) 272 + |> Jsont.Object.finish 273 + 274 + end 275 + module ListKeys = struct 276 + type public_key = { 277 + created_at : string; 278 + did : string; 279 + key : string; 280 + } 281 + 282 + let public_key_jsont = 283 + Jsont.Object.map ~kind:"Public_key" 284 + (fun _typ created_at did key -> { created_at; did; key }) 285 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.knot.listKeys#publicKey" ~enc:(fun _ -> "sh.tangled.knot.listKeys#publicKey") 286 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 287 + |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 288 + |> Jsont.Object.mem "key" Jsont.string ~enc:(fun r -> r.key) 289 + |> Jsont.Object.finish 290 + 291 + type params = { 292 + cursor : string option; 293 + limit : int option; 294 + } 295 + 296 + let params_jsont = 297 + Jsont.Object.map ~kind:"Params" 298 + (fun cursor limit -> { 299 + cursor; 300 + limit; 301 + }) 302 + |> Jsont.Object.opt_mem "cursor" Jsont.string 303 + ~enc:(fun r -> r.cursor) 304 + |> Jsont.Object.opt_mem "limit" Jsont.int 305 + ~enc:(fun r -> r.limit) 306 + |> Jsont.Object.finish 307 + 308 + type output = { 309 + cursor : string option; 310 + keys : public_key list; 311 + } 312 + 313 + let output_jsont = 314 + Jsont.Object.map ~kind:"Output" 315 + (fun _typ cursor keys -> { cursor; keys }) 316 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.knot.listKeys#output" ~enc:(fun _ -> "sh.tangled.knot.listKeys#output") 317 + |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 318 + |> Jsont.Object.mem "keys" (Jsont.list public_key_jsont) ~enc:(fun r -> r.keys) 319 + |> Jsont.Object.finish 320 + 321 + end 322 + module Member = struct 323 + type main = { 324 + created_at : string; 325 + domain : string; 326 + subject : string; 327 + } 328 + 329 + let main_jsont = 330 + Jsont.Object.map ~kind:"Main" 331 + (fun _typ created_at domain subject -> { created_at; domain; subject }) 332 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.knot.member" ~enc:(fun _ -> "sh.tangled.knot.member") 333 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 334 + |> Jsont.Object.mem "domain" Jsont.string ~enc:(fun r -> r.domain) 335 + |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 336 + |> Jsont.Object.finish 337 + 338 + end 339 + end 340 + module Label = struct 341 + module Op = struct 342 + type operand = { 343 + key : string; 344 + value : string; 345 + } 346 + 347 + let operand_jsont = 348 + Jsont.Object.map ~kind:"Operand" 349 + (fun _typ key value -> { key; value }) 350 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.label.op#operand" ~enc:(fun _ -> "sh.tangled.label.op#operand") 351 + |> Jsont.Object.mem "key" Jsont.string ~enc:(fun r -> r.key) 352 + |> Jsont.Object.mem "value" Jsont.string ~enc:(fun r -> r.value) 353 + |> Jsont.Object.finish 354 + 355 + type main = { 356 + add : operand list; 357 + delete : operand list; 358 + performed_at : string; 359 + subject : string; 360 + } 361 + 362 + let main_jsont = 363 + Jsont.Object.map ~kind:"Main" 364 + (fun _typ add delete performed_at subject -> { add; delete; performed_at; subject }) 365 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.label.op" ~enc:(fun _ -> "sh.tangled.label.op") 366 + |> Jsont.Object.mem "add" (Jsont.list operand_jsont) ~enc:(fun r -> r.add) 367 + |> Jsont.Object.mem "delete" (Jsont.list operand_jsont) ~enc:(fun r -> r.delete) 368 + |> Jsont.Object.mem "performedAt" Jsont.string ~enc:(fun r -> r.performed_at) 369 + |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 370 + |> Jsont.Object.finish 371 + 372 + end 373 + module Definition = struct 374 + type value_type = { 375 + enum : string list option; 376 + format : string; 377 + type_ : string; 378 + } 379 + 380 + let value_type_jsont = 381 + Jsont.Object.map ~kind:"Value_type" 382 + (fun _typ enum format type_ -> { enum; format; type_ }) 383 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.label.definition#valueType" ~enc:(fun _ -> "sh.tangled.label.definition#valueType") 384 + |> Jsont.Object.opt_mem "enum" (Jsont.list Jsont.string) ~enc:(fun r -> r.enum) 385 + |> Jsont.Object.mem "format" Jsont.string ~enc:(fun r -> r.format) 386 + |> Jsont.Object.mem "type" Jsont.string ~enc:(fun r -> r.type_) 387 + |> Jsont.Object.finish 388 + 389 + type main = { 390 + color : string option; 391 + created_at : string; 392 + multiple : bool option; 393 + name : string; 394 + scope : string list; 395 + value_type : value_type; 396 + } 397 + 398 + let main_jsont = 399 + Jsont.Object.map ~kind:"Main" 400 + (fun _typ color created_at multiple name scope value_type -> { color; created_at; multiple; name; scope; value_type }) 401 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.label.definition" ~enc:(fun _ -> "sh.tangled.label.definition") 402 + |> Jsont.Object.opt_mem "color" Jsont.string ~enc:(fun r -> r.color) 403 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 404 + |> Jsont.Object.opt_mem "multiple" Jsont.bool ~enc:(fun r -> r.multiple) 405 + |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 406 + |> Jsont.Object.mem "scope" (Jsont.list Jsont.string) ~enc:(fun r -> r.scope) 407 + |> Jsont.Object.mem "valueType" value_type_jsont ~enc:(fun r -> r.value_type) 408 + |> Jsont.Object.finish 409 + 410 + end 411 + end 412 + module Feed = struct 413 + module Reaction = struct 414 + type main = { 415 + created_at : string; 416 + reaction : string; 417 + subject : string; 418 + } 419 + 420 + let main_jsont = 421 + Jsont.Object.map ~kind:"Main" 422 + (fun _typ created_at reaction subject -> { created_at; reaction; subject }) 423 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.feed.reaction" ~enc:(fun _ -> "sh.tangled.feed.reaction") 424 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 425 + |> Jsont.Object.mem "reaction" Jsont.string ~enc:(fun r -> r.reaction) 426 + |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 427 + |> Jsont.Object.finish 428 + 429 + end 430 + module Star = struct 431 + type main = { 432 + created_at : string; 433 + subject : string; 434 + } 435 + 436 + let main_jsont = 437 + Jsont.Object.map ~kind:"Main" 438 + (fun _typ created_at subject -> { created_at; subject }) 439 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.feed.star" ~enc:(fun _ -> "sh.tangled.feed.star") 440 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 441 + |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 442 + |> Jsont.Object.finish 443 + 444 + end 445 + end 446 + module PublicKey = struct 447 + type main = { 448 + created_at : string; 449 + key : string; 450 + name : string; 451 + } 452 + 453 + let main_jsont = 454 + Jsont.Object.map ~kind:"Main" 455 + (fun _typ created_at key name -> { created_at; key; name }) 456 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.publicKey" ~enc:(fun _ -> "sh.tangled.publicKey") 457 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 458 + |> Jsont.Object.mem "key" Jsont.string ~enc:(fun r -> r.key) 459 + |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 460 + |> Jsont.Object.finish 461 + 462 + end 463 + module Graph = struct 464 + module Follow = struct 465 + type main = { 466 + created_at : string; 467 + subject : string; 468 + } 469 + 470 + let main_jsont = 471 + Jsont.Object.map ~kind:"Main" 472 + (fun _typ created_at subject -> { created_at; subject }) 473 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.graph.follow" ~enc:(fun _ -> "sh.tangled.graph.follow") 474 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 475 + |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 476 + |> Jsont.Object.finish 477 + 478 + end 479 + end 480 module Git = struct 481 module RefUpdate = struct 482 type individual_language_size = { ··· 567 568 end 569 end 570 module String = struct 571 type main = { 572 contents : string; ··· 586 |> Jsont.Object.finish 587 588 end 589 module Repo = struct 590 type main = { 591 created_at : string; ··· 614 |> Jsont.Object.opt_mem "website" Jsont.string ~enc:(fun r -> r.website) 615 |> Jsont.Object.finish 616 617 + module Issue = struct 618 type main = { 619 + body : string option; 620 created_at : string; 621 + mentions : string list option; 622 + references : string list option; 623 repo : string; 624 + title : string; 625 } 626 627 let main_jsont = 628 Jsont.Object.map ~kind:"Main" 629 + (fun _typ body created_at mentions references repo title -> { body; created_at; mentions; references; repo; title }) 630 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.issue" ~enc:(fun _ -> "sh.tangled.repo.issue") 631 + |> Jsont.Object.opt_mem "body" Jsont.string ~enc:(fun r -> r.body) 632 |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 633 + |> Jsont.Object.opt_mem "mentions" (Jsont.list Jsont.string) ~enc:(fun r -> r.mentions) 634 + |> Jsont.Object.opt_mem "references" (Jsont.list Jsont.string) ~enc:(fun r -> r.references) 635 |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 636 + |> Jsont.Object.mem "title" Jsont.string ~enc:(fun r -> r.title) 637 + |> Jsont.Object.finish 638 + 639 + module Comment = struct 640 + type main = { 641 + body : string; 642 + created_at : string; 643 + issue : string; 644 + mentions : string list option; 645 + references : string list option; 646 + reply_to : string option; 647 + } 648 + 649 + let main_jsont = 650 + Jsont.Object.map ~kind:"Main" 651 + (fun _typ body created_at issue mentions references reply_to -> { body; created_at; issue; mentions; references; reply_to }) 652 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.issue.comment" ~enc:(fun _ -> "sh.tangled.repo.issue.comment") 653 + |> Jsont.Object.mem "body" Jsont.string ~enc:(fun r -> r.body) 654 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 655 + |> Jsont.Object.mem "issue" Jsont.string ~enc:(fun r -> r.issue) 656 + |> Jsont.Object.opt_mem "mentions" (Jsont.list Jsont.string) ~enc:(fun r -> r.mentions) 657 + |> Jsont.Object.opt_mem "references" (Jsont.list Jsont.string) ~enc:(fun r -> r.references) 658 + |> Jsont.Object.opt_mem "replyTo" Jsont.string ~enc:(fun r -> r.reply_to) 659 + |> Jsont.Object.finish 660 + 661 + end 662 + module State = struct 663 + type main = { 664 + issue : string; 665 + state : string; 666 + } 667 + 668 + let main_jsont = 669 + Jsont.Object.map ~kind:"Main" 670 + (fun _typ issue state -> { issue; state }) 671 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.issue.state" ~enc:(fun _ -> "sh.tangled.repo.issue.state") 672 + |> Jsont.Object.mem "issue" Jsont.string ~enc:(fun r -> r.issue) 673 + |> Jsont.Object.mem "state" Jsont.string ~enc:(fun r -> r.state) 674 |> Jsont.Object.finish 675 676 + module Closed = struct 677 + type main = string 678 + let main_jsont = Jsont.string 679 + 680 + end 681 + module Open = struct 682 + type main = string 683 + let main_jsont = Jsont.string 684 + 685 + end 686 + end 687 end 688 + module Pull = struct 689 + type target = { 690 + branch : string; 691 + repo : string; 692 + } 693 + 694 + let target_jsont = 695 + Jsont.Object.map ~kind:"Target" 696 + (fun _typ branch repo -> { branch; repo }) 697 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.pull#target" ~enc:(fun _ -> "sh.tangled.repo.pull#target") 698 + |> Jsont.Object.mem "branch" Jsont.string ~enc:(fun r -> r.branch) 699 + |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 700 + |> Jsont.Object.finish 701 + 702 + type source = { 703 + branch : string; 704 + repo : string option; 705 + sha : string; 706 + } 707 + 708 + let source_jsont = 709 + Jsont.Object.map ~kind:"Source" 710 + (fun _typ branch repo sha -> { branch; repo; sha }) 711 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.pull#source" ~enc:(fun _ -> "sh.tangled.repo.pull#source") 712 + |> Jsont.Object.mem "branch" Jsont.string ~enc:(fun r -> r.branch) 713 + |> Jsont.Object.opt_mem "repo" Jsont.string ~enc:(fun r -> r.repo) 714 + |> Jsont.Object.mem "sha" Jsont.string ~enc:(fun r -> r.sha) 715 + |> Jsont.Object.finish 716 + 717 + type main = { 718 + body : string option; 719 + created_at : string; 720 + mentions : string list option; 721 + patch : string option; 722 + patch_blob : Atp.Blob_ref.t; 723 + references : string list option; 724 + source : source option; 725 + target : target; 726 + title : string; 727 + } 728 + 729 + let main_jsont = 730 + Jsont.Object.map ~kind:"Main" 731 + (fun _typ body created_at mentions patch patch_blob references source target title -> { body; created_at; mentions; patch; patch_blob; references; source; target; title }) 732 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.pull" ~enc:(fun _ -> "sh.tangled.repo.pull") 733 + |> Jsont.Object.opt_mem "body" Jsont.string ~enc:(fun r -> r.body) 734 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 735 + |> Jsont.Object.opt_mem "mentions" (Jsont.list Jsont.string) ~enc:(fun r -> r.mentions) 736 + |> Jsont.Object.opt_mem "patch" Jsont.string ~enc:(fun r -> r.patch) 737 + |> Jsont.Object.mem "patchBlob" Atp.Blob_ref.jsont ~enc:(fun r -> r.patch_blob) 738 + |> Jsont.Object.opt_mem "references" (Jsont.list Jsont.string) ~enc:(fun r -> r.references) 739 + |> Jsont.Object.opt_mem "source" source_jsont ~enc:(fun r -> r.source) 740 + |> Jsont.Object.mem "target" target_jsont ~enc:(fun r -> r.target) 741 + |> Jsont.Object.mem "title" Jsont.string ~enc:(fun r -> r.title) 742 + |> Jsont.Object.finish 743 + 744 + module Comment = struct 745 + type main = { 746 + body : string; 747 + created_at : string; 748 + mentions : string list option; 749 + pull : string; 750 + references : string list option; 751 } 752 753 + let main_jsont = 754 + Jsont.Object.map ~kind:"Main" 755 + (fun _typ body created_at mentions pull references -> { body; created_at; mentions; pull; references }) 756 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.pull.comment" ~enc:(fun _ -> "sh.tangled.repo.pull.comment") 757 + |> Jsont.Object.mem "body" Jsont.string ~enc:(fun r -> r.body) 758 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 759 + |> Jsont.Object.opt_mem "mentions" (Jsont.list Jsont.string) ~enc:(fun r -> r.mentions) 760 + |> Jsont.Object.mem "pull" Jsont.string ~enc:(fun r -> r.pull) 761 + |> Jsont.Object.opt_mem "references" (Jsont.list Jsont.string) ~enc:(fun r -> r.references) 762 |> Jsont.Object.finish 763 764 + end 765 + module Status = struct 766 + type main = { 767 + pull : string; 768 + status : string; 769 + } 770 + 771 + let main_jsont = 772 + Jsont.Object.map ~kind:"Main" 773 + (fun _typ pull status -> { pull; status }) 774 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.pull.status" ~enc:(fun _ -> "sh.tangled.repo.pull.status") 775 + |> Jsont.Object.mem "pull" Jsont.string ~enc:(fun r -> r.pull) 776 + |> Jsont.Object.mem "status" Jsont.string ~enc:(fun r -> r.status) 777 + |> Jsont.Object.finish 778 + 779 + module Merged = struct 780 + type main = string 781 + let main_jsont = Jsont.string 782 + 783 + end 784 + module Closed = struct 785 + type main = string 786 + let main_jsont = Jsont.string 787 + 788 + end 789 + module Open = struct 790 + type main = string 791 + let main_jsont = Jsont.string 792 + 793 + end 794 + end 795 + end 796 + module SetDefaultBranch = struct 797 type input = { 798 + default_branch : string; 799 + repo : string; 800 } 801 802 let input_jsont = 803 Jsont.Object.map ~kind:"Input" 804 + (fun _typ default_branch repo -> { default_branch; repo }) 805 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.setDefaultBranch#input" ~enc:(fun _ -> "sh.tangled.repo.setDefaultBranch#input") 806 + |> Jsont.Object.mem "defaultBranch" Jsont.string ~enc:(fun r -> r.default_branch) 807 + |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 808 + |> Jsont.Object.finish 809 + 810 + end 811 + module GetDefaultBranch = struct 812 + type signature = { 813 + email : string; 814 + name : string; 815 + when_ : string; 816 + } 817 + 818 + let signature_jsont = 819 + Jsont.Object.map ~kind:"Signature" 820 + (fun _typ email name when_ -> { email; name; when_ }) 821 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.getDefaultBranch#signature" ~enc:(fun _ -> "sh.tangled.repo.getDefaultBranch#signature") 822 + |> Jsont.Object.mem "email" Jsont.string ~enc:(fun r -> r.email) 823 |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 824 + |> Jsont.Object.mem "when" Jsont.string ~enc:(fun r -> r.when_) 825 + |> Jsont.Object.finish 826 + 827 + type params = { 828 + repo : string; 829 + } 830 + 831 + let params_jsont = 832 + Jsont.Object.map ~kind:"Params" 833 + (fun repo -> { 834 + repo; 835 + }) 836 + |> Jsont.Object.mem "repo" Jsont.string 837 + ~enc:(fun r -> r.repo) 838 |> Jsont.Object.finish 839 840 type output = { 841 + author : signature option; 842 + hash : string; 843 message : string option; 844 + name : string; 845 + short_hash : string option; 846 + when_ : string; 847 } 848 849 let output_jsont = 850 Jsont.Object.map ~kind:"Output" 851 + (fun _typ author hash message name short_hash when_ -> { author; hash; message; name; short_hash; when_ }) 852 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.getDefaultBranch#output" ~enc:(fun _ -> "sh.tangled.repo.getDefaultBranch#output") 853 + |> Jsont.Object.opt_mem "author" signature_jsont ~enc:(fun r -> r.author) 854 + |> Jsont.Object.mem "hash" Jsont.string ~enc:(fun r -> r.hash) 855 |> Jsont.Object.opt_mem "message" Jsont.string ~enc:(fun r -> r.message) 856 + |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 857 + |> Jsont.Object.opt_mem "shortHash" Jsont.string ~enc:(fun r -> r.short_hash) 858 + |> Jsont.Object.mem "when" Jsont.string ~enc:(fun r -> r.when_) 859 + |> Jsont.Object.finish 860 + 861 + end 862 + module DeleteBranch = struct 863 + type input = { 864 + branch : string; 865 + repo : string; 866 + } 867 + 868 + let input_jsont = 869 + Jsont.Object.map ~kind:"Input" 870 + (fun _typ branch repo -> { branch; repo }) 871 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.deleteBranch#input" ~enc:(fun _ -> "sh.tangled.repo.deleteBranch#input") 872 + |> Jsont.Object.mem "branch" Jsont.string ~enc:(fun r -> r.branch) 873 + |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 874 + |> Jsont.Object.finish 875 + 876 + end 877 + module Delete = struct 878 + type input = { 879 + did : string; 880 + name : string; 881 + rkey : string; 882 + } 883 + 884 + let input_jsont = 885 + Jsont.Object.map ~kind:"Input" 886 + (fun _typ did name rkey -> { did; name; rkey }) 887 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.delete#input" ~enc:(fun _ -> "sh.tangled.repo.delete#input") 888 + |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 889 + |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 890 + |> Jsont.Object.mem "rkey" Jsont.string ~enc:(fun r -> r.rkey) 891 |> Jsont.Object.finish 892 893 end ··· 978 |> Jsont.Object.finish 979 980 end 981 + module AddSecret = struct 982 type input = { 983 + key : string; 984 repo : string; 985 + value : string; 986 } 987 988 let input_jsont = 989 Jsont.Object.map ~kind:"Input" 990 + (fun _typ key repo value -> { key; repo; value }) 991 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.addSecret#input" ~enc:(fun _ -> "sh.tangled.repo.addSecret#input") 992 + |> Jsont.Object.mem "key" Jsont.string ~enc:(fun r -> r.key) 993 |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 994 + |> Jsont.Object.mem "value" Jsont.string ~enc:(fun r -> r.value) 995 |> Jsont.Object.finish 996 997 end 998 + module Branch = struct 999 + type signature = { 1000 + email : string; 1001 + name : string; 1002 + when_ : string; 1003 + } 1004 + 1005 + let signature_jsont = 1006 + Jsont.Object.map ~kind:"Signature" 1007 + (fun _typ email name when_ -> { email; name; when_ }) 1008 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.branch#signature" ~enc:(fun _ -> "sh.tangled.repo.branch#signature") 1009 + |> Jsont.Object.mem "email" Jsont.string ~enc:(fun r -> r.email) 1010 + |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 1011 + |> Jsont.Object.mem "when" Jsont.string ~enc:(fun r -> r.when_) 1012 + |> Jsont.Object.finish 1013 + 1014 type params = { 1015 + name : string; 1016 repo : string; 1017 } 1018 1019 let params_jsont = 1020 Jsont.Object.map ~kind:"Params" 1021 + (fun name repo -> { 1022 + name; 1023 repo; 1024 }) 1025 + |> Jsont.Object.mem "name" Jsont.string 1026 + ~enc:(fun r -> r.name) 1027 |> Jsont.Object.mem "repo" Jsont.string 1028 ~enc:(fun r -> r.repo) 1029 |> Jsont.Object.finish 1030 1031 + type output = { 1032 + author : signature option; 1033 + hash : string; 1034 + is_default : bool option; 1035 + message : string option; 1036 name : string; 1037 + short_hash : string option; 1038 + when_ : string; 1039 } 1040 1041 + let output_jsont = 1042 + Jsont.Object.map ~kind:"Output" 1043 + (fun _typ author hash is_default message name short_hash when_ -> { author; hash; is_default; message; name; short_hash; when_ }) 1044 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.branch#output" ~enc:(fun _ -> "sh.tangled.repo.branch#output") 1045 + |> Jsont.Object.opt_mem "author" signature_jsont ~enc:(fun r -> r.author) 1046 + |> Jsont.Object.mem "hash" Jsont.string ~enc:(fun r -> r.hash) 1047 + |> Jsont.Object.opt_mem "isDefault" Jsont.bool ~enc:(fun r -> r.is_default) 1048 + |> Jsont.Object.opt_mem "message" Jsont.string ~enc:(fun r -> r.message) 1049 |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 1050 + |> Jsont.Object.opt_mem "shortHash" Jsont.string ~enc:(fun r -> r.short_hash) 1051 + |> Jsont.Object.mem "when" Jsont.string ~enc:(fun r -> r.when_) 1052 |> Jsont.Object.finish 1053 1054 end 1055 + module Log = struct 1056 type params = { 1057 cursor : string option; 1058 limit : int option; 1059 + path : string option; 1060 + ref_ : string; 1061 repo : string; 1062 } 1063 1064 let params_jsont = 1065 Jsont.Object.map ~kind:"Params" 1066 + (fun cursor limit path ref_ repo -> { 1067 cursor; 1068 limit; 1069 + path; 1070 + ref_; 1071 repo; 1072 }) 1073 |> Jsont.Object.opt_mem "cursor" Jsont.string 1074 ~enc:(fun r -> r.cursor) 1075 |> Jsont.Object.opt_mem "limit" Jsont.int 1076 ~enc:(fun r -> r.limit) 1077 + |> Jsont.Object.opt_mem "path" Jsont.string 1078 + ~enc:(fun r -> r.path) 1079 + |> Jsont.Object.mem "ref" Jsont.string 1080 + ~enc:(fun r -> r.ref_) 1081 |> Jsont.Object.mem "repo" Jsont.string 1082 ~enc:(fun r -> r.repo) 1083 |> Jsont.Object.finish ··· 1086 let output_jsont = Jsont.ignore 1087 1088 end 1089 + module ListSecrets = struct 1090 + type secret = { 1091 created_at : string; 1092 + created_by : string; 1093 + key : string; 1094 repo : string; 1095 } 1096 1097 + let secret_jsont = 1098 + Jsont.Object.map ~kind:"Secret" 1099 + (fun _typ created_at created_by key repo -> { created_at; created_by; key; repo }) 1100 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.listSecrets#secret" ~enc:(fun _ -> "sh.tangled.repo.listSecrets#secret") 1101 |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 1102 + |> Jsont.Object.mem "createdBy" Jsont.string ~enc:(fun r -> r.created_by) 1103 + |> Jsont.Object.mem "key" Jsont.string ~enc:(fun r -> r.key) 1104 |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 1105 + |> Jsont.Object.finish 1106 + 1107 + type params = { 1108 + repo : string; 1109 + } 1110 + 1111 + let params_jsont = 1112 + Jsont.Object.map ~kind:"Params" 1113 + (fun repo -> { 1114 + repo; 1115 + }) 1116 + |> Jsont.Object.mem "repo" Jsont.string 1117 + ~enc:(fun r -> r.repo) 1118 + |> Jsont.Object.finish 1119 + 1120 + type output = { 1121 + secrets : secret list; 1122 + } 1123 + 1124 + let output_jsont = 1125 + Jsont.Object.map ~kind:"Output" 1126 + (fun _typ secrets -> { secrets }) 1127 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.listSecrets#output" ~enc:(fun _ -> "sh.tangled.repo.listSecrets#output") 1128 + |> Jsont.Object.mem "secrets" (Jsont.list secret_jsont) ~enc:(fun r -> r.secrets) 1129 |> Jsont.Object.finish 1130 1131 end 1132 + module Tags = struct 1133 type params = { 1134 cursor : string option; 1135 limit : int option; ··· 1155 let output_jsont = Jsont.ignore 1156 1157 end 1158 + module Diff = struct 1159 type params = { 1160 + ref_ : string; 1161 repo : string; 1162 } 1163 1164 let params_jsont = 1165 Jsont.Object.map ~kind:"Params" 1166 + (fun ref_ repo -> { 1167 + ref_; 1168 repo; 1169 }) 1170 + |> Jsont.Object.mem "ref" Jsont.string 1171 + ~enc:(fun r -> r.ref_) 1172 |> Jsont.Object.mem "repo" Jsont.string 1173 ~enc:(fun r -> r.repo) 1174 |> Jsont.Object.finish 1175 1176 + type output = unit 1177 + let output_jsont = Jsont.ignore 1178 + 1179 + end 1180 + module Collaborator = struct 1181 + type main = { 1182 + created_at : string; 1183 + repo : string; 1184 + subject : string; 1185 } 1186 1187 + let main_jsont = 1188 + Jsont.Object.map ~kind:"Main" 1189 + (fun _typ created_at repo subject -> { created_at; repo; subject }) 1190 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.collaborator" ~enc:(fun _ -> "sh.tangled.repo.collaborator") 1191 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 1192 + |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 1193 + |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 1194 |> Jsont.Object.finish 1195 1196 end ··· 1211 |> Jsont.Object.finish 1212 1213 end 1214 + module Artifact = struct 1215 + type main = { 1216 + artifact : Atp.Blob_ref.t; 1217 + created_at : string; 1218 name : string; 1219 + repo : string; 1220 + tag : string; 1221 } 1222 1223 + let main_jsont = 1224 + Jsont.Object.map ~kind:"Main" 1225 + (fun _typ artifact created_at name repo tag -> { artifact; created_at; name; repo; tag }) 1226 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.artifact" ~enc:(fun _ -> "sh.tangled.repo.artifact") 1227 + |> Jsont.Object.mem "artifact" Atp.Blob_ref.jsont ~enc:(fun r -> r.artifact) 1228 + |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 1229 |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 1230 + |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 1231 + |> Jsont.Object.mem "tag" Jsont.binary_string ~enc:(fun r -> r.tag) 1232 |> Jsont.Object.finish 1233 1234 end 1235 + module Archive = struct 1236 type params = { 1237 + format : string option; 1238 + prefix : string option; 1239 + ref_ : string; 1240 repo : string; 1241 } 1242 1243 let params_jsont = 1244 Jsont.Object.map ~kind:"Params" 1245 + (fun format prefix ref_ repo -> { 1246 + format; 1247 + prefix; 1248 + ref_; 1249 repo; 1250 }) 1251 + |> Jsont.Object.opt_mem "format" Jsont.string 1252 + ~enc:(fun r -> r.format) 1253 + |> Jsont.Object.opt_mem "prefix" Jsont.string 1254 + ~enc:(fun r -> r.prefix) 1255 + |> Jsont.Object.mem "ref" Jsont.string 1256 + ~enc:(fun r -> r.ref_) 1257 |> Jsont.Object.mem "repo" Jsont.string 1258 ~enc:(fun r -> r.repo) 1259 |> Jsont.Object.finish 1260 1261 + type output = unit 1262 + let output_jsont = Jsont.ignore 1263 1264 end 1265 + module RemoveSecret = struct 1266 type input = { 1267 + key : string; 1268 repo : string; 1269 } 1270 1271 let input_jsont = 1272 Jsont.Object.map ~kind:"Input" 1273 + (fun _typ key repo -> { key; repo }) 1274 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.removeSecret#input" ~enc:(fun _ -> "sh.tangled.repo.removeSecret#input") 1275 + |> Jsont.Object.mem "key" Jsont.string ~enc:(fun r -> r.key) 1276 |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 1277 |> Jsont.Object.finish 1278 1279 end 1280 + module Merge = struct 1281 + type input = { 1282 + author_email : string option; 1283 + author_name : string option; 1284 + branch : string; 1285 + commit_body : string option; 1286 + commit_message : string option; 1287 + did : string; 1288 + name : string; 1289 + patch : string; 1290 } 1291 1292 + let input_jsont = 1293 + Jsont.Object.map ~kind:"Input" 1294 + (fun _typ author_email author_name branch commit_body commit_message did name patch -> { author_email; author_name; branch; commit_body; commit_message; did; name; patch }) 1295 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.merge#input" ~enc:(fun _ -> "sh.tangled.repo.merge#input") 1296 + |> Jsont.Object.opt_mem "authorEmail" Jsont.string ~enc:(fun r -> r.author_email) 1297 + |> Jsont.Object.opt_mem "authorName" Jsont.string ~enc:(fun r -> r.author_name) 1298 + |> Jsont.Object.mem "branch" Jsont.string ~enc:(fun r -> r.branch) 1299 + |> Jsont.Object.opt_mem "commitBody" Jsont.string ~enc:(fun r -> r.commit_body) 1300 + |> Jsont.Object.opt_mem "commitMessage" Jsont.string ~enc:(fun r -> r.commit_message) 1301 + |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 1302 + |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 1303 + |> Jsont.Object.mem "patch" Jsont.string ~enc:(fun r -> r.patch) 1304 |> Jsont.Object.finish 1305 1306 end 1307 module Blob = struct ··· 1407 |> Jsont.Object.finish 1408 1409 end 1410 + module HiddenRef = struct 1411 type input = { 1412 + fork_ref : string; 1413 + remote_ref : string; 1414 repo : string; 1415 } 1416 1417 let input_jsont = 1418 Jsont.Object.map ~kind:"Input" 1419 + (fun _typ fork_ref remote_ref repo -> { fork_ref; remote_ref; repo }) 1420 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.hiddenRef#input" ~enc:(fun _ -> "sh.tangled.repo.hiddenRef#input") 1421 + |> Jsont.Object.mem "forkRef" Jsont.string ~enc:(fun r -> r.fork_ref) 1422 + |> Jsont.Object.mem "remoteRef" Jsont.string ~enc:(fun r -> r.remote_ref) 1423 |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 1424 |> Jsont.Object.finish 1425 1426 type output = { 1427 + error : string option; 1428 + ref_ : string option; 1429 + success : bool; 1430 } 1431 1432 let output_jsont = 1433 Jsont.Object.map ~kind:"Output" 1434 + (fun _typ error ref_ success -> { error; ref_; success }) 1435 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.hiddenRef#output" ~enc:(fun _ -> "sh.tangled.repo.hiddenRef#output") 1436 + |> Jsont.Object.opt_mem "error" Jsont.string ~enc:(fun r -> r.error) 1437 + |> Jsont.Object.opt_mem "ref" Jsont.string ~enc:(fun r -> r.ref_) 1438 + |> Jsont.Object.mem "success" Jsont.bool ~enc:(fun r -> r.success) 1439 |> Jsont.Object.finish 1440 1441 end 1442 + module Compare = struct 1443 type params = { 1444 repo : string; 1445 + rev1 : string; 1446 + rev2 : string; 1447 } 1448 1449 let params_jsont = 1450 Jsont.Object.map ~kind:"Params" 1451 + (fun repo rev1 rev2 -> { 1452 repo; 1453 + rev1; 1454 + rev2; 1455 }) 1456 |> Jsont.Object.mem "repo" Jsont.string 1457 ~enc:(fun r -> r.repo) 1458 + |> Jsont.Object.mem "rev1" Jsont.string 1459 + ~enc:(fun r -> r.rev1) 1460 + |> Jsont.Object.mem "rev2" Jsont.string 1461 + ~enc:(fun r -> r.rev2) 1462 |> Jsont.Object.finish 1463 1464 type output = unit 1465 let output_jsont = Jsont.ignore 1466 1467 end 1468 + module ForkStatus = struct 1469 type input = { 1470 branch : string; 1471 did : string; 1472 + hidden_ref : string; 1473 name : string; 1474 source : string; 1475 } 1476 1477 let input_jsont = 1478 Jsont.Object.map ~kind:"Input" 1479 + (fun _typ branch did hidden_ref name source -> { branch; did; hidden_ref; name; source }) 1480 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.forkStatus#input" ~enc:(fun _ -> "sh.tangled.repo.forkStatus#input") 1481 |> Jsont.Object.mem "branch" Jsont.string ~enc:(fun r -> r.branch) 1482 |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 1483 + |> Jsont.Object.mem "hiddenRef" Jsont.string ~enc:(fun r -> r.hidden_ref) 1484 |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 1485 |> Jsont.Object.mem "source" Jsont.string ~enc:(fun r -> r.source) 1486 |> Jsont.Object.finish 1487 1488 + type output = { 1489 + status : int; 1490 + } 1491 + 1492 + let output_jsont = 1493 + Jsont.Object.map ~kind:"Output" 1494 + (fun _typ status -> { status }) 1495 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.forkStatus#output" ~enc:(fun _ -> "sh.tangled.repo.forkStatus#output") 1496 + |> Jsont.Object.mem "status" Jsont.int ~enc:(fun r -> r.status) 1497 + |> Jsont.Object.finish 1498 + 1499 end 1500 + module MergeCheck = struct 1501 + type conflict_info = { 1502 + filename : string; 1503 + reason : string; 1504 } 1505 1506 + let conflict_info_jsont = 1507 + Jsont.Object.map ~kind:"Conflict_info" 1508 + (fun _typ filename reason -> { filename; reason }) 1509 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.mergeCheck#conflictInfo" ~enc:(fun _ -> "sh.tangled.repo.mergeCheck#conflictInfo") 1510 + |> Jsont.Object.mem "filename" Jsont.string ~enc:(fun r -> r.filename) 1511 + |> Jsont.Object.mem "reason" Jsont.string ~enc:(fun r -> r.reason) 1512 |> Jsont.Object.finish 1513 1514 type input = { 1515 + branch : string; 1516 did : string; 1517 name : string; 1518 + patch : string; 1519 } 1520 1521 let input_jsont = 1522 Jsont.Object.map ~kind:"Input" 1523 + (fun _typ branch did name patch -> { branch; did; name; patch }) 1524 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.mergeCheck#input" ~enc:(fun _ -> "sh.tangled.repo.mergeCheck#input") 1525 + |> Jsont.Object.mem "branch" Jsont.string ~enc:(fun r -> r.branch) 1526 |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 1527 |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 1528 + |> Jsont.Object.mem "patch" Jsont.string ~enc:(fun r -> r.patch) 1529 |> Jsont.Object.finish 1530 1531 type output = { 1532 + conflicts : conflict_info list option; 1533 + error : string option; 1534 + is_conflicted : bool; 1535 + message : string option; 1536 } 1537 1538 let output_jsont = 1539 Jsont.Object.map ~kind:"Output" 1540 + (fun _typ conflicts error is_conflicted message -> { conflicts; error; is_conflicted; message }) 1541 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.mergeCheck#output" ~enc:(fun _ -> "sh.tangled.repo.mergeCheck#output") 1542 + |> Jsont.Object.opt_mem "conflicts" (Jsont.list conflict_info_jsont) ~enc:(fun r -> r.conflicts) 1543 + |> Jsont.Object.opt_mem "error" Jsont.string ~enc:(fun r -> r.error) 1544 + |> Jsont.Object.mem "is_conflicted" Jsont.bool ~enc:(fun r -> r.is_conflicted) 1545 + |> Jsont.Object.opt_mem "message" Jsont.string ~enc:(fun r -> r.message) 1546 |> Jsont.Object.finish 1547 1548 end 1549 + module Branches = struct 1550 type params = { 1551 + cursor : string option; 1552 + limit : int option; 1553 repo : string; 1554 } 1555 1556 let params_jsont = 1557 Jsont.Object.map ~kind:"Params" 1558 + (fun cursor limit repo -> { 1559 + cursor; 1560 + limit; 1561 repo; 1562 }) 1563 + |> Jsont.Object.opt_mem "cursor" Jsont.string 1564 + ~enc:(fun r -> r.cursor) 1565 + |> Jsont.Object.opt_mem "limit" Jsont.int 1566 + ~enc:(fun r -> r.limit) 1567 |> Jsont.Object.mem "repo" Jsont.string 1568 ~enc:(fun r -> r.repo) 1569 |> Jsont.Object.finish ··· 1572 let output_jsont = Jsont.ignore 1573 1574 end 1575 + module ForkSync = struct 1576 type input = { 1577 + branch : string; 1578 + did : string; 1579 + name : string; 1580 + source : string; 1581 } 1582 1583 let input_jsont = 1584 Jsont.Object.map ~kind:"Input" 1585 + (fun _typ branch did name source -> { branch; did; name; source }) 1586 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.forkSync#input" ~enc:(fun _ -> "sh.tangled.repo.forkSync#input") 1587 |> Jsont.Object.mem "branch" Jsont.string ~enc:(fun r -> r.branch) 1588 + |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 1589 + |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 1590 + |> Jsont.Object.mem "source" Jsont.string ~enc:(fun r -> r.source) 1591 |> Jsont.Object.finish 1592 1593 end 1594 + module Languages = struct 1595 + type language = { 1596 color : string option; 1597 + extensions : string list option; 1598 + file_count : int option; 1599 name : string; 1600 + percentage : int; 1601 + size : int; 1602 } 1603 1604 + let language_jsont = 1605 + Jsont.Object.map ~kind:"Language" 1606 + (fun _typ color extensions file_count name percentage size -> { color; extensions; file_count; name; percentage; size }) 1607 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.languages#language" ~enc:(fun _ -> "sh.tangled.repo.languages#language") 1608 |> Jsont.Object.opt_mem "color" Jsont.string ~enc:(fun r -> r.color) 1609 + |> Jsont.Object.opt_mem "extensions" (Jsont.list Jsont.string) ~enc:(fun r -> r.extensions) 1610 + |> Jsont.Object.opt_mem "fileCount" Jsont.int ~enc:(fun r -> r.file_count) 1611 |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 1612 + |> Jsont.Object.mem "percentage" Jsont.int ~enc:(fun r -> r.percentage) 1613 + |> Jsont.Object.mem "size" Jsont.int ~enc:(fun r -> r.size) 1614 |> Jsont.Object.finish 1615 1616 type params = { 1617 + ref_ : string option; 1618 + repo : string; 1619 } 1620 1621 let params_jsont = 1622 Jsont.Object.map ~kind:"Params" 1623 + (fun ref_ repo -> { 1624 + ref_; 1625 + repo; 1626 }) 1627 + |> Jsont.Object.opt_mem "ref" Jsont.string 1628 + ~enc:(fun r -> r.ref_) 1629 + |> Jsont.Object.mem "repo" Jsont.string 1630 + ~enc:(fun r -> r.repo) 1631 |> Jsont.Object.finish 1632 1633 type output = { 1634 + languages : language list; 1635 + ref_ : string; 1636 + total_files : int option; 1637 + total_size : int option; 1638 } 1639 1640 let output_jsont = 1641 Jsont.Object.map ~kind:"Output" 1642 + (fun _typ languages ref_ total_files total_size -> { languages; ref_; total_files; total_size }) 1643 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"sh.tangled.repo.languages#output" ~enc:(fun _ -> "sh.tangled.repo.languages#output") 1644 + |> Jsont.Object.mem "languages" (Jsont.list language_jsont) ~enc:(fun r -> r.languages) 1645 |> Jsont.Object.mem "ref" Jsont.string ~enc:(fun r -> r.ref_) 1646 + |> Jsont.Object.opt_mem "totalFiles" Jsont.int ~enc:(fun r -> r.total_files) 1647 + |> Jsont.Object.opt_mem "totalSize" Jsont.int ~enc:(fun r -> r.total_size) 1648 |> Jsont.Object.finish 1649 1650 end
+639 -639
ocaml-atp/lexicons/tangled/atp_lexicon_tangled.mli
··· 12 13 module Sh : sig 14 module Tangled : sig 15 module Spindle : sig 16 17 type main = { ··· 34 35 end 36 end 37 - module Git : sig 38 - module RefUpdate : sig 39 40 - type individual_language_size = { 41 - lang : string; 42 - size : int; 43 } 44 45 - (** Jsont codec for {!type:individual_language_size}. *) 46 - val individual_language_size_jsont : individual_language_size Jsont.t 47 48 49 - type individual_email_commit_count = { 50 - count : int; 51 - email : string; 52 } 53 54 - (** Jsont codec for {!type:individual_email_commit_count}. *) 55 - val individual_email_commit_count_jsont : individual_email_commit_count Jsont.t 56 57 58 - type lang_breakdown = { 59 - inputs : individual_language_size list option; 60 } 61 62 - (** Jsont codec for {!type:lang_breakdown}. *) 63 - val lang_breakdown_jsont : lang_breakdown Jsont.t 64 65 66 - type commit_count_breakdown = { 67 - by_email : individual_email_commit_count list option; 68 } 69 70 - (** Jsont codec for {!type:commit_count_breakdown}. *) 71 - val commit_count_breakdown_jsont : commit_count_breakdown Jsont.t 72 73 74 - type meta = { 75 - commit_count : commit_count_breakdown; 76 - is_default_ref : bool; 77 - lang_breakdown : lang_breakdown option; 78 } 79 80 - (** Jsont codec for {!type:meta}. *) 81 - val meta_jsont : meta Jsont.t 82 83 - (** An update to a git repository, emitted by knots. *) 84 85 type main = { 86 - committer_did : string; (** did of the user that pushed this ref *) 87 - meta : meta; 88 - new_sha : string; (** new SHA of this ref *) 89 - old_sha : string; (** old SHA of this ref *) 90 - ref_ : string; (** Ref being updated *) 91 - repo_did : string; (** did of the owner of the repo *) 92 - repo_name : string; (** name of the repo *) 93 } 94 95 (** Jsont codec for {!type:main}. *) 96 val main_jsont : main Jsont.t 97 98 - end 99 - end 100 - module Actor : sig 101 - module Profile : sig 102 - (** A declaration of a Tangled account profile. *) 103 104 type main = { 105 - bluesky : bool; (** Include link to this account on Bluesky. *) 106 - description : string option; (** Free-form profile description text. *) 107 - links : string list option; 108 - location : string option; (** Free-form location text. *) 109 - pinned_repositories : string list option; (** Any ATURI, it is up to appviews to validate these fields. *) 110 - pronouns : string option; (** Preferred gender pronouns. *) 111 - stats : string list option; 112 } 113 114 (** Jsont codec for {!type:main}. *) ··· 116 117 end 118 end 119 - module String : sig 120 121 type main = { 122 - contents : string; 123 created_at : string; 124 - description : string; 125 - filename : string; 126 } 127 128 (** Jsont codec for {!type:main}. *) 129 val main_jsont : main Jsont.t 130 131 - end 132 - module Feed : sig 133 - module Star : sig 134 135 type main = { 136 created_at : string; 137 subject : string; 138 } 139 ··· 141 val main_jsont : main Jsont.t 142 143 end 144 - module Reaction : sig 145 146 type main = { 147 - created_at : string; 148 - reaction : string; 149 - subject : string; 150 } 151 152 (** Jsont codec for {!type:main}. *) 153 val main_jsont : main Jsont.t 154 155 end 156 - end 157 - module Repo : sig 158 159 type main = { 160 created_at : string; 161 - description : string option; 162 - knot : string; (** knot where the repo was created *) 163 - labels : string list option; (** List of labels that this repo subscribes to *) 164 - name : string; (** name of the repo *) 165 - source : string option; (** source of the repo *) 166 - spindle : string option; (** CI runner to send jobs to and receive results from *) 167 - topics : string list option; (** Topics related to the repo *) 168 - website : string option; (** Any URI related to the repo *) 169 } 170 171 (** Jsont codec for {!type:main}. *) 172 val main_jsont : main Jsont.t 173 174 - module Artifact : sig 175 176 type main = { 177 - artifact : Atp.Blob_ref.t; (** the artifact *) 178 - created_at : string; (** time of creation of this artifact *) 179 - name : string; (** name of the artifact *) 180 - repo : string; (** repo that this artifact is being uploaded to *) 181 - tag : string; (** hash of the tag object that this artifact is attached to (only annotated tags are supported) *) 182 } 183 184 (** Jsont codec for {!type:main}. *) 185 val main_jsont : main Jsont.t 186 187 end 188 - module MergeCheck : sig 189 190 - type conflict_info = { 191 - filename : string; (** Name of the conflicted file *) 192 - reason : string; (** Reason for the conflict *) 193 } 194 195 - (** Jsont codec for {!type:conflict_info}. *) 196 - val conflict_info_jsont : conflict_info Jsont.t 197 - 198 - (** Check if a merge is possible between two branches *) 199 200 201 - type input = { 202 - branch : string; (** Target branch to merge into *) 203 - did : string; (** DID of the repository owner *) 204 - name : string; (** Name of the repository *) 205 - patch : string; (** Patch or pull request to check for merge conflicts *) 206 } 207 208 - (** Jsont codec for {!type:input}. *) 209 - val input_jsont : input Jsont.t 210 211 212 - type output = { 213 - conflicts : conflict_info list option; (** List of files with merge conflicts *) 214 - error : string option; (** Error message if check failed *) 215 - is_conflicted : bool; (** Whether the merge has conflicts *) 216 - message : string option; (** Additional message about the merge check *) 217 } 218 219 - (** Jsont codec for {!type:output}. *) 220 - val output_jsont : output Jsont.t 221 222 end 223 - module Tree : sig 224 225 - type readme = { 226 - contents : string; (** Contents of the readme file *) 227 - filename : string; (** Name of the readme file *) 228 } 229 230 - (** Jsont codec for {!type:readme}. *) 231 - val readme_jsont : readme Jsont.t 232 233 234 - type last_commit = { 235 - hash : string; (** Commit hash *) 236 - message : string; (** Commit message *) 237 - when_ : string; (** Commit timestamp *) 238 } 239 240 - (** Jsont codec for {!type:last_commit}. *) 241 - val last_commit_jsont : last_commit Jsont.t 242 243 244 - type tree_entry = { 245 - last_commit : last_commit option; 246 - mode : string; (** File mode *) 247 - name : string; (** Relative file or directory name *) 248 - size : int; (** File size in bytes *) 249 } 250 251 - (** Jsont codec for {!type:tree_entry}. *) 252 - val tree_entry_jsont : tree_entry Jsont.t 253 254 255 - (** Query/procedure parameters. *) 256 - type params = { 257 - path : string option; (** Path within the repository tree *) 258 - ref_ : string; (** Git reference (branch, tag, or commit SHA) *) 259 - repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 260 } 261 262 - (** Jsont codec for {!type:params}. *) 263 - val params_jsont : params Jsont.t 264 265 266 - type output = { 267 - dotdot : string option; (** Parent directory path *) 268 - files : tree_entry list; 269 - parent : string option; (** The parent path in the tree *) 270 - readme : readme option; (** Readme for this file tree *) 271 - ref_ : string; (** The git reference used *) 272 } 273 274 - (** Jsont codec for {!type:output}. *) 275 - val output_jsont : output Jsont.t 276 - 277 - end 278 - module SetDefaultBranch : sig 279 - (** Set the default branch for a repository *) 280 281 282 - type input = { 283 - default_branch : string; 284 - repo : string; 285 } 286 287 - (** Jsont codec for {!type:input}. *) 288 - val input_jsont : input Jsont.t 289 290 end 291 - module Compare : sig 292 293 - (** Query/procedure parameters. *) 294 - type params = { 295 - repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 296 - rev1 : string; (** First revision (commit, branch, or tag) *) 297 - rev2 : string; (** Second revision (commit, branch, or tag) *) 298 } 299 300 - (** Jsont codec for {!type:params}. *) 301 - val params_jsont : params Jsont.t 302 303 - (** Compare output in application/json *) 304 305 - type output = unit 306 - val output_jsont : output Jsont.t 307 308 - end 309 - module Merge : sig 310 - (** Merge a patch into a repository branch *) 311 312 313 - type input = { 314 - author_email : string option; (** Author email for the merge commit *) 315 - author_name : string option; (** Author name for the merge commit *) 316 - branch : string; (** Target branch to merge into *) 317 - commit_body : string option; (** Additional commit message body *) 318 - commit_message : string option; (** Merge commit message *) 319 - did : string; (** DID of the repository owner *) 320 - name : string; (** Name of the repository *) 321 - patch : string; (** Patch content to merge *) 322 } 323 324 - (** Jsont codec for {!type:input}. *) 325 - val input_jsont : input Jsont.t 326 327 - end 328 - module Tags : sig 329 330 - (** Query/procedure parameters. *) 331 - type params = { 332 - cursor : string option; (** Pagination cursor *) 333 - limit : int option; (** Maximum number of tags to return *) 334 - repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 335 } 336 337 - (** Jsont codec for {!type:params}. *) 338 - val params_jsont : params Jsont.t 339 - 340 - 341 - type output = unit 342 - val output_jsont : output Jsont.t 343 344 - end 345 - module Collaborator : sig 346 347 type main = { 348 - created_at : string; 349 - repo : string; (** repo to add this user to *) 350 - subject : string; 351 } 352 353 (** Jsont codec for {!type:main}. *) 354 val main_jsont : main Jsont.t 355 356 end 357 - module Branches : sig 358 359 - (** Query/procedure parameters. *) 360 - type params = { 361 - cursor : string option; (** Pagination cursor *) 362 - limit : int option; (** Maximum number of branches to return *) 363 - repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 364 } 365 366 - (** Jsont codec for {!type:params}. *) 367 - val params_jsont : params Jsont.t 368 369 370 - type output = unit 371 - val output_jsont : output Jsont.t 372 373 - end 374 - module GetDefaultBranch : sig 375 376 - type signature = { 377 - email : string; (** Author email *) 378 - name : string; (** Author name *) 379 - when_ : string; (** Author timestamp *) 380 } 381 382 - (** Jsont codec for {!type:signature}. *) 383 - val signature_jsont : signature Jsont.t 384 385 386 - (** Query/procedure parameters. *) 387 - type params = { 388 - repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 389 } 390 391 - (** Jsont codec for {!type:params}. *) 392 - val params_jsont : params Jsont.t 393 394 395 - type output = { 396 - author : signature option; 397 - hash : string; (** Latest commit hash on default branch *) 398 - message : string option; (** Latest commit message *) 399 - name : string; (** Default branch name *) 400 - short_hash : string option; (** Short commit hash *) 401 - when_ : string; (** Timestamp of latest commit *) 402 } 403 404 - (** Jsont codec for {!type:output}. *) 405 - val output_jsont : output Jsont.t 406 407 - end 408 - module Create : sig 409 - (** Create a new repository *) 410 411 412 - type input = { 413 - default_branch : string option; (** Default branch to push to *) 414 - rkey : string; (** Rkey of the repository record *) 415 - source : string option; (** A source URL to clone from, populate this when forking or importing a repository. *) 416 - } 417 418 - (** Jsont codec for {!type:input}. *) 419 - val input_jsont : input Jsont.t 420 421 end 422 - module ForkStatus : sig 423 - (** Check fork status relative to upstream source *) 424 425 426 type input = { 427 - branch : string; (** Branch to check status for *) 428 - did : string; (** DID of the fork owner *) 429 - hidden_ref : string; (** Hidden ref to use for comparison *) 430 - name : string; (** Name of the forked repository *) 431 - source : string; (** Source repository URL *) 432 } 433 434 (** Jsont codec for {!type:input}. *) 435 val input_jsont : input Jsont.t 436 437 - 438 - type output = { 439 - status : int; (** Fork status: 0=UpToDate, 1=FastForwardable, 2=Conflict, 3=MissingBranch *) 440 - } 441 - 442 - (** Jsont codec for {!type:output}. *) 443 - val output_jsont : output Jsont.t 444 - 445 end 446 - module Branch : sig 447 448 type signature = { 449 email : string; (** Author email *) ··· 457 458 (** Query/procedure parameters. *) 459 type params = { 460 - name : string; (** Branch name to get information for *) 461 repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 462 } 463 ··· 467 468 type output = { 469 author : signature option; 470 - hash : string; (** Latest commit hash on this branch *) 471 - is_default : bool option; (** Whether this is the default branch *) 472 message : string option; (** Latest commit message *) 473 - name : string; (** Branch name *) 474 short_hash : string option; (** Short commit hash *) 475 when_ : string; (** Timestamp of latest commit *) 476 } ··· 492 val input_jsont : input Jsont.t 493 494 end 495 - module Log : sig 496 - 497 - (** Query/procedure parameters. *) 498 - type params = { 499 - cursor : string option; (** Pagination cursor (commit SHA) *) 500 - limit : int option; (** Maximum number of commits to return *) 501 - path : string option; (** Path to filter commits by *) 502 - ref_ : string; (** Git reference (branch, tag, or commit SHA) *) 503 - repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 504 - } 505 - 506 - (** Jsont codec for {!type:params}. *) 507 - val params_jsont : params Jsont.t 508 - 509 - 510 - type output = unit 511 - val output_jsont : output Jsont.t 512 513 - end 514 - module Blob : sig 515 516 - type submodule = { 517 - branch : string option; (** Branch to track in the submodule *) 518 - name : string; (** Submodule name *) 519 - url : string; (** Submodule repository URL *) 520 } 521 522 - (** Jsont codec for {!type:submodule}. *) 523 - val submodule_jsont : submodule Jsont.t 524 525 526 - type signature = { 527 - email : string; (** Author email *) 528 - name : string; (** Author name *) 529 - when_ : string; (** Author timestamp *) 530 } 531 532 - (** Jsont codec for {!type:signature}. *) 533 - val signature_jsont : signature Jsont.t 534 535 536 type last_commit = { 537 - author : signature option; 538 hash : string; (** Commit hash *) 539 message : string; (** Commit message *) 540 - short_hash : string option; (** Short commit hash *) 541 when_ : string; (** Commit timestamp *) 542 } 543 ··· 545 val last_commit_jsont : last_commit Jsont.t 546 547 548 (** Query/procedure parameters. *) 549 type params = { 550 - path : string; (** Path to the file within the repository *) 551 - raw : bool option; (** Return raw file content instead of JSON response *) 552 ref_ : string; (** Git reference (branch, tag, or commit SHA) *) 553 repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 554 } ··· 558 559 560 type output = { 561 - content : string option; (** File content (base64 encoded for binary files) *) 562 - encoding : string option; (** Content encoding *) 563 - is_binary : bool option; (** Whether the file is binary *) 564 - last_commit : last_commit option; 565 - mime_type : string option; (** MIME type of the file *) 566 - path : string; (** The file path *) 567 ref_ : string; (** The git reference used *) 568 - size : int option; (** File size in bytes *) 569 - submodule : submodule option; (** Submodule information if path is a submodule *) 570 } 571 572 (** Jsont codec for {!type:output}. *) 573 val output_jsont : output Jsont.t 574 575 end 576 - module RemoveSecret : sig 577 - (** Remove a CI secret *) 578 579 580 type input = { 581 key : string; 582 repo : string; 583 } 584 585 (** Jsont codec for {!type:input}. *) 586 val input_jsont : input Jsont.t 587 588 end 589 - module Languages : sig 590 591 - type language = { 592 - color : string option; (** Hex color code for this language *) 593 - extensions : string list option; (** File extensions associated with this language *) 594 - file_count : int option; (** Number of files in this language *) 595 - name : string; (** Programming language name *) 596 - percentage : int; (** Percentage of total codebase (0-100) *) 597 - size : int; (** Total size of files in this language (bytes) *) 598 } 599 600 - (** Jsont codec for {!type:language}. *) 601 - val language_jsont : language Jsont.t 602 603 604 (** Query/procedure parameters. *) 605 type params = { 606 - ref_ : string option; (** Git reference (branch, tag, or commit SHA) *) 607 repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 608 } 609 ··· 612 613 614 type output = { 615 - languages : language list; 616 - ref_ : string; (** The git reference used *) 617 - total_files : int option; (** Total number of files analyzed *) 618 - total_size : int option; (** Total size of all analyzed files in bytes *) 619 } 620 621 (** Jsont codec for {!type:output}. *) 622 val output_jsont : output Jsont.t 623 624 end 625 - module Diff : sig 626 627 (** Query/procedure parameters. *) 628 type params = { 629 ref_ : string; (** Git reference (branch, tag, or commit SHA) *) 630 repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 631 } ··· 638 val output_jsont : output Jsont.t 639 640 end 641 - module ForkSync : sig 642 - (** Sync a forked repository with its upstream source *) 643 - 644 - 645 - type input = { 646 - branch : string; (** Branch to sync *) 647 - did : string; (** DID of the fork owner *) 648 - name : string; (** Name of the forked repository *) 649 - source : string; (** AT-URI of the source repository *) 650 - } 651 - 652 - (** Jsont codec for {!type:input}. *) 653 - val input_jsont : input Jsont.t 654 - 655 - end 656 - module AddSecret : sig 657 - (** Add a CI secret *) 658 - 659 - 660 - type input = { 661 - key : string; 662 - repo : string; 663 - value : string; 664 - } 665 - 666 - (** Jsont codec for {!type:input}. *) 667 - val input_jsont : input Jsont.t 668 - 669 - end 670 - module Delete : sig 671 - (** Delete a repository *) 672 - 673 - 674 - type input = { 675 - did : string; (** DID of the repository owner *) 676 - name : string; (** Name of the repository to delete *) 677 - rkey : string; (** Rkey of the repository record *) 678 - } 679 - 680 - (** Jsont codec for {!type:input}. *) 681 - val input_jsont : input Jsont.t 682 - 683 - end 684 module ListSecrets : sig 685 686 type secret = { ··· 711 val output_jsont : output Jsont.t 712 713 end 714 - module Archive : sig 715 716 (** Query/procedure parameters. *) 717 type params = { 718 - format : string option; (** Archive format *) 719 - prefix : string option; (** Prefix for files in the archive *) 720 - ref_ : string; (** Git reference (branch, tag, or commit SHA) *) 721 repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 722 } 723 724 (** Jsont codec for {!type:params}. *) 725 val params_jsont : params Jsont.t 726 727 - (** Binary archive data *) 728 729 type output = unit 730 val output_jsont : output Jsont.t 731 732 end 733 - module HiddenRef : sig 734 - (** Create a hidden ref in a repository *) 735 736 - 737 - type input = { 738 - fork_ref : string; (** Fork reference name *) 739 - remote_ref : string; (** Remote reference name *) 740 - repo : string; (** AT-URI of the repository *) 741 } 742 743 - (** Jsont codec for {!type:input}. *) 744 - val input_jsont : input Jsont.t 745 746 747 - type output = { 748 - error : string option; (** Error message if creation failed *) 749 - ref_ : string option; (** The created hidden ref name *) 750 - success : bool; (** Whether the hidden ref was created successfully *) 751 - } 752 - 753 - (** Jsont codec for {!type:output}. *) 754 val output_jsont : output Jsont.t 755 756 end 757 - module Pull : sig 758 - 759 - type target = { 760 - branch : string; 761 - repo : string; 762 - } 763 - 764 - (** Jsont codec for {!type:target}. *) 765 - val target_jsont : target Jsont.t 766 - 767 - 768 - type source = { 769 - branch : string; 770 - repo : string option; 771 - sha : string; 772 - } 773 - 774 - (** Jsont codec for {!type:source}. *) 775 - val source_jsont : source Jsont.t 776 - 777 778 type main = { 779 - body : string option; 780 created_at : string; 781 - mentions : string list option; 782 - patch : string option; (** (deprecated) use patchBlob instead *) 783 - patch_blob : Atp.Blob_ref.t; (** patch content *) 784 - references : string list option; 785 - source : source option; 786 - target : target; 787 - title : string; 788 } 789 790 (** Jsont codec for {!type:main}. *) 791 val main_jsont : main Jsont.t 792 793 - module Comment : sig 794 795 - type main = { 796 - body : string; 797 - created_at : string; 798 - mentions : string list option; 799 - pull : string; 800 - references : string list option; 801 } 802 803 - (** Jsont codec for {!type:main}. *) 804 - val main_jsont : main Jsont.t 805 806 - end 807 - module Status : sig 808 809 type main = { 810 - pull : string; 811 - status : string; (** status of the pull request *) 812 } 813 814 (** Jsont codec for {!type:main}. *) 815 val main_jsont : main Jsont.t 816 817 - module Closed : sig 818 - (** closed pull request *) 819 - 820 - type main = string 821 - val main_jsont : main Jsont.t 822 823 - end 824 - module Open : sig 825 - (** open pull request *) 826 827 - type main = string 828 - val main_jsont : main Jsont.t 829 830 - end 831 - module Merged : sig 832 - (** merged pull request *) 833 834 - type main = string 835 - val main_jsont : main Jsont.t 836 837 - end 838 - end 839 end 840 - module Issue : sig 841 842 - type main = { 843 - body : string option; 844 - created_at : string; 845 - mentions : string list option; 846 - references : string list option; 847 repo : string; 848 - title : string; 849 } 850 851 - (** Jsont codec for {!type:main}. *) 852 - val main_jsont : main Jsont.t 853 - 854 - module Comment : sig 855 - 856 - type main = { 857 - body : string; 858 - created_at : string; 859 - issue : string; 860 - mentions : string list option; 861 - references : string list option; 862 - reply_to : string option; 863 - } 864 865 - (** Jsont codec for {!type:main}. *) 866 - val main_jsont : main Jsont.t 867 868 - end 869 - module State : sig 870 871 - type main = { 872 - issue : string; 873 - state : string; (** state of the issue *) 874 } 875 876 - (** Jsont codec for {!type:main}. *) 877 - val main_jsont : main Jsont.t 878 - 879 - module Closed : sig 880 - (** closed issue *) 881 882 - type main = string 883 - val main_jsont : main Jsont.t 884 - 885 - end 886 - module Open : sig 887 - (** open issue *) 888 - 889 - type main = string 890 - val main_jsont : main Jsont.t 891 - 892 - end 893 - end 894 end 895 - end 896 - module Label : sig 897 - module Definition : sig 898 899 - type value_type = { 900 - enum : string list option; (** Closed set of values that this label can take. *) 901 - format : string; (** An optional constraint that can be applied on string concrete types. *) 902 - type_ : string; (** The concrete type of this label's value. *) 903 } 904 905 - (** Jsont codec for {!type:value_type}. *) 906 - val value_type_jsont : value_type Jsont.t 907 908 909 - type main = { 910 - color : string option; (** The hex value for the background color for the label. Appviews may choose to respect this. *) 911 - created_at : string; 912 - multiple : bool option; (** Whether this label can be repeated for a given entity, eg.: \[reviewer:foo, reviewer:bar\] *) 913 - name : string; (** The display name of this label. *) 914 - scope : string list; (** The areas of the repo this label may apply to, eg.: sh.tangled.repo.issue. Appviews may choose to respect this. *) 915 - value_type : value_type; (** The type definition of this label. Appviews may allow sorting for certain types. *) 916 } 917 918 - (** Jsont codec for {!type:main}. *) 919 - val main_jsont : main Jsont.t 920 921 - end 922 - module Op : sig 923 924 - type operand = { 925 - key : string; (** ATURI to the label definition *) 926 - value : string; (** Stringified value of the label. This is first unstringed by appviews and then interpreted as a concrete value. *) 927 } 928 929 - (** Jsont codec for {!type:operand}. *) 930 - val operand_jsont : operand Jsont.t 931 932 933 - type main = { 934 - add : operand list; 935 - delete : operand list; 936 - performed_at : string; 937 - subject : string; (** The subject (task, pull or discussion) of this label. Appviews may apply a `scope` check and refuse this op. *) 938 } 939 940 - (** Jsont codec for {!type:main}. *) 941 - val main_jsont : main Jsont.t 942 943 - end 944 - end 945 - module Graph : sig 946 - module Follow : sig 947 948 - type main = { 949 - created_at : string; 950 - subject : string; 951 } 952 953 - (** Jsont codec for {!type:main}. *) 954 - val main_jsont : main Jsont.t 955 956 end 957 - end 958 - module Knot : sig 959 - 960 - type main = { 961 - created_at : string; 962 - } 963 - 964 - (** Jsont codec for {!type:main}. *) 965 - val main_jsont : main Jsont.t 966 967 - module Member : sig 968 969 - type main = { 970 - created_at : string; 971 - domain : string; (** domain that this member now belongs to *) 972 - subject : string; 973 } 974 975 - (** Jsont codec for {!type:main}. *) 976 - val main_jsont : main Jsont.t 977 978 - end 979 - module ListKeys : sig 980 981 - type public_key = { 982 - created_at : string; (** Key upload timestamp *) 983 - did : string; (** DID associated with the public key *) 984 - key : string; (** Public key contents *) 985 } 986 987 - (** Jsont codec for {!type:public_key}. *) 988 - val public_key_jsont : public_key Jsont.t 989 990 - (** List all public keys stored in the knot server *) 991 992 (** Query/procedure parameters. *) 993 type params = { 994 - cursor : string option; (** Pagination cursor *) 995 - limit : int option; (** Maximum number of keys to return *) 996 } 997 998 (** Jsont codec for {!type:params}. *) 999 val params_jsont : params Jsont.t 1000 1001 - 1002 - type output = { 1003 - cursor : string option; (** Pagination cursor for next page *) 1004 - keys : public_key list; 1005 - } 1006 1007 - (** Jsont codec for {!type:output}. *) 1008 val output_jsont : output Jsont.t 1009 1010 end 1011 - module Version : sig 1012 - (** Get the version of a knot *) 1013 1014 1015 - type output = { 1016 - version : string; 1017 } 1018 1019 - (** Jsont codec for {!type:output}. *) 1020 - val output_jsont : output Jsont.t 1021 - 1022 - end 1023 - end 1024 - module Owner : sig 1025 - (** Get the owner of a service *) 1026 1027 1028 type output = { 1029 - owner : string; 1030 } 1031 1032 (** Jsont codec for {!type:output}. *) 1033 val output_jsont : output Jsont.t 1034 1035 - end 1036 - module PublicKey : sig 1037 1038 - type main = { 1039 - created_at : string; (** key upload timestamp *) 1040 - key : string; (** public key contents *) 1041 - name : string; (** human-readable name for this key *) 1042 } 1043 1044 - (** Jsont codec for {!type:main}. *) 1045 - val main_jsont : main Jsont.t 1046 - 1047 - end 1048 - module Pipeline : sig 1049 - 1050 - type trigger_repo = { 1051 - default_branch : string; 1052 - did : string; 1053 - knot : string; 1054 - repo : string; 1055 - } 1056 1057 - (** Jsont codec for {!type:trigger_repo}. *) 1058 - val trigger_repo_jsont : trigger_repo Jsont.t 1059 1060 1061 - type push_trigger_data = { 1062 - new_sha : string; 1063 - old_sha : string; 1064 - ref_ : string; 1065 } 1066 1067 - (** Jsont codec for {!type:push_trigger_data}. *) 1068 - val push_trigger_data_jsont : push_trigger_data Jsont.t 1069 1070 1071 - type pull_request_trigger_data = { 1072 - action : string; 1073 - source_branch : string; 1074 - source_sha : string; 1075 - target_branch : string; 1076 } 1077 1078 - (** Jsont codec for {!type:pull_request_trigger_data}. *) 1079 - val pull_request_trigger_data_jsont : pull_request_trigger_data Jsont.t 1080 1081 1082 - type pair = { 1083 - key : string; 1084 - value : string; 1085 } 1086 1087 - (** Jsont codec for {!type:pair}. *) 1088 - val pair_jsont : pair Jsont.t 1089 1090 1091 - type clone_opts = { 1092 - depth : int; 1093 - skip : bool; 1094 - submodules : bool; 1095 - } 1096 1097 - (** Jsont codec for {!type:clone_opts}. *) 1098 - val clone_opts_jsont : clone_opts Jsont.t 1099 1100 1101 - type workflow = { 1102 - clone : clone_opts; 1103 - engine : string; 1104 - name : string; 1105 - raw : string; 1106 } 1107 1108 - (** Jsont codec for {!type:workflow}. *) 1109 - val workflow_jsont : workflow Jsont.t 1110 1111 1112 - type manual_trigger_data = { 1113 - inputs : pair list option; 1114 } 1115 1116 - (** Jsont codec for {!type:manual_trigger_data}. *) 1117 - val manual_trigger_data_jsont : manual_trigger_data Jsont.t 1118 1119 1120 - type trigger_metadata = { 1121 - kind : string; 1122 - manual : manual_trigger_data option; 1123 - pull_request : pull_request_trigger_data option; 1124 - push : push_trigger_data option; 1125 - repo : trigger_repo; 1126 } 1127 1128 - (** Jsont codec for {!type:trigger_metadata}. *) 1129 - val trigger_metadata_jsont : trigger_metadata Jsont.t 1130 1131 1132 - type main = { 1133 - trigger_metadata : trigger_metadata; 1134 - workflows : workflow list; 1135 } 1136 1137 - (** Jsont codec for {!type:main}. *) 1138 - val main_jsont : main Jsont.t 1139 - 1140 - module Status : sig 1141 - 1142 - type main = { 1143 - created_at : string; (** time of creation of this status update *) 1144 - error : string option; (** error message if failed *) 1145 - exit_code : int option; (** exit code if failed *) 1146 - pipeline : string; (** ATURI of the pipeline *) 1147 - status : string; (** status of the workflow *) 1148 - workflow : string; (** name of the workflow within this pipeline *) 1149 - } 1150 - 1151 - (** Jsont codec for {!type:main}. *) 1152 - val main_jsont : main Jsont.t 1153 1154 end 1155 end
··· 12 13 module Sh : sig 14 module Tangled : sig 15 + module Actor : sig 16 + module Profile : sig 17 + (** A declaration of a Tangled account profile. *) 18 + 19 + type main = { 20 + bluesky : bool; (** Include link to this account on Bluesky. *) 21 + description : string option; (** Free-form profile description text. *) 22 + links : string list option; 23 + location : string option; (** Free-form location text. *) 24 + pinned_repositories : string list option; (** Any ATURI, it is up to appviews to validate these fields. *) 25 + pronouns : string option; (** Preferred gender pronouns. *) 26 + stats : string list option; 27 + } 28 + 29 + (** Jsont codec for {!type:main}. *) 30 + val main_jsont : main Jsont.t 31 + 32 + end 33 + end 34 + module Owner : sig 35 + (** Get the owner of a service *) 36 + 37 + 38 + type output = { 39 + owner : string; 40 + } 41 + 42 + (** Jsont codec for {!type:output}. *) 43 + val output_jsont : output Jsont.t 44 + 45 + end 46 module Spindle : sig 47 48 type main = { ··· 65 66 end 67 end 68 + module Pipeline : sig 69 70 + type trigger_repo = { 71 + default_branch : string; 72 + did : string; 73 + knot : string; 74 + repo : string; 75 } 76 77 + (** Jsont codec for {!type:trigger_repo}. *) 78 + val trigger_repo_jsont : trigger_repo Jsont.t 79 80 81 + type push_trigger_data = { 82 + new_sha : string; 83 + old_sha : string; 84 + ref_ : string; 85 } 86 87 + (** Jsont codec for {!type:push_trigger_data}. *) 88 + val push_trigger_data_jsont : push_trigger_data Jsont.t 89 90 91 + type pull_request_trigger_data = { 92 + action : string; 93 + source_branch : string; 94 + source_sha : string; 95 + target_branch : string; 96 } 97 98 + (** Jsont codec for {!type:pull_request_trigger_data}. *) 99 + val pull_request_trigger_data_jsont : pull_request_trigger_data Jsont.t 100 101 102 + type pair = { 103 + key : string; 104 + value : string; 105 } 106 107 + (** Jsont codec for {!type:pair}. *) 108 + val pair_jsont : pair Jsont.t 109 110 111 + type clone_opts = { 112 + depth : int; 113 + skip : bool; 114 + submodules : bool; 115 } 116 117 + (** Jsont codec for {!type:clone_opts}. *) 118 + val clone_opts_jsont : clone_opts Jsont.t 119 120 + 121 + type workflow = { 122 + clone : clone_opts; 123 + engine : string; 124 + name : string; 125 + raw : string; 126 + } 127 + 128 + (** Jsont codec for {!type:workflow}. *) 129 + val workflow_jsont : workflow Jsont.t 130 + 131 + 132 + type manual_trigger_data = { 133 + inputs : pair list option; 134 + } 135 + 136 + (** Jsont codec for {!type:manual_trigger_data}. *) 137 + val manual_trigger_data_jsont : manual_trigger_data Jsont.t 138 + 139 + 140 + type trigger_metadata = { 141 + kind : string; 142 + manual : manual_trigger_data option; 143 + pull_request : pull_request_trigger_data option; 144 + push : push_trigger_data option; 145 + repo : trigger_repo; 146 + } 147 + 148 + (** Jsont codec for {!type:trigger_metadata}. *) 149 + val trigger_metadata_jsont : trigger_metadata Jsont.t 150 + 151 152 type main = { 153 + trigger_metadata : trigger_metadata; 154 + workflows : workflow list; 155 } 156 157 (** Jsont codec for {!type:main}. *) 158 val main_jsont : main Jsont.t 159 160 + module Status : sig 161 162 type main = { 163 + created_at : string; (** time of creation of this status update *) 164 + error : string option; (** error message if failed *) 165 + exit_code : int option; (** exit code if failed *) 166 + pipeline : string; (** ATURI of the pipeline *) 167 + status : string; (** status of the workflow *) 168 + workflow : string; (** name of the workflow within this pipeline *) 169 } 170 171 (** Jsont codec for {!type:main}. *) ··· 173 174 end 175 end 176 + module Knot : sig 177 178 type main = { 179 created_at : string; 180 } 181 182 (** Jsont codec for {!type:main}. *) 183 val main_jsont : main Jsont.t 184 185 + module Version : sig 186 + (** Get the version of a knot *) 187 + 188 + 189 + type output = { 190 + version : string; 191 + } 192 + 193 + (** Jsont codec for {!type:output}. *) 194 + val output_jsont : output Jsont.t 195 + 196 + end 197 + module ListKeys : sig 198 + 199 + type public_key = { 200 + created_at : string; (** Key upload timestamp *) 201 + did : string; (** DID associated with the public key *) 202 + key : string; (** Public key contents *) 203 + } 204 + 205 + (** Jsont codec for {!type:public_key}. *) 206 + val public_key_jsont : public_key Jsont.t 207 + 208 + (** List all public keys stored in the knot server *) 209 + 210 + (** Query/procedure parameters. *) 211 + type params = { 212 + cursor : string option; (** Pagination cursor *) 213 + limit : int option; (** Maximum number of keys to return *) 214 + } 215 + 216 + (** Jsont codec for {!type:params}. *) 217 + val params_jsont : params Jsont.t 218 + 219 + 220 + type output = { 221 + cursor : string option; (** Pagination cursor for next page *) 222 + keys : public_key list; 223 + } 224 + 225 + (** Jsont codec for {!type:output}. *) 226 + val output_jsont : output Jsont.t 227 + 228 + end 229 + module Member : sig 230 231 type main = { 232 created_at : string; 233 + domain : string; (** domain that this member now belongs to *) 234 subject : string; 235 } 236 ··· 238 val main_jsont : main Jsont.t 239 240 end 241 + end 242 + module Label : sig 243 + module Op : sig 244 + 245 + type operand = { 246 + key : string; (** ATURI to the label definition *) 247 + value : string; (** Stringified value of the label. This is first unstringed by appviews and then interpreted as a concrete value. *) 248 + } 249 + 250 + (** Jsont codec for {!type:operand}. *) 251 + val operand_jsont : operand Jsont.t 252 + 253 254 type main = { 255 + add : operand list; 256 + delete : operand list; 257 + performed_at : string; 258 + subject : string; (** The subject (task, pull or discussion) of this label. Appviews may apply a `scope` check and refuse this op. *) 259 } 260 261 (** Jsont codec for {!type:main}. *) 262 val main_jsont : main Jsont.t 263 264 end 265 + module Definition : sig 266 + 267 + type value_type = { 268 + enum : string list option; (** Closed set of values that this label can take. *) 269 + format : string; (** An optional constraint that can be applied on string concrete types. *) 270 + type_ : string; (** The concrete type of this label's value. *) 271 + } 272 + 273 + (** Jsont codec for {!type:value_type}. *) 274 + val value_type_jsont : value_type Jsont.t 275 + 276 277 type main = { 278 + color : string option; (** The hex value for the background color for the label. Appviews may choose to respect this. *) 279 created_at : string; 280 + multiple : bool option; (** Whether this label can be repeated for a given entity, eg.: \[reviewer:foo, reviewer:bar\] *) 281 + name : string; (** The display name of this label. *) 282 + scope : string list; (** The areas of the repo this label may apply to, eg.: sh.tangled.repo.issue. Appviews may choose to respect this. *) 283 + value_type : value_type; (** The type definition of this label. Appviews may allow sorting for certain types. *) 284 } 285 286 (** Jsont codec for {!type:main}. *) 287 val main_jsont : main Jsont.t 288 289 + end 290 + end 291 + module Feed : sig 292 + module Reaction : sig 293 294 type main = { 295 + created_at : string; 296 + reaction : string; 297 + subject : string; 298 } 299 300 (** Jsont codec for {!type:main}. *) 301 val main_jsont : main Jsont.t 302 303 end 304 + module Star : sig 305 306 + type main = { 307 + created_at : string; 308 + subject : string; 309 } 310 311 + (** Jsont codec for {!type:main}. *) 312 + val main_jsont : main Jsont.t 313 314 + end 315 + end 316 + module PublicKey : sig 317 318 + type main = { 319 + created_at : string; (** key upload timestamp *) 320 + key : string; (** public key contents *) 321 + name : string; (** human-readable name for this key *) 322 } 323 324 + (** Jsont codec for {!type:main}. *) 325 + val main_jsont : main Jsont.t 326 327 + end 328 + module Graph : sig 329 + module Follow : sig 330 331 + type main = { 332 + created_at : string; 333 + subject : string; 334 } 335 336 + (** Jsont codec for {!type:main}. *) 337 + val main_jsont : main Jsont.t 338 339 end 340 + end 341 + module Git : sig 342 + module RefUpdate : sig 343 344 + type individual_language_size = { 345 + lang : string; 346 + size : int; 347 } 348 349 + (** Jsont codec for {!type:individual_language_size}. *) 350 + val individual_language_size_jsont : individual_language_size Jsont.t 351 352 353 + type individual_email_commit_count = { 354 + count : int; 355 + email : string; 356 } 357 358 + (** Jsont codec for {!type:individual_email_commit_count}. *) 359 + val individual_email_commit_count_jsont : individual_email_commit_count Jsont.t 360 361 362 + type lang_breakdown = { 363 + inputs : individual_language_size list option; 364 } 365 366 + (** Jsont codec for {!type:lang_breakdown}. *) 367 + val lang_breakdown_jsont : lang_breakdown Jsont.t 368 369 370 + type commit_count_breakdown = { 371 + by_email : individual_email_commit_count list option; 372 } 373 374 + (** Jsont codec for {!type:commit_count_breakdown}. *) 375 + val commit_count_breakdown_jsont : commit_count_breakdown Jsont.t 376 377 378 + type meta = { 379 + commit_count : commit_count_breakdown; 380 + is_default_ref : bool; 381 + lang_breakdown : lang_breakdown option; 382 } 383 384 + (** Jsont codec for {!type:meta}. *) 385 + val meta_jsont : meta Jsont.t 386 387 + (** An update to a git repository, emitted by knots. *) 388 389 + type main = { 390 + committer_did : string; (** did of the user that pushed this ref *) 391 + meta : meta; 392 + new_sha : string; (** new SHA of this ref *) 393 + old_sha : string; (** old SHA of this ref *) 394 + ref_ : string; (** Ref being updated *) 395 + repo_did : string; (** did of the owner of the repo *) 396 + repo_name : string; (** name of the repo *) 397 } 398 399 + (** Jsont codec for {!type:main}. *) 400 + val main_jsont : main Jsont.t 401 402 end 403 + end 404 + module String : sig 405 406 + type main = { 407 + contents : string; 408 + created_at : string; 409 + description : string; 410 + filename : string; 411 } 412 413 + (** Jsont codec for {!type:main}. *) 414 + val main_jsont : main Jsont.t 415 416 + end 417 + module Repo : sig 418 419 + type main = { 420 + created_at : string; 421 + description : string option; 422 + knot : string; (** knot where the repo was created *) 423 + labels : string list option; (** List of labels that this repo subscribes to *) 424 + name : string; (** name of the repo *) 425 + source : string option; (** source of the repo *) 426 + spindle : string option; (** CI runner to send jobs to and receive results from *) 427 + topics : string list option; (** Topics related to the repo *) 428 + website : string option; (** Any URI related to the repo *) 429 + } 430 431 + (** Jsont codec for {!type:main}. *) 432 + val main_jsont : main Jsont.t 433 434 + module Issue : sig 435 436 + type main = { 437 + body : string option; 438 + created_at : string; 439 + mentions : string list option; 440 + references : string list option; 441 + repo : string; 442 + title : string; 443 } 444 445 + (** Jsont codec for {!type:main}. *) 446 + val main_jsont : main Jsont.t 447 448 + module Comment : sig 449 450 + type main = { 451 + body : string; 452 + created_at : string; 453 + issue : string; 454 + mentions : string list option; 455 + references : string list option; 456 + reply_to : string option; 457 } 458 459 + (** Jsont codec for {!type:main}. *) 460 + val main_jsont : main Jsont.t 461 462 + end 463 + module State : sig 464 465 type main = { 466 + issue : string; 467 + state : string; (** state of the issue *) 468 } 469 470 (** Jsont codec for {!type:main}. *) 471 val main_jsont : main Jsont.t 472 473 + module Closed : sig 474 + (** closed issue *) 475 + 476 + type main = string 477 + val main_jsont : main Jsont.t 478 + 479 + end 480 + module Open : sig 481 + (** open issue *) 482 + 483 + type main = string 484 + val main_jsont : main Jsont.t 485 + 486 + end 487 + end 488 end 489 + module Pull : sig 490 491 + type target = { 492 + branch : string; 493 + repo : string; 494 } 495 496 + (** Jsont codec for {!type:target}. *) 497 + val target_jsont : target Jsont.t 498 499 500 + type source = { 501 + branch : string; 502 + repo : string option; 503 + sha : string; 504 + } 505 506 + (** Jsont codec for {!type:source}. *) 507 + val source_jsont : source Jsont.t 508 509 + 510 + type main = { 511 + body : string option; 512 + created_at : string; 513 + mentions : string list option; 514 + patch : string option; (** (deprecated) use patchBlob instead *) 515 + patch_blob : Atp.Blob_ref.t; (** patch content *) 516 + references : string list option; 517 + source : source option; 518 + target : target; 519 + title : string; 520 } 521 522 + (** Jsont codec for {!type:main}. *) 523 + val main_jsont : main Jsont.t 524 525 + module Comment : sig 526 527 + type main = { 528 + body : string; 529 + created_at : string; 530 + mentions : string list option; 531 + pull : string; 532 + references : string list option; 533 } 534 535 + (** Jsont codec for {!type:main}. *) 536 + val main_jsont : main Jsont.t 537 538 + end 539 + module Status : sig 540 541 + type main = { 542 + pull : string; 543 + status : string; (** status of the pull request *) 544 } 545 546 + (** Jsont codec for {!type:main}. *) 547 + val main_jsont : main Jsont.t 548 549 + module Merged : sig 550 + (** merged pull request *) 551 552 + type main = string 553 + val main_jsont : main Jsont.t 554 555 + end 556 + module Closed : sig 557 + (** closed pull request *) 558 559 + type main = string 560 + val main_jsont : main Jsont.t 561 562 + end 563 + module Open : sig 564 + (** open pull request *) 565 + 566 + type main = string 567 + val main_jsont : main Jsont.t 568 + 569 + end 570 + end 571 end 572 + module SetDefaultBranch : sig 573 + (** Set the default branch for a repository *) 574 575 576 type input = { 577 + default_branch : string; 578 + repo : string; 579 } 580 581 (** Jsont codec for {!type:input}. *) 582 val input_jsont : input Jsont.t 583 584 end 585 + module GetDefaultBranch : sig 586 587 type signature = { 588 email : string; (** Author email *) ··· 596 597 (** Query/procedure parameters. *) 598 type params = { 599 repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 600 } 601 ··· 605 606 type output = { 607 author : signature option; 608 + hash : string; (** Latest commit hash on default branch *) 609 message : string option; (** Latest commit message *) 610 + name : string; (** Default branch name *) 611 short_hash : string option; (** Short commit hash *) 612 when_ : string; (** Timestamp of latest commit *) 613 } ··· 629 val input_jsont : input Jsont.t 630 631 end 632 + module Delete : sig 633 + (** Delete a repository *) 634 635 636 + type input = { 637 + did : string; (** DID of the repository owner *) 638 + name : string; (** Name of the repository to delete *) 639 + rkey : string; (** Rkey of the repository record *) 640 } 641 642 + (** Jsont codec for {!type:input}. *) 643 + val input_jsont : input Jsont.t 644 645 + end 646 + module Tree : sig 647 648 + type readme = { 649 + contents : string; (** Contents of the readme file *) 650 + filename : string; (** Name of the readme file *) 651 } 652 653 + (** Jsont codec for {!type:readme}. *) 654 + val readme_jsont : readme Jsont.t 655 656 657 type last_commit = { 658 hash : string; (** Commit hash *) 659 message : string; (** Commit message *) 660 when_ : string; (** Commit timestamp *) 661 } 662 ··· 664 val last_commit_jsont : last_commit Jsont.t 665 666 667 + type tree_entry = { 668 + last_commit : last_commit option; 669 + mode : string; (** File mode *) 670 + name : string; (** Relative file or directory name *) 671 + size : int; (** File size in bytes *) 672 + } 673 + 674 + (** Jsont codec for {!type:tree_entry}. *) 675 + val tree_entry_jsont : tree_entry Jsont.t 676 + 677 + 678 (** Query/procedure parameters. *) 679 type params = { 680 + path : string option; (** Path within the repository tree *) 681 ref_ : string; (** Git reference (branch, tag, or commit SHA) *) 682 repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 683 } ··· 687 688 689 type output = { 690 + dotdot : string option; (** Parent directory path *) 691 + files : tree_entry list; 692 + parent : string option; (** The parent path in the tree *) 693 + readme : readme option; (** Readme for this file tree *) 694 ref_ : string; (** The git reference used *) 695 } 696 697 (** Jsont codec for {!type:output}. *) 698 val output_jsont : output Jsont.t 699 700 end 701 + module AddSecret : sig 702 + (** Add a CI secret *) 703 704 705 type input = { 706 key : string; 707 repo : string; 708 + value : string; 709 } 710 711 (** Jsont codec for {!type:input}. *) 712 val input_jsont : input Jsont.t 713 714 end 715 + module Branch : sig 716 717 + type signature = { 718 + email : string; (** Author email *) 719 + name : string; (** Author name *) 720 + when_ : string; (** Author timestamp *) 721 } 722 723 + (** Jsont codec for {!type:signature}. *) 724 + val signature_jsont : signature Jsont.t 725 726 727 (** Query/procedure parameters. *) 728 type params = { 729 + name : string; (** Branch name to get information for *) 730 repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 731 } 732 ··· 735 736 737 type output = { 738 + author : signature option; 739 + hash : string; (** Latest commit hash on this branch *) 740 + is_default : bool option; (** Whether this is the default branch *) 741 + message : string option; (** Latest commit message *) 742 + name : string; (** Branch name *) 743 + short_hash : string option; (** Short commit hash *) 744 + when_ : string; (** Timestamp of latest commit *) 745 } 746 747 (** Jsont codec for {!type:output}. *) 748 val output_jsont : output Jsont.t 749 750 end 751 + module Log : sig 752 753 (** Query/procedure parameters. *) 754 type params = { 755 + cursor : string option; (** Pagination cursor (commit SHA) *) 756 + limit : int option; (** Maximum number of commits to return *) 757 + path : string option; (** Path to filter commits by *) 758 ref_ : string; (** Git reference (branch, tag, or commit SHA) *) 759 repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 760 } ··· 767 val output_jsont : output Jsont.t 768 769 end 770 module ListSecrets : sig 771 772 type secret = { ··· 797 val output_jsont : output Jsont.t 798 799 end 800 + module Tags : sig 801 802 (** Query/procedure parameters. *) 803 type params = { 804 + cursor : string option; (** Pagination cursor *) 805 + limit : int option; (** Maximum number of tags to return *) 806 repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 807 } 808 809 (** Jsont codec for {!type:params}. *) 810 val params_jsont : params Jsont.t 811 812 813 type output = unit 814 val output_jsont : output Jsont.t 815 816 end 817 + module Diff : sig 818 819 + (** Query/procedure parameters. *) 820 + type params = { 821 + ref_ : string; (** Git reference (branch, tag, or commit SHA) *) 822 + repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 823 } 824 825 + (** Jsont codec for {!type:params}. *) 826 + val params_jsont : params Jsont.t 827 828 829 + type output = unit 830 val output_jsont : output Jsont.t 831 832 end 833 + module Collaborator : sig 834 835 type main = { 836 created_at : string; 837 + repo : string; (** repo to add this user to *) 838 + subject : string; 839 } 840 841 (** Jsont codec for {!type:main}. *) 842 val main_jsont : main Jsont.t 843 844 + end 845 + module Create : sig 846 + (** Create a new repository *) 847 848 + 849 + type input = { 850 + default_branch : string option; (** Default branch to push to *) 851 + rkey : string; (** Rkey of the repository record *) 852 + source : string option; (** A source URL to clone from, populate this when forking or importing a repository. *) 853 } 854 855 + (** Jsont codec for {!type:input}. *) 856 + val input_jsont : input Jsont.t 857 858 + end 859 + module Artifact : sig 860 861 type main = { 862 + artifact : Atp.Blob_ref.t; (** the artifact *) 863 + created_at : string; (** time of creation of this artifact *) 864 + name : string; (** name of the artifact *) 865 + repo : string; (** repo that this artifact is being uploaded to *) 866 + tag : string; (** hash of the tag object that this artifact is attached to (only annotated tags are supported) *) 867 } 868 869 (** Jsont codec for {!type:main}. *) 870 val main_jsont : main Jsont.t 871 872 + end 873 + module Archive : sig 874 875 + (** Query/procedure parameters. *) 876 + type params = { 877 + format : string option; (** Archive format *) 878 + prefix : string option; (** Prefix for files in the archive *) 879 + ref_ : string; (** Git reference (branch, tag, or commit SHA) *) 880 + repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 881 + } 882 883 + (** Jsont codec for {!type:params}. *) 884 + val params_jsont : params Jsont.t 885 886 + (** Binary archive data *) 887 888 + type output = unit 889 + val output_jsont : output Jsont.t 890 891 end 892 + module RemoveSecret : sig 893 + (** Remove a CI secret *) 894 895 + 896 + type input = { 897 + key : string; 898 repo : string; 899 } 900 901 + (** Jsont codec for {!type:input}. *) 902 + val input_jsont : input Jsont.t 903 904 + end 905 + module Merge : sig 906 + (** Merge a patch into a repository branch *) 907 908 909 + type input = { 910 + author_email : string option; (** Author email for the merge commit *) 911 + author_name : string option; (** Author name for the merge commit *) 912 + branch : string; (** Target branch to merge into *) 913 + commit_body : string option; (** Additional commit message body *) 914 + commit_message : string option; (** Merge commit message *) 915 + did : string; (** DID of the repository owner *) 916 + name : string; (** Name of the repository *) 917 + patch : string; (** Patch content to merge *) 918 } 919 920 + (** Jsont codec for {!type:input}. *) 921 + val input_jsont : input Jsont.t 922 923 end 924 + module Blob : sig 925 926 + type submodule = { 927 + branch : string option; (** Branch to track in the submodule *) 928 + name : string; (** Submodule name *) 929 + url : string; (** Submodule repository URL *) 930 } 931 932 + (** Jsont codec for {!type:submodule}. *) 933 + val submodule_jsont : submodule Jsont.t 934 935 936 + type signature = { 937 + email : string; (** Author email *) 938 + name : string; (** Author name *) 939 + when_ : string; (** Author timestamp *) 940 } 941 942 + (** Jsont codec for {!type:signature}. *) 943 + val signature_jsont : signature Jsont.t 944 945 946 + type last_commit = { 947 + author : signature option; 948 + hash : string; (** Commit hash *) 949 + message : string; (** Commit message *) 950 + short_hash : string option; (** Short commit hash *) 951 + when_ : string; (** Commit timestamp *) 952 } 953 954 + (** Jsont codec for {!type:last_commit}. *) 955 + val last_commit_jsont : last_commit Jsont.t 956 957 958 + (** Query/procedure parameters. *) 959 + type params = { 960 + path : string; (** Path to the file within the repository *) 961 + raw : bool option; (** Return raw file content instead of JSON response *) 962 + ref_ : string; (** Git reference (branch, tag, or commit SHA) *) 963 + repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 964 } 965 966 + (** Jsont codec for {!type:params}. *) 967 + val params_jsont : params Jsont.t 968 969 970 + type output = { 971 + content : string option; (** File content (base64 encoded for binary files) *) 972 + encoding : string option; (** Content encoding *) 973 + is_binary : bool option; (** Whether the file is binary *) 974 + last_commit : last_commit option; 975 + mime_type : string option; (** MIME type of the file *) 976 + path : string; (** The file path *) 977 + ref_ : string; (** The git reference used *) 978 + size : int option; (** File size in bytes *) 979 + submodule : submodule option; (** Submodule information if path is a submodule *) 980 } 981 982 + (** Jsont codec for {!type:output}. *) 983 + val output_jsont : output Jsont.t 984 985 end 986 + module HiddenRef : sig 987 + (** Create a hidden ref in a repository *) 988 989 990 + type input = { 991 + fork_ref : string; (** Fork reference name *) 992 + remote_ref : string; (** Remote reference name *) 993 + repo : string; (** AT-URI of the repository *) 994 } 995 996 + (** Jsont codec for {!type:input}. *) 997 + val input_jsont : input Jsont.t 998 999 1000 + type output = { 1001 + error : string option; (** Error message if creation failed *) 1002 + ref_ : string option; (** The created hidden ref name *) 1003 + success : bool; (** Whether the hidden ref was created successfully *) 1004 } 1005 1006 + (** Jsont codec for {!type:output}. *) 1007 + val output_jsont : output Jsont.t 1008 1009 + end 1010 + module Compare : sig 1011 1012 (** Query/procedure parameters. *) 1013 type params = { 1014 + repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 1015 + rev1 : string; (** First revision (commit, branch, or tag) *) 1016 + rev2 : string; (** Second revision (commit, branch, or tag) *) 1017 } 1018 1019 (** Jsont codec for {!type:params}. *) 1020 val params_jsont : params Jsont.t 1021 1022 + (** Compare output in application/json *) 1023 1024 + type output = unit 1025 val output_jsont : output Jsont.t 1026 1027 end 1028 + module ForkStatus : sig 1029 + (** Check fork status relative to upstream source *) 1030 1031 1032 + type input = { 1033 + branch : string; (** Branch to check status for *) 1034 + did : string; (** DID of the fork owner *) 1035 + hidden_ref : string; (** Hidden ref to use for comparison *) 1036 + name : string; (** Name of the forked repository *) 1037 + source : string; (** Source repository URL *) 1038 } 1039 1040 + (** Jsont codec for {!type:input}. *) 1041 + val input_jsont : input Jsont.t 1042 1043 1044 type output = { 1045 + status : int; (** Fork status: 0=UpToDate, 1=FastForwardable, 2=Conflict, 3=MissingBranch *) 1046 } 1047 1048 (** Jsont codec for {!type:output}. *) 1049 val output_jsont : output Jsont.t 1050 1051 + end 1052 + module MergeCheck : sig 1053 1054 + type conflict_info = { 1055 + filename : string; (** Name of the conflicted file *) 1056 + reason : string; (** Reason for the conflict *) 1057 } 1058 1059 + (** Jsont codec for {!type:conflict_info}. *) 1060 + val conflict_info_jsont : conflict_info Jsont.t 1061 1062 + (** Check if a merge is possible between two branches *) 1063 1064 1065 + type input = { 1066 + branch : string; (** Target branch to merge into *) 1067 + did : string; (** DID of the repository owner *) 1068 + name : string; (** Name of the repository *) 1069 + patch : string; (** Patch or pull request to check for merge conflicts *) 1070 } 1071 1072 + (** Jsont codec for {!type:input}. *) 1073 + val input_jsont : input Jsont.t 1074 1075 1076 + type output = { 1077 + conflicts : conflict_info list option; (** List of files with merge conflicts *) 1078 + error : string option; (** Error message if check failed *) 1079 + is_conflicted : bool; (** Whether the merge has conflicts *) 1080 + message : string option; (** Additional message about the merge check *) 1081 } 1082 1083 + (** Jsont codec for {!type:output}. *) 1084 + val output_jsont : output Jsont.t 1085 1086 + end 1087 + module Branches : sig 1088 1089 + (** Query/procedure parameters. *) 1090 + type params = { 1091 + cursor : string option; (** Pagination cursor *) 1092 + limit : int option; (** Maximum number of branches to return *) 1093 + repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 1094 } 1095 1096 + (** Jsont codec for {!type:params}. *) 1097 + val params_jsont : params Jsont.t 1098 1099 1100 + type output = unit 1101 + val output_jsont : output Jsont.t 1102 1103 + end 1104 + module ForkSync : sig 1105 + (** Sync a forked repository with its upstream source *) 1106 1107 1108 + type input = { 1109 + branch : string; (** Branch to sync *) 1110 + did : string; (** DID of the fork owner *) 1111 + name : string; (** Name of the forked repository *) 1112 + source : string; (** AT-URI of the source repository *) 1113 } 1114 1115 + (** Jsont codec for {!type:input}. *) 1116 + val input_jsont : input Jsont.t 1117 1118 + end 1119 + module Languages : sig 1120 1121 + type language = { 1122 + color : string option; (** Hex color code for this language *) 1123 + extensions : string list option; (** File extensions associated with this language *) 1124 + file_count : int option; (** Number of files in this language *) 1125 + name : string; (** Programming language name *) 1126 + percentage : int; (** Percentage of total codebase (0-100) *) 1127 + size : int; (** Total size of files in this language (bytes) *) 1128 } 1129 1130 + (** Jsont codec for {!type:language}. *) 1131 + val language_jsont : language Jsont.t 1132 1133 1134 + (** Query/procedure parameters. *) 1135 + type params = { 1136 + ref_ : string option; (** Git reference (branch, tag, or commit SHA) *) 1137 + repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 1138 } 1139 1140 + (** Jsont codec for {!type:params}. *) 1141 + val params_jsont : params Jsont.t 1142 1143 1144 + type output = { 1145 + languages : language list; 1146 + ref_ : string; (** The git reference used *) 1147 + total_files : int option; (** Total number of files analyzed *) 1148 + total_size : int option; (** Total size of all analyzed files in bytes *) 1149 } 1150 1151 + (** Jsont codec for {!type:output}. *) 1152 + val output_jsont : output Jsont.t 1153 1154 end 1155 end
+669
ocaml-imap/IMPLEMENTATION-PLAN.md
···
··· 1 + # Comprehensive IMAP Implementation Plan 2 + 3 + This document consolidates all RFC implementation plans from `spec/` and `lib/imap/PLAN.md` into a single, prioritized implementation roadmap. Per the design goals, we favor OCaml variants over strings and do not require backwards compatibility. 4 + 5 + ## Executive Summary 6 + 7 + The ocaml-imap library implements IMAP4rev2 (RFC 9051) with several extensions. This plan covers: 8 + - **P0**: Critical fixes and core infrastructure 9 + - **P1**: Core protocol compliance 10 + - **P2**: Extension support (SORT/THREAD, QUOTA, etc.) 11 + - **P3**: Advanced features (UTF-8, CONDSTORE/QRESYNC) 12 + - **P4**: Polish (documentation, unified flag library) 13 + 14 + --- 15 + 16 + ## Phase 0: Critical Fixes (P0) 17 + 18 + These are blocking issues that need immediate attention. 19 + 20 + ### 0.1 Fix SEARCH Response Parsing (Client Library) 21 + 22 + **Source**: `lib/imap/PLAN.md` - P0 Broken Functionality 23 + 24 + **Problem**: `search` function always returns empty list - response is never parsed. 25 + 26 + **Files**: 27 + - `lib/imap/read.ml` - Add SEARCH response parsing 28 + - `lib/imap/client.ml:536-544` - Fix to read response 29 + 30 + **Implementation**: 31 + ```ocaml 32 + (* In read.ml - add case for SEARCH response *) 33 + | "SEARCH" -> 34 + let rec parse_numbers acc = 35 + match R.peek_char r with 36 + | Some ' ' -> sp r; parse_numbers (number r :: acc) 37 + | Some c when c >= '0' && c <= '9' -> parse_numbers (number r :: acc) 38 + | _ -> List.rev acc 39 + in 40 + let nums = parse_numbers [] in 41 + crlf r; 42 + Response.Search nums 43 + ``` 44 + 45 + **Tests** (`test/test_read.ml`): 46 + ```ocaml 47 + let test_search_response () = 48 + let resp = parse "* SEARCH 2 4 7 11\r\n" in 49 + Alcotest.(check (list int)) "search" [2; 4; 7; 11] 50 + (match resp with Response.Search nums -> nums | _ -> []) 51 + 52 + let test_search_empty () = 53 + let resp = parse "* SEARCH\r\n" in 54 + Alcotest.(check (list int)) "empty search" [] 55 + (match resp with Response.Search nums -> nums | _ -> [-1]) 56 + ``` 57 + 58 + ### 0.2 Parse BODY/BODYSTRUCTURE Responses 59 + 60 + **Source**: `lib/imap/PLAN.md` - P1 Incomplete Core Features 61 + 62 + **Problem**: FETCH responses with BODY/BODYSTRUCTURE fall back to empty flags. 63 + 64 + **Files**: 65 + - `lib/imap/read.ml:284-302` - Add BODY/BODYSTRUCTURE parsing 66 + - `lib/imap/body.ml` - Body structure types (may need new file) 67 + 68 + **Implementation**: Parse nested multipart MIME structures recursively. 69 + 70 + **Tests**: 71 + ```ocaml 72 + let test_body_structure () = 73 + let resp = parse {|* 1 FETCH (BODYSTRUCTURE ("TEXT" "PLAIN" ("CHARSET" "UTF-8") NIL NIL "7BIT" 1234 56))|} in 74 + (* verify body structure parsed correctly *) 75 + ``` 76 + 77 + ### 0.3 Parse BODY[section] Literal Responses 78 + 79 + **Source**: `lib/imap/PLAN.md` - P1 80 + 81 + **Problem**: Cannot read actual message content from FETCH. 82 + 83 + **Implementation**: Parse section specifiers and literal data: 84 + ```ocaml 85 + (* Patterns: BODY[HEADER], BODY[TEXT], BODY[1.2.MIME], BODY[section]<origin> *) 86 + ``` 87 + 88 + --- 89 + 90 + ## Phase 1: Core Protocol Compliance (P1) 91 + 92 + ### 1.1 Complete ESEARCH Support (RFC 4731) 93 + 94 + **Source**: `spec/PLAN-rfc4731.md` 95 + 96 + **Current State**: Response type exists, parsing not implemented. 97 + 98 + **Tasks**: 99 + 1. Add ESEARCH response parsing to `lib/imap/read.ml` 100 + 2. Add search return options to Command type 101 + 3. Add serialization for `RETURN (MIN MAX COUNT ALL)` 102 + 4. Add client API functions 103 + 104 + **Types** (use variants, no strings): 105 + ```ocaml 106 + type search_return_opt = 107 + | Return_min 108 + | Return_max 109 + | Return_all 110 + | Return_count 111 + 112 + type esearch_result = 113 + | Esearch_min of int 114 + | Esearch_max of int 115 + | Esearch_count of int 116 + | Esearch_all of Seq.t 117 + ``` 118 + 119 + **Tests**: 120 + ```ocaml 121 + let test_esearch_parsing () = 122 + let resp = parse "* ESEARCH (TAG \"A282\") MIN 2 COUNT 3\r\n" in 123 + assert (resp = Response.Esearch { 124 + tag = Some "A282"; 125 + uid = false; 126 + results = [Esearch_min 2; Esearch_count 3] 127 + }) 128 + ``` 129 + 130 + ### 1.2 Parse APPENDUID/COPYUID Response Codes 131 + 132 + **Source**: `lib/imap/PLAN.md` - P1 133 + 134 + **Files**: `lib/imap/read.ml:169-228` 135 + 136 + **Implementation**: 137 + ```ocaml 138 + (* Add to response_code parsing *) 139 + | "APPENDUID" -> 140 + sp r; 141 + let uidvalidity = number32 r in 142 + sp r; 143 + let uid = number32 r in 144 + Code.Appenduid (uidvalidity, uid) 145 + | "COPYUID" -> 146 + sp r; 147 + let uidvalidity = number32 r in 148 + sp r; 149 + let source_uids = parse_uid_set r in 150 + sp r; 151 + let dest_uids = parse_uid_set r in 152 + Code.Copyuid (uidvalidity, source_uids, dest_uids) 153 + ``` 154 + 155 + ### 1.3 UNSELECT Capability Advertisement 156 + 157 + **Source**: `spec/PLAN-rfc3691.md` 158 + 159 + **Status**: Fully implemented except capability not advertised. 160 + 161 + **Fix** (`lib/imapd/server.ml`): 162 + ```ocaml 163 + let base_capabilities_pre_tls = [ 164 + (* existing *) 165 + "UNSELECT"; (* RFC 3691 - already implemented *) 166 + ] 167 + ``` 168 + 169 + ### 1.4 SPECIAL-USE Support (RFC 6154) 170 + 171 + **Source**: `spec/PLAN-rfc6154.md` 172 + 173 + **Current**: Types exist, capability not advertised, flags not returned. 174 + 175 + **Tasks**: 176 + 1. Add `SPECIAL-USE` to capabilities 177 + 2. Return special-use flags in LIST responses 178 + 3. Map standard mailbox names to attributes 179 + 180 + **Types** (already exist, ensure completeness): 181 + ```ocaml 182 + type special_use = 183 + | All | Archive | Drafts | Flagged | Important 184 + | Junk | Sent | Trash 185 + | Snoozed | Scheduled | Memos (* draft-ietf-mailmaint *) 186 + ``` 187 + 188 + **Tests**: 189 + ```ocaml 190 + let test_list_special_use () = 191 + (* LIST "" "*" should return \Drafts on Drafts mailbox *) 192 + ``` 193 + 194 + --- 195 + 196 + ## Phase 2: Extension Support (P2) 197 + 198 + ### 2.1 SORT/THREAD Extension (RFC 5256) 199 + 200 + **Source**: `spec/PLAN-rfc5256.md` 201 + 202 + **Scope**: Large feature - server-side sorting and threading. 203 + 204 + #### 2.1.1 Thread Module Types 205 + 206 + **New file**: `lib/imap/thread.ml` 207 + 208 + ```ocaml 209 + type algorithm = 210 + | Orderedsubject (** Group by subject, sort by date *) 211 + | References (** Full JWZ threading algorithm *) 212 + | Extension of string 213 + 214 + type 'a node = 215 + | Message of 'a * 'a node list 216 + | Dummy of 'a node list 217 + 218 + type 'a t = 'a node list 219 + ``` 220 + 221 + #### 2.1.2 Base Subject Extraction 222 + 223 + **New file**: `lib/imap/subject.ml` 224 + 225 + Implements RFC 5256 Section 2.1 algorithm: 226 + 1. Decode RFC 2047 encoded-words 227 + 2. Remove `Re:`, `Fw:`, `Fwd:` prefixes 228 + 3. Remove `[blob]` prefixes 229 + 4. Remove `(fwd)` trailers 230 + 5. Unwrap `[fwd: ...]` wrappers 231 + 232 + ```ocaml 233 + val base_subject : string -> string 234 + val is_reply_or_forward : string -> bool 235 + ``` 236 + 237 + #### 2.1.3 Sent Date Handling 238 + 239 + **New file**: `lib/imap/date.ml` 240 + 241 + ```ocaml 242 + type t 243 + 244 + val of_header : string -> t option 245 + val of_internaldate : string -> t 246 + val sent_date : date_header:string option -> internaldate:string -> t 247 + val compare : t -> t -> int 248 + ``` 249 + 250 + #### 2.1.4 Server-Side SORT Handler 251 + 252 + **File**: `lib/imapd/server.ml` 253 + 254 + 1. Implement sort key extraction 255 + 2. Implement comparison by criteria 256 + 3. Return SORT response 257 + 258 + #### 2.1.5 Threading Algorithms 259 + 260 + **New file**: `lib/imapd/thread.ml` 261 + 262 + 1. `orderedsubject` - simple subject-based grouping 263 + 2. `references` - full JWZ algorithm (6 steps) 264 + 265 + **Tests**: 266 + ```ocaml 267 + let test_base_subject () = 268 + assert (Subject.base_subject "Re: test" = "test"); 269 + assert (Subject.base_subject "Re: Re: test" = "test"); 270 + assert (Subject.base_subject "[PATCH] Re: [ocaml] test" = "test"); 271 + assert (Subject.base_subject "[fwd: wrapped]" = "wrapped") 272 + 273 + let test_orderedsubject () = 274 + (* Test grouping by subject *) 275 + 276 + let test_references_threading () = 277 + (* Test parent/child relationships *) 278 + ``` 279 + 280 + ### 2.2 QUOTA Extension (RFC 9208) 281 + 282 + **Source**: `spec/PLAN-rfc9208.md` 283 + 284 + #### 2.2.1 Protocol Types 285 + 286 + **File**: `lib/imapd/protocol.ml` 287 + 288 + ```ocaml 289 + type quota_resource = 290 + | Quota_storage (** KB of storage *) 291 + | Quota_message (** Number of messages *) 292 + | Quota_mailbox (** Number of mailboxes *) 293 + | Quota_annotation_storage 294 + 295 + type quota_resource_info = { 296 + resource : quota_resource; 297 + usage : int64; 298 + limit : int64; 299 + } 300 + 301 + (* Commands *) 302 + | Getquota of string 303 + | Getquotaroot of mailbox_name 304 + | Setquota of { root : string; limits : (quota_resource * int64) list } 305 + 306 + (* Responses *) 307 + | Quota_response of { root : string; resources : quota_resource_info list } 308 + | Quotaroot_response of { mailbox : mailbox_name; roots : string list } 309 + ``` 310 + 311 + #### 2.2.2 Storage Backend Interface 312 + 313 + **File**: `lib/imapd/storage.mli` 314 + 315 + ```ocaml 316 + val get_quota_roots : t -> username:string -> mailbox_name -> string list 317 + val get_quota : t -> username:string -> string -> (quota_resource_info list, error) result 318 + val set_quota : t -> username:string -> string -> (quota_resource * int64) list -> (quota_resource_info list, error) result 319 + val check_quota : t -> username:string -> mailbox_name -> additional_size:int64 -> bool 320 + ``` 321 + 322 + #### 2.2.3 Server Handlers 323 + 324 + Implement `handle_getquota`, `handle_getquotaroot`, `handle_setquota`. 325 + 326 + Add quota checks to APPEND/COPY/MOVE: 327 + ```ocaml 328 + if not (Storage.check_quota ...) then 329 + send_response flow (No { code = Some Code_overquota; ... }) 330 + ``` 331 + 332 + **Tests**: 333 + ```ocaml 334 + let test_getquotaroot () = 335 + (* GETQUOTAROOT INBOX returns quota info *) 336 + 337 + let test_quota_exceeded () = 338 + (* APPEND fails with OVERQUOTA when over limit *) 339 + ``` 340 + 341 + ### 2.3 LIST-EXTENDED (RFC 5258) 342 + 343 + **Source**: `spec/PLAN-rfc5258.md` 344 + 345 + **Types**: 346 + ```ocaml 347 + type list_select_option = 348 + | List_select_subscribed 349 + | List_select_remote 350 + | List_select_recursivematch 351 + | List_select_special_use (* RFC 6154 *) 352 + 353 + type list_return_option = 354 + | List_return_subscribed 355 + | List_return_children 356 + | List_return_special_use 357 + 358 + type list_extended_item = 359 + | Childinfo of string list 360 + 361 + type list_command = 362 + | List_basic of { reference : string; pattern : string } 363 + | List_extended of { 364 + selection : list_select_option list; 365 + reference : string; 366 + patterns : string list; 367 + return_opts : list_return_option list; 368 + } 369 + ``` 370 + 371 + **Tasks**: 372 + 1. Update grammar for extended LIST syntax 373 + 2. Add `\NonExistent` and `\Remote` attributes 374 + 3. Implement subscription tracking in storage 375 + 4. Handle RECURSIVEMATCH with CHILDINFO 376 + 5. Add `LIST-EXTENDED` capability 377 + 378 + --- 379 + 380 + ## Phase 3: Advanced Features (P3) 381 + 382 + ### 3.1 UTF-8 Support (RFC 6855) 383 + 384 + **Source**: `spec/PLAN-rfc6855.md` 385 + 386 + #### 3.1.1 Session State Tracking 387 + 388 + ```ocaml 389 + type session_state = { 390 + utf8_enabled : bool; 391 + (* ... *) 392 + } 393 + ``` 394 + 395 + #### 3.1.2 UTF-8 Validation 396 + 397 + **New file**: `lib/imapd/utf8.ml` 398 + 399 + ```ocaml 400 + val is_valid_utf8 : string -> bool 401 + val has_non_ascii : string -> bool 402 + val is_valid_utf8_mailbox_name : string -> bool 403 + ``` 404 + 405 + #### 3.1.3 ENABLE Handler Update 406 + 407 + Track UTF8=ACCEPT state, reject SEARCH with CHARSET after enable. 408 + 409 + #### 3.1.4 UTF8 APPEND Extension 410 + 411 + Parse `UTF8 (literal)` syntax for 8-bit headers. 412 + 413 + **Tests**: 414 + ```ocaml 415 + let test_utf8_validation () = 416 + assert (Utf8.is_valid_utf8 "Hello"); 417 + assert (Utf8.is_valid_utf8 "\xe4\xb8\xad\xe6\x96\x87"); 418 + assert (not (Utf8.is_valid_utf8 "\xff\xfe")) 419 + ``` 420 + 421 + ### 3.2 CONDSTORE/QRESYNC (RFC 7162) 422 + 423 + **Source**: `lib/imap/PLAN.md` - P2, `PLAN.md` - Phase 2.2 424 + 425 + #### 3.2.1 CONDSTORE Types 426 + 427 + ```ocaml 428 + (* Fetch items *) 429 + | Modseq 430 + | Item_modseq of int64 431 + 432 + (* Response codes *) 433 + | Highestmodseq of int64 434 + | Nomodseq 435 + | Modified of Seq.t 436 + 437 + (* Command modifiers *) 438 + type fetch_modifier = { changedsince : int64 option } 439 + type store_modifier = { unchangedsince : int64 option } 440 + ``` 441 + 442 + #### 3.2.2 Storage Backend 443 + 444 + Add `modseq` to message type and mailbox state: 445 + ```ocaml 446 + type message = { 447 + (* existing *) 448 + modseq : int64; 449 + } 450 + 451 + type mailbox_state = { 452 + (* existing *) 453 + highestmodseq : int64; 454 + } 455 + ``` 456 + 457 + #### 3.2.3 QRESYNC 458 + 459 + ```ocaml 460 + type qresync_params = { 461 + uidvalidity : int32; 462 + modseq : int64; 463 + known_uids : Seq.t option; 464 + seq_match : (Seq.t * Seq.t) option; 465 + } 466 + 467 + (* Response *) 468 + | Vanished of { earlier : bool; uids : Seq.t } 469 + ``` 470 + 471 + --- 472 + 473 + ## Phase 4: Polish and Infrastructure (P4) 474 + 475 + ### 4.1 RFC 5530 Response Code Documentation 476 + 477 + **Source**: `spec/PLAN-rfc5530.md` 478 + 479 + All 16 response codes already implemented. Add OCamldoc citations. 480 + 481 + ### 4.2 Unified Mail Flag Library 482 + 483 + **Source**: `spec/PLAN-unified-mail-flag.md` 484 + 485 + Create shared `mail-flag` library for IMAP/JMAP: 486 + 487 + ``` 488 + mail-flag/ 489 + ├── keyword.ml # Message keywords (typed variants) 490 + ├── system_flag.ml # IMAP \Seen, \Deleted, etc. 491 + ├── mailbox_attr.ml # Mailbox attributes/roles 492 + ├── flag_color.ml # Apple Mail flag colors 493 + ├── imap_wire.ml # IMAP serialization 494 + └── jmap_wire.ml # JMAP serialization 495 + ``` 496 + 497 + ### 4.3 Infrastructure Improvements 498 + 499 + **Source**: `PLAN.md` - Phase 1 500 + 501 + 1. **Replace Menhir with Eio.Buf_read** - Pure functional parser 502 + 2. **Integrate conpool** - Connection pooling for client 503 + 3. **Add bytesrw streaming** - Large message handling 504 + 4. **Fuzz testing** - Parser robustness with Crowbar 505 + 5. **Eio mock testing** - Deterministic tests 506 + 507 + --- 508 + 509 + ## Testing Strategy 510 + 511 + ### Unit Tests 512 + 513 + Each module should have corresponding tests in `test/`: 514 + 515 + | Module | Test File | Coverage | 516 + |--------|-----------|----------| 517 + | `lib/imap/read.ml` | `test/test_read.ml` | Response parsing | 518 + | `lib/imap/write.ml` | `test/test_write.ml` | Command serialization | 519 + | `lib/imap/subject.ml` | `test/test_subject.ml` | Base subject extraction | 520 + | `lib/imap/thread.ml` | `test/test_thread.ml` | Threading algorithms | 521 + | `lib/imapd/server.ml` | `test/test_server.ml` | Command handlers | 522 + | `lib/imapd/storage.ml` | `test/test_storage.ml` | Storage backends | 523 + 524 + ### Integration Tests 525 + 526 + **File**: `test/integration/` 527 + 528 + - Protocol compliance testing against real servers 529 + - ImapTest compatibility suite 530 + - Dovecot interoperability 531 + 532 + ### Fuzz Tests 533 + 534 + **File**: `test/fuzz_parser.ml` 535 + 536 + ```ocaml 537 + let fuzz_command_parser = 538 + Crowbar.(map [bytes] (fun input -> 539 + try 540 + ignore (Imap_parser.parse_command input); 541 + true 542 + with _ -> true (* Parser should never crash *) 543 + )) 544 + ``` 545 + 546 + --- 547 + 548 + ## Implementation Order 549 + 550 + ### Sprint 1: P0 Critical Fixes 551 + 1. [ ] Fix SEARCH response parsing 552 + 2. [ ] Parse BODY/BODYSTRUCTURE responses 553 + 3. [ ] Parse BODY[section] literals 554 + 555 + ### Sprint 2: P1 Core Compliance 556 + 4. [ ] Complete ESEARCH support 557 + 5. [ ] Parse APPENDUID/COPYUID response codes 558 + 6. [ ] Add UNSELECT to capabilities 559 + 7. [ ] Complete SPECIAL-USE support 560 + 561 + ### Sprint 3: P2 SORT/THREAD 562 + 8. [ ] Thread module types 563 + 9. [ ] Base subject extraction 564 + 10. [ ] Sent date handling 565 + 11. [ ] ORDEREDSUBJECT algorithm 566 + 12. [ ] REFERENCES algorithm 567 + 13. [ ] Server SORT/THREAD handlers 568 + 569 + ### Sprint 4: P2 QUOTA 570 + 14. [ ] Quota protocol types 571 + 15. [ ] Storage backend interface 572 + 16. [ ] Memory storage quota 573 + 17. [ ] Maildir storage quota 574 + 18. [ ] Server handlers 575 + 576 + ### Sprint 5: P2 LIST-EXTENDED 577 + 19. [ ] Extended LIST grammar 578 + 20. [ ] New attributes 579 + 21. [ ] Subscription tracking 580 + 22. [ ] RECURSIVEMATCH support 581 + 582 + ### Sprint 6: P3 UTF-8 & CONDSTORE 583 + 23. [ ] UTF-8 session state 584 + 24. [ ] UTF-8 validation 585 + 25. [ ] UTF8 APPEND extension 586 + 26. [ ] CONDSTORE types 587 + 27. [ ] CONDSTORE handlers 588 + 28. [ ] QRESYNC support 589 + 590 + ### Sprint 7: P4 Polish 591 + 29. [ ] Response code documentation 592 + 30. [ ] Unified mail flag library 593 + 31. [ ] Infrastructure improvements 594 + 32. [ ] Comprehensive test suite 595 + 596 + --- 597 + 598 + ## File Modification Summary 599 + 600 + ### New Files 601 + 602 + | File | Purpose | 603 + |------|---------| 604 + | `lib/imap/thread.ml` | Thread types and parsing | 605 + | `lib/imap/subject.ml` | Base subject extraction | 606 + | `lib/imap/date.ml` | Sent date handling | 607 + | `lib/imap/collation.ml` | Unicode collation | 608 + | `lib/imap/mime.ml` | RFC 2047 decoding | 609 + | `lib/imapd/thread.ml` | Threading algorithms | 610 + | `lib/imapd/utf8.ml` | UTF-8 validation | 611 + | `test/test_subject.ml` | Subject tests | 612 + | `test/test_thread.ml` | Threading tests | 613 + | `test/test_quota.ml` | Quota tests | 614 + | `test/fuzz_parser.ml` | Fuzz tests | 615 + 616 + ### Modified Files 617 + 618 + | File | Changes | 619 + |------|---------| 620 + | `lib/imap/read.ml` | SEARCH, ESEARCH, BODY parsing | 621 + | `lib/imap/write.ml` | ESEARCH, THREAD serialization | 622 + | `lib/imap/command.ml` | Return options, THREAD command | 623 + | `lib/imap/response.ml` | ESEARCH, THREAD responses | 624 + | `lib/imap/client.ml` | Fix search, add esearch/thread | 625 + | `lib/imap/code.ml` | OCamldoc citations | 626 + | `lib/imap/list_attr.ml` | Add NonExistent, Remote | 627 + | `lib/imapd/protocol.ml` | Quota types, LIST-EXTENDED | 628 + | `lib/imapd/server.ml` | Handlers, capabilities | 629 + | `lib/imapd/storage.ml` | Quota ops, subscription tracking | 630 + | `lib/imapd/grammar.mly` | Extended LIST, QUOTA, UTF8 | 631 + | `lib/imapd/lexer.mll` | New tokens | 632 + | `lib/imapd/parser.ml` | Response serialization | 633 + 634 + --- 635 + 636 + ## Design Principles 637 + 638 + 1. **Favor OCaml variants** - Use typed variants over strings where possible 639 + 2. **No backwards compatibility** - Clean API without legacy shims 640 + 3. **RFC citations** - OCamldoc links to RFC sections 641 + 4. **Incremental** - Each task is independently useful 642 + 5. **Test-driven** - Tests accompany each feature 643 + 6. **Eio-native** - Use Eio patterns throughout 644 + 645 + --- 646 + 647 + ## References 648 + 649 + ### Implemented RFCs 650 + - RFC 9051 - IMAP4rev2 (core) 651 + - RFC 8314 - Implicit TLS 652 + - RFC 2177 - IDLE 653 + - RFC 2342 - NAMESPACE 654 + - RFC 2971 - ID 655 + - RFC 4315 - UIDPLUS 656 + - RFC 5161 - ENABLE 657 + - RFC 6851 - MOVE 658 + - RFC 7888 - LITERAL+ 659 + 660 + ### RFCs in This Plan 661 + - RFC 3691 - UNSELECT (partially complete) 662 + - RFC 4731 - ESEARCH 663 + - RFC 5256 - SORT/THREAD 664 + - RFC 5258 - LIST-EXTENDED 665 + - RFC 5530 - Response Codes (types complete) 666 + - RFC 6154 - SPECIAL-USE (partially complete) 667 + - RFC 6855 - UTF-8 Support 668 + - RFC 7162 - CONDSTORE/QRESYNC 669 + - RFC 9208 - QUOTA
+48 -2
ocaml-imap/lib/imap/client.ml
··· 570 571 let search t ?charset criteria = 572 require_selected t; 573 - let tag = send_command t (Command.Search { charset; criteria }) in 574 let untagged, final = receive_responses t tag in 575 check_ok tag untagged final; 576 (* Extract search results from untagged responses *) ··· 582 583 let uid_search t ?charset criteria = 584 require_selected t; 585 - let tag = send_command t (Command.Uid (Uid_search { charset; criteria })) in 586 let untagged, final = receive_responses t tag in 587 check_ok tag untagged final; 588 (* Extract UID search results from untagged responses - UIDs are returned as int64 *) ··· 685 (function Response.Enabled exts -> enabled := exts | _ -> ()) 686 untagged; 687 !enabled
··· 570 571 let search t ?charset criteria = 572 require_selected t; 573 + let tag = send_command t (Command.Search { charset; criteria; return_opts = None }) in 574 let untagged, final = receive_responses t tag in 575 check_ok tag untagged final; 576 (* Extract search results from untagged responses *) ··· 582 583 let uid_search t ?charset criteria = 584 require_selected t; 585 + let tag = send_command t (Command.Uid (Uid_search { charset; criteria; return_opts = None })) in 586 let untagged, final = receive_responses t tag in 587 check_ok tag untagged final; 588 (* Extract UID search results from untagged responses - UIDs are returned as int64 *) ··· 685 (function Response.Enabled exts -> enabled := exts | _ -> ()) 686 untagged; 687 !enabled 688 + 689 + (** {1 ESEARCH Support (RFC 4731)} *) 690 + 691 + type esearch_result = { 692 + min : int option; 693 + max : int option; 694 + count : int option; 695 + all : Seq.t option; 696 + } 697 + 698 + let empty_esearch_result = { 699 + min = None; 700 + max = None; 701 + count = None; 702 + all = None; 703 + } 704 + 705 + let parse_esearch_response responses = 706 + List.fold_left (fun acc resp -> 707 + match resp with 708 + | Response.Esearch { results; _ } -> 709 + List.fold_left (fun acc item -> 710 + match item with 711 + | Response.Esearch_min n -> { acc with min = Some n } 712 + | Response.Esearch_max n -> { acc with max = Some n } 713 + | Response.Esearch_count n -> { acc with count = Some n } 714 + | Response.Esearch_all seq -> { acc with all = Some seq } 715 + ) acc results 716 + | _ -> acc 717 + ) empty_esearch_result responses 718 + 719 + let esearch t ?charset ?(return_opts = [Command.Return_all]) criteria = 720 + require_selected t; 721 + require_capability t "ESEARCH"; 722 + let tag = send_command t (Command.Search { charset; criteria; return_opts = Some return_opts }) in 723 + let untagged, final = receive_responses t tag in 724 + check_ok tag untagged final; 725 + parse_esearch_response untagged 726 + 727 + let uid_esearch t ?charset ?(return_opts = [Command.Return_all]) criteria = 728 + require_selected t; 729 + require_capability t "ESEARCH"; 730 + let tag = send_command t (Command.Uid (Uid_search { charset; criteria; return_opts = Some return_opts })) in 731 + let untagged, final = receive_responses t tag in 732 + check_ok tag untagged final; 733 + parse_esearch_response untagged
+30
ocaml-imap/lib/imap/client.mli
··· 247 248 val enable : t -> string list -> string list 249 (** [enable client extensions] enables protocol extensions. *)
··· 247 248 val enable : t -> string list -> string list 249 (** [enable client extensions] enables protocol extensions. *) 250 + 251 + (** {1 ESEARCH Support (RFC 4731)} *) 252 + 253 + type esearch_result = { 254 + min : int option; 255 + max : int option; 256 + count : int option; 257 + all : Seq.t option; 258 + } 259 + (** ESEARCH result containing optional min, max, count, and all values. *) 260 + 261 + val esearch : 262 + t -> 263 + ?charset:string -> 264 + ?return_opts:Command.search_return_opt list -> 265 + Search.t -> 266 + esearch_result 267 + (** [esearch client ?charset ?return_opts criteria] performs an extended search. 268 + Returns an {!esearch_result} with the requested information. 269 + Default [return_opts] is [[Return_all]]. 270 + Requires ESEARCH extension. *) 271 + 272 + val uid_esearch : 273 + t -> 274 + ?charset:string -> 275 + ?return_opts:Command.search_return_opt list -> 276 + Search.t -> 277 + esearch_result 278 + (** [uid_esearch client ?charset ?return_opts criteria] like {!esearch} but for UID searches. 279 + Requires ESEARCH extension. *)
+6
ocaml-imap/lib/imap/code.ml
··· 24 | Expired 25 | Expungeissued 26 | Haschildren 27 | Inuse 28 | Limit 29 | Nonexistent 30 | Noperm 31 | Overquota ··· 61 | Expired -> Fmt.string ppf "EXPIRED" 62 | Expungeissued -> Fmt.string ppf "EXPUNGEISSUED" 63 | Haschildren -> Fmt.string ppf "HASCHILDREN" 64 | Inuse -> Fmt.string ppf "INUSE" 65 | Limit -> Fmt.string ppf "LIMIT" 66 | Nonexistent -> Fmt.string ppf "NONEXISTENT" 67 | Noperm -> Fmt.string ppf "NOPERM" 68 | Overquota -> Fmt.string ppf "OVERQUOTA"
··· 24 | Expired 25 | Expungeissued 26 | Haschildren 27 + | Highestmodseq of int64 (** Highest MODSEQ in mailbox - RFC 7162 CONDSTORE *) 28 | Inuse 29 | Limit 30 + | Modified of Seq.t (** Messages modified since UNCHANGEDSINCE - RFC 7162 CONDSTORE *) 31 + | Nomodseq (** Mailbox doesn't support MODSEQ - RFC 7162 CONDSTORE *) 32 | Nonexistent 33 | Noperm 34 | Overquota ··· 64 | Expired -> Fmt.string ppf "EXPIRED" 65 | Expungeissued -> Fmt.string ppf "EXPUNGEISSUED" 66 | Haschildren -> Fmt.string ppf "HASCHILDREN" 67 + | Highestmodseq m -> Fmt.pf ppf "HIGHESTMODSEQ %Ld" m 68 | Inuse -> Fmt.string ppf "INUSE" 69 | Limit -> Fmt.string ppf "LIMIT" 70 + | Modified s -> Fmt.pf ppf "MODIFIED %a" Seq.pp s 71 + | Nomodseq -> Fmt.string ppf "NOMODSEQ" 72 | Nonexistent -> Fmt.string ppf "NONEXISTENT" 73 | Noperm -> Fmt.string ppf "NOPERM" 74 | Overquota -> Fmt.string ppf "OVERQUOTA"
+3
ocaml-imap/lib/imap/code.mli
··· 24 | Expired 25 | Expungeissued 26 | Haschildren 27 | Inuse 28 | Limit 29 | Nonexistent 30 | Noperm 31 | Overquota
··· 24 | Expired 25 | Expungeissued 26 | Haschildren 27 + | Highestmodseq of int64 (** Highest MODSEQ in mailbox - RFC 7162 CONDSTORE *) 28 | Inuse 29 | Limit 30 + | Modified of Seq.t (** Messages modified since UNCHANGEDSINCE - RFC 7162 CONDSTORE *) 31 + | Nomodseq (** Mailbox doesn't support MODSEQ - RFC 7162 CONDSTORE *) 32 | Nonexistent 33 | Noperm 34 | Overquota
+13 -2
ocaml-imap/lib/imap/command.ml
··· 7 8 Client-to-server commands as specified in RFC 9051. *) 9 10 type t = 11 | Capability 12 | Noop ··· 35 | Close 36 | Unselect 37 | Expunge 38 - | Search of { charset : string option; criteria : Search.t } 39 | Sort of { charset : string; criteria : Sort.t; search : Search.t } 40 | Fetch of { sequence : Seq.t; items : Fetch.request list; changedsince : int64 option } 41 | Store of { 42 sequence : Seq.t; ··· 61 } 62 | Uid_copy of { sequence : Seq.t; mailbox : Mailbox.t } 63 | Uid_move of { sequence : Seq.t; mailbox : Mailbox.t } 64 - | Uid_search of { charset : string option; criteria : Search.t } 65 | Uid_sort of { charset : string; criteria : Sort.t; search : Search.t } 66 | Uid_expunge of Seq.t 67 68 type tagged = { tag : string; command : t } ··· 95 | Expunge -> Fmt.string ppf "EXPUNGE" 96 | Search _ -> Fmt.string ppf "SEARCH (...)" 97 | Sort _ -> Fmt.string ppf "SORT (...)" 98 | Fetch { sequence; _ } -> Fmt.pf ppf "FETCH %a (...)" Seq.pp sequence 99 | Store { sequence; action; _ } -> 100 let action_str = match action with Store.Set -> "FLAGS" | Store.Add -> "+FLAGS" | Store.Remove -> "-FLAGS" in ··· 113 | Uid_move { sequence; mailbox } -> Fmt.pf ppf "MOVE %a %s" Seq.pp sequence mailbox 114 | Uid_search _ -> Fmt.string ppf "SEARCH (...)" 115 | Uid_sort _ -> Fmt.string ppf "SORT (...)" 116 | Uid_expunge seq -> Fmt.pf ppf "EXPUNGE %a" Seq.pp seq
··· 7 8 Client-to-server commands as specified in RFC 9051. *) 9 10 + (** ESEARCH return options (RFC 4731) *) 11 + type search_return_opt = 12 + | Return_min (** Return minimum matching sequence number/UID *) 13 + | Return_max (** Return maximum matching sequence number/UID *) 14 + | Return_all (** Return all matching sequence numbers/UIDs as a sequence set *) 15 + | Return_count (** Return count of matching messages *) 16 + 17 type t = 18 | Capability 19 | Noop ··· 42 | Close 43 | Unselect 44 | Expunge 45 + | Search of { charset : string option; criteria : Search.t; return_opts : search_return_opt list option } 46 | Sort of { charset : string; criteria : Sort.t; search : Search.t } 47 + | Thread of { algorithm : Thread.algorithm; charset : string; search : Search.t } 48 | Fetch of { sequence : Seq.t; items : Fetch.request list; changedsince : int64 option } 49 | Store of { 50 sequence : Seq.t; ··· 69 } 70 | Uid_copy of { sequence : Seq.t; mailbox : Mailbox.t } 71 | Uid_move of { sequence : Seq.t; mailbox : Mailbox.t } 72 + | Uid_search of { charset : string option; criteria : Search.t; return_opts : search_return_opt list option } 73 | Uid_sort of { charset : string; criteria : Sort.t; search : Search.t } 74 + | Uid_thread of { algorithm : Thread.algorithm; charset : string; search : Search.t } 75 | Uid_expunge of Seq.t 76 77 type tagged = { tag : string; command : t } ··· 104 | Expunge -> Fmt.string ppf "EXPUNGE" 105 | Search _ -> Fmt.string ppf "SEARCH (...)" 106 | Sort _ -> Fmt.string ppf "SORT (...)" 107 + | Thread _ -> Fmt.string ppf "THREAD (...)" 108 | Fetch { sequence; _ } -> Fmt.pf ppf "FETCH %a (...)" Seq.pp sequence 109 | Store { sequence; action; _ } -> 110 let action_str = match action with Store.Set -> "FLAGS" | Store.Add -> "+FLAGS" | Store.Remove -> "-FLAGS" in ··· 123 | Uid_move { sequence; mailbox } -> Fmt.pf ppf "MOVE %a %s" Seq.pp sequence mailbox 124 | Uid_search _ -> Fmt.string ppf "SEARCH (...)" 125 | Uid_sort _ -> Fmt.string ppf "SORT (...)" 126 + | Uid_thread _ -> Fmt.string ppf "THREAD (...)" 127 | Uid_expunge seq -> Fmt.pf ppf "EXPUNGE %a" Seq.pp seq
+11 -2
ocaml-imap/lib/imap/command.mli
··· 7 8 Client-to-server commands as specified in RFC 9051. *) 9 10 type t = 11 | Capability 12 | Noop ··· 35 | Close 36 | Unselect 37 | Expunge 38 - | Search of { charset : string option; criteria : Search.t } 39 | Sort of { charset : string; criteria : Sort.t; search : Search.t } 40 | Fetch of { sequence : Seq.t; items : Fetch.request list; changedsince : int64 option } 41 | Store of { 42 sequence : Seq.t; ··· 61 } 62 | Uid_copy of { sequence : Seq.t; mailbox : Mailbox.t } 63 | Uid_move of { sequence : Seq.t; mailbox : Mailbox.t } 64 - | Uid_search of { charset : string option; criteria : Search.t } 65 | Uid_sort of { charset : string; criteria : Sort.t; search : Search.t } 66 | Uid_expunge of Seq.t 67 68 type tagged = { tag : string; command : t }
··· 7 8 Client-to-server commands as specified in RFC 9051. *) 9 10 + (** ESEARCH return options (RFC 4731) *) 11 + type search_return_opt = 12 + | Return_min (** Return minimum matching sequence number/UID *) 13 + | Return_max (** Return maximum matching sequence number/UID *) 14 + | Return_all (** Return all matching sequence numbers/UIDs as a sequence set *) 15 + | Return_count (** Return count of matching messages *) 16 + 17 type t = 18 | Capability 19 | Noop ··· 42 | Close 43 | Unselect 44 | Expunge 45 + | Search of { charset : string option; criteria : Search.t; return_opts : search_return_opt list option } 46 | Sort of { charset : string; criteria : Sort.t; search : Search.t } 47 + | Thread of { algorithm : Thread.algorithm; charset : string; search : Search.t } 48 | Fetch of { sequence : Seq.t; items : Fetch.request list; changedsince : int64 option } 49 | Store of { 50 sequence : Seq.t; ··· 69 } 70 | Uid_copy of { sequence : Seq.t; mailbox : Mailbox.t } 71 | Uid_move of { sequence : Seq.t; mailbox : Mailbox.t } 72 + | Uid_search of { charset : string option; criteria : Search.t; return_opts : search_return_opt list option } 73 | Uid_sort of { charset : string; criteria : Sort.t; search : Search.t } 74 + | Uid_thread of { algorithm : Thread.algorithm; charset : string; search : Search.t } 75 | Uid_expunge of Seq.t 76 77 type tagged = { tag : string; command : t }
+1
ocaml-imap/lib/imap/dune
··· 9 base64 10 fmt 11 logs 12 unix))
··· 9 base64 10 fmt 11 logs 12 + mail-flag 13 unix))
+2
ocaml-imap/lib/imap/fetch.ml
··· 25 | Binary of string * (int * int) option 26 | Binary_peek of string * (int * int) option 27 | Binary_size of string 28 29 let pp_request ppf = function 30 | Envelope -> Fmt.string ppf "ENVELOPE" ··· 42 | Binary (s, _) -> Fmt.pf ppf "BINARY[%s]" s 43 | Binary_peek (s, _) -> Fmt.pf ppf "BINARY.PEEK[%s]" s 44 | Binary_size s -> Fmt.pf ppf "BINARY.SIZE[%s]" s 45 46 (** {1 Response Items} *) 47
··· 25 | Binary of string * (int * int) option 26 | Binary_peek of string * (int * int) option 27 | Binary_size of string 28 + | Modseq (** Request MODSEQ value - RFC 7162 CONDSTORE *) 29 30 let pp_request ppf = function 31 | Envelope -> Fmt.string ppf "ENVELOPE" ··· 43 | Binary (s, _) -> Fmt.pf ppf "BINARY[%s]" s 44 | Binary_peek (s, _) -> Fmt.pf ppf "BINARY.PEEK[%s]" s 45 | Binary_size s -> Fmt.pf ppf "BINARY.SIZE[%s]" s 46 + | Modseq -> Fmt.string ppf "MODSEQ" 47 48 (** {1 Response Items} *) 49
+1
ocaml-imap/lib/imap/fetch.mli
··· 25 | Binary of string * (int * int) option 26 | Binary_peek of string * (int * int) option 27 | Binary_size of string 28 29 val pp_request : Format.formatter -> request -> unit 30
··· 25 | Binary of string * (int * int) option 26 | Binary_peek of string * (int * int) option 27 | Binary_size of string 28 + | Modseq (** Request MODSEQ value - RFC 7162 CONDSTORE *) 29 30 val pp_request : Format.formatter -> request -> unit 31
+52 -1
ocaml-imap/lib/imap/flag.ml
··· 5 6 (** Message Flags 7 8 - IMAP message flags as specified in RFC 9051 Section 2.3.2. *) 9 10 type system = 11 | Seen (** Message has been read *) ··· 20 | Flagged -> Fmt.string ppf "\\Flagged" 21 | Deleted -> Fmt.string ppf "\\Deleted" 22 | Draft -> Fmt.string ppf "\\Draft" 23 24 type t = 25 | System of system ··· 47 | "\\DRAFT" -> Some (System Draft) 48 | _ -> 49 if String.length s > 0 && s.[0] <> '\\' then Some (Keyword s) else None
··· 5 6 (** Message Flags 7 8 + Re-exports from {!Mail_flag} for IMAP-specific use. 9 + See {{:https://datatracker.ietf.org/doc/html/rfc9051#section-2.3.2}RFC 9051 Section 2.3.2}. *) 10 + 11 + (** {1 System Flags} *) 12 13 type system = 14 | Seen (** Message has been read *) ··· 23 | Flagged -> Fmt.string ppf "\\Flagged" 24 | Deleted -> Fmt.string ppf "\\Deleted" 25 | Draft -> Fmt.string ppf "\\Draft" 26 + 27 + (** {1 Flags} *) 28 29 type t = 30 | System of system ··· 52 | "\\DRAFT" -> Some (System Draft) 53 | _ -> 54 if String.length s > 0 && s.[0] <> '\\' then Some (Keyword s) else None 55 + 56 + (** {1 Conversion to/from mail-flag} *) 57 + 58 + let system_to_keyword : system -> Mail_flag.Keyword.t = function 59 + | Seen -> `Seen 60 + | Answered -> `Answered 61 + | Flagged -> `Flagged 62 + | Deleted -> `Deleted 63 + | Draft -> `Draft 64 + 65 + let system_of_keyword : Mail_flag.Keyword.standard -> system option = function 66 + | `Seen -> Some Seen 67 + | `Answered -> Some Answered 68 + | `Flagged -> Some Flagged 69 + | `Deleted -> Some Deleted 70 + | `Draft -> Some Draft 71 + | `Forwarded -> None 72 + 73 + let to_mail_flag : t -> Mail_flag.Imap_wire.flag = function 74 + | System Seen -> Mail_flag.Imap_wire.System `Seen 75 + | System Answered -> Mail_flag.Imap_wire.System `Answered 76 + | System Flagged -> Mail_flag.Imap_wire.System `Flagged 77 + | System Deleted -> Mail_flag.Imap_wire.System `Deleted 78 + | System Draft -> Mail_flag.Imap_wire.System `Draft 79 + | Keyword k -> Mail_flag.Imap_wire.Keyword (Mail_flag.Keyword.of_string k) 80 + 81 + let of_mail_flag : Mail_flag.Imap_wire.flag -> t = function 82 + | Mail_flag.Imap_wire.System `Seen -> System Seen 83 + | Mail_flag.Imap_wire.System `Answered -> System Answered 84 + | Mail_flag.Imap_wire.System `Flagged -> System Flagged 85 + | Mail_flag.Imap_wire.System `Deleted -> System Deleted 86 + | Mail_flag.Imap_wire.System `Draft -> System Draft 87 + | Mail_flag.Imap_wire.Keyword k -> Keyword (Mail_flag.Keyword.to_string k) 88 + 89 + let to_keyword : t -> Mail_flag.Keyword.t = function 90 + | System s -> system_to_keyword s 91 + | Keyword k -> Mail_flag.Keyword.of_string k 92 + 93 + let of_keyword (k : Mail_flag.Keyword.t) : t = 94 + match k with 95 + | `Seen -> System Seen 96 + | `Answered -> System Answered 97 + | `Flagged -> System Flagged 98 + | `Deleted -> System Deleted 99 + | `Draft -> System Draft 100 + | other -> Keyword (Mail_flag.Keyword.to_string other)
+26 -1
ocaml-imap/lib/imap/flag.mli
··· 5 6 (** Message Flags 7 8 - IMAP message flags as specified in RFC 9051 Section 2.3.2. *) 9 10 (** {1 System Flags} *) 11 ··· 36 val pp : Format.formatter -> t -> unit 37 val to_string : t -> string 38 val of_string : string -> t option
··· 5 6 (** Message Flags 7 8 + Re-exports from {!Mail_flag} for IMAP-specific use. 9 + See {{:https://datatracker.ietf.org/doc/html/rfc9051#section-2.3.2}RFC 9051 Section 2.3.2}. *) 10 11 (** {1 System Flags} *) 12 ··· 37 val pp : Format.formatter -> t -> unit 38 val to_string : t -> string 39 val of_string : string -> t option 40 + 41 + (** {1 Conversion to/from mail-flag} 42 + 43 + These functions allow interoperability with the {!Mail_flag} library 44 + for cross-protocol flag handling. *) 45 + 46 + val system_to_keyword : system -> Mail_flag.Keyword.t 47 + (** [system_to_keyword sys] converts an IMAP system flag to a mail-flag keyword. *) 48 + 49 + val system_of_keyword : Mail_flag.Keyword.standard -> system option 50 + (** [system_of_keyword kw] converts a standard mail-flag keyword to an IMAP system flag. 51 + Returns [None] for keywords like [`Forwarded] that have no IMAP system flag equivalent. *) 52 + 53 + val to_mail_flag : t -> Mail_flag.Imap_wire.flag 54 + (** [to_mail_flag flag] converts an IMAP flag to a mail-flag wire format flag. *) 55 + 56 + val of_mail_flag : Mail_flag.Imap_wire.flag -> t 57 + (** [of_mail_flag flag] converts a mail-flag wire format flag to an IMAP flag. *) 58 + 59 + val to_keyword : t -> Mail_flag.Keyword.t 60 + (** [to_keyword flag] converts an IMAP flag to a mail-flag keyword. *) 61 + 62 + val of_keyword : Mail_flag.Keyword.t -> t 63 + (** [of_keyword kw] converts a mail-flag keyword to an IMAP flag. *)
+3
ocaml-imap/lib/imap/imap.ml
··· 57 - {!module:Fetch} - FETCH request/response items 58 - {!module:Search} - SEARCH criteria 59 - {!module:Sort} - SORT criteria (RFC 5256) 60 - {!module:Store} - STORE actions 61 - {!module:Status} - STATUS items 62 - {!module:List_attr} - LIST mailbox attributes ··· 99 module Store = Store 100 module Status = Status 101 module List_attr = List_attr 102 103 (** {1 Client} *) 104
··· 57 - {!module:Fetch} - FETCH request/response items 58 - {!module:Search} - SEARCH criteria 59 - {!module:Sort} - SORT criteria (RFC 5256) 60 + - {!module:Subject} - Base subject extraction (RFC 5256) 61 - {!module:Store} - STORE actions 62 - {!module:Status} - STATUS items 63 - {!module:List_attr} - LIST mailbox attributes ··· 100 module Store = Store 101 module Status = Status 102 module List_attr = List_attr 103 + module Subject = Subject 104 + module Thread = Thread 105 106 (** {1 Client} *) 107
+3
ocaml-imap/lib/imap/imap.mli
··· 57 - {!module:Fetch} - FETCH request/response items 58 - {!module:Search} - SEARCH criteria 59 - {!module:Sort} - SORT criteria (RFC 5256) 60 - {!module:Store} - STORE actions 61 - {!module:Status} - STATUS items 62 - {!module:List_attr} - LIST mailbox attributes ··· 99 module Store = Store 100 module Status = Status 101 module List_attr = List_attr 102 103 (** {1 Client} *) 104
··· 57 - {!module:Fetch} - FETCH request/response items 58 - {!module:Search} - SEARCH criteria 59 - {!module:Sort} - SORT criteria (RFC 5256) 60 + - {!module:Subject} - Base subject extraction (RFC 5256) 61 - {!module:Store} - STORE actions 62 - {!module:Status} - STATUS items 63 - {!module:List_attr} - LIST mailbox attributes ··· 100 module Store = Store 101 module Status = Status 102 module List_attr = List_attr 103 + module Subject = Subject 104 + module Thread = Thread 105 106 (** {1 Client} *) 107
+102 -1
ocaml-imap/lib/imap/list_attr.ml
··· 5 6 (** LIST Command Attributes 7 8 - Mailbox attributes returned by LIST command. 9 See RFC 9051 Section 7.2.2. *) 10 11 type t = ··· 43 | Extension s -> Fmt.string ppf s 44 45 let to_string a = Fmt.str "%a" pp a
··· 5 6 (** LIST Command Attributes 7 8 + Re-exports from {!Mail_flag.Mailbox_attr}. 9 See RFC 9051 Section 7.2.2. *) 10 11 type t = ··· 43 | Extension s -> Fmt.string ppf s 44 45 let to_string a = Fmt.str "%a" pp a 46 + 47 + let of_string s = 48 + let s' = String.lowercase_ascii s in 49 + (* Remove leading backslash if present *) 50 + let s' = if String.length s' > 0 && s'.[0] = '\\' then 51 + String.sub s' 1 (String.length s' - 1) 52 + else s' 53 + in 54 + match s' with 55 + | "noinferiors" -> Noinferiors 56 + | "noselect" -> Noselect 57 + | "marked" -> Marked 58 + | "unmarked" -> Unmarked 59 + | "subscribed" -> Subscribed 60 + | "haschildren" -> Haschildren 61 + | "hasnochildren" -> Hasnochildren 62 + | "all" -> All 63 + | "archive" -> Archive 64 + | "drafts" -> Drafts 65 + | "flagged" -> Flagged 66 + | "junk" | "spam" -> Junk 67 + | "sent" -> Sent 68 + | "trash" -> Trash 69 + | _ -> Extension s 70 + 71 + (** {1 Conversion to/from mail-flag} *) 72 + 73 + let to_mailbox_attr : t -> Mail_flag.Mailbox_attr.t = function 74 + | Noinferiors -> `Noinferiors 75 + | Noselect -> `Noselect 76 + | Marked -> `Marked 77 + | Unmarked -> `Unmarked 78 + | Subscribed -> `Subscribed 79 + | Haschildren -> `HasChildren 80 + | Hasnochildren -> `HasNoChildren 81 + | All -> `All 82 + | Archive -> `Archive 83 + | Drafts -> `Drafts 84 + | Flagged -> `Flagged 85 + | Junk -> `Junk 86 + | Sent -> `Sent 87 + | Trash -> `Trash 88 + | Extension s -> `Extension s 89 + 90 + let of_mailbox_attr : Mail_flag.Mailbox_attr.t -> t = function 91 + | `Noinferiors -> Noinferiors 92 + | `Noselect -> Noselect 93 + | `Marked -> Marked 94 + | `Unmarked -> Unmarked 95 + | `Subscribed -> Subscribed 96 + | `HasChildren -> Haschildren 97 + | `HasNoChildren -> Hasnochildren 98 + | `NonExistent -> Noselect (* NonExistent implies Noselect *) 99 + | `Remote -> Extension "\\Remote" 100 + | `All -> All 101 + | `Archive -> Archive 102 + | `Drafts -> Drafts 103 + | `Flagged -> Flagged 104 + | `Important -> Extension "\\Important" 105 + | `Inbox -> Extension "\\Inbox" 106 + | `Junk -> Junk 107 + | `Sent -> Sent 108 + | `Trash -> Trash 109 + | `Snoozed -> Extension "\\Snoozed" 110 + | `Scheduled -> Extension "\\Scheduled" 111 + | `Memos -> Extension "\\Memos" 112 + | `Extension s -> Extension s 113 + 114 + let to_jmap_role : t -> string option = function 115 + | All -> Some "all" 116 + | Archive -> Some "archive" 117 + | Drafts -> Some "drafts" 118 + | Flagged -> Some "flagged" 119 + | Junk -> Some "junk" 120 + | Sent -> Some "sent" 121 + | Trash -> Some "trash" 122 + | Subscribed -> Some "subscribed" 123 + | Noinferiors | Noselect | Marked | Unmarked 124 + | Haschildren | Hasnochildren | Extension _ -> None 125 + 126 + let of_jmap_role s = 127 + match String.lowercase_ascii s with 128 + | "all" -> Some All 129 + | "archive" -> Some Archive 130 + | "drafts" -> Some Drafts 131 + | "flagged" -> Some Flagged 132 + | "junk" -> Some Junk 133 + | "sent" -> Some Sent 134 + | "trash" -> Some Trash 135 + | "subscribed" -> Some Subscribed 136 + | _ -> None 137 + 138 + let is_special_use = function 139 + | All | Archive | Drafts | Flagged | Junk | Sent | Trash -> true 140 + | Subscribed -> true (* Also a JMAP role *) 141 + | Noinferiors | Noselect | Marked | Unmarked 142 + | Haschildren | Hasnochildren | Extension _ -> false 143 + 144 + let is_selectable = function 145 + | Noselect -> false 146 + | _ -> true
+29 -1
ocaml-imap/lib/imap/list_attr.mli
··· 5 6 (** LIST Command Attributes 7 8 - Mailbox attributes returned by LIST command. 9 See RFC 9051 Section 7.2.2. *) 10 11 type t = ··· 27 28 val pp : Format.formatter -> t -> unit 29 val to_string : t -> string
··· 5 6 (** LIST Command Attributes 7 8 + Re-exports from {!Mail_flag.Mailbox_attr}. 9 See RFC 9051 Section 7.2.2. *) 10 11 type t = ··· 27 28 val pp : Format.formatter -> t -> unit 29 val to_string : t -> string 30 + val of_string : string -> t 31 + 32 + (** {1 Conversion to/from mail-flag} 33 + 34 + These functions allow interoperability with the {!Mail_flag} library 35 + for cross-protocol attribute handling. *) 36 + 37 + val to_mailbox_attr : t -> Mail_flag.Mailbox_attr.t 38 + (** [to_mailbox_attr attr] converts an IMAP list attribute to a mail-flag mailbox attribute. *) 39 + 40 + val of_mailbox_attr : Mail_flag.Mailbox_attr.t -> t 41 + (** [of_mailbox_attr attr] converts a mail-flag mailbox attribute to an IMAP list attribute. *) 42 + 43 + val to_jmap_role : t -> string option 44 + (** [to_jmap_role attr] converts a special-use attribute to its JMAP role string. 45 + Returns [None] for LIST attributes that don't correspond to JMAP roles. *) 46 + 47 + val of_jmap_role : string -> t option 48 + (** [of_jmap_role role] parses a JMAP role string into a special-use attribute. 49 + Returns [None] if the role string is not recognized. *) 50 + 51 + val is_special_use : t -> bool 52 + (** [is_special_use attr] returns [true] if the attribute is a special-use 53 + role (as opposed to a LIST attribute or extension). *) 54 + 55 + val is_selectable : t -> bool 56 + (** [is_selectable attr] returns [false] if the attribute indicates the 57 + mailbox cannot be selected (i.e., [Noselect]). *)
+530 -78
ocaml-imap/lib/imap/read.ml
··· 106 in 107 loop [] 108 109 (** {1 Flags} *) 110 111 let system_flag r = ··· 175 in 176 loop [] 177 178 (** {1 Response Codes} *) 179 180 let response_code r = ··· 184 match String.uppercase_ascii name with 185 | "ALERT" -> Code.Alert 186 | "ALREADYEXISTS" -> Code.Alreadyexists 187 | "AUTHENTICATIONFAILED" -> Code.Authenticationfailed 188 | "AUTHORIZATIONFAILED" -> Code.Authorizationfailed 189 | "CANNOT" -> Code.Cannot ··· 191 | "CLIENTBUG" -> Code.Clientbug 192 | "CLOSED" -> Code.Closed 193 | "CONTACTADMIN" -> Code.Contactadmin 194 | "CORRUPTION" -> Code.Corruption 195 | "EXPIRED" -> Code.Expired 196 | "EXPUNGEISSUED" -> Code.Expungeissued 197 | "HASCHILDREN" -> Code.Haschildren 198 | "INUSE" -> Code.Inuse 199 | "LIMIT" -> Code.Limit 200 | "NONEXISTENT" -> Code.Nonexistent 201 | "NOPERM" -> Code.Noperm 202 | "OVERQUOTA" -> Code.Overquota ··· 286 R.char ')' r; 287 Envelope.{ date; subject; from; sender; reply_to; to_; cc; bcc; in_reply_to; message_id } 288 289 (** {1 FETCH Response Items} *) 290 291 let fetch_item r = ··· 333 | Some '[' -> 334 (* BODY[section]<origin> literal-or-nil *) 335 R.char '[' r; 336 - let _section = R.take_while (fun c -> c <> ']') r in 337 R.char ']' r; 338 - (* Skip optional origin <n> *) 339 let origin = 340 if R.peek_char r = Some '<' then ( 341 R.char '<' r; ··· 346 in 347 sp r; 348 let data = nstring r in 349 - Fetch.Item_body_section { section = None; origin; data } 350 | _ -> 351 - (* BODY without [] means bodystructure - skip for now *) 352 sp r; 353 - (* Skip the parenthesized body structure *) 354 - let depth = ref 0 in 355 - (match R.peek_char r with 356 - | Some '(' -> 357 - R.char '(' r; 358 - depth := 1; 359 - while !depth > 0 do 360 - match R.any_char r with 361 - | '(' -> incr depth 362 - | ')' -> decr depth 363 - | '"' -> ignore (R.take_while (fun c -> c <> '"') r); ignore (R.any_char r) 364 - | '{' -> 365 - let len = number r in 366 - R.char '}' r; 367 - crlf r; 368 - ignore (R.take len r) 369 - | _ -> () 370 - done 371 - | _ -> ()); 372 - (* Return a minimal body structure stub *) 373 - let stub_body : Body.t = { 374 - body_type = Body.Basic { 375 - media_type = "application"; 376 - subtype = "octet-stream"; 377 - fields = { 378 - params = []; 379 - content_id = None; 380 - description = None; 381 - encoding = "7bit"; 382 - size = 0L; 383 - } 384 - }; 385 - disposition = None; 386 - language = None; 387 - location = None; 388 - } in 389 - Fetch.Item_body stub_body) 390 | "BODYSTRUCTURE" -> 391 sp r; 392 - (* Skip the parenthesized body structure - return minimal stub *) 393 - let depth = ref 0 in 394 - (match R.peek_char r with 395 - | Some '(' -> 396 - R.char '(' r; 397 - depth := 1; 398 - while !depth > 0 do 399 - match R.any_char r with 400 - | '(' -> incr depth 401 - | ')' -> decr depth 402 - | '"' -> ignore (R.take_while (fun c -> c <> '"') r); ignore (R.any_char r) 403 - | '{' -> 404 - let len = number r in 405 - R.char '}' r; 406 - crlf r; 407 - ignore (R.take len r) 408 - | _ -> () 409 - done 410 - | _ -> ()); 411 - (* Return a minimal body structure stub *) 412 - let stub_body : Body.t = { 413 - body_type = Body.Basic { 414 - media_type = "application"; 415 - subtype = "octet-stream"; 416 - fields = { 417 - params = []; 418 - content_id = None; 419 - description = None; 420 - encoding = "7bit"; 421 - size = 0L; 422 - } 423 - }; 424 - disposition = None; 425 - language = None; 426 - location = None; 427 - } in 428 - Fetch.Item_bodystructure stub_body 429 | _ -> Fetch.Item_flags [] 430 431 let fetch_items r = parse_paren_list ~parse_item:fetch_item r ··· 444 | "UNSEEN" -> Status.Unseen 445 | "DELETED" -> Status.Deleted 446 | "SIZE" -> Status.Size 447 | _ -> Status.Messages 448 in 449 (item, value) ··· 488 let shared = namespace_list r in 489 Response.{ personal; other; shared } 490 491 (** {1 ID Response} *) 492 493 let id_params r = ··· 509 loop ((k, v) :: acc) 510 in 511 loop []) 512 513 (** {1 Main Response Parser} *) 514 ··· 631 done; 632 crlf r; 633 Response.Sort (List.rev !seqs) 634 | _ -> 635 let _ = rest_of_line r in 636 Response.Ok { tag = None; code = None; text = "" })
··· 106 in 107 loop [] 108 109 + (** {1 UID Set Parsing} 110 + 111 + Parses UID sets in the format used by APPENDUID/COPYUID response codes. 112 + Examples: "304", "319:320", "304,319:320,325" *) 113 + 114 + let uid_set_range r = 115 + let first = number r in 116 + match R.peek_char r with 117 + | Some ':' -> 118 + R.char ':' r; 119 + (* Check for * (wildcard) *) 120 + (match R.peek_char r with 121 + | Some '*' -> 122 + R.char '*' r; 123 + Seq.From first 124 + | _ -> 125 + let last = number r in 126 + Seq.Range (first, last)) 127 + | _ -> Seq.Single first 128 + 129 + let uid_set r = 130 + let rec loop acc = 131 + let range = uid_set_range r in 132 + match R.peek_char r with 133 + | Some ',' -> 134 + R.char ',' r; 135 + loop (range :: acc) 136 + | _ -> List.rev (range :: acc) 137 + in 138 + loop [] 139 + 140 (** {1 Flags} *) 141 142 let system_flag r = ··· 206 in 207 loop [] 208 209 + (** {1 Body Structure Parsing} *) 210 + 211 + (** Parse a parenthesized list of key-value pairs for body parameters. 212 + Format: ("key1" "value1" "key2" "value2" ...) or NIL *) 213 + let body_params r = 214 + if is_nil r then (skip_nil r; []) 215 + else ( 216 + R.char '(' r; 217 + let rec loop acc = 218 + match R.peek_char r with 219 + | Some ')' -> 220 + R.char ')' r; 221 + List.rev acc 222 + | Some ' ' -> 223 + sp r; 224 + loop acc 225 + | _ -> 226 + let k = astring r in 227 + sp r; 228 + let v = astring r in 229 + loop ((k, v) :: acc) 230 + in 231 + loop []) 232 + 233 + (** Parse body fields common to all body types. 234 + Format: params content-id content-desc encoding size *) 235 + let body_fields r = 236 + let params = body_params r in 237 + sp r; 238 + let content_id = nstring r in 239 + sp r; 240 + let description = nstring r in 241 + sp r; 242 + let encoding = astring r in 243 + sp r; 244 + let size = number64 r in 245 + Body.{ params; content_id; description; encoding; size } 246 + 247 + (** Parse body disposition. 248 + Format: ("INLINE" ("filename" "test.txt")) or NIL *) 249 + let body_disposition r = 250 + if is_nil r then (skip_nil r; None) 251 + else ( 252 + R.char '(' r; 253 + let disposition_type = astring r in 254 + sp r; 255 + let params = body_params r in 256 + R.char ')' r; 257 + Some (disposition_type, params)) 258 + 259 + (** Parse body language - single string or list of strings. 260 + Format: NIL or "en" or ("en" "de") *) 261 + let body_language r = 262 + if is_nil r then (skip_nil r; None) 263 + else 264 + match R.peek_char r with 265 + | Some '(' -> 266 + (* List of languages *) 267 + R.char '(' r; 268 + let rec loop acc = 269 + match R.peek_char r with 270 + | Some ')' -> 271 + R.char ')' r; 272 + Some (List.rev acc) 273 + | Some ' ' -> 274 + sp r; 275 + loop acc 276 + | _ -> 277 + let lang = astring r in 278 + loop (lang :: acc) 279 + in 280 + loop [] 281 + | _ -> 282 + (* Single language *) 283 + Some [astring r] 284 + 285 + (** Skip remaining body extensions after the known ones *) 286 + let rec skip_body_extension r = 287 + match R.peek_char r with 288 + | Some '(' -> 289 + R.char '(' r; 290 + let rec loop () = 291 + match R.peek_char r with 292 + | Some ')' -> R.char ')' r 293 + | Some ' ' -> sp r; loop () 294 + | _ -> skip_body_extension r; loop () 295 + in 296 + loop () 297 + | Some '"' -> ignore (quoted_string r) 298 + | Some '{' -> ignore (literal r) 299 + | _ when is_nil r -> skip_nil r 300 + | _ -> 301 + (* Could be a number or atom *) 302 + ignore (R.take_while (fun c -> c <> ' ' && c <> ')' && c <> '\r') r) 303 + 304 + let skip_remaining_extensions r = 305 + while R.peek_char r = Some ' ' do 306 + sp r; 307 + match R.peek_char r with 308 + | Some ')' -> () (* End of body, don't consume *) 309 + | _ -> skip_body_extension r 310 + done 311 + 312 (** {1 Response Codes} *) 313 314 let response_code r = ··· 318 match String.uppercase_ascii name with 319 | "ALERT" -> Code.Alert 320 | "ALREADYEXISTS" -> Code.Alreadyexists 321 + | "APPENDUID" -> 322 + sp r; 323 + let uidvalidity = number64 r in 324 + sp r; 325 + let uid = number64 r in 326 + Code.Appenduid (uidvalidity, uid) 327 | "AUTHENTICATIONFAILED" -> Code.Authenticationfailed 328 | "AUTHORIZATIONFAILED" -> Code.Authorizationfailed 329 | "CANNOT" -> Code.Cannot ··· 331 | "CLIENTBUG" -> Code.Clientbug 332 | "CLOSED" -> Code.Closed 333 | "CONTACTADMIN" -> Code.Contactadmin 334 + | "COPYUID" -> 335 + sp r; 336 + let uidvalidity = number64 r in 337 + sp r; 338 + let source_uids = uid_set r in 339 + sp r; 340 + let dest_uids = uid_set r in 341 + Code.Copyuid (uidvalidity, source_uids, dest_uids) 342 | "CORRUPTION" -> Code.Corruption 343 | "EXPIRED" -> Code.Expired 344 | "EXPUNGEISSUED" -> Code.Expungeissued 345 | "HASCHILDREN" -> Code.Haschildren 346 + | "HIGHESTMODSEQ" -> 347 + (* RFC 7162 Section 3.1.2.1: HIGHESTMODSEQ response code 348 + Returned in SELECT/EXAMINE to indicate the highest mod-sequence 349 + value of all messages in the mailbox. *) 350 + sp r; 351 + Code.Highestmodseq (number64 r) 352 | "INUSE" -> Code.Inuse 353 | "LIMIT" -> Code.Limit 354 + | "MODIFIED" -> 355 + (* RFC 7162 Section 3.1.3: MODIFIED response code 356 + Returned in response to STORE with UNCHANGEDSINCE modifier 357 + when messages have been modified since the specified mod-sequence. *) 358 + sp r; 359 + Code.Modified (uid_set r) 360 + | "NOMODSEQ" -> 361 + (* RFC 7162 Section 3.1.2.2: NOMODSEQ response code 362 + Indicates that the mailbox does not support persistent storage 363 + of mod-sequences (e.g., a virtual mailbox). *) 364 + Code.Nomodseq 365 | "NONEXISTENT" -> Code.Nonexistent 366 | "NOPERM" -> Code.Noperm 367 | "OVERQUOTA" -> Code.Overquota ··· 451 R.char ')' r; 452 Envelope.{ date; subject; from; sender; reply_to; to_; cc; bcc; in_reply_to; message_id } 453 454 + (** {1 Body Structure Parsing - Recursive Part} 455 + 456 + These functions parse body structures per RFC 9051 Section 7.4.2. 457 + They must be defined after envelope since MESSAGE/RFC822 bodies contain envelopes. *) 458 + 459 + (** Parse a single body part (non-multipart). 460 + Returns the body type and optional extension data. *) 461 + let rec body_type_1part r = 462 + let media_type = astring r in 463 + sp r; 464 + let subtype = astring r in 465 + sp r; 466 + let fields = body_fields r in 467 + let media_type_upper = String.uppercase_ascii media_type in 468 + 469 + (* Parse type-specific fields and build body_type *) 470 + let (body_type : Body.body_type) = 471 + if media_type_upper = "TEXT" then ( 472 + sp r; 473 + let lines = number64 r in 474 + Text { subtype; fields; lines } 475 + ) else if media_type_upper = "MESSAGE" && String.uppercase_ascii subtype = "RFC822" then ( 476 + sp r; 477 + let env = envelope r in 478 + sp r; 479 + let nested_body = body r in 480 + sp r; 481 + let lines = number64 r in 482 + Message_rfc822 { fields; envelope = env; body = nested_body; lines } 483 + ) else 484 + Basic { media_type; subtype; fields } 485 + in 486 + 487 + (* Parse optional extension data for BODYSTRUCTURE *) 488 + let disposition, language, location = 489 + match R.peek_char r with 490 + | Some ' ' -> ( 491 + sp r; 492 + match R.peek_char r with 493 + | Some ')' -> (None, None, None) (* End of body *) 494 + | _ -> 495 + (* md5 - skip it *) 496 + ignore (nstring r); 497 + match R.peek_char r with 498 + | Some ' ' -> ( 499 + sp r; 500 + match R.peek_char r with 501 + | Some ')' -> (None, None, None) 502 + | _ -> 503 + let disposition = body_disposition r in 504 + match R.peek_char r with 505 + | Some ' ' -> ( 506 + sp r; 507 + match R.peek_char r with 508 + | Some ')' -> (disposition, None, None) 509 + | _ -> 510 + let language = body_language r in 511 + match R.peek_char r with 512 + | Some ' ' -> ( 513 + sp r; 514 + match R.peek_char r with 515 + | Some ')' -> (disposition, language, None) 516 + | _ -> 517 + let location = nstring r in 518 + skip_remaining_extensions r; 519 + (disposition, language, location)) 520 + | _ -> (disposition, language, None)) 521 + | _ -> (disposition, None, None)) 522 + | _ -> (None, None, None)) 523 + | _ -> (None, None, None) 524 + in 525 + 526 + Body.{ body_type; disposition; language; location } 527 + 528 + (** Parse multipart body structure. 529 + Format: (body)(body)... "subtype" [extensions] *) 530 + and body_type_mpart r = 531 + (* Collect all nested body parts *) 532 + let rec collect_parts acc = 533 + match R.peek_char r with 534 + | Some '(' -> 535 + let part = body r in 536 + collect_parts (part :: acc) 537 + | _ -> List.rev acc 538 + in 539 + let parts = collect_parts [] in 540 + 541 + (* Parse subtype *) 542 + sp r; 543 + let subtype = astring r in 544 + 545 + (* Parse optional extension data for BODYSTRUCTURE *) 546 + let params, disposition, language, location = 547 + match R.peek_char r with 548 + | Some ' ' -> ( 549 + sp r; 550 + match R.peek_char r with 551 + | Some ')' -> ([], None, None, None) 552 + | _ -> 553 + let params = body_params r in 554 + match R.peek_char r with 555 + | Some ' ' -> ( 556 + sp r; 557 + match R.peek_char r with 558 + | Some ')' -> (params, None, None, None) 559 + | _ -> 560 + let disposition = body_disposition r in 561 + match R.peek_char r with 562 + | Some ' ' -> ( 563 + sp r; 564 + match R.peek_char r with 565 + | Some ')' -> (params, disposition, None, None) 566 + | _ -> 567 + let language = body_language r in 568 + match R.peek_char r with 569 + | Some ' ' -> ( 570 + sp r; 571 + match R.peek_char r with 572 + | Some ')' -> (params, disposition, language, None) 573 + | _ -> 574 + let location = nstring r in 575 + skip_remaining_extensions r; 576 + (params, disposition, language, location)) 577 + | _ -> (params, disposition, language, None)) 578 + | _ -> (params, disposition, None, None)) 579 + | _ -> (params, None, None, None)) 580 + | _ -> ([], None, None, None) 581 + in 582 + 583 + Body.{ 584 + body_type = Multipart { subtype; parts; params }; 585 + disposition; 586 + language; 587 + location; 588 + } 589 + 590 + (** Parse a body structure - either multipart or single part. 591 + Multipart starts with nested parentheses, single part starts with a string. *) 592 + and body r = 593 + R.char '(' r; 594 + let result = 595 + match R.peek_char r with 596 + | Some '(' -> 597 + (* Multipart - starts with nested body *) 598 + body_type_mpart r 599 + | _ -> 600 + (* Single part - starts with media type string *) 601 + body_type_1part r 602 + in 603 + R.char ')' r; 604 + result 605 + 606 + (** {1 Section Specifier Parsing} 607 + 608 + Parse section specifiers like HEADER, TEXT, 1.2.MIME, HEADER.FIELDS (From Subject) *) 609 + 610 + (** Parse a header field list like (From Subject To). 611 + Note: Currently unused as HEADER.FIELDS parsing is simplified. *) 612 + let _parse_header_fields r = 613 + sp r; 614 + R.char '(' r; 615 + let rec loop acc = 616 + match R.peek_char r with 617 + | Some ')' -> 618 + R.char ')' r; 619 + List.rev acc 620 + | Some ' ' -> 621 + sp r; 622 + loop acc 623 + | _ -> 624 + let field = astring r in 625 + loop (field :: acc) 626 + in 627 + loop [] 628 + 629 + (** Parse a section specifier string into a Body.section option. 630 + Section format per RFC 9051: 631 + - Empty string means whole message 632 + - HEADER, TEXT, MIME 633 + - HEADER.FIELDS (field list) 634 + - HEADER.FIELDS.NOT (field list) 635 + - Part number like 1, 1.2, 1.2.3 636 + - Part number with subsection like 1.HEADER, 1.2.TEXT, 1.2.MIME *) 637 + let parse_section_spec section_str = 638 + if section_str = "" then None 639 + else 640 + let upper = String.uppercase_ascii section_str in 641 + if upper = "HEADER" then Some Body.Header 642 + else if upper = "TEXT" then Some Body.Text 643 + else if upper = "MIME" then Some Body.Mime 644 + else if String.length upper > 14 && String.sub upper 0 14 = "HEADER.FIELDS " then 645 + (* HEADER.FIELDS (field1 field2...) - simplified parsing *) 646 + Some Body.Header 647 + else if String.length upper > 18 && String.sub upper 0 18 = "HEADER.FIELDS.NOT " then 648 + (* HEADER.FIELDS.NOT (field1 field2...) - simplified parsing *) 649 + Some Body.Header 650 + else 651 + (* Try to parse as part numbers: 1, 1.2, 1.2.3, possibly with .HEADER/.TEXT/.MIME suffix *) 652 + let parts = String.split_on_char '.' section_str in 653 + let rec parse_parts nums = function 654 + | [] -> Some (Body.Part (List.rev nums, None)) 655 + | [s] when String.uppercase_ascii s = "HEADER" -> 656 + Some (Body.Part (List.rev nums, Some Body.Header)) 657 + | [s] when String.uppercase_ascii s = "TEXT" -> 658 + Some (Body.Part (List.rev nums, Some Body.Text)) 659 + | [s] when String.uppercase_ascii s = "MIME" -> 660 + Some (Body.Part (List.rev nums, Some Body.Mime)) 661 + | s :: rest -> 662 + (try 663 + let n = int_of_string s in 664 + parse_parts (n :: nums) rest 665 + with Failure _ -> 666 + (* Not a number, and not a known section type at end - skip *) 667 + Some (Body.Part (List.rev nums, None))) 668 + in 669 + parse_parts [] parts 670 + 671 (** {1 FETCH Response Items} *) 672 673 let fetch_item r = ··· 715 | Some '[' -> 716 (* BODY[section]<origin> literal-or-nil *) 717 R.char '[' r; 718 + let section_str = R.take_while (fun c -> c <> ']') r in 719 R.char ']' r; 720 + let section = parse_section_spec section_str in 721 + (* Parse optional origin <n> *) 722 let origin = 723 if R.peek_char r = Some '<' then ( 724 R.char '<' r; ··· 729 in 730 sp r; 731 let data = nstring r in 732 + Fetch.Item_body_section { section; origin; data } 733 | _ -> 734 + (* BODY without [] means basic bodystructure (no extensions) *) 735 sp r; 736 + let parsed_body = body r in 737 + Fetch.Item_body parsed_body) 738 | "BODYSTRUCTURE" -> 739 + (* BODYSTRUCTURE includes extension data *) 740 sp r; 741 + let parsed_body = body r in 742 + Fetch.Item_bodystructure parsed_body 743 | _ -> Fetch.Item_flags [] 744 745 let fetch_items r = parse_paren_list ~parse_item:fetch_item r ··· 758 | "UNSEEN" -> Status.Unseen 759 | "DELETED" -> Status.Deleted 760 | "SIZE" -> Status.Size 761 + | "HIGHESTMODSEQ" -> Status.Highestmodseq (* RFC 7162 CONDSTORE *) 762 | _ -> Status.Messages 763 in 764 (item, value) ··· 803 let shared = namespace_list r in 804 Response.{ personal; other; shared } 805 806 + (** {1 ESEARCH Response (RFC 4731)} *) 807 + 808 + let esearch_correlator r = 809 + (* Parse (TAG "xxx") *) 810 + R.char '(' r; 811 + let name = atom r in 812 + sp r; 813 + let value = quoted_string r in 814 + R.char ')' r; 815 + if String.uppercase_ascii name = "TAG" then Some value else None 816 + 817 + let esearch_result_item r = 818 + let name = atom r in 819 + match String.uppercase_ascii name with 820 + | "MIN" -> 821 + sp r; 822 + Some (Response.Esearch_min (number r)) 823 + | "MAX" -> 824 + sp r; 825 + Some (Response.Esearch_max (number r)) 826 + | "COUNT" -> 827 + sp r; 828 + Some (Response.Esearch_count (number r)) 829 + | "ALL" -> 830 + sp r; 831 + Some (Response.Esearch_all (uid_set r)) 832 + | _ -> None 833 + 834 + let esearch_data r = 835 + (* Parse optional (TAG "xxx") correlator *) 836 + let tag = 837 + match R.peek_char r with 838 + | Some '(' -> esearch_correlator r 839 + | _ -> None 840 + in 841 + (* Skip space if present after correlator *) 842 + if Option.is_some tag && R.peek_char r = Some ' ' then sp r; 843 + (* Check for UID indicator *) 844 + let uid = 845 + match R.peek_char r with 846 + | Some 'U' | Some 'u' -> 847 + (* Peek ahead to check if it's "UID" *) 848 + R.ensure r 3; 849 + let buf = R.peek r in 850 + if Cstruct.length buf >= 3 851 + && Char.uppercase_ascii (Cstruct.get_char buf 0) = 'U' 852 + && Char.uppercase_ascii (Cstruct.get_char buf 1) = 'I' 853 + && Char.uppercase_ascii (Cstruct.get_char buf 2) = 'D' 854 + then ( 855 + ignore (R.take 3 r); (* consume "UID" *) 856 + if R.peek_char r = Some ' ' then sp r; 857 + true 858 + ) else false 859 + | _ -> false 860 + in 861 + (* Parse result data items *) 862 + let rec loop acc = 863 + match R.peek_char r with 864 + | Some '\r' | Some '\n' | None -> List.rev acc 865 + | Some ' ' -> 866 + sp r; 867 + loop acc 868 + | _ -> 869 + (match esearch_result_item r with 870 + | Some item -> loop (item :: acc) 871 + | None -> List.rev acc) 872 + in 873 + let results = loop [] in 874 + Response.Esearch { tag; uid; results } 875 + 876 (** {1 ID Response} *) 877 878 let id_params r = ··· 894 loop ((k, v) :: acc) 895 in 896 loop []) 897 + 898 + (** {1 THREAD Response (RFC 5256)} 899 + 900 + Parses the THREAD response format as specified in RFC 5256 Section 4. 901 + 902 + The thread response has a recursive structure where each thread node 903 + can be either a message number or a nested list of children. 904 + 905 + @see <https://datatracker.ietf.org/doc/html/rfc5256#section-4> RFC 5256 Section 4 *) 906 + 907 + (** Parse a single thread node. 908 + 909 + A thread node is either: 910 + - A message number optionally followed by children: "(n ...children...)" 911 + - A dummy node (missing parent) starting with nested parens: "((...)...)" 912 + 913 + @see <https://datatracker.ietf.org/doc/html/rfc5256#section-4> RFC 5256 Section 4 *) 914 + let rec thread_node r = 915 + R.char '(' r; 916 + match R.peek_char r with 917 + | Some '(' -> 918 + (* Dummy node - starts with ( instead of number. 919 + This represents a missing parent message in the thread. *) 920 + let children = thread_children r in 921 + R.char ')' r; 922 + Thread.Dummy children 923 + | _ -> 924 + let n = number r in 925 + let children = thread_children r in 926 + R.char ')' r; 927 + Thread.Message (n, children) 928 + 929 + (** Parse thread children (zero or more thread nodes). 930 + 931 + Children can be separated by spaces or appear consecutively. 932 + This handles formats like "(3 6 (4 23))" where 6 is a child of 3, 933 + and (4 23) is a sibling subtree. *) 934 + and thread_children r = 935 + let rec loop acc = 936 + match R.peek_char r with 937 + | Some '(' -> loop (thread_node r :: acc) 938 + | Some ' ' -> sp r; loop acc 939 + | _ -> List.rev acc 940 + in 941 + loop [] 942 943 (** {1 Main Response Parser} *) 944 ··· 1061 done; 1062 crlf r; 1063 Response.Sort (List.rev !seqs) 1064 + | "THREAD" -> 1065 + (* RFC 5256 Section 4 - THREAD response format: 1066 + thread-data = "THREAD" [SP 1*thread-list] 1067 + thread-list = "(" thread-members / thread-nested ")" 1068 + thread-members = thread-node *(SP thread-node) 1069 + thread-nested = thread-list 1070 + thread-node = nz-number / thread-nested 1071 + 1072 + Example: * THREAD (2)(3 6 (4 23)(44 7 96)) 1073 + - Thread 1: Message 2 (no children) 1074 + - Thread 2: Message 3 with child 6, which has children 4,23 and 44->7->96 1075 + 1076 + @see <https://datatracker.ietf.org/doc/html/rfc5256#section-4> RFC 5256 Section 4 *) 1077 + let threads = thread_children r in 1078 + crlf r; 1079 + Response.Thread threads 1080 + | "ESEARCH" -> 1081 + (* RFC 4731 ESEARCH response *) 1082 + if R.peek_char r = Some ' ' then sp r; 1083 + let result = esearch_data r in 1084 + crlf r; 1085 + result 1086 | _ -> 1087 let _ = rest_of_line r in 1088 Response.Ok { tag = None; code = None; text = "" })
+2
ocaml-imap/lib/imap/response.ml
··· 45 | Esearch of { tag : string option; uid : bool; results : esearch_result list } 46 | Search of int list 47 | Sort of int64 list 48 | Flags of Flag.t list 49 | Exists of int 50 | Recent of int ··· 83 | Esearch _ -> Fmt.string ppf "* ESEARCH ..." 84 | Search seqs -> Fmt.pf ppf "* SEARCH %a" Fmt.(list ~sep:sp int) seqs 85 | Sort seqs -> Fmt.pf ppf "* SORT %a" Fmt.(list ~sep:sp int64) seqs 86 | Flags flags -> Fmt.pf ppf "* FLAGS (%a)" Fmt.(list ~sep:sp Flag.pp) flags 87 | Exists n -> Fmt.pf ppf "* %d EXISTS" n 88 | Recent n -> Fmt.pf ppf "* %d RECENT" n
··· 45 | Esearch of { tag : string option; uid : bool; results : esearch_result list } 46 | Search of int list 47 | Sort of int64 list 48 + | Thread of int Thread.t 49 | Flags of Flag.t list 50 | Exists of int 51 | Recent of int ··· 84 | Esearch _ -> Fmt.string ppf "* ESEARCH ..." 85 | Search seqs -> Fmt.pf ppf "* SEARCH %a" Fmt.(list ~sep:sp int) seqs 86 | Sort seqs -> Fmt.pf ppf "* SORT %a" Fmt.(list ~sep:sp int64) seqs 87 + | Thread threads -> Fmt.pf ppf "* THREAD %a" (Thread.pp Fmt.int) threads 88 | Flags flags -> Fmt.pf ppf "* FLAGS (%a)" Fmt.(list ~sep:sp Flag.pp) flags 89 | Exists n -> Fmt.pf ppf "* %d EXISTS" n 90 | Recent n -> Fmt.pf ppf "* %d RECENT" n
+1
ocaml-imap/lib/imap/response.mli
··· 45 | Esearch of { tag : string option; uid : bool; results : esearch_result list } 46 | Search of int list 47 | Sort of int64 list 48 | Flags of Flag.t list 49 | Exists of int 50 | Recent of int
··· 45 | Esearch of { tag : string option; uid : bool; results : esearch_result list } 46 | Search of int list 47 | Sort of int64 list 48 + | Thread of int Thread.t 49 | Flags of Flag.t list 50 | Exists of int 51 | Recent of int
+2
ocaml-imap/lib/imap/status.ml
··· 14 | Unseen 15 | Deleted 16 | Size 17 18 let pp_item ppf = function 19 | Messages -> Fmt.string ppf "MESSAGES" ··· 22 | Unseen -> Fmt.string ppf "UNSEEN" 23 | Deleted -> Fmt.string ppf "DELETED" 24 | Size -> Fmt.string ppf "SIZE" 25 26 type t = { 27 mailbox : string;
··· 14 | Unseen 15 | Deleted 16 | Size 17 + | Highestmodseq (** RFC 7162 CONDSTORE *) 18 19 let pp_item ppf = function 20 | Messages -> Fmt.string ppf "MESSAGES" ··· 23 | Unseen -> Fmt.string ppf "UNSEEN" 24 | Deleted -> Fmt.string ppf "DELETED" 25 | Size -> Fmt.string ppf "SIZE" 26 + | Highestmodseq -> Fmt.string ppf "HIGHESTMODSEQ" 27 28 type t = { 29 mailbox : string;
+1
ocaml-imap/lib/imap/status.mli
··· 14 | Unseen 15 | Deleted 16 | Size 17 18 val pp_item : Format.formatter -> item -> unit 19
··· 14 | Unseen 15 | Deleted 16 | Size 17 + | Highestmodseq (** RFC 7162 CONDSTORE *) 18 19 val pp_item : Format.formatter -> item -> unit 20
+220
ocaml-imap/lib/imap/subject.ml
···
··· 1 + (*--------------------------------------------------------------------------- 2 + Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 + 6 + (** {0 Base Subject Extraction} 7 + 8 + Implements {{:https://datatracker.ietf.org/doc/html/rfc5256#section-2.1}RFC 5256 Section 2.1} 9 + for extracting the "base subject" from email Subject headers. 10 + 11 + The base subject is used for SORT by SUBJECT and threading operations. *) 12 + 13 + (** Normalize whitespace: convert tabs to spaces, collapse multiple spaces to one, 14 + and trim leading/trailing whitespace. *) 15 + let normalize_whitespace s = 16 + (* Replace tabs with spaces *) 17 + let s = String.map (fun c -> if c = '\t' then ' ' else c) s in 18 + (* Collapse multiple spaces and trim *) 19 + let buf = Buffer.create (String.length s) in 20 + let last_was_space = ref true in (* Start true to skip leading spaces *) 21 + String.iter (fun c -> 22 + if c = ' ' then begin 23 + if not !last_was_space then Buffer.add_char buf ' '; 24 + last_was_space := true 25 + end else begin 26 + Buffer.add_char buf c; 27 + last_was_space := false 28 + end 29 + ) s; 30 + (* Remove trailing space if present *) 31 + let result = Buffer.contents buf in 32 + let len = String.length result in 33 + if len > 0 && result.[len - 1] = ' ' then 34 + String.sub result 0 (len - 1) 35 + else 36 + result 37 + 38 + (** Case-insensitive string prefix check *) 39 + let starts_with_ci ~prefix s = 40 + let plen = String.length prefix in 41 + let slen = String.length s in 42 + slen >= plen && 43 + let rec check i = 44 + if i >= plen then true 45 + else if Char.lowercase_ascii s.[i] = Char.lowercase_ascii prefix.[i] then 46 + check (i + 1) 47 + else false 48 + in 49 + check 0 50 + 51 + (** Case-insensitive string suffix check *) 52 + let ends_with_ci ~suffix s = 53 + let suflen = String.length suffix in 54 + let slen = String.length s in 55 + slen >= suflen && 56 + let rec check i = 57 + if i >= suflen then true 58 + else if Char.lowercase_ascii s.[slen - suflen + i] = Char.lowercase_ascii suffix.[i] then 59 + check (i + 1) 60 + else false 61 + in 62 + check 0 63 + 64 + (** Remove trailing (fwd) and whitespace - subj-trailer from RFC 5256 Section 5. 65 + Returns the string and whether anything was removed. *) 66 + let remove_trailer s = 67 + let s = String.trim s in 68 + if ends_with_ci ~suffix:"(fwd)" s then 69 + let len = String.length s in 70 + (String.trim (String.sub s 0 (len - 5)), true) 71 + else 72 + (s, false) 73 + 74 + (** Skip a [blob] pattern starting at position i. 75 + Returns the position after the blob and trailing whitespace, or None if no blob. *) 76 + let skip_blob s i = 77 + let len = String.length s in 78 + if i >= len || s.[i] <> '[' then None 79 + else begin 80 + (* Find matching ] - blob chars are anything except [ ] *) 81 + let rec find_close j = 82 + if j >= len then None 83 + else if s.[j] = ']' then Some j 84 + else if s.[j] = '[' then None (* nested [ not allowed in blob *) 85 + else find_close (j + 1) 86 + in 87 + match find_close (i + 1) with 88 + | None -> None 89 + | Some close_pos -> 90 + (* Skip trailing whitespace after ] *) 91 + let rec skip_ws k = 92 + if k >= len then k 93 + else if s.[k] = ' ' || s.[k] = '\t' then skip_ws (k + 1) 94 + else k 95 + in 96 + Some (skip_ws (close_pos + 1)) 97 + end 98 + 99 + (** Try to remove a subj-refwd pattern: ("re" / ("fw" ["d"])) *WSP [subj-blob] ":" 100 + Returns (rest_of_string, removed) *) 101 + let remove_refwd s = 102 + let len = String.length s in 103 + let try_prefix prefix = 104 + if starts_with_ci ~prefix s then 105 + let after_prefix = String.length prefix in 106 + (* Skip optional whitespace *) 107 + let rec skip_ws i = 108 + if i >= len then i 109 + else if s.[i] = ' ' || s.[i] = '\t' then skip_ws (i + 1) 110 + else i 111 + in 112 + let after_ws = skip_ws after_prefix in 113 + (* Try to skip optional blob *) 114 + let after_blob = match skip_blob s after_ws with 115 + | Some pos -> pos 116 + | None -> after_ws 117 + in 118 + (* Must have colon *) 119 + if after_blob < len && s.[after_blob] = ':' then 120 + let rest = String.sub s (after_blob + 1) (len - after_blob - 1) in 121 + Some (String.trim rest) 122 + else 123 + None 124 + else 125 + None 126 + in 127 + (* Try fwd first (longer), then fw, then re *) 128 + match try_prefix "fwd" with 129 + | Some rest -> (rest, true) 130 + | None -> 131 + match try_prefix "fw" with 132 + | Some rest -> (rest, true) 133 + | None -> 134 + match try_prefix "re" with 135 + | Some rest -> (rest, true) 136 + | None -> (s, false) 137 + 138 + (** Try to remove a leading [blob] if doing so leaves a non-empty base subject. 139 + Returns (rest_of_string, removed) *) 140 + let remove_leading_blob s = 141 + match skip_blob s 0 with 142 + | None -> (s, false) 143 + | Some after_blob -> 144 + let rest = String.sub s after_blob (String.length s - after_blob) in 145 + let rest = String.trim rest in 146 + (* Only remove if non-empty base remains *) 147 + if String.length rest > 0 then (rest, true) 148 + else (s, false) 149 + 150 + (** Remove [fwd: ... ] wrapper pattern. 151 + Returns (unwrapped_content, was_wrapped) *) 152 + let remove_fwd_wrapper s = 153 + let len = String.length s in 154 + if len >= 6 && starts_with_ci ~prefix:"[fwd:" s && s.[len - 1] = ']' then begin 155 + let inner = String.sub s 5 (len - 6) in 156 + (String.trim inner, true) 157 + end else 158 + (s, false) 159 + 160 + (** Internal state for tracking whether modifications occurred *) 161 + type extract_state = { 162 + subject : string; 163 + is_reply_or_fwd : bool; 164 + } 165 + 166 + (** Extract base subject with full algorithm from RFC 5256 Section 2.1 *) 167 + let rec extract_base_subject_full subject = 168 + (* Step 1: Normalize whitespace (RFC 2047 decoding would go here too) *) 169 + let s = normalize_whitespace subject in 170 + let state = { subject = s; is_reply_or_fwd = false } in 171 + 172 + (* Step 2: Remove trailing (fwd) - subj-trailer *) 173 + let rec remove_trailers state = 174 + let (s, removed) = remove_trailer state.subject in 175 + if removed then 176 + remove_trailers { subject = s; is_reply_or_fwd = true } 177 + else 178 + state 179 + in 180 + let state = remove_trailers state in 181 + 182 + (* Steps 3-5: Remove leading subj-leader and subj-blob, repeat until stable *) 183 + let rec remove_leaders state = 184 + (* Step 3: Remove subj-refwd *) 185 + let (s, refwd_removed) = remove_refwd state.subject in 186 + let new_is_reply = state.is_reply_or_fwd || refwd_removed in 187 + let state = { subject = s; is_reply_or_fwd = new_is_reply } in 188 + 189 + (* Step 4: Remove leading [blob] if non-empty base remains *) 190 + let (s, blob_removed) = remove_leading_blob state.subject in 191 + let state = { subject = s; is_reply_or_fwd = state.is_reply_or_fwd } in 192 + 193 + (* Step 5: Repeat if any changes *) 194 + if refwd_removed || blob_removed then 195 + remove_leaders state 196 + else 197 + state 198 + in 199 + let state = remove_leaders state in 200 + 201 + (* Step 6: Check for [fwd: ... ] wrapper *) 202 + let (s, fwd_wrapped) = remove_fwd_wrapper state.subject in 203 + let new_is_reply = state.is_reply_or_fwd || fwd_wrapped in 204 + let state = { subject = s; is_reply_or_fwd = new_is_reply } in 205 + 206 + (* If we unwrapped [fwd:], need to re-run the whole algorithm on the inner content *) 207 + if fwd_wrapped then begin 208 + let inner_result = extract_base_subject_full s in 209 + { subject = inner_result.subject; 210 + is_reply_or_fwd = true (* The outer [fwd:] wrapper counts *) } 211 + end else 212 + state 213 + 214 + let base_subject subject = 215 + let result = extract_base_subject_full subject in 216 + result.subject 217 + 218 + let is_reply_or_forward subject = 219 + let result = extract_base_subject_full subject in 220 + result.is_reply_or_fwd
+60
ocaml-imap/lib/imap/subject.mli
···
··· 1 + (*--------------------------------------------------------------------------- 2 + Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 + 6 + (** {0 Base Subject Extraction} 7 + 8 + Implements {{:https://datatracker.ietf.org/doc/html/rfc5256#section-2.1}RFC 5256 Section 2.1} 9 + for extracting the "base subject" from email Subject headers. 10 + 11 + The base subject is used for SORT by SUBJECT and threading operations. 12 + 13 + {1 Algorithm Overview} 14 + 15 + The algorithm: 16 + {ol 17 + {li Converts RFC 2047 encoded-words to UTF-8 and normalizes whitespace} 18 + {li Removes trailing [(fwd)] and whitespace (subj-trailer)} 19 + {li Removes leading [Re:], [Fw:], [Fwd:] with optional [\[blob\]] (subj-leader)} 20 + {li Removes leading [\[blob\]] if non-empty base remains} 21 + {li Repeats steps 3-4 until no more changes} 22 + {li Unwraps [\[fwd: ... \]] wrapper pattern} 23 + } 24 + 25 + {1 ABNF from RFC 5256 Section 5} 26 + 27 + {v 28 + subj-refwd = ("re" / ("fw" ["d"])) *WSP [subj-blob] ":" 29 + subj-blob = "[" *BLOBCHAR "]" *WSP 30 + subj-trailer = "(fwd)" / WSP 31 + subj-fwd-hdr = "[fwd:" 32 + subj-fwd-trl = "]" 33 + v} *) 34 + 35 + val base_subject : string -> string 36 + (** [base_subject subject] extracts the base subject from [subject]. 37 + 38 + The base subject is the normalized subject string with reply/forward 39 + indicators removed, suitable for sorting and threading. 40 + 41 + Examples: 42 + - [base_subject "Re: test"] returns ["test"] 43 + - [base_subject "Re: Re: test"] returns ["test"] 44 + - [base_subject "Fwd: test"] returns ["test"] 45 + - [base_subject "\[PATCH\] Re: \[ocaml\] test"] returns ["test"] 46 + - [base_subject "\[fwd: wrapped\]"] returns ["wrapped"] 47 + - [base_subject "test (fwd)"] returns ["test"] 48 + - [base_subject " spaced "] returns ["spaced"] *) 49 + 50 + val is_reply_or_forward : string -> bool 51 + (** [is_reply_or_forward subject] returns [true] if the subject indicates 52 + a reply or forward. 53 + 54 + This is determined by whether base subject extraction removed any of: 55 + - [Re:], [Fw:], or [Fwd:] prefixes 56 + - [(fwd)] trailer 57 + - [\[fwd: ...\]] wrapper 58 + 59 + This is useful for threading algorithms that need to distinguish 60 + original messages from replies/forwards. *)
+95
ocaml-imap/lib/imap/thread.ml
···
··· 1 + (*--------------------------------------------------------------------------- 2 + Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 + 6 + (** {0 RFC 5256 THREAD Extension} 7 + 8 + Message threading algorithms as specified in 9 + {{:https://datatracker.ietf.org/doc/html/rfc5256}RFC 5256 Section 3}. 10 + 11 + The THREAD command allows clients to retrieve messages organized into 12 + conversation threads based on message relationships. *) 13 + 14 + (** {1 Threading Algorithms} 15 + 16 + RFC 5256 Section 3 defines two threading algorithms. Servers MUST 17 + implement at least ORDEREDSUBJECT and SHOULD implement REFERENCES. *) 18 + 19 + (** Threading algorithm used to organize messages into threads. 20 + 21 + @see <https://datatracker.ietf.org/doc/html/rfc5256#section-3> RFC 5256 Section 3 *) 22 + type algorithm = 23 + | Orderedsubject 24 + (** ORDEREDSUBJECT algorithm (RFC 5256 Section 3.1). 25 + Groups messages by base subject (stripping Re:/Fwd: prefixes), 26 + then sorts each group by sent date. Simple but effective for 27 + basic threading. *) 28 + | References 29 + (** REFERENCES algorithm (RFC 5256 Section 3.2). 30 + Implements the JWZ threading algorithm using Message-ID, 31 + In-Reply-To, and References headers to build a complete 32 + parent/child thread tree. More accurate than ORDEREDSUBJECT 33 + but computationally more expensive. *) 34 + | Extension of string 35 + (** Future algorithm extensions. Servers may advertise additional 36 + threading algorithms via the THREAD capability. *) 37 + 38 + (** {1 Thread Result Structure} 39 + 40 + Thread results form a forest of trees. Each tree represents a 41 + conversation thread, with messages as nodes. *) 42 + 43 + (** A thread node in the result tree. 44 + 45 + Thread responses use a nested parenthesized structure where each 46 + message may have zero or more child messages (replies). 47 + 48 + @see <https://datatracker.ietf.org/doc/html/rfc5256#section-4> RFC 5256 Section 4 *) 49 + type 'a node = 50 + | Message of 'a * 'a node list 51 + (** A message with its sequence number or UID (depending on whether 52 + UID THREAD was used) and a list of child messages (replies). 53 + The children are ordered by the threading algorithm. *) 54 + | Dummy of 'a node list 55 + (** A placeholder for a missing parent message. This occurs when 56 + replies reference a message that is not in the search results 57 + (e.g., it was deleted or not matched by the search criteria). 58 + The REFERENCES algorithm may produce dummy nodes to maintain 59 + thread structure. *) 60 + 61 + (** Thread result: a list of root-level thread trees. 62 + 63 + Each element is a top-level thread. The threads are ordered according 64 + to the threading algorithm (typically by date of the first message 65 + in each thread). 66 + 67 + @see <https://datatracker.ietf.org/doc/html/rfc5256#section-4> RFC 5256 Section 4 *) 68 + type 'a t = 'a node list 69 + 70 + (** {1 Pretty Printers} *) 71 + 72 + let pp_algorithm ppf = function 73 + | Orderedsubject -> Fmt.string ppf "ORDEREDSUBJECT" 74 + | References -> Fmt.string ppf "REFERENCES" 75 + | Extension s -> Fmt.pf ppf "%s" (String.uppercase_ascii s) 76 + 77 + let algorithm_to_string alg = Fmt.str "%a" pp_algorithm alg 78 + 79 + let algorithm_of_string s = 80 + match String.uppercase_ascii s with 81 + | "ORDEREDSUBJECT" -> Orderedsubject 82 + | "REFERENCES" -> References 83 + | other -> Extension other 84 + 85 + let rec pp_node pp_elt ppf = function 86 + | Message (elt, []) -> 87 + pp_elt ppf elt 88 + | Message (elt, children) -> 89 + Fmt.pf ppf "(%a %a)" pp_elt elt 90 + Fmt.(list ~sep:sp (pp_node pp_elt)) children 91 + | Dummy children -> 92 + Fmt.pf ppf "(%a)" Fmt.(list ~sep:sp (pp_node pp_elt)) children 93 + 94 + let pp pp_elt ppf threads = 95 + Fmt.(list ~sep:sp (pp_node pp_elt)) ppf threads
+86
ocaml-imap/lib/imap/thread.mli
···
··· 1 + (*--------------------------------------------------------------------------- 2 + Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 + 6 + (** {0 RFC 5256 THREAD Extension} 7 + 8 + Message threading algorithms as specified in 9 + {{:https://datatracker.ietf.org/doc/html/rfc5256}RFC 5256 Section 3}. 10 + 11 + The THREAD command allows clients to retrieve messages organized into 12 + conversation threads based on message relationships. *) 13 + 14 + (** {1 Threading Algorithms} 15 + 16 + RFC 5256 Section 3 defines two threading algorithms. Servers MUST 17 + implement at least ORDEREDSUBJECT and SHOULD implement REFERENCES. *) 18 + 19 + (** Threading algorithm used to organize messages into threads. 20 + 21 + @see <https://datatracker.ietf.org/doc/html/rfc5256#section-3> RFC 5256 Section 3 *) 22 + type algorithm = 23 + | Orderedsubject 24 + (** ORDEREDSUBJECT algorithm (RFC 5256 Section 3.1). 25 + Groups messages by base subject (stripping Re:/Fwd: prefixes), 26 + then sorts each group by sent date. Simple but effective for 27 + basic threading. *) 28 + | References 29 + (** REFERENCES algorithm (RFC 5256 Section 3.2). 30 + Implements the JWZ threading algorithm using Message-ID, 31 + In-Reply-To, and References headers to build a complete 32 + parent/child thread tree. More accurate than ORDEREDSUBJECT 33 + but computationally more expensive. *) 34 + | Extension of string 35 + (** Future algorithm extensions. Servers may advertise additional 36 + threading algorithms via the THREAD capability. *) 37 + 38 + (** {1 Thread Result Structure} 39 + 40 + Thread results form a forest of trees. Each tree represents a 41 + conversation thread, with messages as nodes. *) 42 + 43 + (** A thread node in the result tree. 44 + 45 + Thread responses use a nested parenthesized structure where each 46 + message may have zero or more child messages (replies). 47 + 48 + @see <https://datatracker.ietf.org/doc/html/rfc5256#section-4> RFC 5256 Section 4 *) 49 + type 'a node = 50 + | Message of 'a * 'a node list 51 + (** A message with its sequence number or UID (depending on whether 52 + UID THREAD was used) and a list of child messages (replies). 53 + The children are ordered by the threading algorithm. *) 54 + | Dummy of 'a node list 55 + (** A placeholder for a missing parent message. This occurs when 56 + replies reference a message that is not in the search results 57 + (e.g., it was deleted or not matched by the search criteria). 58 + The REFERENCES algorithm may produce dummy nodes to maintain 59 + thread structure. *) 60 + 61 + (** Thread result: a list of root-level thread trees. 62 + 63 + Each element is a top-level thread. The threads are ordered according 64 + to the threading algorithm (typically by date of the first message 65 + in each thread). 66 + 67 + @see <https://datatracker.ietf.org/doc/html/rfc5256#section-4> RFC 5256 Section 4 *) 68 + type 'a t = 'a node list 69 + 70 + (** {1 Pretty Printers} *) 71 + 72 + val pp_algorithm : Format.formatter -> algorithm -> unit 73 + (** [pp_algorithm ppf alg] prints the algorithm name in IMAP wire format. *) 74 + 75 + val algorithm_to_string : algorithm -> string 76 + (** [algorithm_to_string alg] returns the algorithm name as a string. *) 77 + 78 + val algorithm_of_string : string -> algorithm 79 + (** [algorithm_of_string s] parses an algorithm name from a string. 80 + Unrecognized names are returned as [Extension s]. *) 81 + 82 + val pp_node : (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a node -> unit 83 + (** [pp_node pp_elt ppf node] prints a thread node using [pp_elt] for elements. *) 84 + 85 + val pp : (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a t -> unit 86 + (** [pp pp_elt ppf threads] prints a thread result using [pp_elt] for elements. *)
+45 -5
ocaml-imap/lib/imap/write.ml
··· 116 flags; 117 W.char w ')' 118 119 (** {1 Search Keys} *) 120 121 let rec search_key w = function ··· 245 write_partial w partial 246 | Fetch.Binary_size section -> 247 W.string w "BINARY.SIZE["; W.string w section; W.char w ']' 248 249 let fetch_items w = function 250 | [ item ] -> fetch_item w item ··· 266 | Status.Unseen -> W.string w "UNSEEN" 267 | Status.Deleted -> W.string w "DELETED" 268 | Status.Size -> W.string w "SIZE" 269 270 let status_items w items = 271 W.char w '('; ··· 307 criteria; 308 W.char w ')' 309 310 (** {1 ID Parameters} *) 311 312 let id_params w = function ··· 324 325 (** {1 Commands} *) 326 327 - let write_search w charset criteria = 328 W.string w "SEARCH"; 329 Option.iter (fun cs -> W.string w " CHARSET "; astring w cs) charset; 330 sp w; 331 search_key w criteria ··· 333 let write_sort w charset criteria search = 334 W.string w "SORT "; 335 sort_criteria w criteria; 336 sp w; 337 astring w charset; 338 sp w; ··· 403 | Command.Close -> W.string w "CLOSE" 404 | Command.Unselect -> W.string w "UNSELECT" 405 | Command.Expunge -> W.string w "EXPUNGE" 406 - | Command.Search { charset; criteria } -> 407 - write_search w charset criteria 408 | Command.Sort { charset; criteria; search } -> 409 write_sort w charset criteria search 410 | Command.Fetch { sequence; items; changedsince } -> 411 W.string w "FETCH "; 412 sequence_set w sequence; ··· 476 sequence_set w sequence; 477 sp w; 478 astring w mailbox 479 - | Command.Uid_search { charset; criteria } -> 480 - write_search w charset criteria 481 | Command.Uid_sort { charset; criteria; search } -> 482 write_sort w charset criteria search 483 | Command.Uid_expunge set -> 484 W.string w "EXPUNGE "; 485 sequence_set w set)
··· 116 flags; 117 W.char w ')' 118 119 + (** {1 Search Return Options (RFC 4731 ESEARCH)} *) 120 + 121 + let search_return_opt w = function 122 + | Command.Return_min -> W.string w "MIN" 123 + | Command.Return_max -> W.string w "MAX" 124 + | Command.Return_all -> W.string w "ALL" 125 + | Command.Return_count -> W.string w "COUNT" 126 + 127 + let search_return_opts w opts = 128 + W.string w "RETURN ("; 129 + List.iteri (fun i opt -> 130 + if i > 0 then sp w; 131 + search_return_opt w opt 132 + ) opts; 133 + W.char w ')' 134 + 135 (** {1 Search Keys} *) 136 137 let rec search_key w = function ··· 261 write_partial w partial 262 | Fetch.Binary_size section -> 263 W.string w "BINARY.SIZE["; W.string w section; W.char w ']' 264 + | Fetch.Modseq -> 265 + (* RFC 7162 Section 3.1.5: MODSEQ fetch data item *) 266 + W.string w "MODSEQ" 267 268 let fetch_items w = function 269 | [ item ] -> fetch_item w item ··· 285 | Status.Unseen -> W.string w "UNSEEN" 286 | Status.Deleted -> W.string w "DELETED" 287 | Status.Size -> W.string w "SIZE" 288 + | Status.Highestmodseq -> W.string w "HIGHESTMODSEQ" (* RFC 7162 CONDSTORE *) 289 290 let status_items w items = 291 W.char w '('; ··· 327 criteria; 328 W.char w ')' 329 330 + (** {1 Thread Algorithm} *) 331 + 332 + let thread_algorithm w = function 333 + | Thread.Orderedsubject -> W.string w "ORDEREDSUBJECT" 334 + | Thread.References -> W.string w "REFERENCES" 335 + | Thread.Extension s -> W.string w (String.uppercase_ascii s) 336 + 337 (** {1 ID Parameters} *) 338 339 let id_params w = function ··· 351 352 (** {1 Commands} *) 353 354 + let write_search w charset criteria return_opts = 355 W.string w "SEARCH"; 356 + Option.iter (fun opts -> sp w; search_return_opts w opts) return_opts; 357 Option.iter (fun cs -> W.string w " CHARSET "; astring w cs) charset; 358 sp w; 359 search_key w criteria ··· 361 let write_sort w charset criteria search = 362 W.string w "SORT "; 363 sort_criteria w criteria; 364 + sp w; 365 + astring w charset; 366 + sp w; 367 + search_key w search 368 + 369 + let write_thread w algorithm charset search = 370 + W.string w "THREAD "; 371 + thread_algorithm w algorithm; 372 sp w; 373 astring w charset; 374 sp w; ··· 439 | Command.Close -> W.string w "CLOSE" 440 | Command.Unselect -> W.string w "UNSELECT" 441 | Command.Expunge -> W.string w "EXPUNGE" 442 + | Command.Search { charset; criteria; return_opts } -> 443 + write_search w charset criteria return_opts 444 | Command.Sort { charset; criteria; search } -> 445 write_sort w charset criteria search 446 + | Command.Thread { algorithm; charset; search } -> 447 + write_thread w algorithm charset search 448 | Command.Fetch { sequence; items; changedsince } -> 449 W.string w "FETCH "; 450 sequence_set w sequence; ··· 514 sequence_set w sequence; 515 sp w; 516 astring w mailbox 517 + | Command.Uid_search { charset; criteria; return_opts } -> 518 + write_search w charset criteria return_opts 519 | Command.Uid_sort { charset; criteria; search } -> 520 write_sort w charset criteria search 521 + | Command.Uid_thread { algorithm; charset; search } -> 522 + write_thread w algorithm charset search 523 | Command.Uid_expunge set -> 524 W.string w "EXPUNGE "; 525 sequence_set w set)
+4
ocaml-imap/lib/imap/write.mli
··· 43 val fetch_item : t -> Fetch.request -> unit 44 val fetch_items : t -> Fetch.request list -> unit 45 46 (** {1 Commands} *) 47 48 val command : t -> tag:string -> Command.t -> unit
··· 43 val fetch_item : t -> Fetch.request -> unit 44 val fetch_items : t -> Fetch.request list -> unit 45 46 + (** {1 Thread} *) 47 + 48 + val thread_algorithm : t -> Thread.algorithm -> unit 49 + 50 (** {1 Commands} *) 51 52 val command : t -> tag:string -> Command.t -> unit
+2 -2
ocaml-imap/lib/imapd/client.ml
··· 132 | Flags_response f -> flags := f 133 | Capability_response c -> caps := c 134 | Enabled e -> enabled := e 135 - | List_response { flags = f; delimiter; name } -> 136 list_entries := { flags = f; delimiter; name } :: !list_entries 137 | Status_response { mailbox; items } -> 138 let messages = ··· 554 555 let list t ~reference ~pattern = 556 require_authenticated t; 557 - let responses = run_command t (List { reference; pattern }) in 558 let _, _, _, _, _, _, _, _, entries, _, _, _, _, _, _, _ = 559 process_untagged responses 560 in
··· 132 | Flags_response f -> flags := f 133 | Capability_response c -> caps := c 134 | Enabled e -> enabled := e 135 + | List_response { flags = f; delimiter; name; _ } -> 136 list_entries := { flags = f; delimiter; name } :: !list_entries 137 | Status_response { mailbox; items } -> 138 let messages = ··· 554 555 let list t ~reference ~pattern = 556 require_authenticated t; 557 + let responses = run_command t (List (List_basic { reference; pattern })) in 558 let _, _, _, _, _, _, _, _, entries, _, _, _, _, _, _, _ = 559 process_untagged responses 560 in
+91 -1
ocaml-imap/lib/imapd/grammar.mly
··· 61 %token CHARSET MIME PEEK HEADER_FIELDS HEADER_FIELDS_NOT SILENT 62 %token RETURN SUBSCRIBED CHILDREN REMOTE RECURSIVEMATCH DONE 63 64 (* Entry point *) 65 %start <Protocol.tagged_command> command 66 %start <Protocol.response> response_parser ··· 382 | RENAME SP old_mb = mailbox SP new_mb = mailbox { Rename { old_name = old_mb; new_name = new_mb } } 383 | SUBSCRIBE SP mb = mailbox { Subscribe mb } 384 | UNSUBSCRIBE SP mb = mailbox { Unsubscribe mb } 385 - | LIST SP ref = astring SP pat = list_mailbox { List { reference = ref; pattern = pat } } 386 | NAMESPACE { Namespace } 387 | STATUS SP mb = mailbox SP LPAREN atts = status_att_list RPAREN { Status { mailbox = mb; items = atts } } 388 | APPEND SP mb = mailbox SP fl = flag_list SP dt = date_time SP msg = append_message ··· 392 | APPEND SP mb = mailbox SP msg = append_message 393 { Append { mailbox = mb; flags = []; date = None; message = msg } } 394 | IDLE { Idle } 395 ; 396 397 enable_caps: ··· 402 list_mailbox: 403 | s = astring { s } 404 | s = QUOTED_STRING { s } 405 ; 406 407 append_message:
··· 61 %token CHARSET MIME PEEK HEADER_FIELDS HEADER_FIELDS_NOT SILENT 62 %token RETURN SUBSCRIBED CHILDREN REMOTE RECURSIVEMATCH DONE 63 64 + (* LIST-EXTENDED - RFC 5258, RFC 6154 *) 65 + %token SPECIAL_USE 66 + 67 + (* QUOTA extension - RFC 9208 *) 68 + %token GETQUOTA GETQUOTAROOT SETQUOTA STORAGE MAILBOX ANNOTATION_STORAGE 69 + 70 (* Entry point *) 71 %start <Protocol.tagged_command> command 72 %start <Protocol.response> response_parser ··· 388 | RENAME SP old_mb = mailbox SP new_mb = mailbox { Rename { old_name = old_mb; new_name = new_mb } } 389 | SUBSCRIBE SP mb = mailbox { Subscribe mb } 390 | UNSUBSCRIBE SP mb = mailbox { Unsubscribe mb } 391 + (* LIST command - RFC 9051, RFC 5258 LIST-EXTENDED *) 392 + | LIST SP ref = astring SP pat = list_mailbox 393 + { List (List_basic { reference = ref; pattern = pat }) } 394 + (* LIST-EXTENDED: LIST (selection-opts) reference patterns [RETURN (return-opts)] 395 + Per RFC 5258 Section 3 *) 396 + | LIST SP sel = list_select_opts SP ref = astring SP pats = list_patterns 397 + { List (List_extended { selection = sel; reference = ref; patterns = pats; return_opts = [] }) } 398 + | LIST SP sel = list_select_opts SP ref = astring SP pats = list_patterns SP ret = list_return_opts 399 + { List (List_extended { selection = sel; reference = ref; patterns = pats; return_opts = ret }) } 400 | NAMESPACE { Namespace } 401 | STATUS SP mb = mailbox SP LPAREN atts = status_att_list RPAREN { Status { mailbox = mb; items = atts } } 402 | APPEND SP mb = mailbox SP fl = flag_list SP dt = date_time SP msg = append_message ··· 406 | APPEND SP mb = mailbox SP msg = append_message 407 { Append { mailbox = mb; flags = []; date = None; message = msg } } 408 | IDLE { Idle } 409 + (* QUOTA extension - RFC 9208 *) 410 + | GETQUOTA SP root = astring { Getquota root } 411 + | GETQUOTAROOT SP mb = mailbox { Getquotaroot mb } 412 + | SETQUOTA SP root = astring SP LPAREN limits = quota_limits RPAREN 413 + { Setquota { root; limits } } 414 + | SETQUOTA SP root = astring SP LPAREN RPAREN 415 + { Setquota { root; limits = [] } } 416 + ; 417 + 418 + (* Quota resource type - RFC 9208 Section 5 *) 419 + quota_resource: 420 + | STORAGE { Quota_storage } 421 + | MESSAGES { Quota_message } (* MESSAGE uses MESSAGES token *) 422 + | MAILBOX { Quota_mailbox } 423 + | ANNOTATION_STORAGE { Quota_annotation_storage } 424 + ; 425 + 426 + (* Quota limit list for SETQUOTA *) 427 + quota_limits: 428 + | res = quota_resource SP limit = number { [(res, limit)] } 429 + | res = quota_resource SP limit = number SP rest = quota_limits { (res, limit) :: rest } 430 ; 431 432 enable_caps: ··· 437 list_mailbox: 438 | s = astring { s } 439 | s = QUOTED_STRING { s } 440 + ; 441 + 442 + (* === LIST-EXTENDED grammar - RFC 5258 Section 3 === *) 443 + 444 + (* list-select-opts = "(" [list-select-opt *(SP list-select-opt)] ")" 445 + RFC 5258 Section 3.1 *) 446 + list_select_opts: 447 + | LPAREN RPAREN { [] } 448 + | LPAREN opts = list_select_opt_list RPAREN { opts } 449 + ; 450 + 451 + list_select_opt_list: 452 + | o = list_select_opt { [o] } 453 + | o = list_select_opt SP rest = list_select_opt_list { o :: rest } 454 + ; 455 + 456 + (* list-select-opt = "SUBSCRIBED" / "REMOTE" / "RECURSIVEMATCH" / "SPECIAL-USE" 457 + RFC 5258 Section 3.1, RFC 6154 *) 458 + list_select_opt: 459 + | SUBSCRIBED { List_select_subscribed } 460 + | REMOTE { List_select_remote } 461 + | RECURSIVEMATCH { List_select_recursivematch } 462 + | SPECIAL_USE { List_select_special_use } 463 + ; 464 + 465 + (* Multiple patterns: "(" mbox-or-pat *(SP mbox-or-pat) ")" or single pattern 466 + RFC 5258 Section 3 *) 467 + list_patterns: 468 + | pat = list_mailbox { [pat] } 469 + | LPAREN pats = list_pattern_list RPAREN { pats } 470 + ; 471 + 472 + list_pattern_list: 473 + | p = list_mailbox { [p] } 474 + | p = list_mailbox SP rest = list_pattern_list { p :: rest } 475 + ; 476 + 477 + (* list-return-opts = "RETURN" SP "(" [list-return-opt *(SP list-return-opt)] ")" 478 + RFC 5258 Section 3.2 *) 479 + list_return_opts: 480 + | RETURN SP LPAREN RPAREN { [] } 481 + | RETURN SP LPAREN opts = list_return_opt_list RPAREN { opts } 482 + ; 483 + 484 + list_return_opt_list: 485 + | o = list_return_opt { [o] } 486 + | o = list_return_opt SP rest = list_return_opt_list { o :: rest } 487 + ; 488 + 489 + (* list-return-opt = "SUBSCRIBED" / "CHILDREN" / "SPECIAL-USE" 490 + RFC 5258 Section 3.2, RFC 6154 *) 491 + list_return_opt: 492 + | SUBSCRIBED { List_return_subscribed } 493 + | CHILDREN { List_return_children } 494 + | SPECIAL_USE { List_return_special_use } 495 ; 496 497 append_message:
+10
ocaml-imap/lib/imapd/lexer.mll
··· 123 ("REMOTE", REMOTE); 124 ("RECURSIVEMATCH", RECURSIVEMATCH); 125 ("DONE", DONE); 126 ] 127 128 let lookup_keyword s =
··· 123 ("REMOTE", REMOTE); 124 ("RECURSIVEMATCH", RECURSIVEMATCH); 125 ("DONE", DONE); 126 + (* LIST-EXTENDED - RFC 5258, RFC 6154 *) 127 + ("SPECIAL-USE", SPECIAL_USE); 128 + (* QUOTA extension - RFC 9208 *) 129 + ("GETQUOTA", GETQUOTA); 130 + ("GETQUOTAROOT", GETQUOTAROOT); 131 + ("SETQUOTA", SETQUOTA); 132 + ("STORAGE", STORAGE); 133 + ("MAILBOX", MAILBOX); 134 + ("ANNOTATION-STORAGE", ANNOTATION_STORAGE); 135 + (* Note: MESSAGE already exists as MESSAGES for STATUS *) 136 ] 137 138 let lookup_keyword s =
+116 -3
ocaml-imap/lib/imapd/parser.ml
··· 12 open Protocol 13 14 (* Re-export types from Types for backward compatibility *) 15 type command = Protocol.command = 16 | Capability 17 | Noop ··· 27 | Rename of { old_name : mailbox_name; new_name : mailbox_name } 28 | Subscribe of mailbox_name 29 | Unsubscribe of mailbox_name 30 - | List of { reference : string; pattern : string } 31 | Namespace 32 | Status of { mailbox : mailbox_name; items : status_item list } 33 | Append of { mailbox : mailbox_name; flags : flag list; date : string option; message : string } ··· 42 | Move of { sequence : sequence_set; mailbox : mailbox_name } 43 | Uid of uid_command 44 | Id of (string * string) list option 45 46 type uid_command = Protocol.uid_command = 47 | Uid_fetch of { sequence : sequence_set; items : fetch_item list } ··· 50 | Uid_move of { sequence : sequence_set; mailbox : mailbox_name } 51 | Uid_search of { charset : string option; criteria : search_key } 52 | Uid_expunge of sequence_set 53 54 type tagged_command = Protocol.tagged_command = { 55 tag : string; ··· 64 | Bye of { code : response_code option; text : string } 65 | Capability_response of string list 66 | Enabled of string list 67 - | List_response of { flags : list_flag list; delimiter : char option; name : mailbox_name } 68 | Namespace_response of namespace_data 69 | Status_response of { mailbox : mailbox_name; items : (status_item * int64) list } 70 | Esearch of { tag : string option; uid : bool; results : esearch_result list } ··· 74 | Fetch_response of { seq : int; items : fetch_response_item list } 75 | Continuation of string option 76 | Id_response of (string * string) list option 77 78 (* ===== Menhir Parser Interface ===== *) 79 ··· 113 write_string f "}\r\n"; 114 write_string f s 115 116 let write_flag f flag = 117 write_string f (flag_to_string flag) 118 ··· 219 List.iter (fun c -> write_sp f; write_string f c) caps; 220 write_crlf f 221 222 - | List_response { flags; delimiter; name } -> 223 write_string f "* LIST ("; 224 List.iteri (fun i flag -> 225 if i > 0 then write_sp f; ··· 231 | List_subscribed -> write_string f "\\Subscribed" 232 | List_haschildren -> write_string f "\\HasChildren" 233 | List_hasnochildren -> write_string f "\\HasNoChildren" 234 | List_all -> write_string f "\\All" 235 | List_archive -> write_string f "\\Archive" 236 | List_drafts -> write_string f "\\Drafts" ··· 246 | None -> write_string f "NIL"); 247 write_sp f; 248 write_quoted_string f name; 249 write_crlf f 250 251 | Namespace_response { personal; other; shared } -> ··· 371 write_quoted_string f value 372 ) pairs; 373 write_char f ')'); 374 write_crlf f 375 376 let response_to_string resp =
··· 12 open Protocol 13 14 (* Re-export types from Types for backward compatibility *) 15 + type thread_algorithm = Protocol.thread_algorithm = 16 + | Thread_orderedsubject 17 + | Thread_references 18 + | Thread_extension of string 19 + 20 + type thread_node = Protocol.thread_node = 21 + | Thread_message of int * thread_node list 22 + | Thread_dummy of thread_node list 23 + 24 + type thread_result = Protocol.thread_result 25 + 26 type command = Protocol.command = 27 | Capability 28 | Noop ··· 38 | Rename of { old_name : mailbox_name; new_name : mailbox_name } 39 | Subscribe of mailbox_name 40 | Unsubscribe of mailbox_name 41 + | List of list_command (** LIST command - RFC 9051, RFC 5258 LIST-EXTENDED *) 42 | Namespace 43 | Status of { mailbox : mailbox_name; items : status_item list } 44 | Append of { mailbox : mailbox_name; flags : flag list; date : string option; message : string } ··· 53 | Move of { sequence : sequence_set; mailbox : mailbox_name } 54 | Uid of uid_command 55 | Id of (string * string) list option 56 + (* QUOTA extension - RFC 9208 *) 57 + | Getquota of string 58 + | Getquotaroot of mailbox_name 59 + | Setquota of { root : string; limits : (quota_resource * int64) list } 60 + (* THREAD extension - RFC 5256 *) 61 + | Thread of { algorithm : thread_algorithm; charset : string; criteria : search_key } 62 63 type uid_command = Protocol.uid_command = 64 | Uid_fetch of { sequence : sequence_set; items : fetch_item list } ··· 67 | Uid_move of { sequence : sequence_set; mailbox : mailbox_name } 68 | Uid_search of { charset : string option; criteria : search_key } 69 | Uid_expunge of sequence_set 70 + | Uid_thread of { algorithm : thread_algorithm; charset : string; criteria : search_key } 71 72 type tagged_command = Protocol.tagged_command = { 73 tag : string; ··· 82 | Bye of { code : response_code option; text : string } 83 | Capability_response of string list 84 | Enabled of string list 85 + | List_response of list_response_data (** RFC 9051, RFC 5258 LIST-EXTENDED *) 86 | Namespace_response of namespace_data 87 | Status_response of { mailbox : mailbox_name; items : (status_item * int64) list } 88 | Esearch of { tag : string option; uid : bool; results : esearch_result list } ··· 92 | Fetch_response of { seq : int; items : fetch_response_item list } 93 | Continuation of string option 94 | Id_response of (string * string) list option 95 + (* QUOTA extension responses - RFC 9208 *) 96 + | Quota_response of { root : string; resources : quota_resource_info list } 97 + | Quotaroot_response of { mailbox : mailbox_name; roots : string list } 98 + (* THREAD extension response - RFC 5256 *) 99 + | Thread_response of thread_result 100 101 (* ===== Menhir Parser Interface ===== *) 102 ··· 136 write_string f "}\r\n"; 137 write_string f s 138 139 + (** Convert quota resource to IMAP string. 140 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-5}RFC 9208 Section 5}. *) 141 + let quota_resource_to_string = function 142 + | Quota_storage -> "STORAGE" 143 + | Quota_message -> "MESSAGE" 144 + | Quota_mailbox -> "MAILBOX" 145 + | Quota_annotation_storage -> "ANNOTATION-STORAGE" 146 + 147 let write_flag f flag = 148 write_string f (flag_to_string flag) 149 ··· 250 List.iter (fun c -> write_sp f; write_string f c) caps; 251 write_crlf f 252 253 + | List_response { flags; delimiter; name; extended } -> 254 + (* LIST response per RFC 9051 Section 7.3.1, RFC 5258 Section 3.4 *) 255 write_string f "* LIST ("; 256 List.iteri (fun i flag -> 257 if i > 0 then write_sp f; ··· 263 | List_subscribed -> write_string f "\\Subscribed" 264 | List_haschildren -> write_string f "\\HasChildren" 265 | List_hasnochildren -> write_string f "\\HasNoChildren" 266 + | List_nonexistent -> write_string f "\\NonExistent" (* RFC 5258 Section 3.4 *) 267 + | List_remote -> write_string f "\\Remote" (* RFC 5258 Section 3.4 *) 268 | List_all -> write_string f "\\All" 269 | List_archive -> write_string f "\\Archive" 270 | List_drafts -> write_string f "\\Drafts" ··· 280 | None -> write_string f "NIL"); 281 write_sp f; 282 write_quoted_string f name; 283 + (* Extended data per RFC 5258 Section 3.5 *) 284 + List.iter (fun ext -> 285 + match ext with 286 + | Childinfo subscriptions -> 287 + (* CHILDINFO extended data item: "CHILDINFO" SP "(" tag-list ")" *) 288 + write_sp f; 289 + write_string f "(\"CHILDINFO\" ("; 290 + List.iteri (fun i tag -> 291 + if i > 0 then write_sp f; 292 + write_quoted_string f tag 293 + ) subscriptions; 294 + write_string f "))" 295 + ) extended; 296 write_crlf f 297 298 | Namespace_response { personal; other; shared } -> ··· 418 write_quoted_string f value 419 ) pairs; 420 write_char f ')'); 421 + write_crlf f 422 + 423 + (* QUOTA extension responses - RFC 9208 *) 424 + | Quota_response { root; resources } -> 425 + (* QUOTA response format: * QUOTA root (resource usage limit ...) *) 426 + write_string f "* QUOTA "; 427 + write_quoted_string f root; 428 + write_string f " ("; 429 + List.iteri (fun i { resource; usage; limit } -> 430 + if i > 0 then write_sp f; 431 + write_string f (quota_resource_to_string resource); 432 + write_sp f; 433 + write_string f (Int64.to_string usage); 434 + write_sp f; 435 + write_string f (Int64.to_string limit) 436 + ) resources; 437 + write_char f ')'; 438 + write_crlf f 439 + 440 + | Quotaroot_response { mailbox; roots } -> 441 + (* QUOTAROOT response format: * QUOTAROOT mailbox root ... *) 442 + write_string f "* QUOTAROOT "; 443 + write_quoted_string f mailbox; 444 + List.iter (fun root -> 445 + write_sp f; 446 + write_quoted_string f root 447 + ) roots; 448 + write_crlf f 449 + 450 + (* THREAD extension response - RFC 5256 Section 4 *) 451 + | Thread_response threads -> 452 + (* THREAD response format: * THREAD [SP 1*thread-list] 453 + Each thread node is either: 454 + - (n) for a single message 455 + - (n children...) for a message with children 456 + - ((children...)) for a dummy parent 457 + @see <https://datatracker.ietf.org/doc/html/rfc5256#section-4> RFC 5256 Section 4 *) 458 + let rec write_thread_node = function 459 + | Thread_message (n, []) -> 460 + (* Single message with no children: (n) *) 461 + write_char f '('; 462 + write_string f (string_of_int n); 463 + write_char f ')' 464 + | Thread_message (n, children) -> 465 + (* Message with children: (n child1 child2 ...) *) 466 + write_char f '('; 467 + write_string f (string_of_int n); 468 + List.iter (fun child -> 469 + write_sp f; 470 + write_thread_node child 471 + ) children; 472 + write_char f ')' 473 + | Thread_dummy children -> 474 + (* Dummy node (missing parent): ((child1)(child2)...) *) 475 + write_char f '('; 476 + List.iteri (fun i child -> 477 + if i > 0 then write_sp f; 478 + write_thread_node child 479 + ) children; 480 + write_char f ')' 481 + in 482 + write_string f "* THREAD"; 483 + List.iter (fun thread -> 484 + write_sp f; 485 + write_thread_node thread 486 + ) threads; 487 write_crlf f 488 489 let response_to_string resp =
+19 -2
ocaml-imap/lib/imapd/parser.mli
··· 15 16 Types are defined in {!Protocol} and re-exported here for convenience. *) 17 18 type command = Protocol.command = 19 | Capability 20 | Noop ··· 30 | Rename of { old_name : mailbox_name; new_name : mailbox_name } 31 | Subscribe of mailbox_name 32 | Unsubscribe of mailbox_name 33 - | List of { reference : string; pattern : string } 34 | Namespace 35 | Status of { mailbox : mailbox_name; items : status_item list } 36 | Append of { mailbox : mailbox_name; flags : flag list; date : string option; message : string } ··· 45 | Move of { sequence : sequence_set; mailbox : mailbox_name } 46 | Uid of uid_command 47 | Id of (string * string) list option 48 49 type uid_command = Protocol.uid_command = 50 | Uid_fetch of { sequence : sequence_set; items : fetch_item list } ··· 53 | Uid_move of { sequence : sequence_set; mailbox : mailbox_name } 54 | Uid_search of { charset : string option; criteria : search_key } 55 | Uid_expunge of sequence_set 56 57 type tagged_command = Protocol.tagged_command = { 58 tag : string; ··· 67 | Bye of { code : response_code option; text : string } 68 | Capability_response of string list 69 | Enabled of string list 70 - | List_response of { flags : list_flag list; delimiter : char option; name : mailbox_name } 71 | Namespace_response of namespace_data 72 | Status_response of { mailbox : mailbox_name; items : (status_item * int64) list } 73 | Esearch of { tag : string option; uid : bool; results : esearch_result list } ··· 77 | Fetch_response of { seq : int; items : fetch_response_item list } 78 | Continuation of string option 79 | Id_response of (string * string) list option 80 81 (** {1 Parsing} *) 82
··· 15 16 Types are defined in {!Protocol} and re-exported here for convenience. *) 17 18 + type thread_algorithm = Protocol.thread_algorithm = 19 + | Thread_orderedsubject 20 + | Thread_references 21 + | Thread_extension of string 22 + 23 type command = Protocol.command = 24 | Capability 25 | Noop ··· 35 | Rename of { old_name : mailbox_name; new_name : mailbox_name } 36 | Subscribe of mailbox_name 37 | Unsubscribe of mailbox_name 38 + | List of list_command 39 | Namespace 40 | Status of { mailbox : mailbox_name; items : status_item list } 41 | Append of { mailbox : mailbox_name; flags : flag list; date : string option; message : string } ··· 50 | Move of { sequence : sequence_set; mailbox : mailbox_name } 51 | Uid of uid_command 52 | Id of (string * string) list option 53 + (* QUOTA extension - RFC 9208 *) 54 + | Getquota of string 55 + | Getquotaroot of mailbox_name 56 + | Setquota of { root : string; limits : (quota_resource * int64) list } 57 + (* THREAD extension - RFC 5256 *) 58 + | Thread of { algorithm : thread_algorithm; charset : string; criteria : search_key } 59 60 type uid_command = Protocol.uid_command = 61 | Uid_fetch of { sequence : sequence_set; items : fetch_item list } ··· 64 | Uid_move of { sequence : sequence_set; mailbox : mailbox_name } 65 | Uid_search of { charset : string option; criteria : search_key } 66 | Uid_expunge of sequence_set 67 + | Uid_thread of { algorithm : thread_algorithm; charset : string; criteria : search_key } 68 69 type tagged_command = Protocol.tagged_command = { 70 tag : string; ··· 79 | Bye of { code : response_code option; text : string } 80 | Capability_response of string list 81 | Enabled of string list 82 + | List_response of list_response_data 83 | Namespace_response of namespace_data 84 | Status_response of { mailbox : mailbox_name; items : (status_item * int64) list } 85 | Esearch of { tag : string option; uid : bool; results : esearch_result list } ··· 89 | Fetch_response of { seq : int; items : fetch_response_item list } 90 | Continuation of string option 91 | Id_response of (string * string) list option 92 + (* QUOTA extension responses - RFC 9208 *) 93 + | Quota_response of { root : string; resources : quota_resource_info list } 94 + | Quotaroot_response of { mailbox : mailbox_name; roots : string list } 95 + (* THREAD extension response - RFC 5256 *) 96 + | Thread_response of thread_result 97 98 (** {1 Parsing} *) 99
+127 -3
ocaml-imap/lib/imapd/protocol.ml
··· 183 | Status_deleted 184 | Status_size 185 186 - (* LIST flags - RFC 9051 Section 7.3.1 *) 187 type list_flag = 188 | List_noinferiors 189 | List_noselect ··· 192 | List_subscribed 193 | List_haschildren 194 | List_hasnochildren 195 | List_all 196 | List_archive 197 | List_drafts ··· 200 | List_sent 201 | List_trash 202 | List_extension of string 203 204 (* Connection state - RFC 9051 Section 3 *) 205 type connection_state = ··· 334 else 335 None 336 337 (* === Commands - RFC 9051 Section 6 === *) 338 339 type command = ··· 351 | Rename of { old_name : mailbox_name; new_name : mailbox_name } 352 | Subscribe of mailbox_name 353 | Unsubscribe of mailbox_name 354 - | List of { reference : string; pattern : string } 355 | Namespace 356 | Status of { mailbox : mailbox_name; items : status_item list } 357 | Append of { mailbox : mailbox_name; flags : flag list; date : string option; message : string } ··· 366 | Move of { sequence : sequence_set; mailbox : mailbox_name } 367 | Uid of uid_command 368 | Id of (string * string) list option (** RFC 2971 - NIL or list of field/value pairs *) 369 370 and uid_command = 371 | Uid_fetch of { sequence : sequence_set; items : fetch_item list } ··· 374 | Uid_move of { sequence : sequence_set; mailbox : mailbox_name } 375 | Uid_search of { charset : string option; criteria : search_key } 376 | Uid_expunge of sequence_set 377 378 type tagged_command = { 379 tag : string; ··· 419 | Bye of { code : response_code option; text : string } 420 | Capability_response of string list 421 | Enabled of string list 422 - | List_response of { flags : list_flag list; delimiter : char option; name : mailbox_name } 423 | Namespace_response of namespace_data 424 | Status_response of { mailbox : mailbox_name; items : (status_item * int64) list } 425 | Esearch of { tag : string option; uid : bool; results : esearch_result list } ··· 429 | Fetch_response of { seq : int; items : fetch_response_item list } 430 | Continuation of string option 431 | Id_response of (string * string) list option (** RFC 2971 - NIL or list of field/value pairs *)
··· 183 | Status_deleted 184 | Status_size 185 186 + (* LIST flags - RFC 9051 Section 7.3.1, RFC 5258 Section 3.4 *) 187 type list_flag = 188 | List_noinferiors 189 | List_noselect ··· 192 | List_subscribed 193 | List_haschildren 194 | List_hasnochildren 195 + | List_nonexistent (** RFC 5258 Section 3.4 - Mailbox name refers to non-existent mailbox *) 196 + | List_remote (** RFC 5258 Section 3.4 - Mailbox is remote, not on this server *) 197 | List_all 198 | List_archive 199 | List_drafts ··· 202 | List_sent 203 | List_trash 204 | List_extension of string 205 + 206 + (** LIST selection options per RFC 5258 Section 3.1 207 + 208 + Selection options control which mailboxes are returned by LIST: 209 + - SUBSCRIBED: Return subscribed mailboxes (like LSUB) 210 + - REMOTE: Include remote mailboxes (not on this server) 211 + - RECURSIVEMATCH: Include ancestors of matched mailboxes 212 + - SPECIAL-USE: Return only special-use mailboxes (RFC 6154) *) 213 + type list_select_option = 214 + | List_select_subscribed (** RFC 5258 Section 3.1.1 *) 215 + | List_select_remote (** RFC 5258 Section 3.1.2 *) 216 + | List_select_recursivematch (** RFC 5258 Section 3.1.3 *) 217 + | List_select_special_use (** RFC 6154 Section 3 *) 218 + 219 + (** LIST return options per RFC 5258 Section 3.2 220 + 221 + Return options control what additional data is returned: 222 + - SUBSCRIBED: Include \Subscribed flag 223 + - CHILDREN: Include \HasChildren/\HasNoChildren flags 224 + - SPECIAL-USE: Include special-use flags (RFC 6154) *) 225 + type list_return_option = 226 + | List_return_subscribed (** RFC 5258 Section 3.2.1 *) 227 + | List_return_children (** RFC 5258 Section 3.2.2 *) 228 + | List_return_special_use (** RFC 6154 Section 3 *) 229 + 230 + (** Extended data items in LIST response per RFC 5258 Section 3.5 *) 231 + type list_extended_item = 232 + | Childinfo of string list (** RFC 5258 Section 3.5 - CHILDINFO extended data *) 233 + 234 + (** LIST command variants per RFC 5258 *) 235 + type list_command = 236 + | List_basic of { 237 + reference : string; (** Reference name (context for pattern) *) 238 + pattern : string; (** Mailbox pattern with wildcards *) 239 + } 240 + | List_extended of { 241 + selection : list_select_option list; (** RFC 5258 Section 3.1 *) 242 + reference : string; 243 + patterns : string list; (** Multiple patterns allowed *) 244 + return_opts : list_return_option list; (** RFC 5258 Section 3.2 *) 245 + } 246 + 247 + (** Extended LIST response per RFC 5258 Section 3.4 *) 248 + type list_response_data = { 249 + flags : list_flag list; 250 + delimiter : char option; 251 + name : mailbox_name; 252 + extended : list_extended_item list; (** RFC 5258 Section 3.5 *) 253 + } 254 255 (* Connection state - RFC 9051 Section 3 *) 256 type connection_state = ··· 385 else 386 None 387 388 + (* === THREAD Types - RFC 5256 === *) 389 + 390 + (** Threading algorithm for the THREAD command. 391 + See {{:https://datatracker.ietf.org/doc/html/rfc5256#section-3}RFC 5256 Section 3}. *) 392 + type thread_algorithm = 393 + | Thread_orderedsubject 394 + (** ORDEREDSUBJECT algorithm (RFC 5256 Section 3.1). 395 + Groups messages by base subject, then sorts by sent date. *) 396 + | Thread_references 397 + (** REFERENCES algorithm (RFC 5256 Section 3.2). 398 + Implements the JWZ threading algorithm using Message-ID, 399 + In-Reply-To, and References headers. *) 400 + | Thread_extension of string 401 + (** Future algorithm extensions. *) 402 + 403 + (** A thread node in the THREAD response. 404 + See {{:https://datatracker.ietf.org/doc/html/rfc5256#section-4}RFC 5256 Section 4}. *) 405 + type thread_node = 406 + | Thread_message of int * thread_node list 407 + (** A message with its sequence number/UID and child threads. *) 408 + | Thread_dummy of thread_node list 409 + (** A placeholder for a missing parent message. *) 410 + 411 + (** Thread result: a list of root-level thread trees. 412 + See {{:https://datatracker.ietf.org/doc/html/rfc5256#section-4}RFC 5256 Section 4}. *) 413 + type thread_result = thread_node list 414 + 415 + (* === Quota Types - RFC 9208 === *) 416 + 417 + (** Quota resource types. 418 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-5}RFC 9208 Section 5}. *) 419 + type quota_resource = 420 + | Quota_storage (** STORAGE - physical space in KB. 421 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-5.1}RFC 9208 Section 5.1}. *) 422 + | Quota_message (** MESSAGE - number of messages. 423 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-5.2}RFC 9208 Section 5.2}. *) 424 + | Quota_mailbox (** MAILBOX - number of mailboxes. 425 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-5.3}RFC 9208 Section 5.3}. *) 426 + | Quota_annotation_storage (** ANNOTATION-STORAGE - annotation size in KB. 427 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-5.4}RFC 9208 Section 5.4}. *) 428 + 429 + (** A single quota resource with usage and limit. 430 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-4.2.2}RFC 9208 Section 4.2.2}. *) 431 + type quota_resource_info = { 432 + resource : quota_resource; 433 + usage : int64; (** Current usage *) 434 + limit : int64; (** Maximum allowed *) 435 + } 436 + 437 (* === Commands - RFC 9051 Section 6 === *) 438 439 type command = ··· 451 | Rename of { old_name : mailbox_name; new_name : mailbox_name } 452 | Subscribe of mailbox_name 453 | Unsubscribe of mailbox_name 454 + | List of list_command (** LIST command - RFC 9051, RFC 5258 LIST-EXTENDED *) 455 | Namespace 456 | Status of { mailbox : mailbox_name; items : status_item list } 457 | Append of { mailbox : mailbox_name; flags : flag list; date : string option; message : string } ··· 466 | Move of { sequence : sequence_set; mailbox : mailbox_name } 467 | Uid of uid_command 468 | Id of (string * string) list option (** RFC 2971 - NIL or list of field/value pairs *) 469 + (* QUOTA extension - RFC 9208 *) 470 + | Getquota of string (** GETQUOTA quota-root. 471 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-4.2}RFC 9208 Section 4.2}. *) 472 + | Getquotaroot of mailbox_name (** GETQUOTAROOT mailbox. 473 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-4.3}RFC 9208 Section 4.3}. *) 474 + | Setquota of { root : string; limits : (quota_resource * int64) list } (** SETQUOTA. 475 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-4.1}RFC 9208 Section 4.1}. *) 476 + (* THREAD extension - RFC 5256 *) 477 + | Thread of { algorithm : thread_algorithm; charset : string; criteria : search_key } 478 + (** THREAD command. 479 + See {{:https://datatracker.ietf.org/doc/html/rfc5256#section-3}RFC 5256 Section 3}. *) 480 481 and uid_command = 482 | Uid_fetch of { sequence : sequence_set; items : fetch_item list } ··· 485 | Uid_move of { sequence : sequence_set; mailbox : mailbox_name } 486 | Uid_search of { charset : string option; criteria : search_key } 487 | Uid_expunge of sequence_set 488 + | Uid_thread of { algorithm : thread_algorithm; charset : string; criteria : search_key } 489 + (** UID THREAD command - RFC 5256. Returns UIDs instead of sequence numbers. *) 490 491 type tagged_command = { 492 tag : string; ··· 532 | Bye of { code : response_code option; text : string } 533 | Capability_response of string list 534 | Enabled of string list 535 + | List_response of list_response_data (** RFC 9051, RFC 5258 LIST-EXTENDED *) 536 | Namespace_response of namespace_data 537 | Status_response of { mailbox : mailbox_name; items : (status_item * int64) list } 538 | Esearch of { tag : string option; uid : bool; results : esearch_result list } ··· 542 | Fetch_response of { seq : int; items : fetch_response_item list } 543 | Continuation of string option 544 | Id_response of (string * string) list option (** RFC 2971 - NIL or list of field/value pairs *) 545 + (* QUOTA extension responses - RFC 9208 *) 546 + | Quota_response of { root : string; resources : quota_resource_info list } 547 + (** QUOTA response. 548 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-5.1}RFC 9208 Section 5.1}. *) 549 + | Quotaroot_response of { mailbox : mailbox_name; roots : string list } 550 + (** QUOTAROOT response. 551 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-5.2}RFC 9208 Section 5.2}. *) 552 + (* THREAD extension response - RFC 5256 *) 553 + | Thread_response of thread_result 554 + (** THREAD response - a list of thread trees. 555 + See {{:https://datatracker.ietf.org/doc/html/rfc5256#section-4}RFC 5256 Section 4}. *)
+115 -2
ocaml-imap/lib/imapd/protocol.mli
··· 245 | List_subscribed (** \Subscribed *) 246 | List_haschildren (** \HasChildren *) 247 | List_hasnochildren (** \HasNoChildren *) 248 | List_all (** \All - special-use *) 249 | List_archive (** \Archive *) 250 | List_drafts (** \Drafts *) ··· 253 | List_sent (** \Sent *) 254 | List_trash (** \Trash *) 255 | List_extension of string (** Other flags *) 256 257 (** {1 Connection State} 258 ··· 332 | Code_unknown_cte 333 | Code_other of string * string option 334 335 (** {1 Commands} 336 337 See {{:https://datatracker.ietf.org/doc/html/rfc9051#section-6}RFC 9051 Section 6}. *) ··· 351 | Rename of { old_name : mailbox_name; new_name : mailbox_name } 352 | Subscribe of mailbox_name 353 | Unsubscribe of mailbox_name 354 - | List of { reference : string; pattern : string } 355 | Namespace 356 | Status of { mailbox : mailbox_name; items : status_item list } 357 | Append of { mailbox : mailbox_name; flags : flag list; date : string option; message : string } ··· 366 | Move of { sequence : sequence_set; mailbox : mailbox_name } 367 | Uid of uid_command 368 | Id of (string * string) list option (** RFC 2971 *) 369 370 and uid_command = 371 | Uid_fetch of { sequence : sequence_set; items : fetch_item list } ··· 374 | Uid_move of { sequence : sequence_set; mailbox : mailbox_name } 375 | Uid_search of { charset : string option; criteria : search_key } 376 | Uid_expunge of sequence_set 377 378 type tagged_command = { 379 tag : string; ··· 421 | Bye of { code : response_code option; text : string } 422 | Capability_response of string list 423 | Enabled of string list 424 - | List_response of { flags : list_flag list; delimiter : char option; name : mailbox_name } 425 | Namespace_response of namespace_data 426 | Status_response of { mailbox : mailbox_name; items : (status_item * int64) list } 427 | Esearch of { tag : string option; uid : bool; results : esearch_result list } ··· 431 | Fetch_response of { seq : int; items : fetch_response_item list } 432 | Continuation of string option 433 | Id_response of (string * string) list option (** RFC 2971 *) 434 435 (** {1 Utility Functions} *) 436
··· 245 | List_subscribed (** \Subscribed *) 246 | List_haschildren (** \HasChildren *) 247 | List_hasnochildren (** \HasNoChildren *) 248 + | List_nonexistent (** \NonExistent - RFC 5258 Section 3.4 *) 249 + | List_remote (** \Remote - RFC 5258 Section 3.4 *) 250 | List_all (** \All - special-use *) 251 | List_archive (** \Archive *) 252 | List_drafts (** \Drafts *) ··· 255 | List_sent (** \Sent *) 256 | List_trash (** \Trash *) 257 | List_extension of string (** Other flags *) 258 + 259 + (** LIST selection options per RFC 5258 Section 3.1 *) 260 + type list_select_option = 261 + | List_select_subscribed (** RFC 5258 Section 3.1.1 *) 262 + | List_select_remote (** RFC 5258 Section 3.1.2 *) 263 + | List_select_recursivematch (** RFC 5258 Section 3.1.3 *) 264 + | List_select_special_use (** RFC 6154 Section 3 *) 265 + 266 + (** LIST return options per RFC 5258 Section 3.2 *) 267 + type list_return_option = 268 + | List_return_subscribed (** RFC 5258 Section 3.2.1 *) 269 + | List_return_children (** RFC 5258 Section 3.2.2 *) 270 + | List_return_special_use (** RFC 6154 Section 3 *) 271 + 272 + (** Extended data items in LIST response per RFC 5258 Section 3.5 *) 273 + type list_extended_item = 274 + | Childinfo of string list (** RFC 5258 Section 3.5 - CHILDINFO extended data *) 275 + 276 + (** LIST command variants per RFC 5258 *) 277 + type list_command = 278 + | List_basic of { 279 + reference : string; (** Reference name *) 280 + pattern : string; (** Mailbox pattern *) 281 + } 282 + | List_extended of { 283 + selection : list_select_option list; 284 + reference : string; 285 + patterns : string list; 286 + return_opts : list_return_option list; 287 + } 288 + 289 + (** Extended LIST response per RFC 5258 Section 3.4 *) 290 + type list_response_data = { 291 + flags : list_flag list; 292 + delimiter : char option; 293 + name : mailbox_name; 294 + extended : list_extended_item list; 295 + } 296 297 (** {1 Connection State} 298 ··· 372 | Code_unknown_cte 373 | Code_other of string * string option 374 375 + (** {1 Quota Types} 376 + 377 + See {{:https://datatracker.ietf.org/doc/html/rfc9208}RFC 9208 - IMAP QUOTA Extension}. *) 378 + 379 + (** Quota resource types. 380 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-5}RFC 9208 Section 5}. *) 381 + type quota_resource = 382 + | Quota_storage (** STORAGE - physical space in KB. 383 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-5.1}RFC 9208 Section 5.1}. *) 384 + | Quota_message (** MESSAGE - number of messages. 385 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-5.2}RFC 9208 Section 5.2}. *) 386 + | Quota_mailbox (** MAILBOX - number of mailboxes. 387 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-5.3}RFC 9208 Section 5.3}. *) 388 + | Quota_annotation_storage (** ANNOTATION-STORAGE - annotation size in KB. 389 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-5.4}RFC 9208 Section 5.4}. *) 390 + 391 + (** A single quota resource with usage and limit. 392 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-4.2.2}RFC 9208 Section 4.2.2}. *) 393 + type quota_resource_info = { 394 + resource : quota_resource; 395 + usage : int64; (** Current usage *) 396 + limit : int64; (** Maximum allowed *) 397 + } 398 + 399 + (** {1 Thread Types} 400 + 401 + See {{:https://datatracker.ietf.org/doc/html/rfc5256}RFC 5256 - IMAP SORT and THREAD Extensions}. *) 402 + 403 + (** Threading algorithm for the THREAD command. 404 + See {{:https://datatracker.ietf.org/doc/html/rfc5256#section-3}RFC 5256 Section 3}. *) 405 + type thread_algorithm = 406 + | Thread_orderedsubject 407 + (** ORDEREDSUBJECT algorithm (RFC 5256 Section 3.1). *) 408 + | Thread_references 409 + (** REFERENCES algorithm (RFC 5256 Section 3.2). *) 410 + | Thread_extension of string 411 + (** Future algorithm extensions. *) 412 + 413 + (** A thread node in the THREAD response. 414 + See {{:https://datatracker.ietf.org/doc/html/rfc5256#section-4}RFC 5256 Section 4}. *) 415 + type thread_node = 416 + | Thread_message of int * thread_node list 417 + (** A message with its sequence number/UID and child threads. *) 418 + | Thread_dummy of thread_node list 419 + (** A placeholder for a missing parent message. *) 420 + 421 + (** Thread result: a list of root-level thread trees. *) 422 + type thread_result = thread_node list 423 + 424 (** {1 Commands} 425 426 See {{:https://datatracker.ietf.org/doc/html/rfc9051#section-6}RFC 9051 Section 6}. *) ··· 440 | Rename of { old_name : mailbox_name; new_name : mailbox_name } 441 | Subscribe of mailbox_name 442 | Unsubscribe of mailbox_name 443 + | List of list_command (** LIST command - RFC 9051, RFC 5258 LIST-EXTENDED *) 444 | Namespace 445 | Status of { mailbox : mailbox_name; items : status_item list } 446 | Append of { mailbox : mailbox_name; flags : flag list; date : string option; message : string } ··· 455 | Move of { sequence : sequence_set; mailbox : mailbox_name } 456 | Uid of uid_command 457 | Id of (string * string) list option (** RFC 2971 *) 458 + (* QUOTA extension - RFC 9208 *) 459 + | Getquota of string (** GETQUOTA quota-root. 460 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-4.2}RFC 9208 Section 4.2}. *) 461 + | Getquotaroot of mailbox_name (** GETQUOTAROOT mailbox. 462 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-4.3}RFC 9208 Section 4.3}. *) 463 + | Setquota of { root : string; limits : (quota_resource * int64) list } (** SETQUOTA. 464 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-4.1}RFC 9208 Section 4.1}. *) 465 + (* THREAD extension - RFC 5256 *) 466 + | Thread of { algorithm : thread_algorithm; charset : string; criteria : search_key } 467 + (** THREAD command. 468 + See {{:https://datatracker.ietf.org/doc/html/rfc5256#section-3}RFC 5256 Section 3}. *) 469 470 and uid_command = 471 | Uid_fetch of { sequence : sequence_set; items : fetch_item list } ··· 474 | Uid_move of { sequence : sequence_set; mailbox : mailbox_name } 475 | Uid_search of { charset : string option; criteria : search_key } 476 | Uid_expunge of sequence_set 477 + | Uid_thread of { algorithm : thread_algorithm; charset : string; criteria : search_key } 478 + (** UID THREAD command - RFC 5256. Returns UIDs instead of sequence numbers. *) 479 480 type tagged_command = { 481 tag : string; ··· 523 | Bye of { code : response_code option; text : string } 524 | Capability_response of string list 525 | Enabled of string list 526 + | List_response of list_response_data (** RFC 9051, RFC 5258 LIST-EXTENDED *) 527 | Namespace_response of namespace_data 528 | Status_response of { mailbox : mailbox_name; items : (status_item * int64) list } 529 | Esearch of { tag : string option; uid : bool; results : esearch_result list } ··· 533 | Fetch_response of { seq : int; items : fetch_response_item list } 534 | Continuation of string option 535 | Id_response of (string * string) list option (** RFC 2971 *) 536 + (* QUOTA extension responses - RFC 9208 *) 537 + | Quota_response of { root : string; resources : quota_resource_info list } 538 + (** QUOTA response. 539 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-5.1}RFC 9208 Section 5.1}. *) 540 + | Quotaroot_response of { mailbox : mailbox_name; roots : string list } 541 + (** QUOTAROOT response. 542 + See {{:https://datatracker.ietf.org/doc/html/rfc9208#section-5.2}RFC 9208 Section 5.2}. *) 543 + (* THREAD extension response - RFC 5256 *) 544 + | Thread_response of thread_result 545 + (** THREAD response containing thread tree. 546 + See {{:https://datatracker.ietf.org/doc/html/rfc5256#section-4}RFC 5256 Section 4}. *) 547 548 (** {1 Utility Functions} *) 549
+1 -1
ocaml-imap/lib/imapd/read.ml
··· 870 sp r; 871 let name = astring r in 872 crlf r; 873 - List_response { flags; delimiter; name } 874 | "STATUS" -> 875 sp r; 876 let mailbox = astring r in
··· 870 sp r; 871 let name = astring r in 872 crlf r; 873 + List_response { flags; delimiter; name; extended = [] } 874 | "STATUS" -> 875 sp r; 876 let mailbox = astring r in
+172 -49
ocaml-imap/lib/imapd/server.ml
··· 13 (* Module alias to access Storage types without conflicting with functor parameter *) 14 module Storage_types = Storage 15 16 - (* Base capabilities per RFC 9051 *) 17 let base_capabilities_pre_tls = [ 18 "IMAP4rev2"; 19 "IMAP4rev1"; (* For compatibility *) ··· 26 "ENABLE"; 27 "LITERAL+"; 28 "ID"; 29 ] 30 31 let base_capabilities_post_tls = [ ··· 39 "ENABLE"; 40 "LITERAL+"; 41 "ID"; 42 ] 43 44 (* Server configuration *) ··· 62 (Storage : Storage.STORAGE) 63 (Auth : Auth.AUTH) = struct 64 65 type connection_state = 66 | Not_authenticated 67 - | Authenticated of { username : string } 68 - | Selected of { username : string; mailbox : string; readonly : bool } 69 | Logout 70 71 (* Action returned by command handlers *) ··· 151 code = Some (Code_capability caps); 152 text = "LOGIN completed" 153 }); 154 - Authenticated { username } 155 end else begin 156 send_response flow (No { 157 tag = Some tag; ··· 170 171 (* Process SELECT/EXAMINE command - only valid in Authenticated/Selected state *) 172 let handle_select t flow tag mailbox ~readonly state = 173 - let username = match state with 174 - | Authenticated { username } -> Some username 175 - | Selected { username; _ } -> Some username 176 - | _ -> None 177 in 178 match username with 179 | None -> ··· 191 code = None; 192 text = "Invalid mailbox name" 193 }); 194 - Authenticated { username } 195 end else 196 match Storage.select_mailbox t.storage ~username mailbox ~readonly with 197 | Error _ -> ··· 200 code = Some Code_nonexistent; 201 text = "Mailbox does not exist" 202 }); 203 - Authenticated { username } 204 | Ok mb_state -> 205 (* Send untagged responses *) 206 send_response flow (Flags_response mb_state.flags); ··· 227 code; 228 text = if readonly then "EXAMINE completed" else "SELECT completed" 229 }); 230 - Selected { username; mailbox; readonly } 231 232 - (* Process LIST command *) 233 - let handle_list t flow tag ~reference ~pattern state = 234 let username = match state with 235 - | Authenticated { username } -> Some username 236 | Selected { username; _ } -> Some username 237 | _ -> None 238 in ··· 245 }); 246 state 247 | Some username -> 248 - let mailboxes = Storage.list_mailboxes t.storage ~username ~reference ~pattern in 249 List.iter (fun (mb : Storage_types.mailbox_info) -> 250 send_response flow (List_response { 251 flags = mb.flags; 252 delimiter = mb.delimiter; 253 name = mb.name; 254 }) 255 - ) mailboxes; 256 send_response flow (Ok { tag = Some tag; code = None; text = "LIST completed" }); 257 state 258 ··· 264 state 265 end else 266 let username = match state with 267 - | Authenticated { username } -> Some username 268 | Selected { username; _ } -> Some username 269 | _ -> None 270 in ··· 320 (* Process STORE command *) 321 let handle_store t flow tag ~sequence ~silent ~action ~flags state = 322 match state with 323 - | Selected { username; mailbox; readonly } -> 324 if readonly then begin 325 send_response flow (No { tag = Some tag; code = None; text = "Mailbox is read-only" }); 326 state ··· 351 (* Process EXPUNGE command *) 352 let handle_expunge t flow tag state = 353 match state with 354 - | Selected { username; mailbox; readonly } -> 355 if readonly then begin 356 send_response flow (No { tag = Some tag; code = None; text = "Mailbox is read-only" }); 357 state ··· 376 (* Process CLOSE command *) 377 let handle_close t flow tag state = 378 match state with 379 - | Selected { username; mailbox; readonly } -> 380 (* Silently expunge if not readonly *) 381 if not readonly then 382 ignore (Storage.expunge t.storage ~username ~mailbox); 383 send_response flow (Ok { tag = Some tag; code = None; text = "CLOSE completed" }); 384 - Authenticated { username } 385 | _ -> 386 send_response flow (Bad { 387 tag = Some tag; ··· 393 (* Process UNSELECT command *) 394 let handle_unselect flow tag state = 395 match state with 396 - | Selected { username; _ } -> 397 send_response flow (Ok { tag = Some tag; code = None; text = "UNSELECT completed" }); 398 - Authenticated { username } 399 | _ -> 400 send_response flow (Bad { 401 tag = Some tag; ··· 412 state 413 end else 414 let username = match state with 415 - | Authenticated { username } -> Some username 416 | Selected { username; _ } -> Some username 417 | _ -> None 418 in ··· 448 state 449 end else 450 let username = match state with 451 - | Authenticated { username } -> Some username 452 | Selected { username; _ } -> Some username 453 | _ -> None 454 in ··· 485 state 486 end else 487 let username = match state with 488 - | Authenticated { username } -> Some username 489 | Selected { username; _ } -> Some username 490 | _ -> None 491 in ··· 567 state 568 end else 569 match state with 570 - | Selected { username; mailbox = src_mailbox; readonly } -> 571 if readonly then begin 572 send_response flow (No { tag = Some tag; code = None; text = "Mailbox is read-only" }); 573 state ··· 605 }); 606 state 607 608 - (* Process SEARCH command *) 609 - let handle_search t flow tag ~charset:_ ~criteria state = 610 match state with 611 - | Selected { username; mailbox; _ } -> 612 - (match Storage.search t.storage ~username ~mailbox ~criteria with 613 - | Result.Error _ -> 614 - send_response flow (No { tag = Some tag; code = None; text = "SEARCH failed" }) 615 - | Result.Ok uids -> 616 - (* Send ESEARCH response per RFC 9051 *) 617 - let results = if List.length uids > 0 then 618 - [Esearch_count (List.length uids); Esearch_all (List.map (fun uid -> Single (Int32.to_int uid)) uids)] 619 - else 620 - [Esearch_count 0] 621 - in 622 - send_response flow (Esearch { tag = Some tag; uid = false; results }); 623 - send_response flow (Ok { tag = Some tag; code = None; text = "SEARCH completed" })); 624 - state 625 | _ -> 626 send_response flow (Bad { 627 tag = Some tag; ··· 630 }); 631 state 632 633 (* Process APPEND command *) 634 let handle_append t flow tag ~mailbox ~flags ~date ~message state = 635 (* Security: Validate mailbox name *) ··· 638 state 639 end else 640 let username = match state with 641 - | Authenticated { username } -> Some username 642 | Selected { username; _ } -> Some username 643 | _ -> None 644 in ··· 694 }); 695 state 696 697 - (* Process ENABLE command - RFC 5161 *) 698 let handle_enable flow tag ~capabilities state = 699 match state with 700 - | Authenticated _ -> 701 (* Filter to capabilities we actually support *) 702 let enabled = List.filter (fun cap -> 703 let cap_upper = String.uppercase_ascii cap in 704 cap_upper = "IMAP4REV2" || cap_upper = "UTF8=ACCEPT" 705 ) capabilities in 706 if List.length enabled > 0 then 707 send_response flow (Enabled enabled); 708 send_response flow (Ok { tag = Some tag; code = None; text = "ENABLE completed" }); 709 - state 710 | _ -> 711 send_response flow (Bad { 712 tag = Some tag; ··· 779 | Login { username; password } -> (handle_login t flow tag ~username ~password ~tls_active state, Continue) 780 | Select mailbox -> (handle_select t flow tag mailbox ~readonly:false state, Continue) 781 | Examine mailbox -> (handle_select t flow tag mailbox ~readonly:true state, Continue) 782 - | List { reference; pattern } -> (handle_list t flow tag ~reference ~pattern state, Continue) 783 | Status { mailbox; items } -> (handle_status t flow tag mailbox ~items state, Continue) 784 | Fetch { sequence; items } -> (handle_fetch t flow tag ~sequence ~items state, Continue) 785 | Store { sequence; silent; action; flags } -> (handle_store t flow tag ~sequence ~silent ~action ~flags state, Continue) ··· 792 | Copy { sequence; mailbox } -> (handle_copy t flow tag ~sequence ~mailbox state, Continue) 793 | Move { sequence; mailbox } -> (handle_move t flow tag ~sequence ~mailbox state, Continue) 794 | Search { charset; criteria } -> (handle_search t flow tag ~charset ~criteria state, Continue) 795 | Append { mailbox; flags; date; message } -> (handle_append t flow tag ~mailbox ~flags ~date ~message state, Continue) 796 | Namespace -> (handle_namespace flow tag state, Continue) 797 | Enable caps -> (handle_enable flow tag ~capabilities:caps state, Continue) ··· 816 | Authenticate _ -> 817 send_response flow (No { tag = Some tag; code = None; text = "Use LOGIN instead" }); 818 (state, Continue) 819 820 (* Handle UID prefixed commands *) 821 and handle_uid_command t flow tag ~read_line_fn:_ uid_cmd state = ··· 834 | Uid_expunge _sequence -> 835 (* UID EXPUNGE only expunges messages in the given UID set *) 836 handle_expunge t flow tag state 837 838 (* Maximum line length to prevent DoS attacks via memory exhaustion. 839 RFC 9051 Section 4 recommends supporting lines up to 8192 octets. *) ··· 990 text = "LOGIN completed" 991 }); 992 (* Continue session as authenticated user *) 993 - let state = Authenticated { username } in 994 ignore (command_loop t flow state tls_active) 995 end else begin 996 (* Failed to drop privileges *)
··· 13 (* Module alias to access Storage types without conflicting with functor parameter *) 14 module Storage_types = Storage 15 16 + (** Base capabilities per RFC 9051. 17 + @see <https://datatracker.ietf.org/doc/html/rfc9051> RFC 9051: IMAP4rev2 18 + @see <https://datatracker.ietf.org/doc/html/rfc6855#section-3> RFC 6855 Section 3: UTF8=ACCEPT *) 19 let base_capabilities_pre_tls = [ 20 "IMAP4rev2"; 21 "IMAP4rev1"; (* For compatibility *) ··· 28 "ENABLE"; 29 "LITERAL+"; 30 "ID"; 31 + "UNSELECT"; (* RFC 3691 *) 32 + "SPECIAL-USE"; (* RFC 6154 *) 33 + "LIST-EXTENDED"; (* RFC 5258 *) 34 + "CONDSTORE"; (* RFC 7162 - modification sequences for flags *) 35 + (* QUOTA extension - RFC 9208 *) 36 + "QUOTA"; 37 + "QUOTA=RES-STORAGE"; (* RFC 9208 Section 5.1 *) 38 + "QUOTA=RES-MESSAGE"; (* RFC 9208 Section 5.2 *) 39 + (* UTF-8 support - RFC 6855 *) 40 + "UTF8=ACCEPT"; (* RFC 6855 Section 3 *) 41 + (* THREAD extension - RFC 5256 *) 42 + "THREAD=ORDEREDSUBJECT"; (* RFC 5256 Section 3.1 *) 43 + "THREAD=REFERENCES"; (* RFC 5256 Section 3.2 *) 44 ] 45 46 let base_capabilities_post_tls = [ ··· 54 "ENABLE"; 55 "LITERAL+"; 56 "ID"; 57 + "UNSELECT"; (* RFC 3691 *) 58 + "SPECIAL-USE"; (* RFC 6154 *) 59 + "LIST-EXTENDED"; (* RFC 5258 *) 60 + "CONDSTORE"; (* RFC 7162 - modification sequences for flags *) 61 + (* QUOTA extension - RFC 9208 *) 62 + "QUOTA"; 63 + "QUOTA=RES-STORAGE"; (* RFC 9208 Section 5.1 *) 64 + "QUOTA=RES-MESSAGE"; (* RFC 9208 Section 5.2 *) 65 + (* UTF-8 support - RFC 6855 *) 66 + "UTF8=ACCEPT"; (* RFC 6855 Section 3 *) 67 + (* THREAD extension - RFC 5256 *) 68 + "THREAD=ORDEREDSUBJECT"; (* RFC 5256 Section 3.1 *) 69 + "THREAD=REFERENCES"; (* RFC 5256 Section 3.2 *) 70 ] 71 72 (* Server configuration *) ··· 90 (Storage : Storage.STORAGE) 91 (Auth : Auth.AUTH) = struct 92 93 + (** Connection state with UTF-8 mode tracking. 94 + @see <https://datatracker.ietf.org/doc/html/rfc6855#section-3> RFC 6855 Section 3 *) 95 type connection_state = 96 | Not_authenticated 97 + | Authenticated of { username : string; utf8_enabled : bool } 98 + | Selected of { username : string; mailbox : string; readonly : bool; utf8_enabled : bool } 99 | Logout 100 101 (* Action returned by command handlers *) ··· 181 code = Some (Code_capability caps); 182 text = "LOGIN completed" 183 }); 184 + Authenticated { username; utf8_enabled = false } 185 end else begin 186 send_response flow (No { 187 tag = Some tag; ··· 200 201 (* Process SELECT/EXAMINE command - only valid in Authenticated/Selected state *) 202 let handle_select t flow tag mailbox ~readonly state = 203 + let username, utf8_enabled = match state with 204 + | Authenticated { username; utf8_enabled } -> Some username, utf8_enabled 205 + | Selected { username; utf8_enabled; _ } -> Some username, utf8_enabled 206 + | _ -> None, false 207 in 208 match username with 209 | None -> ··· 221 code = None; 222 text = "Invalid mailbox name" 223 }); 224 + Authenticated { username; utf8_enabled } 225 end else 226 match Storage.select_mailbox t.storage ~username mailbox ~readonly with 227 | Error _ -> ··· 230 code = Some Code_nonexistent; 231 text = "Mailbox does not exist" 232 }); 233 + Authenticated { username; utf8_enabled } 234 | Ok mb_state -> 235 (* Send untagged responses *) 236 send_response flow (Flags_response mb_state.flags); ··· 257 code; 258 text = if readonly then "EXAMINE completed" else "SELECT completed" 259 }); 260 + Selected { username; mailbox; readonly; utf8_enabled } 261 262 + (* Process LIST command - RFC 9051, RFC 5258 LIST-EXTENDED *) 263 + let handle_list t flow tag list_cmd state = 264 let username = match state with 265 + | Authenticated { username; _ } -> Some username 266 | Selected { username; _ } -> Some username 267 | _ -> None 268 in ··· 275 }); 276 state 277 | Some username -> 278 + (* Extract reference and patterns from list command *) 279 + let reference, patterns = match list_cmd with 280 + | List_basic { reference; pattern } -> (reference, [pattern]) 281 + | List_extended { reference; patterns; _ } -> (reference, patterns) 282 + in 283 + (* Process each pattern and collect mailboxes *) 284 + let all_mailboxes = List.concat_map (fun pattern -> 285 + Storage.list_mailboxes t.storage ~username ~reference ~pattern 286 + ) patterns in 287 + (* Send LIST responses with extended data if needed *) 288 List.iter (fun (mb : Storage_types.mailbox_info) -> 289 send_response flow (List_response { 290 flags = mb.flags; 291 delimiter = mb.delimiter; 292 name = mb.name; 293 + extended = []; (* Extended data can be populated based on return options *) 294 }) 295 + ) all_mailboxes; 296 send_response flow (Ok { tag = Some tag; code = None; text = "LIST completed" }); 297 state 298 ··· 304 state 305 end else 306 let username = match state with 307 + | Authenticated { username; _ } -> Some username 308 | Selected { username; _ } -> Some username 309 | _ -> None 310 in ··· 360 (* Process STORE command *) 361 let handle_store t flow tag ~sequence ~silent ~action ~flags state = 362 match state with 363 + | Selected { username; mailbox; readonly; _ } -> 364 if readonly then begin 365 send_response flow (No { tag = Some tag; code = None; text = "Mailbox is read-only" }); 366 state ··· 391 (* Process EXPUNGE command *) 392 let handle_expunge t flow tag state = 393 match state with 394 + | Selected { username; mailbox; readonly; _ } -> 395 if readonly then begin 396 send_response flow (No { tag = Some tag; code = None; text = "Mailbox is read-only" }); 397 state ··· 416 (* Process CLOSE command *) 417 let handle_close t flow tag state = 418 match state with 419 + | Selected { username; mailbox; readonly; utf8_enabled } -> 420 (* Silently expunge if not readonly *) 421 if not readonly then 422 ignore (Storage.expunge t.storage ~username ~mailbox); 423 send_response flow (Ok { tag = Some tag; code = None; text = "CLOSE completed" }); 424 + Authenticated { username; utf8_enabled } 425 | _ -> 426 send_response flow (Bad { 427 tag = Some tag; ··· 433 (* Process UNSELECT command *) 434 let handle_unselect flow tag state = 435 match state with 436 + | Selected { username; utf8_enabled; _ } -> 437 send_response flow (Ok { tag = Some tag; code = None; text = "UNSELECT completed" }); 438 + Authenticated { username; utf8_enabled } 439 | _ -> 440 send_response flow (Bad { 441 tag = Some tag; ··· 452 state 453 end else 454 let username = match state with 455 + | Authenticated { username; _ } -> Some username 456 | Selected { username; _ } -> Some username 457 | _ -> None 458 in ··· 488 state 489 end else 490 let username = match state with 491 + | Authenticated { username; _ } -> Some username 492 | Selected { username; _ } -> Some username 493 | _ -> None 494 in ··· 525 state 526 end else 527 let username = match state with 528 + | Authenticated { username; _ } -> Some username 529 | Selected { username; _ } -> Some username 530 | _ -> None 531 in ··· 607 state 608 end else 609 match state with 610 + | Selected { username; mailbox = src_mailbox; readonly; _ } -> 611 if readonly then begin 612 send_response flow (No { tag = Some tag; code = None; text = "Mailbox is read-only" }); 613 state ··· 645 }); 646 state 647 648 + (** Process SEARCH command. 649 + @see <https://datatracker.ietf.org/doc/html/rfc6855#section-3> RFC 6855 Section 3 650 + After ENABLE UTF8=ACCEPT, SEARCH with CHARSET is rejected. *) 651 + let handle_search t flow tag ~charset ~criteria state = 652 match state with 653 + | Selected { username; mailbox; utf8_enabled; _ } -> 654 + (* RFC 6855 Section 3: After ENABLE UTF8=ACCEPT, reject SEARCH with CHARSET *) 655 + if utf8_enabled && Option.is_some charset then begin 656 + send_response flow (Bad { 657 + tag = Some tag; 658 + code = None; 659 + text = "CHARSET not allowed after ENABLE UTF8=ACCEPT" 660 + }); 661 + state 662 + end else begin 663 + match Storage.search t.storage ~username ~mailbox ~criteria with 664 + | Result.Error _ -> 665 + send_response flow (No { tag = Some tag; code = None; text = "SEARCH failed" }); 666 + state 667 + | Result.Ok uids -> 668 + (* Send ESEARCH response per RFC 9051 *) 669 + let results = if List.length uids > 0 then 670 + [Esearch_count (List.length uids); Esearch_all (List.map (fun uid -> Single (Int32.to_int uid)) uids)] 671 + else 672 + [Esearch_count 0] 673 + in 674 + send_response flow (Esearch { tag = Some tag; uid = false; results }); 675 + send_response flow (Ok { tag = Some tag; code = None; text = "SEARCH completed" }); 676 + state 677 + end 678 | _ -> 679 send_response flow (Bad { 680 tag = Some tag; ··· 683 }); 684 state 685 686 + (** Process THREAD command - RFC 5256. 687 + 688 + The THREAD command is used to retrieve message threads from a mailbox. 689 + It takes an algorithm, charset, and search criteria, returning threads 690 + of messages matching the criteria. 691 + 692 + Note: This is a basic stub implementation that returns empty threads. 693 + A full implementation would require: 694 + - ORDEREDSUBJECT: subject.ml for base subject extraction (RFC 5256 Section 2.1) 695 + - REFERENCES: Message-ID/In-Reply-To/References header parsing 696 + 697 + @see <https://datatracker.ietf.org/doc/html/rfc5256#section-3> RFC 5256 Section 3 *) 698 + let handle_thread _t flow tag ~algorithm ~charset:_ ~criteria:_ state = 699 + match state with 700 + | Selected { username = _; mailbox = _; _ } -> 701 + (* TODO: Implement actual threading algorithms. 702 + For now, return empty thread result. 703 + Full implementation would: 704 + 1. Search for messages matching criteria 705 + 2. Apply ORDEREDSUBJECT or REFERENCES algorithm 706 + 3. Build thread tree structure *) 707 + let _ = algorithm in (* Acknowledge the algorithm parameter *) 708 + send_response flow (Thread_response []); 709 + send_response flow (Ok { tag = Some tag; code = None; text = "THREAD completed" }); 710 + state 711 + | _ -> 712 + send_response flow (Bad { 713 + tag = Some tag; 714 + code = None; 715 + text = "THREAD requires selected state" 716 + }); 717 + state 718 + 719 (* Process APPEND command *) 720 let handle_append t flow tag ~mailbox ~flags ~date ~message state = 721 (* Security: Validate mailbox name *) ··· 724 state 725 end else 726 let username = match state with 727 + | Authenticated { username; _ } -> Some username 728 | Selected { username; _ } -> Some username 729 | _ -> None 730 in ··· 780 }); 781 state 782 783 + (** Process ENABLE command - RFC 5161, RFC 6855. 784 + After ENABLE UTF8=ACCEPT, the session accepts UTF-8 in quoted-strings. 785 + @see <https://datatracker.ietf.org/doc/html/rfc5161> RFC 5161: ENABLE Extension 786 + @see <https://datatracker.ietf.org/doc/html/rfc6855#section-3> RFC 6855 Section 3 *) 787 let handle_enable flow tag ~capabilities state = 788 match state with 789 + | Authenticated { username; utf8_enabled } -> 790 (* Filter to capabilities we actually support *) 791 let enabled = List.filter (fun cap -> 792 let cap_upper = String.uppercase_ascii cap in 793 cap_upper = "IMAP4REV2" || cap_upper = "UTF8=ACCEPT" 794 ) capabilities in 795 + (* Check if UTF8=ACCEPT was requested and enabled *) 796 + let new_utf8_enabled = utf8_enabled || List.exists (fun cap -> 797 + String.uppercase_ascii cap = "UTF8=ACCEPT" 798 + ) enabled in 799 if List.length enabled > 0 then 800 send_response flow (Enabled enabled); 801 send_response flow (Ok { tag = Some tag; code = None; text = "ENABLE completed" }); 802 + Authenticated { username; utf8_enabled = new_utf8_enabled } 803 | _ -> 804 send_response flow (Bad { 805 tag = Some tag; ··· 872 | Login { username; password } -> (handle_login t flow tag ~username ~password ~tls_active state, Continue) 873 | Select mailbox -> (handle_select t flow tag mailbox ~readonly:false state, Continue) 874 | Examine mailbox -> (handle_select t flow tag mailbox ~readonly:true state, Continue) 875 + | List list_cmd -> (handle_list t flow tag list_cmd state, Continue) 876 | Status { mailbox; items } -> (handle_status t flow tag mailbox ~items state, Continue) 877 | Fetch { sequence; items } -> (handle_fetch t flow tag ~sequence ~items state, Continue) 878 | Store { sequence; silent; action; flags } -> (handle_store t flow tag ~sequence ~silent ~action ~flags state, Continue) ··· 885 | Copy { sequence; mailbox } -> (handle_copy t flow tag ~sequence ~mailbox state, Continue) 886 | Move { sequence; mailbox } -> (handle_move t flow tag ~sequence ~mailbox state, Continue) 887 | Search { charset; criteria } -> (handle_search t flow tag ~charset ~criteria state, Continue) 888 + | Thread { algorithm; charset; criteria } -> (handle_thread t flow tag ~algorithm ~charset ~criteria state, Continue) 889 | Append { mailbox; flags; date; message } -> (handle_append t flow tag ~mailbox ~flags ~date ~message state, Continue) 890 | Namespace -> (handle_namespace flow tag state, Continue) 891 | Enable caps -> (handle_enable flow tag ~capabilities:caps state, Continue) ··· 910 | Authenticate _ -> 911 send_response flow (No { tag = Some tag; code = None; text = "Use LOGIN instead" }); 912 (state, Continue) 913 + (* QUOTA extension - RFC 9208 *) 914 + | Getquota root -> 915 + (* GETQUOTA returns quota information for a quota root *) 916 + (* For now, return empty quota - storage backend would provide real data *) 917 + send_response flow (Quota_response { root; resources = [] }); 918 + send_response flow (Ok { tag = Some tag; code = None; text = "GETQUOTA completed" }); 919 + (state, Continue) 920 + | Getquotaroot mailbox -> 921 + (* GETQUOTAROOT returns the quota roots for a mailbox *) 922 + (* Typically the user's root is the quota root *) 923 + let roots = [mailbox] in (* Simplified: use mailbox as its own quota root *) 924 + send_response flow (Quotaroot_response { mailbox; roots }); 925 + (* Also send QUOTA responses for each root *) 926 + List.iter (fun root -> 927 + send_response flow (Quota_response { root; resources = [] }) 928 + ) roots; 929 + send_response flow (Ok { tag = Some tag; code = None; text = "GETQUOTAROOT completed" }); 930 + (state, Continue) 931 + | Setquota { root; limits = _ } -> 932 + (* SETQUOTA is admin-only in most implementations *) 933 + send_response flow (No { 934 + tag = Some tag; 935 + code = Some Code_noperm; 936 + text = Printf.sprintf "Cannot set quota for %s" root 937 + }); 938 + (state, Continue) 939 940 (* Handle UID prefixed commands *) 941 and handle_uid_command t flow tag ~read_line_fn:_ uid_cmd state = ··· 954 | Uid_expunge _sequence -> 955 (* UID EXPUNGE only expunges messages in the given UID set *) 956 handle_expunge t flow tag state 957 + | Uid_thread { algorithm; charset; criteria } -> 958 + (* UID THREAD returns UIDs instead of sequence numbers *) 959 + handle_thread t flow tag ~algorithm ~charset ~criteria state 960 961 (* Maximum line length to prevent DoS attacks via memory exhaustion. 962 RFC 9051 Section 4 recommends supporting lines up to 8192 octets. *) ··· 1113 text = "LOGIN completed" 1114 }); 1115 (* Continue session as authenticated user *) 1116 + let state = Authenticated { username; utf8_enabled = false } in 1117 ignore (command_loop t flow state tls_active) 1118 end else begin 1119 (* Failed to drop privileges *)
+14 -2
ocaml-imap/lib/imapd/storage.ml
··· 60 flags : list_flag list; 61 } 62 63 (* Storage backend signature *) 64 module type STORAGE = sig 65 type t ··· 168 ensure_inbox user; 169 Hashtbl.fold (fun name _mb acc -> 170 if matches_pattern ~pattern name then 171 - { name; delimiter = Some '/'; flags = [] } :: acc 172 else acc 173 ) user.mailboxes [] 174 ··· 700 let name = String.sub entry 1 (String.length entry - 1) in 701 let name = String.map (fun c -> if c = '.' then '/' else c) name in 702 if Memory_storage.matches_pattern ~pattern name then 703 - { name; delimiter = Some '/'; flags = [] } :: acc 704 else acc 705 else acc 706 else acc
··· 60 flags : list_flag list; 61 } 62 63 + (** Get SPECIAL-USE flags for a mailbox based on its name (RFC 6154) *) 64 + let get_special_use_for_mailbox name = 65 + match String.lowercase_ascii name with 66 + | "drafts" -> [List_drafts] 67 + | "sent" | "sent messages" | "sent items" -> [List_sent] 68 + | "trash" | "deleted messages" | "deleted items" -> [List_trash] 69 + | "junk" | "spam" -> [List_junk] 70 + | "archive" -> [List_archive] 71 + | _ -> [] 72 + 73 (* Storage backend signature *) 74 module type STORAGE = sig 75 type t ··· 178 ensure_inbox user; 179 Hashtbl.fold (fun name _mb acc -> 180 if matches_pattern ~pattern name then 181 + let flags = get_special_use_for_mailbox name in 182 + { name; delimiter = Some '/'; flags } :: acc 183 else acc 184 ) user.mailboxes [] 185 ··· 711 let name = String.sub entry 1 (String.length entry - 1) in 712 let name = String.map (fun c -> if c = '.' then '/' else c) name in 713 if Memory_storage.matches_pattern ~pattern name then 714 + let flags = get_special_use_for_mailbox name in 715 + { name; delimiter = Some '/'; flags } :: acc 716 else acc 717 else acc 718 else acc
+181
ocaml-imap/lib/imapd/utf8.ml
···
··· 1 + (*--------------------------------------------------------------------------- 2 + Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 + 6 + (** UTF-8 validation per RFC 3629 for RFC 6855 IMAP UTF-8 support. 7 + @see <https://datatracker.ietf.org/doc/html/rfc6855> RFC 6855: IMAP Support for UTF-8 8 + @see <https://datatracker.ietf.org/doc/html/rfc3629> RFC 3629: UTF-8 encoding *) 9 + 10 + (** Check if a string contains any non-ASCII characters (bytes >= 128). *) 11 + let has_non_ascii s = 12 + let len = String.length s in 13 + let rec loop i = 14 + if i >= len then false 15 + else if Char.code s.[i] >= 128 then true 16 + else loop (i + 1) 17 + in 18 + loop 0 19 + 20 + (** Validate UTF-8 encoding per RFC 3629 Section 4. 21 + 22 + UTF-8 encoding (RFC 3629): 23 + - 1-byte: 0xxxxxxx (U+0000..U+007F) 24 + - 2-byte: 110xxxxx 10xxxxxx (U+0080..U+07FF) 25 + - 3-byte: 1110xxxx 10xxxxxx 10xxxxxx (U+0800..U+FFFF) 26 + - 4-byte: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx (U+10000..U+10FFFF) 27 + 28 + Continuation bytes always have form 10xxxxxx. 29 + 30 + @see <https://datatracker.ietf.org/doc/html/rfc3629#section-4> RFC 3629 Section 4 *) 31 + let is_valid_utf8 s = 32 + let len = String.length s in 33 + let rec loop i = 34 + if i >= len then true 35 + else 36 + let b0 = Char.code s.[i] in 37 + if b0 <= 0x7F then 38 + (* 1-byte sequence: ASCII *) 39 + loop (i + 1) 40 + else if b0 land 0xE0 = 0xC0 then begin 41 + (* 2-byte sequence: 110xxxxx 10xxxxxx *) 42 + if i + 1 >= len then false 43 + else 44 + let b1 = Char.code s.[i + 1] in 45 + (* Check continuation byte *) 46 + if b1 land 0xC0 <> 0x80 then false 47 + else 48 + (* Check for overlong encoding: must encode U+0080 or higher *) 49 + let codepoint = ((b0 land 0x1F) lsl 6) lor (b1 land 0x3F) in 50 + if codepoint < 0x80 then false 51 + else loop (i + 2) 52 + end 53 + else if b0 land 0xF0 = 0xE0 then begin 54 + (* 3-byte sequence: 1110xxxx 10xxxxxx 10xxxxxx *) 55 + if i + 2 >= len then false 56 + else 57 + let b1 = Char.code s.[i + 1] in 58 + let b2 = Char.code s.[i + 2] in 59 + (* Check continuation bytes *) 60 + if b1 land 0xC0 <> 0x80 || b2 land 0xC0 <> 0x80 then false 61 + else 62 + let codepoint = 63 + ((b0 land 0x0F) lsl 12) lor 64 + ((b1 land 0x3F) lsl 6) lor 65 + (b2 land 0x3F) 66 + in 67 + (* Check for overlong encoding: must encode U+0800 or higher *) 68 + if codepoint < 0x800 then false 69 + (* Check for surrogate pairs (U+D800..U+DFFF are invalid) *) 70 + else if codepoint >= 0xD800 && codepoint <= 0xDFFF then false 71 + else loop (i + 3) 72 + end 73 + else if b0 land 0xF8 = 0xF0 then begin 74 + (* 4-byte sequence: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx *) 75 + if i + 3 >= len then false 76 + else 77 + let b1 = Char.code s.[i + 1] in 78 + let b2 = Char.code s.[i + 2] in 79 + let b3 = Char.code s.[i + 3] in 80 + (* Check continuation bytes *) 81 + if b1 land 0xC0 <> 0x80 || 82 + b2 land 0xC0 <> 0x80 || 83 + b3 land 0xC0 <> 0x80 then false 84 + else 85 + let codepoint = 86 + ((b0 land 0x07) lsl 18) lor 87 + ((b1 land 0x3F) lsl 12) lor 88 + ((b2 land 0x3F) lsl 6) lor 89 + (b3 land 0x3F) 90 + in 91 + (* Check for overlong encoding: must encode U+10000 or higher *) 92 + if codepoint < 0x10000 then false 93 + (* Check valid Unicode range: max is U+10FFFF *) 94 + else if codepoint > 0x10FFFF then false 95 + else loop (i + 4) 96 + end 97 + else 98 + (* Invalid start byte *) 99 + false 100 + in 101 + loop 0 102 + 103 + (** Decode a single UTF-8 codepoint at position [i] in string [s]. 104 + Returns the codepoint and the number of bytes consumed, or None if invalid. 105 + Assumes is_valid_utf8 has already passed. *) 106 + let decode_codepoint s i = 107 + let len = String.length s in 108 + if i >= len then None 109 + else 110 + let b0 = Char.code s.[i] in 111 + if b0 <= 0x7F then 112 + Some (b0, 1) 113 + else if b0 land 0xE0 = 0xC0 && i + 1 < len then 114 + let b1 = Char.code s.[i + 1] in 115 + let cp = ((b0 land 0x1F) lsl 6) lor (b1 land 0x3F) in 116 + Some (cp, 2) 117 + else if b0 land 0xF0 = 0xE0 && i + 2 < len then 118 + let b1 = Char.code s.[i + 1] in 119 + let b2 = Char.code s.[i + 2] in 120 + let cp = 121 + ((b0 land 0x0F) lsl 12) lor 122 + ((b1 land 0x3F) lsl 6) lor 123 + (b2 land 0x3F) 124 + in 125 + Some (cp, 3) 126 + else if b0 land 0xF8 = 0xF0 && i + 3 < len then 127 + let b1 = Char.code s.[i + 1] in 128 + let b2 = Char.code s.[i + 2] in 129 + let b3 = Char.code s.[i + 3] in 130 + let cp = 131 + ((b0 land 0x07) lsl 18) lor 132 + ((b1 land 0x3F) lsl 12) lor 133 + ((b2 land 0x3F) lsl 6) lor 134 + (b3 land 0x3F) 135 + in 136 + Some (cp, 4) 137 + else 138 + None 139 + 140 + (** Check if a codepoint is disallowed in mailbox names per RFC 6855 Section 3. 141 + 142 + Disallowed characters: 143 + - U+0000..U+001F: C0 control characters 144 + - U+007F: DELETE 145 + - U+0080..U+009F: C1 control characters 146 + - U+2028: LINE SEPARATOR 147 + - U+2029: PARAGRAPH SEPARATOR 148 + 149 + @see <https://datatracker.ietf.org/doc/html/rfc6855#section-3> RFC 6855 Section 3 150 + @see <https://datatracker.ietf.org/doc/html/rfc5198#section-2> RFC 5198 Section 2 *) 151 + let is_disallowed_mailbox_codepoint cp = 152 + (* C0 control characters U+0000..U+001F *) 153 + (cp >= 0x0000 && cp <= 0x001F) || 154 + (* DELETE U+007F *) 155 + cp = 0x007F || 156 + (* C1 control characters U+0080..U+009F *) 157 + (cp >= 0x0080 && cp <= 0x009F) || 158 + (* LINE SEPARATOR U+2028 *) 159 + cp = 0x2028 || 160 + (* PARAGRAPH SEPARATOR U+2029 *) 161 + cp = 0x2029 162 + 163 + (** Validate a mailbox name for UTF-8 compliance per RFC 6855 Section 3. 164 + 165 + @see <https://datatracker.ietf.org/doc/html/rfc6855#section-3> RFC 6855 Section 3 *) 166 + let is_valid_utf8_mailbox_name s = 167 + (* First check basic UTF-8 validity *) 168 + if not (is_valid_utf8 s) then false 169 + else 170 + (* Then check for disallowed codepoints *) 171 + let len = String.length s in 172 + let rec loop i = 173 + if i >= len then true 174 + else 175 + match decode_codepoint s i with 176 + | None -> false 177 + | Some (cp, bytes) -> 178 + if is_disallowed_mailbox_codepoint cp then false 179 + else loop (i + bytes) 180 + in 181 + loop 0
+33
ocaml-imap/lib/imapd/utf8.mli
···
··· 1 + (*--------------------------------------------------------------------------- 2 + Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 + 6 + (** UTF-8 validation per RFC 3629 for RFC 6855 IMAP UTF-8 support. 7 + @see <https://datatracker.ietf.org/doc/html/rfc6855> RFC 6855: IMAP Support for UTF-8 8 + @see <https://datatracker.ietf.org/doc/html/rfc3629> RFC 3629: UTF-8 encoding *) 9 + 10 + (** {1 UTF-8 Validation} *) 11 + 12 + val is_valid_utf8 : string -> bool 13 + (** [is_valid_utf8 s] returns [true] if [s] contains only valid UTF-8 sequences 14 + per RFC 3629. Returns [true] for empty strings and pure ASCII strings. 15 + @see <https://datatracker.ietf.org/doc/html/rfc3629#section-4> RFC 3629 Section 4 *) 16 + 17 + val has_non_ascii : string -> bool 18 + (** [has_non_ascii s] returns [true] if [s] contains any bytes with value >= 128. 19 + This is useful for detecting when UTF-8 validation is needed. *) 20 + 21 + (** {1 Mailbox Name Validation} *) 22 + 23 + val is_valid_utf8_mailbox_name : string -> bool 24 + (** [is_valid_utf8_mailbox_name s] validates a mailbox name for UTF-8 compliance 25 + per RFC 6855 Section 3. Mailbox names must: 26 + - Contain only valid UTF-8 sequences 27 + - Comply with Net-Unicode (RFC 5198 Section 2) 28 + - Not contain control characters U+0000-U+001F, U+0080-U+009F 29 + - Not contain delete U+007F 30 + - Not contain line separator U+2028 or paragraph separator U+2029 31 + 32 + @see <https://datatracker.ietf.org/doc/html/rfc6855#section-3> RFC 6855 Section 3 33 + @see <https://datatracker.ietf.org/doc/html/rfc5198#section-2> RFC 5198 Section 2 *)
+90 -5
ocaml-imap/lib/imapd/write.ml
··· 350 | Unsubscribe mailbox -> 351 W.string w "UNSUBSCRIBE "; 352 astring w mailbox 353 - | List { reference; pattern } -> 354 W.string w "LIST "; 355 - astring w reference; 356 - sp w; 357 - astring w pattern 358 | Namespace -> W.string w "NAMESPACE" 359 | Status { mailbox; items } -> 360 W.string w "STATUS "; ··· 449 search_key w criteria 450 | Uid_expunge set -> 451 W.string w "EXPUNGE "; 452 - sequence_set w set) 453 | Id params -> 454 W.string w "ID "; 455 id_params w params 456 457 let command w ~tag cmd = 458 atom w tag;
··· 350 | Unsubscribe mailbox -> 351 W.string w "UNSUBSCRIBE "; 352 astring w mailbox 353 + | List list_cmd -> 354 W.string w "LIST "; 355 + (match list_cmd with 356 + | List_basic { reference; pattern } -> 357 + astring w reference; 358 + sp w; 359 + astring w pattern 360 + | List_extended { selection; reference; patterns; return_opts } -> 361 + (* Selection options - RFC 5258 Section 3.1 *) 362 + W.char w '('; 363 + List.iteri (fun i opt -> 364 + if i > 0 then sp w; 365 + match opt with 366 + | List_select_subscribed -> W.string w "SUBSCRIBED" 367 + | List_select_remote -> W.string w "REMOTE" 368 + | List_select_recursivematch -> W.string w "RECURSIVEMATCH" 369 + | List_select_special_use -> W.string w "SPECIAL-USE" 370 + ) selection; 371 + W.char w ')'; 372 + sp w; 373 + astring w reference; 374 + sp w; 375 + (* Patterns - multiple patterns in parentheses *) 376 + (match patterns with 377 + | [p] -> astring w p 378 + | ps -> 379 + W.char w '('; 380 + List.iteri (fun i p -> 381 + if i > 0 then sp w; 382 + astring w p 383 + ) ps; 384 + W.char w ')'); 385 + (* Return options - RFC 5258 Section 3.2 *) 386 + (match return_opts with 387 + | [] -> () 388 + | opts -> 389 + sp w; 390 + W.string w "RETURN ("; 391 + List.iteri (fun i opt -> 392 + if i > 0 then sp w; 393 + match opt with 394 + | List_return_subscribed -> W.string w "SUBSCRIBED" 395 + | List_return_children -> W.string w "CHILDREN" 396 + | List_return_special_use -> W.string w "SPECIAL-USE" 397 + ) opts; 398 + W.char w ')')) 399 | Namespace -> W.string w "NAMESPACE" 400 | Status { mailbox; items } -> 401 W.string w "STATUS "; ··· 490 search_key w criteria 491 | Uid_expunge set -> 492 W.string w "EXPUNGE "; 493 + sequence_set w set 494 + | Uid_thread { algorithm; charset; criteria } -> 495 + W.string w "THREAD "; 496 + (match algorithm with 497 + | Thread_orderedsubject -> W.string w "ORDEREDSUBJECT" 498 + | Thread_references -> W.string w "REFERENCES" 499 + | Thread_extension ext -> astring w ext); 500 + sp w; 501 + astring w charset; 502 + sp w; 503 + search_key w criteria) 504 | Id params -> 505 W.string w "ID "; 506 id_params w params 507 + (* QUOTA extension - RFC 9208 *) 508 + | Getquota root -> 509 + W.string w "GETQUOTA "; 510 + astring w root 511 + | Getquotaroot mailbox -> 512 + W.string w "GETQUOTAROOT "; 513 + astring w mailbox 514 + | Setquota { root; limits } -> 515 + W.string w "SETQUOTA "; 516 + astring w root; 517 + sp w; 518 + W.char w '('; 519 + List.iteri (fun i (res, limit) -> 520 + if i > 0 then sp w; 521 + (match res with 522 + | Quota_storage -> W.string w "STORAGE" 523 + | Quota_message -> W.string w "MESSAGE" 524 + | Quota_mailbox -> W.string w "MAILBOX" 525 + | Quota_annotation_storage -> W.string w "ANNOTATION-STORAGE"); 526 + sp w; 527 + W.string w (Int64.to_string limit) 528 + ) limits; 529 + W.char w ')' 530 + (* THREAD extension - RFC 5256 *) 531 + | Thread { algorithm; charset; criteria } -> 532 + W.string w "THREAD "; 533 + (match algorithm with 534 + | Thread_orderedsubject -> W.string w "ORDEREDSUBJECT" 535 + | Thread_references -> W.string w "REFERENCES" 536 + | Thread_extension ext -> astring w ext); 537 + sp w; 538 + astring w charset; 539 + sp w; 540 + search_key w criteria 541 542 let command w ~tag cmd = 543 atom w tag;
+8
ocaml-imap/test/dune
··· 29 (test 30 (name test_client) 31 (libraries imap alcotest eio eio_main))
··· 29 (test 30 (name test_client) 31 (libraries imap alcotest eio eio_main)) 32 + 33 + (test 34 + (name test_subject) 35 + (libraries imap alcotest)) 36 + 37 + (test 38 + (name test_utf8) 39 + (libraries imapd alcotest))
+1 -1
ocaml-imap/test/test_parser.ml
··· 64 65 let test_parse_list () = 66 match parse_command "A008 LIST \"\" \"*\"\r\n" with 67 - | Ok { tag; command = List { reference; pattern } } -> 68 Alcotest.(check string) "tag" "A008" tag; 69 Alcotest.(check string) "reference" "" reference; 70 Alcotest.(check string) "pattern" "*" pattern
··· 64 65 let test_parse_list () = 66 match parse_command "A008 LIST \"\" \"*\"\r\n" with 67 + | Ok { tag; command = List (List_basic { reference; pattern }) } -> 68 Alcotest.(check string) "tag" "A008" tag; 69 Alcotest.(check string) "reference" "" reference; 70 Alcotest.(check string) "pattern" "*" pattern
+449
ocaml-imap/test/test_read.ml
··· 81 let is_enabled = function Imap.Response.Enabled _ -> true | _ -> false 82 let is_id = function Imap.Response.Id _ -> true | _ -> false 83 let is_fetch = function Imap.Response.Fetch _ -> true | _ -> false 84 85 let test_response_ok_tagged () = 86 let result = with_reader "A001 OK Success\r\n" (fun r -> Imap.Read.response r) in ··· 288 Alcotest.(check int) "untagged count" 2 (List.length untagged); 289 Alcotest.(check bool) "final is OK" true (is_ok final) 290 291 let () = 292 let open Alcotest in 293 run "imap_read" ··· 337 test_case "ENABLED" `Quick test_response_enabled; 338 test_case "ID" `Quick test_response_id; 339 test_case "ID NIL" `Quick test_response_id_nil; 340 test_case "responses until tagged" `Quick test_responses_until_tagged; 341 ] ); 342 ]
··· 81 let is_enabled = function Imap.Response.Enabled _ -> true | _ -> false 82 let is_id = function Imap.Response.Id _ -> true | _ -> false 83 let is_fetch = function Imap.Response.Fetch _ -> true | _ -> false 84 + let is_search = function Imap.Response.Search _ -> true | _ -> false 85 + let is_sort = function Imap.Response.Sort _ -> true | _ -> false 86 87 let test_response_ok_tagged () = 88 let result = with_reader "A001 OK Success\r\n" (fun r -> Imap.Read.response r) in ··· 290 Alcotest.(check int) "untagged count" 2 (List.length untagged); 291 Alcotest.(check bool) "final is OK" true (is_ok final) 292 293 + (* BODY/BODYSTRUCTURE parsing tests *) 294 + 295 + let is_body_text body = 296 + match body.Imap.Body.body_type with 297 + | Imap.Body.Text _ -> true 298 + | _ -> false 299 + 300 + let is_body_basic body = 301 + match body.Imap.Body.body_type with 302 + | Imap.Body.Basic _ -> true 303 + | _ -> false 304 + 305 + let is_body_multipart body = 306 + match body.Imap.Body.body_type with 307 + | Imap.Body.Multipart _ -> true 308 + | _ -> false 309 + 310 + let test_fetch_body_text_plain () = 311 + (* Simple TEXT/PLAIN body structure *) 312 + let result = 313 + with_reader "* 1 FETCH (BODY (\"TEXT\" \"PLAIN\" (\"CHARSET\" \"UTF-8\") NIL NIL \"7BIT\" 100 5))\r\n" 314 + (fun r -> Imap.Read.response r) 315 + in 316 + Alcotest.(check bool) "is FETCH" true (is_fetch result); 317 + match result with 318 + | Imap.Response.Fetch { items; _ } -> 319 + let body_opt = 320 + List.find_map 321 + (function Imap.Fetch.Item_body b -> Some b | _ -> None) 322 + items 323 + in 324 + (match body_opt with 325 + | Some body -> 326 + Alcotest.(check bool) "is text type" true (is_body_text body); 327 + (match body.body_type with 328 + | Imap.Body.Text { subtype; fields; lines } -> 329 + Alcotest.(check string) "subtype" "PLAIN" subtype; 330 + Alcotest.(check int64) "size" 100L fields.size; 331 + Alcotest.(check int64) "lines" 5L lines; 332 + Alcotest.(check string) "encoding" "7BIT" fields.encoding 333 + | _ -> Alcotest.fail "expected Text body type") 334 + | None -> Alcotest.fail "expected BODY item") 335 + | _ -> Alcotest.fail "expected FETCH" 336 + 337 + let test_fetch_body_basic () = 338 + (* Basic APPLICATION/OCTET-STREAM body structure *) 339 + let result = 340 + with_reader "* 1 FETCH (BODY (\"APPLICATION\" \"OCTET-STREAM\" NIL NIL NIL \"BASE64\" 2048))\r\n" 341 + (fun r -> Imap.Read.response r) 342 + in 343 + match result with 344 + | Imap.Response.Fetch { items; _ } -> 345 + let body_opt = 346 + List.find_map 347 + (function Imap.Fetch.Item_body b -> Some b | _ -> None) 348 + items 349 + in 350 + (match body_opt with 351 + | Some body -> 352 + Alcotest.(check bool) "is basic type" true (is_body_basic body); 353 + (match body.body_type with 354 + | Imap.Body.Basic { media_type; subtype; fields } -> 355 + Alcotest.(check string) "media_type" "APPLICATION" media_type; 356 + Alcotest.(check string) "subtype" "OCTET-STREAM" subtype; 357 + Alcotest.(check int64) "size" 2048L fields.size 358 + | _ -> Alcotest.fail "expected Basic body type") 359 + | None -> Alcotest.fail "expected BODY item") 360 + | _ -> Alcotest.fail "expected FETCH" 361 + 362 + let test_fetch_bodystructure_multipart () = 363 + (* Multipart ALTERNATIVE body structure *) 364 + let result = 365 + with_reader "* 1 FETCH (BODYSTRUCTURE ((\"TEXT\" \"PLAIN\" NIL NIL NIL \"7BIT\" 50 2)(\"TEXT\" \"HTML\" NIL NIL NIL \"QUOTED-PRINTABLE\" 200 10) \"ALTERNATIVE\"))\r\n" 366 + (fun r -> Imap.Read.response r) 367 + in 368 + match result with 369 + | Imap.Response.Fetch { items; _ } -> 370 + let body_opt = 371 + List.find_map 372 + (function Imap.Fetch.Item_bodystructure b -> Some b | _ -> None) 373 + items 374 + in 375 + (match body_opt with 376 + | Some body -> 377 + Alcotest.(check bool) "is multipart" true (is_body_multipart body); 378 + (match body.body_type with 379 + | Imap.Body.Multipart { subtype; parts; _ } -> 380 + Alcotest.(check string) "subtype" "ALTERNATIVE" subtype; 381 + Alcotest.(check int) "parts count" 2 (List.length parts) 382 + | _ -> Alcotest.fail "expected Multipart body type") 383 + | None -> Alcotest.fail "expected BODYSTRUCTURE item") 384 + | _ -> Alcotest.fail "expected FETCH" 385 + 386 + let test_fetch_body_section () = 387 + (* BODY[TEXT] with literal content *) 388 + let result = 389 + with_reader "* 1 FETCH (BODY[TEXT] {10}\r\nHello test)\r\n" 390 + (fun r -> Imap.Read.response r) 391 + in 392 + match result with 393 + | Imap.Response.Fetch { items; _ } -> 394 + let section_opt = 395 + List.find_map 396 + (function 397 + | Imap.Fetch.Item_body_section { section; origin; data } -> 398 + Some (section, origin, data) 399 + | _ -> None) 400 + items 401 + in 402 + (match section_opt with 403 + | Some (section, origin, data) -> 404 + (match section with 405 + | Some Imap.Body.Text -> () 406 + | _ -> Alcotest.fail "expected TEXT section"); 407 + Alcotest.(check (option int)) "no origin" None origin; 408 + Alcotest.(check (option string)) "data" (Some "Hello test") data 409 + | None -> Alcotest.fail "expected BODY section item") 410 + | _ -> Alcotest.fail "expected FETCH" 411 + 412 + let test_fetch_body_section_header () = 413 + (* BODY[HEADER] with quoted string content *) 414 + (* Note: IMAP quoted strings treat \r and \n as literal backslash + char *) 415 + let result = 416 + with_reader "* 1 FETCH (BODY[HEADER] \"Subject: Test\")\r\n" 417 + (fun r -> Imap.Read.response r) 418 + in 419 + match result with 420 + | Imap.Response.Fetch { items; _ } -> 421 + let section_opt = 422 + List.find_map 423 + (function 424 + | Imap.Fetch.Item_body_section { section; data; _ } -> 425 + Some (section, data) 426 + | _ -> None) 427 + items 428 + in 429 + (match section_opt with 430 + | Some (section, data) -> 431 + (match section with 432 + | Some Imap.Body.Header -> () 433 + | _ -> Alcotest.fail "expected HEADER section"); 434 + Alcotest.(check (option string)) "data" (Some "Subject: Test") data 435 + | None -> Alcotest.fail "expected BODY section item") 436 + | _ -> Alcotest.fail "expected FETCH" 437 + 438 + let test_fetch_body_section_with_origin () = 439 + (* BODY[]<0> with partial origin *) 440 + let result = 441 + with_reader "* 1 FETCH (BODY[]<0> {5}\r\nhello)\r\n" 442 + (fun r -> Imap.Read.response r) 443 + in 444 + match result with 445 + | Imap.Response.Fetch { items; _ } -> 446 + let section_opt = 447 + List.find_map 448 + (function 449 + | Imap.Fetch.Item_body_section { section; origin; data } -> 450 + Some (section, origin, data) 451 + | _ -> None) 452 + items 453 + in 454 + (match section_opt with 455 + | Some (section, origin, data) -> 456 + Alcotest.(check (option int)) "origin" (Some 0) origin; 457 + Alcotest.(check bool) "no section" true (Option.is_none section); 458 + Alcotest.(check (option string)) "data" (Some "hello") data 459 + | None -> Alcotest.fail "expected BODY section item") 460 + | _ -> Alcotest.fail "expected FETCH" 461 + 462 + let test_fetch_body_section_part () = 463 + (* BODY[1.2] for nested part *) 464 + let result = 465 + with_reader "* 1 FETCH (BODY[1.2] \"part data\")\r\n" 466 + (fun r -> Imap.Read.response r) 467 + in 468 + match result with 469 + | Imap.Response.Fetch { items; _ } -> 470 + let section_opt = 471 + List.find_map 472 + (function 473 + | Imap.Fetch.Item_body_section { section; data; _ } -> 474 + Some (section, data) 475 + | _ -> None) 476 + items 477 + in 478 + (match section_opt with 479 + | Some (section, data) -> 480 + (match section with 481 + | Some (Imap.Body.Part ([1; 2], None)) -> () 482 + | Some (Imap.Body.Part (nums, _)) -> 483 + Alcotest.fail (Printf.sprintf "wrong part numbers: [%s]" 484 + (String.concat "; " (List.map string_of_int nums))) 485 + | _ -> Alcotest.fail "expected Part section"); 486 + Alcotest.(check (option string)) "data" (Some "part data") data 487 + | None -> Alcotest.fail "expected BODY section item") 488 + | _ -> Alcotest.fail "expected FETCH" 489 + 490 + let test_fetch_body_section_nil () = 491 + (* BODY[TEXT] with NIL content *) 492 + let result = 493 + with_reader "* 1 FETCH (BODY[TEXT] NIL)\r\n" 494 + (fun r -> Imap.Read.response r) 495 + in 496 + match result with 497 + | Imap.Response.Fetch { items; _ } -> 498 + let section_opt = 499 + List.find_map 500 + (function 501 + | Imap.Fetch.Item_body_section { data; _ } -> Some data 502 + | _ -> None) 503 + items 504 + in 505 + (match section_opt with 506 + | Some data -> 507 + Alcotest.(check (option string)) "nil data" None data 508 + | None -> Alcotest.fail "expected BODY section item") 509 + | _ -> Alcotest.fail "expected FETCH" 510 + 511 + let test_fetch_bodystructure_with_extensions () = 512 + (* BODYSTRUCTURE with extension data (disposition, language, location) *) 513 + let result = 514 + with_reader "* 1 FETCH (BODYSTRUCTURE (\"TEXT\" \"PLAIN\" (\"CHARSET\" \"UTF-8\") NIL NIL \"7BIT\" 100 5 NIL (\"INLINE\" NIL) \"EN\" NIL))\r\n" 515 + (fun r -> Imap.Read.response r) 516 + in 517 + match result with 518 + | Imap.Response.Fetch { items; _ } -> 519 + let body_opt = 520 + List.find_map 521 + (function Imap.Fetch.Item_bodystructure b -> Some b | _ -> None) 522 + items 523 + in 524 + (match body_opt with 525 + | Some body -> 526 + Alcotest.(check bool) "is text type" true (is_body_text body); 527 + (match body.disposition with 528 + | Some (disp_type, _) -> 529 + Alcotest.(check string) "disposition" "INLINE" disp_type 530 + | None -> Alcotest.fail "expected disposition"); 531 + (match body.language with 532 + | Some [lang] -> Alcotest.(check string) "language" "EN" lang 533 + | _ -> Alcotest.fail "expected language") 534 + | None -> Alcotest.fail "expected BODYSTRUCTURE item") 535 + | _ -> Alcotest.fail "expected FETCH" 536 + 537 + let test_response_search () = 538 + let result = 539 + with_reader "* SEARCH 2 4 7 11\r\n" (fun r -> Imap.Read.response r) 540 + in 541 + Alcotest.(check bool) "is SEARCH" true (is_search result); 542 + match result with 543 + | Imap.Response.Search seqs -> 544 + Alcotest.(check (list int)) "search results" [2; 4; 7; 11] seqs 545 + | _ -> Alcotest.fail "expected SEARCH" 546 + 547 + let test_response_search_empty () = 548 + let result = 549 + with_reader "* SEARCH\r\n" (fun r -> Imap.Read.response r) 550 + in 551 + Alcotest.(check bool) "is SEARCH" true (is_search result); 552 + match result with 553 + | Imap.Response.Search seqs -> 554 + Alcotest.(check (list int)) "empty search" [] seqs 555 + | _ -> Alcotest.fail "expected SEARCH" 556 + 557 + let test_response_search_single () = 558 + let result = 559 + with_reader "* SEARCH 42\r\n" (fun r -> Imap.Read.response r) 560 + in 561 + match result with 562 + | Imap.Response.Search seqs -> 563 + Alcotest.(check (list int)) "single search result" [42] seqs 564 + | _ -> Alcotest.fail "expected SEARCH" 565 + 566 + let test_response_sort () = 567 + let result = 568 + with_reader "* SORT 5 3 1 8\r\n" (fun r -> Imap.Read.response r) 569 + in 570 + Alcotest.(check bool) "is SORT" true (is_sort result); 571 + match result with 572 + | Imap.Response.Sort seqs -> 573 + Alcotest.(check (list int64)) "sort results" [5L; 3L; 1L; 8L] seqs 574 + | _ -> Alcotest.fail "expected SORT" 575 + 576 + let test_response_sort_empty () = 577 + let result = 578 + with_reader "* SORT\r\n" (fun r -> Imap.Read.response r) 579 + in 580 + match result with 581 + | Imap.Response.Sort seqs -> 582 + Alcotest.(check (list int64)) "empty sort" [] seqs 583 + | _ -> Alcotest.fail "expected SORT" 584 + 585 + let test_response_appenduid () = 586 + let result = 587 + with_reader "A001 OK [APPENDUID 38505 3955] APPEND completed\r\n" (fun r -> Imap.Read.response r) 588 + in 589 + match result with 590 + | Imap.Response.Ok { code = Some (Imap.Code.Appenduid (uidvalidity, uid)); _ } -> 591 + Alcotest.(check int64) "uidvalidity" 38505L uidvalidity; 592 + Alcotest.(check int64) "uid" 3955L uid 593 + | _ -> Alcotest.fail "expected APPENDUID" 594 + 595 + let test_response_copyuid_single () = 596 + let result = 597 + with_reader "A002 OK [COPYUID 38505 304 3956] Done\r\n" (fun r -> Imap.Read.response r) 598 + in 599 + match result with 600 + | Imap.Response.Ok { code = Some (Imap.Code.Copyuid (uidvalidity, source_uids, dest_uids)); _ } -> 601 + Alcotest.(check int64) "uidvalidity" 38505L uidvalidity; 602 + Alcotest.(check int) "source count" 1 (List.length source_uids); 603 + Alcotest.(check int) "dest count" 1 (List.length dest_uids) 604 + | _ -> Alcotest.fail "expected COPYUID" 605 + 606 + let test_response_copyuid_range () = 607 + let result = 608 + with_reader "A002 OK [COPYUID 38505 304,319:320 3956:3958] Done\r\n" (fun r -> Imap.Read.response r) 609 + in 610 + match result with 611 + | Imap.Response.Ok { code = Some (Imap.Code.Copyuid (uidvalidity, source_uids, dest_uids)); _ } -> 612 + Alcotest.(check int64) "uidvalidity" 38505L uidvalidity; 613 + (* source_uids should have 2 ranges: 304 and 319:320 *) 614 + Alcotest.(check int) "source count" 2 (List.length source_uids); 615 + (* dest_uids should have 1 range: 3956:3958 *) 616 + Alcotest.(check int) "dest count" 1 (List.length dest_uids) 617 + | _ -> Alcotest.fail "expected COPYUID" 618 + 619 + (* Helper to check if response is THREAD *) 620 + let is_thread = function Imap.Response.Thread _ -> true | _ -> false 621 + 622 + (* RFC 5256 THREAD response tests *) 623 + let test_response_thread_empty () = 624 + (* Empty THREAD response - no matching messages or no threads *) 625 + let result = 626 + with_reader "* THREAD\r\n" (fun r -> Imap.Read.response r) 627 + in 628 + Alcotest.(check bool) "is THREAD" true (is_thread result); 629 + match result with 630 + | Imap.Response.Thread threads -> 631 + Alcotest.(check int) "empty threads" 0 (List.length threads) 632 + | _ -> Alcotest.fail "expected THREAD" 633 + 634 + let test_response_thread_single () = 635 + (* Single thread with one message: (2) *) 636 + let result = 637 + with_reader "* THREAD (2)\r\n" (fun r -> Imap.Read.response r) 638 + in 639 + Alcotest.(check bool) "is THREAD" true (is_thread result); 640 + match result with 641 + | Imap.Response.Thread threads -> 642 + Alcotest.(check int) "thread count" 1 (List.length threads); 643 + (match List.hd threads with 644 + | Imap.Thread.Message (n, children) -> 645 + Alcotest.(check int) "message number" 2 n; 646 + Alcotest.(check int) "no children" 0 (List.length children) 647 + | _ -> Alcotest.fail "expected Message node") 648 + | _ -> Alcotest.fail "expected THREAD" 649 + 650 + let test_response_thread_multiple_roots () = 651 + (* Multiple independent threads: (2)(3) *) 652 + let result = 653 + with_reader "* THREAD (2)(3)\r\n" (fun r -> Imap.Read.response r) 654 + in 655 + match result with 656 + | Imap.Response.Thread threads -> 657 + Alcotest.(check int) "thread count" 2 (List.length threads) 658 + | _ -> Alcotest.fail "expected THREAD" 659 + 660 + let test_response_thread_with_children () = 661 + (* Thread with parent-child: (3 (6)) means 3 has child 6 *) 662 + let result = 663 + with_reader "* THREAD (3 (6))\r\n" (fun r -> Imap.Read.response r) 664 + in 665 + match result with 666 + | Imap.Response.Thread threads -> 667 + Alcotest.(check int) "thread count" 1 (List.length threads); 668 + (match List.hd threads with 669 + | Imap.Thread.Message (n, children) -> 670 + Alcotest.(check int) "parent message" 3 n; 671 + Alcotest.(check int) "one child" 1 (List.length children); 672 + (match List.hd children with 673 + | Imap.Thread.Message (cn, _) -> 674 + Alcotest.(check int) "child message" 6 cn 675 + | _ -> Alcotest.fail "expected child Message node") 676 + | _ -> Alcotest.fail "expected Message node") 677 + | _ -> Alcotest.fail "expected THREAD" 678 + 679 + let test_response_thread_complex () = 680 + (* Complex thread structure: 681 + (2)(3 (6) (4 (23))(44 (7) (96))) 682 + - Thread 1: Message 2 alone 683 + - Thread 2: Message 3 with children 6, (4 with child 23), and (44 with children 7 and 96) *) 684 + let result = 685 + with_reader "* THREAD (2)(3 (6) (4 (23))(44 (7) (96)))\r\n" (fun r -> Imap.Read.response r) 686 + in 687 + match result with 688 + | Imap.Response.Thread threads -> 689 + Alcotest.(check int) "thread count" 2 (List.length threads); 690 + (* First thread should be message 2 *) 691 + (match List.hd threads with 692 + | Imap.Thread.Message (n, _) -> 693 + Alcotest.(check int) "first thread root" 2 n 694 + | _ -> Alcotest.fail "expected Message node for first thread") 695 + | _ -> Alcotest.fail "expected THREAD" 696 + 697 + let test_response_thread_dummy_node () = 698 + (* Dummy node (missing parent): ((5)(6)) - two messages sharing missing parent *) 699 + let result = 700 + with_reader "* THREAD ((5)(6))\r\n" (fun r -> Imap.Read.response r) 701 + in 702 + match result with 703 + | Imap.Response.Thread threads -> 704 + Alcotest.(check int) "thread count" 1 (List.length threads); 705 + (match List.hd threads with 706 + | Imap.Thread.Dummy children -> 707 + Alcotest.(check int) "two orphaned children" 2 (List.length children) 708 + | _ -> Alcotest.fail "expected Dummy node") 709 + | _ -> Alcotest.fail "expected THREAD" 710 + 711 let () = 712 let open Alcotest in 713 run "imap_read" ··· 757 test_case "ENABLED" `Quick test_response_enabled; 758 test_case "ID" `Quick test_response_id; 759 test_case "ID NIL" `Quick test_response_id_nil; 760 + test_case "SEARCH" `Quick test_response_search; 761 + test_case "SEARCH empty" `Quick test_response_search_empty; 762 + test_case "SEARCH single" `Quick test_response_search_single; 763 + test_case "SORT" `Quick test_response_sort; 764 + test_case "SORT empty" `Quick test_response_sort_empty; 765 + test_case "APPENDUID" `Quick test_response_appenduid; 766 + test_case "COPYUID single" `Quick test_response_copyuid_single; 767 + test_case "COPYUID range" `Quick test_response_copyuid_range; 768 test_case "responses until tagged" `Quick test_responses_until_tagged; 769 + ] ); 770 + ( "body", 771 + [ 772 + test_case "BODY TEXT/PLAIN" `Quick test_fetch_body_text_plain; 773 + test_case "BODY basic" `Quick test_fetch_body_basic; 774 + test_case "BODYSTRUCTURE multipart" `Quick test_fetch_bodystructure_multipart; 775 + test_case "BODY[TEXT] section" `Quick test_fetch_body_section; 776 + test_case "BODY[HEADER] section" `Quick test_fetch_body_section_header; 777 + test_case "BODY[]<origin>" `Quick test_fetch_body_section_with_origin; 778 + test_case "BODY[1.2] part" `Quick test_fetch_body_section_part; 779 + test_case "BODY[TEXT] NIL" `Quick test_fetch_body_section_nil; 780 + test_case "BODYSTRUCTURE extensions" `Quick test_fetch_bodystructure_with_extensions; 781 + ] ); 782 + ( "thread", 783 + [ 784 + test_case "THREAD empty" `Quick test_response_thread_empty; 785 + test_case "THREAD single message" `Quick test_response_thread_single; 786 + test_case "THREAD multiple roots" `Quick test_response_thread_multiple_roots; 787 + test_case "THREAD with children" `Quick test_response_thread_with_children; 788 + test_case "THREAD complex" `Quick test_response_thread_complex; 789 + test_case "THREAD dummy node" `Quick test_response_thread_dummy_node; 790 ] ); 791 ]
+3 -2
ocaml-imap/test/test_server.ml
··· 66 (contains_substring ~substring:"STARTTLS" serialized) 67 68 let test_list_response () = 69 - let response = List_response { flags = []; delimiter = Some '/'; name = "INBOX" } in 70 let serialized = response_to_string response in 71 Alcotest.(check bool) "has LIST" true 72 (contains_substring ~substring:"LIST" serialized); ··· 172 | Result.Ok cmd -> 173 Alcotest.(check string) "tag" "A005" cmd.tag; 174 (match cmd.command with 175 - | List { reference; pattern } -> 176 Alcotest.(check string) "reference" "" reference; 177 Alcotest.(check string) "pattern" "*" pattern 178 | _ -> Alcotest.fail "Expected List command") 179 | Result.Error msg -> Alcotest.fail ("Parse failed: " ^ msg) 180
··· 66 (contains_substring ~substring:"STARTTLS" serialized) 67 68 let test_list_response () = 69 + let response = List_response { flags = []; delimiter = Some '/'; name = "INBOX"; extended = [] } in 70 let serialized = response_to_string response in 71 Alcotest.(check bool) "has LIST" true 72 (contains_substring ~substring:"LIST" serialized); ··· 172 | Result.Ok cmd -> 173 Alcotest.(check string) "tag" "A005" cmd.tag; 174 (match cmd.command with 175 + | List (List_basic { reference; pattern }) -> 176 Alcotest.(check string) "reference" "" reference; 177 Alcotest.(check string) "pattern" "*" pattern 178 + | List (List_extended _) -> Alcotest.fail "Expected basic List command" 179 | _ -> Alcotest.fail "Expected List command") 180 | Result.Error msg -> Alcotest.fail ("Parse failed: " ^ msg) 181
+142
ocaml-imap/test/test_subject.ml
···
··· 1 + (*--------------------------------------------------------------------------- 2 + Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 + 6 + (** Tests for Subject base extraction (RFC 5256 Section 2.1) *) 7 + 8 + open Imap 9 + 10 + (* Test basic Re: prefix removal *) 11 + let test_re_prefix () = 12 + Alcotest.(check string) "Re: prefix" "test" (Subject.base_subject "Re: test"); 13 + Alcotest.(check string) "RE: uppercase" "test" (Subject.base_subject "RE: test"); 14 + Alcotest.(check string) "re: lowercase" "test" (Subject.base_subject "re: test"); 15 + Alcotest.(check string) "Re: extra space" "test" (Subject.base_subject "Re: test") 16 + 17 + (* Test Fw: and Fwd: prefix removal *) 18 + let test_fw_fwd_prefix () = 19 + Alcotest.(check string) "Fw: prefix" "test" (Subject.base_subject "Fw: test"); 20 + Alcotest.(check string) "FW: uppercase" "test" (Subject.base_subject "FW: test"); 21 + Alcotest.(check string) "Fwd: prefix" "test" (Subject.base_subject "Fwd: test"); 22 + Alcotest.(check string) "FWD: uppercase" "test" (Subject.base_subject "FWD: test"); 23 + Alcotest.(check string) "fwd: lowercase" "test" (Subject.base_subject "fwd: test") 24 + 25 + (* Test nested prefixes *) 26 + let test_nested_prefixes () = 27 + Alcotest.(check string) "Re: Re:" "test" (Subject.base_subject "Re: Re: test"); 28 + Alcotest.(check string) "Re: Re: Re:" "test" (Subject.base_subject "Re: Re: Re: test"); 29 + Alcotest.(check string) "Fwd: Re:" "test" (Subject.base_subject "Fwd: Re: test"); 30 + Alcotest.(check string) "Re: Fwd:" "test" (Subject.base_subject "Re: Fwd: test"); 31 + Alcotest.(check string) "Re: Fw: Re:" "test" (Subject.base_subject "Re: Fw: Re: test") 32 + 33 + (* Test trailing (fwd) removal *) 34 + let test_fwd_trailer () = 35 + Alcotest.(check string) "trailing (fwd)" "test" (Subject.base_subject "test (fwd)"); 36 + Alcotest.(check string) "trailing (FWD)" "test" (Subject.base_subject "test (FWD)"); 37 + Alcotest.(check string) "trailing (Fwd)" "test" (Subject.base_subject "test (Fwd)"); 38 + Alcotest.(check string) "multiple (fwd)" "test" (Subject.base_subject "test (fwd) (fwd)") 39 + 40 + (* Test [blob] removal *) 41 + let test_blob_removal () = 42 + Alcotest.(check string) "[PATCH] prefix" "test" (Subject.base_subject "[PATCH] test"); 43 + Alcotest.(check string) "[ocaml-list] prefix" "test" (Subject.base_subject "[ocaml-list] test"); 44 + Alcotest.(check string) "multiple blobs" "test" (Subject.base_subject "[PATCH] [v2] test"); 45 + Alcotest.(check string) "blob after Re:" "test" (Subject.base_subject "Re: [PATCH] test"); 46 + Alcotest.(check string) "Re: with blob" "test" (Subject.base_subject "Re[PATCH]: test") 47 + 48 + (* Test combined patterns *) 49 + let test_combined_patterns () = 50 + Alcotest.(check string) "[PATCH] Re: [ocaml] test" "test" 51 + (Subject.base_subject "[PATCH] Re: [ocaml] test"); 52 + Alcotest.(check string) "Re: [list] Re: subject" "subject" 53 + (Subject.base_subject "Re: [list] Re: subject"); 54 + Alcotest.(check string) "complex nested" "actual subject" 55 + (Subject.base_subject "Re: [list] Fwd: Re: [PATCH] actual subject") 56 + 57 + (* Test [fwd: ...] wrapper *) 58 + let test_fwd_wrapper () = 59 + Alcotest.(check string) "[fwd: wrapped]" "wrapped" (Subject.base_subject "[fwd: wrapped]"); 60 + Alcotest.(check string) "[FWD: wrapped]" "wrapped" (Subject.base_subject "[FWD: wrapped]"); 61 + Alcotest.(check string) "[fwd: Re: test]" "test" (Subject.base_subject "[fwd: Re: test]") 62 + 63 + (* Test whitespace normalization *) 64 + let test_whitespace () = 65 + Alcotest.(check string) "leading spaces" "spaced" (Subject.base_subject " spaced"); 66 + Alcotest.(check string) "trailing spaces" "spaced" (Subject.base_subject "spaced "); 67 + Alcotest.(check string) "both sides" "spaced" (Subject.base_subject " spaced "); 68 + Alcotest.(check string) "multiple internal" "hello world" (Subject.base_subject "hello world"); 69 + Alcotest.(check string) "tabs" "hello world" (Subject.base_subject "hello\tworld"); 70 + Alcotest.(check string) "mixed whitespace" "hello world" (Subject.base_subject " hello \t world ") 71 + 72 + (* Test edge cases *) 73 + let test_edge_cases () = 74 + Alcotest.(check string) "empty string" "" (Subject.base_subject ""); 75 + Alcotest.(check string) "only Re:" "" (Subject.base_subject "Re:"); 76 + Alcotest.(check string) "only spaces" "" (Subject.base_subject " "); 77 + Alcotest.(check string) "just a blob" "[PATCH]" (Subject.base_subject "[PATCH]"); 78 + Alcotest.(check string) "incomplete fwd wrapper" "[fwd: test" (Subject.base_subject "[fwd: test"); 79 + Alcotest.(check string) "Re without colon" "Re test" (Subject.base_subject "Re test") 80 + 81 + (* Test is_reply_or_forward *) 82 + let test_is_reply_or_forward () = 83 + Alcotest.(check bool) "Re: is reply" true (Subject.is_reply_or_forward "Re: test"); 84 + Alcotest.(check bool) "Fwd: is forward" true (Subject.is_reply_or_forward "Fwd: test"); 85 + Alcotest.(check bool) "Fw: is forward" true (Subject.is_reply_or_forward "Fw: test"); 86 + Alcotest.(check bool) "(fwd) is forward" true (Subject.is_reply_or_forward "test (fwd)"); 87 + Alcotest.(check bool) "[fwd:] is forward" true (Subject.is_reply_or_forward "[fwd: test]"); 88 + Alcotest.(check bool) "plain is not reply" false (Subject.is_reply_or_forward "test"); 89 + Alcotest.(check bool) "[PATCH] is not reply" false (Subject.is_reply_or_forward "[PATCH] test") 90 + 91 + (* Test real-world examples *) 92 + let test_real_world () = 93 + Alcotest.(check string) "mailing list style" 94 + "How to use functors?" 95 + (Subject.base_subject "[ocaml-list] Re: How to use functors?"); 96 + Alcotest.(check string) "patch series" 97 + "Add new feature" 98 + (Subject.base_subject "[PATCH v3 1/5] Add new feature"); 99 + Alcotest.(check string) "forwarded thread" 100 + "Meeting tomorrow" 101 + (Subject.base_subject "Fwd: Re: Re: Meeting tomorrow"); 102 + Alcotest.(check string) "bug tracker style" 103 + "Fix memory leak" 104 + (Subject.base_subject "Re: [Bug 12345] Fix memory leak (fwd)") 105 + 106 + let () = 107 + let open Alcotest in 108 + run "subject" [ 109 + "re_prefix", [ 110 + test_case "Re: prefix removal" `Quick test_re_prefix; 111 + ]; 112 + "fw_fwd_prefix", [ 113 + test_case "Fw:/Fwd: prefix removal" `Quick test_fw_fwd_prefix; 114 + ]; 115 + "nested_prefixes", [ 116 + test_case "Nested prefixes" `Quick test_nested_prefixes; 117 + ]; 118 + "fwd_trailer", [ 119 + test_case "(fwd) trailer removal" `Quick test_fwd_trailer; 120 + ]; 121 + "blob_removal", [ 122 + test_case "[blob] removal" `Quick test_blob_removal; 123 + ]; 124 + "combined", [ 125 + test_case "Combined patterns" `Quick test_combined_patterns; 126 + ]; 127 + "fwd_wrapper", [ 128 + test_case "[fwd: ...] wrapper" `Quick test_fwd_wrapper; 129 + ]; 130 + "whitespace", [ 131 + test_case "Whitespace normalization" `Quick test_whitespace; 132 + ]; 133 + "edge_cases", [ 134 + test_case "Edge cases" `Quick test_edge_cases; 135 + ]; 136 + "is_reply_or_forward", [ 137 + test_case "is_reply_or_forward" `Quick test_is_reply_or_forward; 138 + ]; 139 + "real_world", [ 140 + test_case "Real-world examples" `Quick test_real_world; 141 + ]; 142 + ]
+104
ocaml-imap/test/test_utf8.ml
···
··· 1 + (*--------------------------------------------------------------------------- 2 + Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 + 6 + (** Tests for UTF-8 validation per RFC 6855. 7 + @see <https://datatracker.ietf.org/doc/html/rfc6855> RFC 6855: IMAP Support for UTF-8 8 + @see <https://datatracker.ietf.org/doc/html/rfc3629> RFC 3629: UTF-8 encoding *) 9 + 10 + open Imapd.Utf8 11 + 12 + (* Test is_valid_utf8 function *) 13 + 14 + let test_valid_utf8_ascii () = 15 + Alcotest.(check bool) "empty string" true (is_valid_utf8 ""); 16 + Alcotest.(check bool) "ASCII string" true (is_valid_utf8 "Hello, World!"); 17 + Alcotest.(check bool) "ASCII with digits" true (is_valid_utf8 "Test123"); 18 + Alcotest.(check bool) "ASCII with special chars" true (is_valid_utf8 "a@b.com") 19 + 20 + let test_valid_utf8_multibyte () = 21 + (* 2-byte UTF-8: U+00E9 (e with acute) = 0xC3 0xA9 *) 22 + Alcotest.(check bool) "2-byte UTF-8: cafe" true (is_valid_utf8 "caf\xc3\xa9"); 23 + (* 3-byte UTF-8: U+4E2D (Chinese character) = 0xE4 0xB8 0xAD *) 24 + Alcotest.(check bool) "3-byte UTF-8: Chinese" true (is_valid_utf8 "\xe4\xb8\xad\xe6\x96\x87"); 25 + (* 4-byte UTF-8: U+1F600 (grinning face emoji) = 0xF0 0x9F 0x98 0x80 *) 26 + Alcotest.(check bool) "4-byte UTF-8: emoji" true (is_valid_utf8 "\xf0\x9f\x98\x80"); 27 + (* Mixed ASCII and UTF-8 *) 28 + Alcotest.(check bool) "mixed" true (is_valid_utf8 "Hello \xe4\xb8\x96\xe7\x95\x8c") 29 + 30 + let test_invalid_utf8 () = 31 + (* Invalid start bytes *) 32 + Alcotest.(check bool) "invalid 0xFF" false (is_valid_utf8 "\xff"); 33 + Alcotest.(check bool) "invalid 0xFE" false (is_valid_utf8 "\xfe"); 34 + (* Continuation byte without start *) 35 + Alcotest.(check bool) "orphan continuation" false (is_valid_utf8 "\x80"); 36 + (* Truncated sequences *) 37 + Alcotest.(check bool) "truncated 2-byte" false (is_valid_utf8 "\xc3"); 38 + Alcotest.(check bool) "truncated 3-byte" false (is_valid_utf8 "\xe4\xb8"); 39 + Alcotest.(check bool) "truncated 4-byte" false (is_valid_utf8 "\xf0\x9f\x98"); 40 + (* Overlong encodings (RFC 3629 explicitly forbids these) *) 41 + Alcotest.(check bool) "overlong NUL" false (is_valid_utf8 "\xc0\x80"); (* U+0000 as 2 bytes *) 42 + Alcotest.(check bool) "overlong /" false (is_valid_utf8 "\xc0\xaf"); (* U+002F as 2 bytes *) 43 + (* Surrogate pairs (U+D800..U+DFFF are invalid in UTF-8) *) 44 + Alcotest.(check bool) "surrogate D800" false (is_valid_utf8 "\xed\xa0\x80"); (* U+D800 *) 45 + Alcotest.(check bool) "surrogate DFFF" false (is_valid_utf8 "\xed\xbf\xbf"); (* U+DFFF *) 46 + (* Code points above U+10FFFF *) 47 + Alcotest.(check bool) "above max" false (is_valid_utf8 "\xf4\x90\x80\x80") (* U+110000 *) 48 + 49 + (* Test has_non_ascii function *) 50 + 51 + let test_has_non_ascii () = 52 + Alcotest.(check bool) "ASCII only" false (has_non_ascii "Hello"); 53 + Alcotest.(check bool) "empty" false (has_non_ascii ""); 54 + Alcotest.(check bool) "with accented" true (has_non_ascii "caf\xc3\xa9"); 55 + Alcotest.(check bool) "all high bytes" true (has_non_ascii "\x80\x81\x82") 56 + 57 + (* Test is_valid_utf8_mailbox_name function *) 58 + 59 + let test_valid_mailbox_names () = 60 + Alcotest.(check bool) "INBOX" true (is_valid_utf8_mailbox_name "INBOX"); 61 + Alcotest.(check bool) "Sent/2024" true (is_valid_utf8_mailbox_name "Sent/2024"); 62 + Alcotest.(check bool) "Drafts" true (is_valid_utf8_mailbox_name "Drafts"); 63 + (* Chinese "Sent" folder *) 64 + Alcotest.(check bool) "Chinese mailbox" true 65 + (is_valid_utf8_mailbox_name "\xe5\x8f\x91\xe4\xbb\xb6\xe7\xae\xb1"); 66 + (* Japanese "Inbox" folder *) 67 + Alcotest.(check bool) "Japanese mailbox" true 68 + (is_valid_utf8_mailbox_name "\xe5\x8f\x97\xe4\xbf\xa1\xe7\xae\xb1") 69 + 70 + let test_invalid_mailbox_names () = 71 + (* C0 control characters (U+0000..U+001F) *) 72 + Alcotest.(check bool) "NUL char" false (is_valid_utf8_mailbox_name "INBOX\x00"); 73 + Alcotest.(check bool) "control 0x01" false (is_valid_utf8_mailbox_name "Test\x01Name"); 74 + Alcotest.(check bool) "control 0x1F" false (is_valid_utf8_mailbox_name "Test\x1f"); 75 + (* DELETE (U+007F) *) 76 + Alcotest.(check bool) "DELETE char" false (is_valid_utf8_mailbox_name "Test\x7fName"); 77 + (* C1 control characters (U+0080..U+009F) - these are 2-byte UTF-8 sequences *) 78 + Alcotest.(check bool) "C1 control 0x80" false (is_valid_utf8_mailbox_name "Test\xc2\x80Name"); 79 + Alcotest.(check bool) "C1 control 0x9F" false (is_valid_utf8_mailbox_name "Test\xc2\x9fName"); 80 + (* Line separator U+2028 = 0xE2 0x80 0xA8 *) 81 + Alcotest.(check bool) "line separator" false 82 + (is_valid_utf8_mailbox_name "Test\xe2\x80\xa8Name"); 83 + (* Paragraph separator U+2029 = 0xE2 0x80 0xA9 *) 84 + Alcotest.(check bool) "paragraph separator" false 85 + (is_valid_utf8_mailbox_name "Test\xe2\x80\xa9Name"); 86 + (* Invalid UTF-8 should also fail *) 87 + Alcotest.(check bool) "invalid UTF-8" false (is_valid_utf8_mailbox_name "\xff\xfe") 88 + 89 + let () = 90 + let open Alcotest in 91 + run "utf8" [ 92 + "is_valid_utf8", [ 93 + test_case "ASCII strings" `Quick test_valid_utf8_ascii; 94 + test_case "multibyte UTF-8" `Quick test_valid_utf8_multibyte; 95 + test_case "invalid UTF-8" `Quick test_invalid_utf8; 96 + ]; 97 + "has_non_ascii", [ 98 + test_case "detect non-ASCII" `Quick test_has_non_ascii; 99 + ]; 100 + "is_valid_utf8_mailbox_name", [ 101 + test_case "valid mailbox names" `Quick test_valid_mailbox_names; 102 + test_case "invalid mailbox names" `Quick test_invalid_mailbox_names; 103 + ]; 104 + ]
+2 -1
ocaml-imap/test/test_write.ml
··· 195 let result = 196 serialize (fun w -> 197 Imap.Write.command w ~tag:"A014" 198 - (Imap.Command.Search { charset = None; criteria = Imap.Search.Unseen })) 199 in 200 Alcotest.(check string) "search" "A014 SEARCH UNSEEN\r\n" result 201 ··· 209 { 210 charset = None; 211 criteria = Imap.Search.And [ Imap.Search.Unseen; Imap.Search.From "alice@example.com" ]; 212 })) 213 in 214 Alcotest.(check string) "search complex"
··· 195 let result = 196 serialize (fun w -> 197 Imap.Write.command w ~tag:"A014" 198 + (Imap.Command.Search { charset = None; criteria = Imap.Search.Unseen; return_opts = None })) 199 in 200 Alcotest.(check string) "search" "A014 SEARCH UNSEEN\r\n" result 201 ··· 209 { 210 charset = None; 211 criteria = Imap.Search.And [ Imap.Search.Unseen; Imap.Search.From "alice@example.com" ]; 212 + return_opts = None; 213 })) 214 in 215 Alcotest.(check string) "search complex"
+75 -145
ocaml-jmap/lib/core/jmap_types.ml
··· 82 (** {1 Keyword Type} *) 83 84 module Keyword = struct 85 - (** RFC 8621 standard keywords *) 86 type standard = [ 87 | `Seen 88 | `Flagged ··· 95 ] 96 97 (** draft-ietf-mailmaint extended keywords *) 98 - type extended = [ 99 - | `Notify 100 - | `Muted 101 - | `Followed 102 - | `Memo 103 - | `HasMemo 104 - | `HasAttachment 105 - | `HasNoAttachment 106 - | `AutoSent 107 - | `Unsubscribed 108 - | `CanUnsubscribe 109 - | `Imported 110 - | `IsTrusted 111 - | `MaskedEmail 112 - | `New 113 - ] 114 115 (** Apple Mail flag color keywords *) 116 - type flag_bits = [ 117 - | `MailFlagBit0 118 - | `MailFlagBit1 119 - | `MailFlagBit2 120 - ] 121 122 type t = [ 123 | standard 124 | extended ··· 126 | `Custom of string 127 ] 128 129 - let of_string = function 130 - (* RFC 8621 standard keywords *) 131 - | "$seen" -> `Seen 132 - | "$flagged" -> `Flagged 133 - | "$answered" -> `Answered 134 - | "$draft" -> `Draft 135 - | "$forwarded" -> `Forwarded 136 - | "$phishing" -> `Phishing 137 - | "$junk" -> `Junk 138 - | "$notjunk" -> `NotJunk 139 - (* draft-ietf-mailmaint extended keywords *) 140 - | "$notify" -> `Notify 141 - | "$muted" -> `Muted 142 - | "$followed" -> `Followed 143 - | "$memo" -> `Memo 144 - | "$hasmemo" -> `HasMemo 145 - | "$hasattachment" -> `HasAttachment 146 - | "$hasnoattachment" -> `HasNoAttachment 147 - | "$autosent" -> `AutoSent 148 - | "$unsubscribed" -> `Unsubscribed 149 - | "$canunsubscribe" -> `CanUnsubscribe 150 - | "$imported" -> `Imported 151 - | "$istrusted" -> `IsTrusted 152 - | "$maskedemail" -> `MaskedEmail 153 - | "$new" -> `New 154 - (* Apple Mail flag color keywords *) 155 - | "$MailFlagBit0" -> `MailFlagBit0 156 - | "$MailFlagBit1" -> `MailFlagBit1 157 - | "$MailFlagBit2" -> `MailFlagBit2 158 - | s -> `Custom s 159 160 - let to_string = function 161 - (* RFC 8621 standard keywords *) 162 - | `Seen -> "$seen" 163 - | `Flagged -> "$flagged" 164 - | `Answered -> "$answered" 165 - | `Draft -> "$draft" 166 - | `Forwarded -> "$forwarded" 167 - | `Phishing -> "$phishing" 168 - | `Junk -> "$junk" 169 - | `NotJunk -> "$notjunk" 170 - (* draft-ietf-mailmaint extended keywords *) 171 - | `Notify -> "$notify" 172 - | `Muted -> "$muted" 173 - | `Followed -> "$followed" 174 - | `Memo -> "$memo" 175 - | `HasMemo -> "$hasmemo" 176 - | `HasAttachment -> "$hasattachment" 177 - | `HasNoAttachment -> "$hasnoattachment" 178 - | `AutoSent -> "$autosent" 179 - | `Unsubscribed -> "$unsubscribed" 180 - | `CanUnsubscribe -> "$canunsubscribe" 181 - | `Imported -> "$imported" 182 - | `IsTrusted -> "$istrusted" 183 - | `MaskedEmail -> "$maskedemail" 184 - | `New -> "$new" 185 - (* Apple Mail flag color keywords *) 186 - | `MailFlagBit0 -> "$MailFlagBit0" 187 - | `MailFlagBit1 -> "$MailFlagBit1" 188 - | `MailFlagBit2 -> "$MailFlagBit2" 189 - | `Custom s -> s 190 191 let pp ppf k = Format.pp_print_string ppf (to_string k) 192 193 (** Apple Mail flag colors *) 194 - type flag_color = [ 195 - | `Red 196 - | `Orange 197 - | `Yellow 198 - | `Green 199 - | `Blue 200 - | `Purple 201 - | `Gray 202 - ] 203 204 let flag_color_of_keywords (keywords : t list) : flag_color option = 205 - let has k = List.mem k keywords in 206 - let bit0 = has `MailFlagBit0 in 207 - let bit1 = has `MailFlagBit1 in 208 - let bit2 = has `MailFlagBit2 in 209 - match (bit0, bit1, bit2) with 210 - | (false, false, false) -> Some `Red 211 - | (true, false, false) -> Some `Orange 212 - | (false, true, false) -> Some `Yellow 213 - | (true, true, true) -> Some `Green 214 - | (false, false, true) -> Some `Blue 215 - | (true, false, true) -> Some `Purple 216 - | (false, true, true) -> Some `Gray 217 - | (true, true, false) -> None 218 219 - let flag_color_to_keywords : flag_color -> t list = function 220 - | `Red -> [] 221 - | `Orange -> [`MailFlagBit0] 222 - | `Yellow -> [`MailFlagBit1] 223 - | `Green -> [`MailFlagBit0; `MailFlagBit1; `MailFlagBit2] 224 - | `Blue -> [`MailFlagBit2] 225 - | `Purple -> [`MailFlagBit0; `MailFlagBit2] 226 - | `Gray -> [`MailFlagBit1; `MailFlagBit2] 227 end 228 229 (** {1 Mailbox Role Type} *) 230 231 module Role = struct 232 (** RFC 8621 standard roles *) 233 type standard = [ 234 | `Inbox ··· 250 | `Memos 251 ] 252 253 type t = [ 254 | standard 255 | extended 256 | `Custom of string 257 ] 258 259 - let of_string = function 260 - (* RFC 8621 standard roles *) 261 - | "inbox" -> `Inbox 262 - | "sent" -> `Sent 263 - | "drafts" -> `Drafts 264 - | "trash" -> `Trash 265 - | "junk" -> `Junk 266 - | "archive" -> `Archive 267 - | "flagged" -> `Flagged 268 - | "important" -> `Important 269 - | "all" -> `All 270 - | "subscribed" -> `Subscribed 271 - (* draft-ietf-mailmaint extended roles *) 272 - | "snoozed" -> `Snoozed 273 - | "scheduled" -> `Scheduled 274 - | "memos" -> `Memos 275 - | s -> `Custom s 276 277 - let to_string = function 278 - (* RFC 8621 standard roles *) 279 - | `Inbox -> "inbox" 280 - | `Sent -> "sent" 281 - | `Drafts -> "drafts" 282 - | `Trash -> "trash" 283 - | `Junk -> "junk" 284 - | `Archive -> "archive" 285 - | `Flagged -> "flagged" 286 - | `Important -> "important" 287 - | `All -> "all" 288 - | `Subscribed -> "subscribed" 289 - (* draft-ietf-mailmaint extended roles *) 290 - | `Snoozed -> "snoozed" 291 - | `Scheduled -> "scheduled" 292 - | `Memos -> "memos" 293 | `Custom s -> s 294 295 let pp ppf r = Format.pp_print_string ppf (to_string r) 296 end
··· 82 (** {1 Keyword Type} *) 83 84 module Keyword = struct 85 + (** Re-export core types from mail-flag. 86 + Note: mail-flag's [standard] type includes [`Deleted] (IMAP only) 87 + which is not part of JMAP's standard keywords. The JMAP standard 88 + keyword type below excludes [`Deleted] for JMAP compliance. *) 89 + 90 + (** RFC 8621 standard keywords (JMAP subset of mail-flag standard). 91 + This excludes [`Deleted] which is IMAP-only. *) 92 type standard = [ 93 | `Seen 94 | `Flagged ··· 101 ] 102 103 (** draft-ietf-mailmaint extended keywords *) 104 + type extended = Mail_flag.Keyword.extended 105 106 (** Apple Mail flag color keywords *) 107 + type flag_bits = Mail_flag.Keyword.flag_bit 108 109 + (** Unified keyword type for JMAP. 110 + This is compatible with mail-flag's keyword type but excludes [`Deleted]. *) 111 type t = [ 112 | standard 113 | extended ··· 115 | `Custom of string 116 ] 117 118 + (** Convert from mail-flag keyword to JMAP keyword. 119 + [`Deleted] is converted to a custom keyword since JMAP doesn't support it. *) 120 + let of_mail_flag : Mail_flag.Keyword.t -> t = function 121 + | `Deleted -> `Custom "$deleted" 122 + | #t as k -> k 123 124 + (** Convert JMAP keyword to mail-flag keyword. *) 125 + let to_mail_flag (k : t) : Mail_flag.Keyword.t = 126 + (k :> Mail_flag.Keyword.t) 127 + 128 + let of_string s = of_mail_flag (Mail_flag.Keyword.of_string s) 129 + 130 + let to_string (k : t) = Mail_flag.Keyword.to_string (to_mail_flag k) 131 132 let pp ppf k = Format.pp_print_string ppf (to_string k) 133 134 (** Apple Mail flag colors *) 135 + type flag_color = Mail_flag.Keyword.flag_color 136 137 let flag_color_of_keywords (keywords : t list) : flag_color option = 138 + let mail_flag_keywords = List.map to_mail_flag keywords in 139 + Mail_flag.Keyword.flag_color_of_keywords mail_flag_keywords 140 141 + let flag_color_to_keywords (color : flag_color) : t list = 142 + Mail_flag.Keyword.flag_color_to_keywords color 143 + |> List.map of_mail_flag 144 end 145 146 (** {1 Mailbox Role Type} *) 147 148 module Role = struct 149 + (** Re-export special-use mailbox attributes from mail-flag as JMAP roles. 150 + JMAP roles correspond to the special_use subset of mailbox attributes. *) 151 + 152 (** RFC 8621 standard roles *) 153 type standard = [ 154 | `Inbox ··· 170 | `Memos 171 ] 172 173 + (** JMAP role type - corresponds to mail-flag's special_use type *) 174 type t = [ 175 | standard 176 | extended 177 | `Custom of string 178 ] 179 180 + (** Convert from mail-flag special_use to JMAP role *) 181 + let of_special_use : Mail_flag.Mailbox_attr.special_use -> t = function 182 + | `All -> `All 183 + | `Archive -> `Archive 184 + | `Drafts -> `Drafts 185 + | `Flagged -> `Flagged 186 + | `Important -> `Important 187 + | `Inbox -> `Inbox 188 + | `Junk -> `Junk 189 + | `Sent -> `Sent 190 + | `Subscribed -> `Subscribed 191 + | `Trash -> `Trash 192 + | `Snoozed -> `Snoozed 193 + | `Scheduled -> `Scheduled 194 + | `Memos -> `Memos 195 196 + (** Convert JMAP role to mail-flag special_use. 197 + Returns None for custom roles that don't map to special_use. *) 198 + let to_special_use : t -> Mail_flag.Mailbox_attr.special_use option = function 199 + | `All -> Some `All 200 + | `Archive -> Some `Archive 201 + | `Drafts -> Some `Drafts 202 + | `Flagged -> Some `Flagged 203 + | `Important -> Some `Important 204 + | `Inbox -> Some `Inbox 205 + | `Junk -> Some `Junk 206 + | `Sent -> Some `Sent 207 + | `Subscribed -> Some `Subscribed 208 + | `Trash -> Some `Trash 209 + | `Snoozed -> Some `Snoozed 210 + | `Scheduled -> Some `Scheduled 211 + | `Memos -> Some `Memos 212 + | `Custom _ -> None 213 + 214 + let of_string s = 215 + match Mail_flag.Mailbox_attr.of_jmap_role s with 216 + | Some special_use -> of_special_use special_use 217 + | None -> `Custom s 218 + 219 + let to_string : t -> string = function 220 | `Custom s -> s 221 + | #Mail_flag.Mailbox_attr.special_use as role -> 222 + (* safe because to_jmap_role returns Some for all special_use *) 223 + Option.get (Mail_flag.Mailbox_attr.to_jmap_role role) 224 225 let pp ppf r = Format.pp_print_string ppf (to_string r) 226 end
+1 -1
ocaml-jmap/lib/dune
··· 3 (library 4 (name jmap) 5 (public_name jmap) 6 - (libraries jsont json-pointer ptime) 7 (modules 8 ; Core unified interface 9 jmap
··· 3 (library 4 (name jmap) 5 (public_name jmap) 6 + (libraries jsont json-pointer ptime mail-flag) 7 (modules 8 ; Core unified interface 9 jmap