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 713 end 714 714 else begin 715 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 () 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 () 747 751 end 748 752 749 753 let push ~proc ~fs ~config ?package ?(upstream = false) () =
+76 -76
ocaml-atp/lexicons/atproto/atp_lexicon_atproto.ml
··· 16 16 module Com = struct 17 17 module Atproto = struct 18 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 19 module Defs = struct 35 20 type commit_meta = { 36 21 cid : string; ··· 43 28 |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"com.atproto.repo.defs#commitMeta" ~enc:(fun _ -> "com.atproto.repo.defs#commitMeta") 44 29 |> Jsont.Object.mem "cid" Jsont.string ~enc:(fun r -> r.cid) 45 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) 46 73 |> Jsont.Object.finish 47 74 48 75 end ··· 105 132 |> Jsont.Object.finish 106 133 107 134 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; 135 + module StrongRef = struct 136 + type main = { 137 + cid : string; 136 138 uri : string; 137 - value : Jsont.json; 138 139 } 139 140 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) 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) 145 146 |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 146 - |> Jsont.Object.mem "value" Jsont.json ~enc:(fun r -> r.value) 147 147 |> Jsont.Object.finish 148 148 149 149 end ··· 189 189 |> Jsont.Object.finish 190 190 191 191 end 192 - module DeleteRecord = struct 192 + module CreateRecord = struct 193 193 type input = { 194 194 collection : string; 195 + record : Jsont.json; 195 196 repo : string; 196 - rkey : string; 197 + rkey : string option; 197 198 swap_commit : string option; 198 - swap_record : string option; 199 + validate : bool option; 199 200 } 200 201 201 202 let input_jsont = 202 203 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") 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") 205 206 |> Jsont.Object.mem "collection" Jsont.string ~enc:(fun r -> r.collection) 207 + |> Jsont.Object.mem "record" Jsont.json ~enc:(fun r -> r.record) 206 208 |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 207 - |> Jsont.Object.mem "rkey" Jsont.string ~enc:(fun r -> r.rkey) 209 + |> Jsont.Object.opt_mem "rkey" Jsont.string ~enc:(fun r -> r.rkey) 208 210 |> 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) 211 + |> Jsont.Object.opt_mem "validate" Jsont.bool ~enc:(fun r -> r.validate) 210 212 |> Jsont.Object.finish 211 213 212 214 type output = { 215 + cid : string; 213 216 commit : Defs.commit_meta option; 217 + uri : string; 218 + validation_status : string option; 214 219 } 215 220 216 221 let output_jsont = 217 222 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") 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) 220 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) 221 229 |> Jsont.Object.finish 222 230 223 231 end 224 - module CreateRecord = struct 232 + module DeleteRecord = struct 225 233 type input = { 226 234 collection : string; 227 - record : Jsont.json; 228 235 repo : string; 229 - rkey : string option; 236 + rkey : string; 230 237 swap_commit : string option; 231 - validate : bool option; 238 + swap_record : string option; 232 239 } 233 240 234 241 let input_jsont = 235 242 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") 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") 238 245 |> Jsont.Object.mem "collection" Jsont.string ~enc:(fun r -> r.collection) 239 - |> Jsont.Object.mem "record" Jsont.json ~enc:(fun r -> r.record) 240 246 |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 241 - |> Jsont.Object.opt_mem "rkey" Jsont.string ~enc:(fun r -> r.rkey) 247 + |> Jsont.Object.mem "rkey" Jsont.string ~enc:(fun r -> r.rkey) 242 248 |> 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) 249 + |> Jsont.Object.opt_mem "swapRecord" Jsont.string ~enc:(fun r -> r.swap_record) 244 250 |> Jsont.Object.finish 245 251 246 252 type output = { 247 - cid : string; 248 253 commit : Defs.commit_meta option; 249 - uri : string; 250 - validation_status : string option; 251 254 } 252 255 253 256 let output_jsont = 254 257 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 + (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") 258 260 |> 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 261 |> Jsont.Object.finish 262 262 263 263 end
+42 -42
ocaml-atp/lexicons/atproto/atp_lexicon_atproto.mli
··· 13 13 module Com : sig 14 14 module Atproto : sig 15 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 16 module Defs : sig 28 17 29 18 type commit_meta = { ··· 33 22 34 23 (** Jsont codec for {!type:commit_meta}. *) 35 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 36 50 37 51 end 38 52 module ListRecords : sig ··· 70 84 val output_jsont : output Jsont.t 71 85 72 86 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 + module StrongRef : sig 87 88 88 - type output = { 89 - cid : string option; 89 + type main = { 90 + cid : string; 90 91 uri : string; 91 - value : Jsont.json; 92 92 } 93 93 94 - (** Jsont codec for {!type:output}. *) 95 - val output_jsont : output Jsont.t 94 + (** Jsont codec for {!type:main}. *) 95 + val main_jsont : main Jsont.t 96 96 97 97 end 98 98 module PutRecord : sig ··· 124 124 val output_jsont : output Jsont.t 125 125 126 126 end 127 - module DeleteRecord : sig 128 - (** Delete a repository record, or ensure it doesn't exist. Requires auth, implemented by PDS. *) 127 + module CreateRecord : sig 128 + (** Create a single new repository record. Requires auth, implemented by PDS. *) 129 129 130 130 131 131 type input = { 132 132 collection : string; (** The NSID of the record collection. *) 133 + record : Jsont.json; (** The record itself. Must contain a $type field. *) 133 134 repo : string; (** The handle or DID of the repo (aka, current account). *) 134 - rkey : string; (** The Record Key. *) 135 + rkey : string option; (** The Record Key. *) 135 136 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 + 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. *) 137 138 } 138 139 139 140 (** Jsont codec for {!type:input}. *) ··· 141 142 142 143 143 144 type output = { 145 + cid : string; 144 146 commit : Defs.commit_meta option; 147 + uri : string; 148 + validation_status : string option; 145 149 } 146 150 147 151 (** Jsont codec for {!type:output}. *) 148 152 val output_jsont : output Jsont.t 149 153 150 154 end 151 - module CreateRecord : sig 152 - (** Create a single new repository record. Requires auth, implemented by PDS. *) 155 + module DeleteRecord : sig 156 + (** Delete a repository record, or ensure it doesn't exist. Requires auth, implemented by PDS. *) 153 157 154 158 155 159 type input = { 156 160 collection : string; (** The NSID of the record collection. *) 157 - record : Jsont.json; (** The record itself. Must contain a $type field. *) 158 161 repo : string; (** The handle or DID of the repo (aka, current account). *) 159 - rkey : string option; (** The Record Key. *) 162 + rkey : string; (** The Record Key. *) 160 163 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. *) 164 + swap_record : string option; (** Compare and swap with the previous record by CID. *) 162 165 } 163 166 164 167 (** Jsont codec for {!type:input}. *) ··· 166 169 167 170 168 171 type output = { 169 - cid : string; 170 172 commit : Defs.commit_meta option; 171 - uri : string; 172 - validation_status : string option; 173 173 } 174 174 175 175 (** Jsont codec for {!type:output}. *)
+2499 -2499
ocaml-atp/lexicons/bsky/atp_lexicon_bsky.ml
··· 15 15 16 16 module Com = struct 17 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 18 49 module Label = struct 19 50 module Defs = struct 20 51 type self_label = { ··· 124 155 125 156 end 126 157 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 158 end 159 159 end 160 160 module App = struct 161 161 module Bsky = struct 162 - module AuthManageLabelerService = struct 162 + module AuthFullApp = struct 163 163 type main = unit 164 164 let main_jsont = Jsont.ignore 165 165 ··· 169 169 let main_jsont = Jsont.ignore 170 170 171 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 172 module AuthManageFeedDeclarations = struct 241 173 type main = unit 242 174 let main_jsont = Jsont.ignore 243 175 244 176 end 245 - module AuthFullApp = struct 177 + module AuthManageNotifications = struct 246 178 type main = unit 247 179 let main_jsont = Jsont.ignore 248 180 249 181 end 250 - module AuthManageNotifications = struct 182 + module AuthManageModeration = struct 251 183 type main = unit 252 184 let main_jsont = Jsont.ignore 253 185 ··· 257 189 let main_jsont = Jsont.ignore 258 190 259 191 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 192 + module AuthManageLabelerService = struct 641 193 type main = unit 642 194 let main_jsont = Jsont.ignore 643 195 644 196 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 197 + module Notification = struct 198 + module GetUnreadCount = struct 709 199 type params = { 710 - job_id : string; 200 + priority : bool option; 201 + seen_at : string option; 711 202 } 712 203 713 204 let params_jsont = 714 205 Jsont.Object.map ~kind:"Params" 715 - (fun job_id -> { 716 - job_id; 206 + (fun priority seen_at -> { 207 + priority; 208 + seen_at; 717 209 }) 718 - |> Jsont.Object.mem "jobId" Jsont.string 719 - ~enc:(fun r -> r.job_id) 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) 720 214 |> Jsont.Object.finish 721 215 722 216 type output = { 723 - job_status : Defs.job_status; 217 + count : int; 724 218 } 725 219 726 220 let output_jsont = 727 221 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_) 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) 791 225 |> Jsont.Object.finish 792 226 793 227 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 228 module UpdateSeen = struct 1043 229 type input = { 1044 230 seen_at : string; ··· 1049 235 (fun _typ seen_at -> { seen_at }) 1050 236 |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.notification.updateSeen#input" ~enc:(fun _ -> "app.bsky.notification.updateSeen#input") 1051 237 |> 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 238 |> Jsont.Object.finish 1074 239 1075 240 end ··· 1148 313 |> Jsont.Object.finish 1149 314 1150 315 end 1151 - module GetUnreadCount = struct 1152 - type params = { 1153 - priority : bool option; 1154 - seen_at : string option; 316 + module Declaration = struct 317 + type main = { 318 + allow_subscriptions : string; 1155 319 } 1156 320 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) 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) 1167 326 |> Jsont.Object.finish 1168 327 1169 - type output = { 1170 - count : int; 328 + end 329 + module PutPreferences = struct 330 + type input = { 331 + priority : bool; 1171 332 } 1172 333 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) 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) 1178 339 |> Jsont.Object.finish 1179 340 1180 341 end 1181 - module UnregisterPush = struct 342 + module RegisterPush = struct 1182 343 type input = { 344 + age_restricted : bool option; 1183 345 app_id : string; 1184 346 platform : string; 1185 347 service_did : string; ··· 1188 350 1189 351 let input_jsont = 1190 352 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") 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) 1193 356 |> Jsont.Object.mem "appId" Jsont.string ~enc:(fun r -> r.app_id) 1194 357 |> Jsont.Object.mem "platform" Jsont.string ~enc:(fun r -> r.platform) 1195 358 |> Jsont.Object.mem "serviceDid" Jsont.string ~enc:(fun r -> r.service_did) ··· 1197 360 |> Jsont.Object.finish 1198 361 1199 362 end 1200 - module PutPreferences = struct 363 + module UnregisterPush = struct 1201 364 type input = { 1202 - priority : bool; 365 + app_id : string; 366 + platform : string; 367 + service_did : string; 368 + token : string; 1203 369 } 1204 370 1205 371 let input_jsont = 1206 372 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) 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) 1210 379 |> Jsont.Object.finish 1211 380 1212 381 end ··· 1318 487 |> Jsont.Object.finish 1319 488 1320 489 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 490 module ListActivitySubscriptions = struct 1335 491 type params = { 1336 492 cursor : string option; ··· 1457 613 1458 614 end 1459 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 1460 751 module Actor = struct 1461 752 module Status = struct 1462 753 type live = string ··· 1477 768 |> Jsont.Object.opt_mem "durationMinutes" Jsont.int ~enc:(fun r -> r.duration_minutes) 1478 769 |> Jsont.Object.opt_mem "embed" Jsont.json ~enc:(fun r -> r.embed) 1479 770 |> 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 771 |> Jsont.Object.finish 1512 772 1513 773 end ··· 2048 1308 |> Jsont.Object.finish 2049 1309 2050 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 2051 1368 module GetPreferences = struct 2052 1369 type params = unit 2053 1370 ··· 2065 1382 |> Jsont.Object.finish 2066 1383 2067 1384 end 2068 - module SearchActorsTypeahead = struct 1385 + module GetSuggestions = struct 2069 1386 type params = { 1387 + cursor : string option; 2070 1388 limit : int option; 2071 - q : string option; 2072 - term : string option; 2073 1389 } 2074 1390 2075 1391 let params_jsont = 2076 1392 Jsont.Object.map ~kind:"Params" 2077 - (fun limit q term -> { 1393 + (fun cursor limit -> { 1394 + cursor; 2078 1395 limit; 2079 - q; 2080 - term; 2081 1396 }) 1397 + |> Jsont.Object.opt_mem "cursor" Jsont.string 1398 + ~enc:(fun r -> r.cursor) 2082 1399 |> Jsont.Object.opt_mem "limit" Jsont.int 2083 1400 ~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 1401 |> Jsont.Object.finish 2089 1402 2090 1403 type output = { 2091 1404 actors : Jsont.json list; 1405 + cursor : string option; 1406 + rec_id : int option; 2092 1407 } 2093 1408 2094 1409 let output_jsont = 2095 1410 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") 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") 2098 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) 2099 1416 |> Jsont.Object.finish 2100 1417 2101 1418 end ··· 2158 1475 |> Jsont.Object.finish 2159 1476 2160 1477 end 2161 - module GetSuggestions = struct 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 2162 1492 type params = { 2163 - cursor : string option; 2164 1493 limit : int option; 1494 + q : string option; 1495 + term : string option; 2165 1496 } 2166 1497 2167 1498 let params_jsont = 2168 1499 Jsont.Object.map ~kind:"Params" 2169 - (fun cursor limit -> { 2170 - cursor; 1500 + (fun limit q term -> { 2171 1501 limit; 1502 + q; 1503 + term; 2172 1504 }) 2173 - |> Jsont.Object.opt_mem "cursor" Jsont.string 2174 - ~enc:(fun r -> r.cursor) 2175 1505 |> Jsont.Object.opt_mem "limit" Jsont.int 2176 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) 2177 1511 |> Jsont.Object.finish 2178 1512 2179 1513 type output = { 2180 1514 actors : Jsont.json list; 2181 - cursor : string option; 2182 - rec_id : int option; 2183 1515 } 2184 1516 2185 1517 let output_jsont = 2186 1518 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") 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") 2189 1521 |> 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 1522 |> Jsont.Object.finish 2193 1523 2194 1524 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 - 1525 + end 1526 + module Video = struct 1527 + module GetUploadLimits = struct 2209 1528 type output = { 2210 - profiles : Jsont.json list; 1529 + can_upload : bool; 1530 + error : string option; 1531 + message : string option; 1532 + remaining_daily_bytes : int option; 1533 + remaining_daily_videos : int option; 2211 1534 } 2212 1535 2213 1536 let output_jsont = 2214 1537 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) 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) 2218 1545 |> Jsont.Object.finish 2219 1546 2220 1547 end 2221 - module PutPreferences = struct 2222 - type input = { 2223 - preferences : Jsont.json; 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; 2224 1557 } 2225 1558 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) 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) 2231 1570 |> Jsont.Object.finish 2232 1571 2233 1572 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; 1573 + module GetJobStatus = struct 1574 + type params = { 1575 + job_id : string; 2253 1576 } 2254 1577 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_) 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) 2261 1585 |> Jsont.Object.finish 2262 1586 2263 - type match_and_contact_index = { 2264 - contact_index : int; 2265 - match_ : Jsont.json; 1587 + type output = { 1588 + job_status : Defs.job_status; 2266 1589 } 2267 1590 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_) 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) 2274 1596 |> Jsont.Object.finish 2275 1597 2276 1598 end 2277 - module RemoveData = struct 1599 + module UploadVideo = struct 2278 1600 type input = unit 2279 - 2280 1601 let input_jsont = Jsont.ignore 2281 1602 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 1603 type output = { 2323 - cursor : string option; 2324 - matches : Jsont.json list; 1604 + job_status : Defs.job_status; 2325 1605 } 2326 1606 2327 1607 let output_jsont = 2328 1608 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) 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) 2333 1612 |> Jsont.Object.finish 2334 1613 2335 1614 end 2336 - module VerifyPhone = struct 2337 - type input = { 2338 - code : string; 2339 - phone : string; 1615 + end 1616 + module Richtext = struct 1617 + module Facet = struct 1618 + type tag = { 1619 + tag : string; 2340 1620 } 2341 1621 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) 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) 2348 1627 |> Jsont.Object.finish 2349 1628 2350 - type output = { 2351 - token : string; 1629 + type mention = { 1630 + did : string; 2352 1631 } 2353 1632 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) 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) 2359 1638 |> Jsont.Object.finish 2360 1639 2361 - end 2362 - module StartPhoneVerification = struct 2363 - type input = { 2364 - phone : string; 1640 + type link = { 1641 + uri : string; 2365 1642 } 2366 1643 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) 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) 2372 1649 |> Jsont.Object.finish 2373 1650 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; 1651 + type byte_slice = { 1652 + byte_end : int; 1653 + byte_start : int; 2383 1654 } 2384 1655 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_) 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) 2391 1662 |> Jsont.Object.finish 2392 1663 2393 - type output = unit 1664 + type main = { 1665 + features : Jsont.json list; 1666 + index : byte_slice; 1667 + } 2394 1668 2395 - let output_jsont = Jsont.ignore 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 2396 1676 2397 1677 end 2398 - module GetSyncStatus = struct 2399 - type params = unit 1678 + end 1679 + module AuthCreatePosts = struct 1680 + type main = unit 1681 + let main_jsont = Jsont.ignore 2400 1682 2401 - let params_jsont = Jsont.ignore 1683 + end 1684 + module Ageassurance = struct 1685 + module Defs = struct 1686 + type status = string 1687 + let status_jsont = Jsont.string 2402 1688 2403 - type output = { 2404 - sync_status : Defs.sync_status option; 1689 + type state_metadata = { 1690 + account_created_at : string option; 2405 1691 } 2406 1692 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) 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) 2412 1698 |> Jsont.Object.finish 2413 1699 2414 - end 2415 - module ImportContacts = struct 2416 - type input = { 2417 - contacts : string list; 2418 - token : string; 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; 2419 1712 } 2420 1713 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) 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) 2427 1729 |> Jsont.Object.finish 2428 1730 2429 - type output = { 2430 - matches_and_contact_indexes : Defs.match_and_contact_index list; 1731 + type config_region = { 1732 + country_code : string; 1733 + min_access_age : int; 1734 + region_code : string option; 1735 + rules : Jsont.json list; 2431 1736 } 2432 1737 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) 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) 2438 1746 |> Jsont.Object.finish 2439 1747 2440 - end 2441 - end 2442 - module Graph = struct 2443 - module Starterpack = struct 2444 - type feed_item = { 2445 - uri : string; 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; 2446 1755 } 2447 1756 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) 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) 2453 1764 |> Jsont.Object.finish 2454 1765 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; 1766 + type config_region_rule_if_declared_under_age = { 1767 + access : access; 1768 + age : int; 2462 1769 } 2463 1770 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) 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) 2474 1777 |> Jsont.Object.finish 2475 1778 2476 - end 2477 - module GetFollows = struct 2478 - type params = { 2479 - actor : string; 2480 - cursor : string option; 2481 - limit : int option; 1779 + type config_region_rule_if_declared_over_age = { 1780 + access : access; 1781 + age : int; 2482 1782 } 2483 1783 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) 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) 2497 1790 |> Jsont.Object.finish 2498 1791 2499 - type output = { 2500 - cursor : string option; 2501 - follows : Jsont.json list; 2502 - subject : Jsont.json; 1792 + type config_region_rule_if_assured_under_age = { 1793 + access : access; 1794 + age : int; 2503 1795 } 2504 1796 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) 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) 2512 1803 |> Jsont.Object.finish 2513 1804 2514 - end 2515 - module GetSuggestedFollowsByActor = struct 2516 - type params = { 2517 - actor : string; 1805 + type config_region_rule_if_assured_over_age = { 1806 + access : access; 1807 + age : int; 2518 1808 } 2519 1809 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) 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) 2527 1816 |> Jsont.Object.finish 2528 1817 2529 - type output = { 2530 - is_fallback : bool option; 2531 - rec_id : int option; 2532 - suggestions : Jsont.json list; 1818 + type config_region_rule_if_account_older_than = { 1819 + access : access; 1820 + date : string; 2533 1821 } 2534 1822 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) 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) 2542 1829 |> Jsont.Object.finish 2543 1830 2544 - end 2545 - module Block = struct 2546 - type main = { 2547 - created_at : string; 2548 - subject : string; 1831 + type config_region_rule_if_account_newer_than = { 1832 + access : access; 1833 + date : string; 2549 1834 } 2550 1835 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) 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) 2557 1842 |> Jsont.Object.finish 2558 1843 2559 - end 2560 - module Listblock = struct 2561 - type main = { 2562 - created_at : string; 2563 - subject : string; 1844 + type config_region_rule_default = { 1845 + access : access; 2564 1846 } 2565 1847 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) 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) 2572 1853 |> Jsont.Object.finish 2573 1854 2574 - end 2575 - module MuteThread = struct 2576 - type input = { 2577 - root : string; 1855 + type config = { 1856 + regions : config_region list; 2578 1857 } 2579 1858 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) 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) 2585 1864 |> Jsont.Object.finish 2586 1865 2587 1866 end 2588 - module GetFollowers = struct 1867 + module GetState = struct 2589 1868 type params = { 2590 - actor : string; 2591 - cursor : string option; 2592 - limit : int option; 1869 + country_code : string; 1870 + region_code : string option; 2593 1871 } 2594 1872 2595 1873 let params_jsont = 2596 1874 Jsont.Object.map ~kind:"Params" 2597 - (fun actor cursor limit -> { 2598 - actor; 2599 - cursor; 2600 - limit; 1875 + (fun country_code region_code -> { 1876 + country_code; 1877 + region_code; 2601 1878 }) 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) 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) 2608 1883 |> Jsont.Object.finish 2609 1884 2610 1885 type output = { 2611 - cursor : string option; 2612 - followers : Jsont.json list; 2613 - subject : Jsont.json; 1886 + metadata : Defs.state_metadata; 1887 + state : Defs.state; 2614 1888 } 2615 1889 2616 1890 let output_jsont = 2617 1891 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) 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) 2623 1896 |> Jsont.Object.finish 2624 1897 2625 1898 end 2626 - module UnmuteThread = struct 1899 + module Begin = struct 2627 1900 type input = { 2628 - root : string; 1901 + country_code : string; 1902 + email : string; 1903 + language : string; 1904 + region_code : string option; 2629 1905 } 2630 1906 2631 1907 let input_jsont = 2632 1908 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) 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) 2636 1915 |> Jsont.Object.finish 2637 1916 1917 + type output = Defs.state 1918 + 1919 + let output_jsont = Defs.state_jsont 1920 + 2638 1921 end 2639 - module Follow = struct 2640 - type main = { 2641 - created_at : string; 2642 - subject : string; 2643 - via : Com.Atproto.Repo.StrongRef.main option; 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; 2644 1934 } 2645 1935 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) 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) 2653 1942 |> Jsont.Object.finish 2654 1943 2655 1944 end 2656 - module UnmuteActor = struct 2657 - type input = { 2658 - actor : string; 1945 + module External = struct 1946 + type view_external = { 1947 + description : string; 1948 + thumb : string option; 1949 + title : string; 1950 + uri : string; 2659 1951 } 2660 1952 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) 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) 2666 1961 |> Jsont.Object.finish 2667 1962 2668 - end 2669 - module MuteActorList = struct 2670 - type input = { 2671 - list_ : string; 1963 + type external_ = { 1964 + description : string; 1965 + thumb : Atp.Blob_ref.t option; 1966 + title : string; 1967 + uri : string; 2672 1968 } 2673 1969 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_) 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) 2679 1978 |> Jsont.Object.finish 2680 1979 2681 - end 2682 - module UnmuteActorList = struct 2683 - type input = { 2684 - list_ : string; 1980 + type view = { 1981 + external_ : Jsont.json; 2685 1982 } 2686 1983 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_) 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_) 2692 2000 |> Jsont.Object.finish 2693 2001 2694 2002 end 2695 - module GetKnownFollowers = struct 2696 - type params = { 2697 - actor : string; 2698 - cursor : string option; 2699 - limit : int option; 2003 + module Images = struct 2004 + type view_image = { 2005 + alt : string; 2006 + aspect_ratio : Jsont.json option; 2007 + fullsize : string; 2008 + thumb : string; 2700 2009 } 2701 2010 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) 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) 2715 2019 |> Jsont.Object.finish 2716 2020 2717 - type output = { 2718 - cursor : string option; 2719 - followers : Jsont.json list; 2720 - subject : Jsont.json; 2021 + type image = { 2022 + alt : string; 2023 + aspect_ratio : Jsont.json option; 2024 + image : Atp.Blob_ref.t; 2721 2025 } 2722 2026 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) 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) 2730 2034 |> Jsont.Object.finish 2731 2035 2732 - end 2733 - module MuteActor = struct 2734 - type input = { 2735 - actor : string; 2036 + type view = { 2037 + images : Jsont.json list; 2736 2038 } 2737 2039 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) 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) 2743 2045 |> Jsont.Object.finish 2744 2046 2745 - end 2746 - module Listitem = struct 2747 2047 type main = { 2748 - created_at : string; 2749 - list_ : string; 2750 - subject : string; 2048 + images : Jsont.json list; 2751 2049 } 2752 2050 2753 2051 let main_jsont = 2754 2052 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) 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) 2760 2056 |> Jsont.Object.finish 2761 2057 2762 2058 end 2763 - module Defs = struct 2764 - type starter_pack_view_basic = { 2059 + module Video = struct 2060 + type view = { 2061 + alt : string option; 2062 + aspect_ratio : Jsont.json option; 2765 2063 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; 2064 + playlist : string; 2065 + thumbnail : string option; 2774 2066 } 2775 2067 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") 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) 2780 2074 |> 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) 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) 2789 2077 |> Jsont.Object.finish 2790 2078 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; 2079 + type caption = { 2080 + file : Atp.Blob_ref.t; 2081 + lang : string; 2799 2082 } 2800 2083 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) 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) 2812 2090 |> Jsont.Object.finish 2813 2091 2814 - type referencelist = string 2815 - let referencelist_jsont = Jsont.string 2816 - 2817 - type not_found_actor = { 2818 - actor : string; 2819 - not_found : bool; 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; 2820 2097 } 2821 2098 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) 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) 2828 2107 |> Jsont.Object.finish 2829 2108 2830 - type modlist = string 2831 - let modlist_jsont = Jsont.string 2832 - 2833 - type list_viewer_state = { 2834 - blocked : string option; 2835 - muted : bool option; 2109 + end 2110 + module RecordWithMedia = struct 2111 + type view = { 2112 + media : Jsont.json; 2113 + record : Jsont.json; 2836 2114 } 2837 2115 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) 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) 2844 2122 |> Jsont.Object.finish 2845 2123 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; 2124 + type main = { 2125 + media : Jsont.json; 2126 + record : Jsont.json; 2852 2127 } 2853 2128 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) 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) 2860 2135 |> Jsont.Object.finish 2861 2136 2862 - type curatelist = string 2863 - let curatelist_jsont = Jsont.string 2864 - 2865 - type list_view_basic = { 2866 - avatar : string option; 2137 + end 2138 + module Record = struct 2139 + type view_record = { 2140 + author : Jsont.json; 2867 2141 cid : string; 2868 - indexed_at : string option; 2142 + embeds : Jsont.json list option; 2143 + indexed_at : string; 2869 2144 labels : Com.Atproto.Label.Defs.label list option; 2870 - list_item_count : int option; 2871 - name : string; 2872 - purpose : Jsont.json; 2145 + like_count : int option; 2146 + quote_count : int option; 2147 + reply_count : int option; 2148 + repost_count : int option; 2873 2149 uri : string; 2874 - viewer : Jsont.json option; 2150 + value : Jsont.json; 2875 2151 } 2876 2152 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) 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) 2882 2158 |> 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) 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) 2884 2161 |> 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) 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) 2888 2166 |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 2889 - |> Jsont.Object.opt_mem "viewer" Jsont.json ~enc:(fun r -> r.viewer) 2167 + |> Jsont.Object.mem "value" Jsont.json ~enc:(fun r -> r.value) 2890 2168 |> Jsont.Object.finish 2891 2169 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; 2170 + type view_not_found = { 2171 + not_found : bool; 2903 2172 uri : string; 2904 - viewer : Jsont.json option; 2905 2173 } 2906 2174 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) 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) 2921 2180 |> 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 2181 |> Jsont.Object.finish 2924 2182 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; 2183 + type view_detached = { 2184 + detached : bool; 2936 2185 uri : string; 2937 2186 } 2938 2187 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) 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) 2953 2193 |> Jsont.Object.mem "uri" Jsont.string ~enc:(fun r -> r.uri) 2954 2194 |> Jsont.Object.finish 2955 2195 2956 - end 2957 - module GetBlocks = struct 2958 - type params = { 2959 - cursor : string option; 2960 - limit : int option; 2196 + type view_blocked = { 2197 + author : Jsont.json; 2198 + blocked : bool; 2199 + uri : string; 2961 2200 } 2962 2201 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) 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) 2973 2209 |> Jsont.Object.finish 2974 2210 2975 - type output = { 2976 - blocks : Jsont.json list; 2977 - cursor : string option; 2211 + type view = { 2212 + record : Jsont.json; 2978 2213 } 2979 2214 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) 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) 2986 2220 |> Jsont.Object.finish 2987 2221 2988 - end 2989 - module Verification = struct 2990 2222 type main = { 2991 - created_at : string; 2992 - display_name : string; 2993 - handle : string; 2994 - subject : string; 2223 + record : Com.Atproto.Repo.StrongRef.main; 2995 2224 } 2996 2225 2997 2226 let main_jsont = 2998 2227 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) 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) 3005 2231 |> Jsont.Object.finish 3006 2232 3007 2233 end 3008 - module GetMutes = struct 3009 - type params = { 3010 - cursor : string option; 3011 - limit : int option; 2234 + end 2235 + module Contact = struct 2236 + module SendNotification = struct 2237 + type input = { 2238 + from : string; 2239 + to_ : string; 3012 2240 } 3013 2241 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) 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_) 3024 2248 |> Jsont.Object.finish 3025 2249 3026 - type output = { 3027 - cursor : string option; 3028 - mutes : Jsont.json list; 3029 - } 2250 + type output = unit 3030 2251 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 2252 + let output_jsont = Jsont.ignore 3038 2253 3039 2254 end 3040 - module GetRelationships = struct 3041 - type params = { 3042 - actor : string; 3043 - others : string list option; 2255 + module StartPhoneVerification = struct 2256 + type input = { 2257 + phone : string; 3044 2258 } 3045 2259 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) 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) 3056 2265 |> Jsont.Object.finish 3057 2266 3058 - type output = { 3059 - actor : string option; 3060 - relationships : Jsont.json list; 3061 - } 2267 + type output = unit 3062 2268 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 2269 + let output_jsont = Jsont.ignore 3070 2270 3071 2271 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 - 2272 + module GetMatches = struct 3086 2273 type params = { 3087 - actor : string; 3088 2274 cursor : string option; 3089 2275 limit : int option; 3090 2276 } 3091 2277 3092 2278 let params_jsont = 3093 2279 Jsont.Object.map ~kind:"Params" 3094 - (fun actor cursor limit -> { 3095 - actor; 2280 + (fun cursor limit -> { 3096 2281 cursor; 3097 2282 limit; 3098 2283 }) 3099 - |> Jsont.Object.mem "actor" Jsont.string 3100 - ~enc:(fun r -> r.actor) 3101 2284 |> Jsont.Object.opt_mem "cursor" Jsont.string 3102 2285 ~enc:(fun r -> r.cursor) 3103 2286 |> Jsont.Object.opt_mem "limit" Jsont.int ··· 3106 2289 3107 2290 type output = { 3108 2291 cursor : string option; 3109 - starter_packs_with_membership : Jsont.json list; 2292 + matches : Jsont.json list; 3110 2293 } 3111 2294 3112 2295 let output_jsont = 3113 2296 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") 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") 3116 2299 |> 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) 2300 + |> Jsont.Object.mem "matches" (Jsont.list Jsont.json) ~enc:(fun r -> r.matches) 3118 2301 |> Jsont.Object.finish 3119 2302 3120 2303 end 3121 - module GetActorStarterPacks = struct 3122 - type params = { 3123 - actor : string; 3124 - cursor : string option; 3125 - limit : int option; 2304 + module VerifyPhone = struct 2305 + type input = { 2306 + code : string; 2307 + phone : string; 3126 2308 } 3127 2309 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) 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) 3141 2316 |> Jsont.Object.finish 3142 2317 3143 2318 type output = { 3144 - cursor : string option; 3145 - starter_packs : Jsont.json list; 2319 + token : string; 3146 2320 } 3147 2321 3148 2322 let output_jsont = 3149 2323 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) 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) 3154 2327 |> Jsont.Object.finish 3155 2328 3156 2329 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 - } 2330 + module RemoveData = struct 2331 + type input = unit 3167 2332 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 2333 + let input_jsont = Jsont.ignore 3180 2334 3181 - end 3182 - module SearchStarterPacks = struct 3183 - type params = { 3184 - cursor : string option; 3185 - limit : int option; 3186 - q : string; 3187 - } 2335 + type output = unit 3188 2336 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 2337 + let output_jsont = Jsont.ignore 3203 2338 3204 - type output = { 3205 - cursor : string option; 3206 - starter_packs : Jsont.json list; 2339 + end 2340 + module Defs = struct 2341 + type sync_status = { 2342 + matches_count : int; 2343 + synced_at : string; 3207 2344 } 3208 2345 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) 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) 3215 2352 |> Jsont.Object.finish 3216 2353 3217 - end 3218 - module GetList = struct 3219 - type params = { 3220 - cursor : string option; 3221 - limit : int option; 3222 - list_ : string; 2354 + type notification = { 2355 + from : string; 2356 + to_ : string; 3223 2357 } 3224 2358 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_) 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_) 3238 2365 |> Jsont.Object.finish 3239 2366 3240 - type output = { 3241 - cursor : string option; 3242 - items : Jsont.json list; 3243 - list_ : Jsont.json; 2367 + type match_and_contact_index = { 2368 + contact_index : int; 2369 + match_ : Jsont.json; 3244 2370 } 3245 2371 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_) 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_) 3253 2378 |> Jsont.Object.finish 3254 2379 3255 2380 end 3256 - module GetListBlocks = struct 3257 - type params = { 3258 - cursor : string option; 3259 - limit : int option; 2381 + module DismissMatch = struct 2382 + type input = { 2383 + subject : string; 3260 2384 } 3261 2385 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) 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) 3272 2391 |> Jsont.Object.finish 3273 2392 3274 - type output = { 3275 - cursor : string option; 3276 - lists : Jsont.json list; 3277 - } 2393 + type output = unit 3278 2394 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 2395 + let output_jsont = Jsont.ignore 3286 2396 3287 2397 end 3288 - module GetStarterPack = struct 3289 - type params = { 3290 - starter_pack : string; 3291 - } 2398 + module GetSyncStatus = struct 2399 + type params = unit 3292 2400 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 2401 + let params_jsont = Jsont.ignore 3301 2402 3302 2403 type output = { 3303 - starter_pack : Jsont.json; 2404 + sync_status : Defs.sync_status option; 3304 2405 } 3305 2406 3306 2407 let output_jsont = 3307 2408 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) 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) 3311 2412 |> Jsont.Object.finish 3312 2413 3313 2414 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; 2415 + module ImportContacts = struct 2416 + type input = { 2417 + contacts : string list; 2418 + token : string; 3333 2419 } 3334 2420 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) 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) 3351 2427 |> Jsont.Object.finish 3352 2428 3353 2429 type output = { 3354 - cursor : string option; 3355 - lists_with_membership : Jsont.json list; 2430 + matches_and_contact_indexes : Defs.match_and_contact_index list; 3356 2431 } 3357 2432 3358 2433 let output_jsont = 3359 2434 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) 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) 3364 2438 |> Jsont.Object.finish 3365 2439 3366 2440 end 3367 - module GetListMutes = struct 3368 - type params = { 3369 - cursor : string option; 3370 - limit : int option; 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; 3371 2448 } 3372 2449 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) 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) 3383 2457 |> Jsont.Object.finish 3384 2458 3385 - type output = { 3386 - cursor : string option; 3387 - lists : Jsont.json list; 2459 + end 2460 + module DescribeFeedGenerator = struct 2461 + type links = { 2462 + privacy_policy : string option; 2463 + terms_of_service : string option; 3388 2464 } 3389 2465 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) 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) 3396 2472 |> Jsont.Object.finish 3397 2473 3398 - end 3399 - module GetStarterPacks = struct 3400 - type params = { 3401 - uris : string list; 2474 + type feed = { 2475 + uri : string; 3402 2476 } 3403 2477 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) 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) 3411 2483 |> Jsont.Object.finish 3412 2484 3413 2485 type output = { 3414 - starter_packs : Jsont.json list; 2486 + did : string; 2487 + feeds : Jsont.json list; 2488 + links : Jsont.json option; 3415 2489 } 3416 2490 3417 2491 let output_jsont = 3418 2492 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) 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) 3422 2498 |> Jsont.Object.finish 3423 2499 3424 2500 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 - } 2501 + module Threadgate = struct 2502 + type mention_rule = unit 3432 2503 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 2504 + let mention_rule_jsont = Jsont.ignore 3450 2505 3451 - type output = { 3452 - cursor : string option; 3453 - lists : Jsont.json list; 2506 + type list_rule = { 2507 + list_ : string; 3454 2508 } 3455 2509 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) 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_) 3462 2515 |> Jsont.Object.finish 3463 2516 3464 - end 3465 - end 3466 - module Feed = struct 3467 - module Post = struct 3468 - type text_slice = { 3469 - end_ : int; 3470 - start : int; 3471 - } 2517 + type following_rule = unit 3472 2518 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 2519 + let following_rule_jsont = Jsont.ignore 3480 2520 3481 - type reply_ref = { 3482 - parent : Com.Atproto.Repo.StrongRef.main; 3483 - root : Com.Atproto.Repo.StrongRef.main; 3484 - } 2521 + type follower_rule = unit 3485 2522 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 2523 + let follower_rule_jsont = Jsont.ignore 3493 2524 3494 - type entity = { 3495 - index : Jsont.json; 3496 - type_ : string; 3497 - value : string; 2525 + type main = { 2526 + allow : Jsont.json list option; 2527 + created_at : string; 2528 + hidden_replies : string list option; 2529 + post : string; 3498 2530 } 3499 2531 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) 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) 3507 2540 |> Jsont.Object.finish 3508 2541 2542 + end 2543 + module Like = struct 3509 2544 type main = { 3510 2545 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; 2546 + subject : Com.Atproto.Repo.StrongRef.main; 2547 + via : Com.Atproto.Repo.StrongRef.main option; 3519 2548 } 3520 2549 3521 2550 let main_jsont = 3522 2551 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") 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") 3525 2554 |> 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) 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) 3534 2557 |> Jsont.Object.finish 3535 2558 3536 2559 end ··· 3593 2616 |> Jsont.Object.finish 3594 2617 3595 2618 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 2619 module GetRepostedBy = struct 3620 2620 type params = { 3621 2621 cid : string option; ··· 3660 2660 |> Jsont.Object.finish 3661 2661 3662 2662 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 = { 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; 3689 2671 did : string; 3690 - feeds : Jsont.json list; 3691 - links : Jsont.json option; 2672 + display_name : string; 2673 + labels : Com.Atproto.Label.Defs.self_labels option; 3692 2674 } 3693 2675 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") 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) 3698 2686 |> 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) 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) 3701 2689 |> Jsont.Object.finish 3702 2690 3703 2691 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 2692 + module Postgate = struct 2693 + type disable_rule = unit 3721 2694 3722 - let following_rule_jsont = Jsont.ignore 3723 - 3724 - type follower_rule = unit 3725 - 3726 - let follower_rule_jsont = Jsont.ignore 2695 + let disable_rule_jsont = Jsont.ignore 3727 2696 3728 2697 type main = { 3729 - allow : Jsont.json list option; 3730 2698 created_at : string; 3731 - hidden_replies : string list option; 2699 + detached_embedding_uris : string list option; 2700 + embedding_rules : Jsont.json list option; 3732 2701 post : string; 3733 2702 } 3734 2703 3735 2704 let main_jsont = 3736 2705 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) 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") 3740 2708 |> 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) 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) 3742 2711 |> 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 2712 |> Jsont.Object.finish 3761 2713 3762 2714 end ··· 4102 3054 |> Jsont.Object.finish 4103 3055 4104 3056 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; 3057 + module Post = struct 3058 + type text_slice = { 3059 + end_ : int; 3060 + start : int; 4110 3061 } 4111 3062 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) 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) 4119 3069 |> Jsont.Object.finish 4120 3070 4121 - end 4122 - module Generator = struct 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 + 4123 3099 type main = { 4124 - accepts_interactions : bool option; 4125 - avatar : Atp.Blob_ref.t option; 4126 - content_mode : string option; 4127 3100 created_at : string; 4128 - description : string option; 4129 - description_facets : Richtext.Facet.main list option; 4130 - did : string; 4131 - display_name : string; 3101 + embed : Jsont.json option; 3102 + entities : Jsont.json list option; 3103 + facets : Richtext.Facet.main list option; 4132 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; 4133 3109 } 4134 3110 4135 3111 let main_jsont = 4136 3112 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) 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") 4142 3115 |> 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) 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) 4147 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) 4148 3124 |> Jsont.Object.finish 4149 3125 4150 3126 end 4151 - module GetPostThread = struct 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 4152 3154 type params = { 4153 - depth : int option; 4154 - parent_height : int option; 3155 + cid : string option; 3156 + cursor : string option; 3157 + limit : int option; 4155 3158 uri : string; 4156 3159 } 4157 3160 4158 3161 let params_jsont = 4159 3162 Jsont.Object.map ~kind:"Params" 4160 - (fun depth parent_height uri -> { 4161 - depth; 4162 - parent_height; 3163 + (fun cid cursor limit uri -> { 3164 + cid; 3165 + cursor; 3166 + limit; 4163 3167 uri; 4164 3168 }) 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) 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) 4169 3175 |> Jsont.Object.mem "uri" Jsont.string 4170 3176 ~enc:(fun r -> r.uri) 4171 3177 |> Jsont.Object.finish 4172 3178 4173 3179 type output = { 4174 - thread : Jsont.json; 4175 - threadgate : Jsont.json option; 3180 + cid : string option; 3181 + cursor : string option; 3182 + posts : Jsont.json list; 3183 + uri : string; 4176 3184 } 4177 3185 4178 3186 let output_jsont = 4179 3187 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) 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) 4184 3194 |> Jsont.Object.finish 4185 3195 4186 3196 end 4187 - module GetFeed = struct 3197 + module GetAuthorFeed = struct 4188 3198 type params = { 3199 + actor : string; 4189 3200 cursor : string option; 4190 - feed : string; 3201 + filter : string option; 3202 + include_pins : bool option; 4191 3203 limit : int option; 4192 3204 } 4193 3205 4194 3206 let params_jsont = 4195 3207 Jsont.Object.map ~kind:"Params" 4196 - (fun cursor feed limit -> { 3208 + (fun actor cursor filter include_pins limit -> { 3209 + actor; 4197 3210 cursor; 4198 - feed; 3211 + filter; 3212 + include_pins; 4199 3213 limit; 4200 3214 }) 3215 + |> Jsont.Object.mem "actor" Jsont.string 3216 + ~enc:(fun r -> r.actor) 4201 3217 |> Jsont.Object.opt_mem "cursor" Jsont.string 4202 3218 ~enc:(fun r -> r.cursor) 4203 - |> Jsont.Object.mem "feed" Jsont.string 4204 - ~enc:(fun r -> r.feed) 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) 4205 3223 |> Jsont.Object.opt_mem "limit" Jsont.int 4206 3224 ~enc:(fun r -> r.limit) 4207 3225 |> Jsont.Object.finish ··· 4214 3232 let output_jsont = 4215 3233 Jsont.Object.map ~kind:"Output" 4216 3234 (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") 3235 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.feed.getAuthorFeed#output" ~enc:(fun _ -> "app.bsky.feed.getAuthorFeed#output") 4218 3236 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 4219 3237 |> Jsont.Object.mem "feed" (Jsont.list Jsont.json) ~enc:(fun r -> r.feed) 4220 3238 |> Jsont.Object.finish 4221 3239 4222 3240 end 4223 - module GetQuotes = struct 3241 + module GetTimeline = struct 4224 3242 type params = { 4225 - cid : string option; 3243 + algorithm : string option; 4226 3244 cursor : string option; 4227 3245 limit : int option; 4228 - uri : string; 4229 3246 } 4230 3247 4231 3248 let params_jsont = 4232 3249 Jsont.Object.map ~kind:"Params" 4233 - (fun cid cursor limit uri -> { 4234 - cid; 3250 + (fun algorithm cursor limit -> { 3251 + algorithm; 4235 3252 cursor; 4236 3253 limit; 4237 - uri; 4238 3254 }) 4239 - |> Jsont.Object.opt_mem "cid" Jsont.string 4240 - ~enc:(fun r -> r.cid) 3255 + |> Jsont.Object.opt_mem "algorithm" Jsont.string 3256 + ~enc:(fun r -> r.algorithm) 4241 3257 |> Jsont.Object.opt_mem "cursor" Jsont.string 4242 3258 ~enc:(fun r -> r.cursor) 4243 3259 |> Jsont.Object.opt_mem "limit" Jsont.int 4244 3260 ~enc:(fun r -> r.limit) 4245 - |> Jsont.Object.mem "uri" Jsont.string 4246 - ~enc:(fun r -> r.uri) 4247 3261 |> Jsont.Object.finish 4248 3262 4249 3263 type output = { 4250 - cid : string option; 4251 3264 cursor : string option; 4252 - posts : Jsont.json list; 4253 - uri : string; 3265 + feed : Jsont.json list; 4254 3266 } 4255 3267 4256 3268 let output_jsont = 4257 3269 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) 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") 4261 3272 |> 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) 3273 + |> Jsont.Object.mem "feed" (Jsont.list Jsont.json) ~enc:(fun r -> r.feed) 4264 3274 |> Jsont.Object.finish 4265 3275 4266 3276 end ··· 4300 3310 |> Jsont.Object.finish 4301 3311 4302 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 4303 3345 module GetActorLikes = struct 4304 3346 type params = { 4305 3347 actor : string; ··· 4336 3378 |> Jsont.Object.finish 4337 3379 4338 3380 end 4339 - module GetFeedSkeleton = struct 3381 + module GetActorFeeds = struct 4340 3382 type params = { 3383 + actor : string; 4341 3384 cursor : string option; 4342 - feed : string; 4343 3385 limit : int option; 4344 3386 } 4345 3387 4346 3388 let params_jsont = 4347 3389 Jsont.Object.map ~kind:"Params" 4348 - (fun cursor feed limit -> { 3390 + (fun actor cursor limit -> { 3391 + actor; 4349 3392 cursor; 4350 - feed; 4351 3393 limit; 4352 3394 }) 3395 + |> Jsont.Object.mem "actor" Jsont.string 3396 + ~enc:(fun r -> r.actor) 4353 3397 |> Jsont.Object.opt_mem "cursor" Jsont.string 4354 3398 ~enc:(fun r -> r.cursor) 4355 - |> Jsont.Object.mem "feed" Jsont.string 4356 - ~enc:(fun r -> r.feed) 4357 3399 |> Jsont.Object.opt_mem "limit" Jsont.int 4358 3400 ~enc:(fun r -> r.limit) 4359 3401 |> Jsont.Object.finish 4360 3402 4361 3403 type output = { 4362 3404 cursor : string option; 4363 - feed : Jsont.json list; 4364 - req_id : string option; 3405 + feeds : Jsont.json list; 4365 3406 } 4366 3407 4367 3408 let output_jsont = 4368 3409 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") 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") 4371 3412 |> 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) 3413 + |> Jsont.Object.mem "feeds" (Jsont.list Jsont.json) ~enc:(fun r -> r.feeds) 4374 3414 |> Jsont.Object.finish 4375 3415 4376 3416 end ··· 4448 3488 |> Jsont.Object.finish 4449 3489 4450 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 4451 3601 module GetFeedGenerators = struct 4452 3602 type params = { 4453 3603 feeds : string list; ··· 4491 3641 let output_jsont = Jsont.ignore 4492 3642 4493 3643 end 4494 - module GetAuthorFeed = struct 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 4495 3944 type params = { 4496 3945 actor : string; 4497 3946 cursor : string option; 4498 - filter : string option; 4499 - include_pins : bool option; 4500 3947 limit : int option; 4501 3948 } 4502 3949 4503 3950 let params_jsont = 4504 3951 Jsont.Object.map ~kind:"Params" 4505 - (fun actor cursor filter include_pins limit -> { 3952 + (fun actor cursor limit -> { 4506 3953 actor; 4507 3954 cursor; 4508 - filter; 4509 - include_pins; 4510 3955 limit; 4511 3956 }) 4512 3957 |> Jsont.Object.mem "actor" Jsont.string 4513 3958 ~enc:(fun r -> r.actor) 4514 3959 |> Jsont.Object.opt_mem "cursor" Jsont.string 4515 3960 ~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) 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) 4520 4021 |> Jsont.Object.opt_mem "limit" Jsont.int 4521 4022 ~enc:(fun r -> r.limit) 4522 4023 |> Jsont.Object.finish 4523 4024 4524 4025 type output = { 4026 + blocks : Jsont.json list; 4525 4027 cursor : string option; 4526 - feed : Jsont.json list; 4527 4028 } 4528 4029 4529 4030 let output_jsont = 4530 4031 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") 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) 4533 4035 |> 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) 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) 4535 4081 |> Jsont.Object.finish 4536 4082 4537 4083 end 4538 - module GetFeedGenerator = struct 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 4539 4119 type params = { 4540 - feed : string; 4120 + actor : string; 4121 + cursor : string option; 4122 + limit : int option; 4541 4123 } 4542 4124 4543 4125 let params_jsont = 4544 4126 Jsont.Object.map ~kind:"Params" 4545 - (fun feed -> { 4546 - feed; 4127 + (fun actor cursor limit -> { 4128 + actor; 4129 + cursor; 4130 + limit; 4547 4131 }) 4548 - |> Jsont.Object.mem "feed" Jsont.string 4549 - ~enc:(fun r -> r.feed) 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) 4550 4138 |> Jsont.Object.finish 4551 4139 4552 4140 type output = { 4553 - is_online : bool; 4554 - is_valid : bool; 4555 - view : Jsont.json; 4141 + cursor : string option; 4142 + follows : Jsont.json list; 4143 + subject : Jsont.json; 4556 4144 } 4557 4145 4558 4146 let output_jsont = 4559 4147 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) 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) 4565 4153 |> Jsont.Object.finish 4566 4154 4567 4155 end 4568 - module GetSuggestedFeeds = struct 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 4569 4189 type params = { 4570 4190 cursor : string option; 4571 4191 limit : int option; ··· 4585 4205 4586 4206 type output = { 4587 4207 cursor : string option; 4588 - feeds : Jsont.json list; 4208 + mutes : Jsont.json list; 4589 4209 } 4590 4210 4591 4211 let output_jsont = 4592 4212 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") 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") 4595 4215 |> 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) 4216 + |> Jsont.Object.mem "mutes" (Jsont.list Jsont.json) ~enc:(fun r -> r.mutes) 4597 4217 |> Jsont.Object.finish 4598 4218 4599 4219 end 4600 - module GetActorFeeds = struct 4220 + module GetKnownFollowers = struct 4601 4221 type params = { 4602 4222 actor : string; 4603 4223 cursor : string option; ··· 4621 4241 4622 4242 type output = { 4623 4243 cursor : string option; 4624 - feeds : Jsont.json list; 4244 + followers : Jsont.json list; 4245 + subject : Jsont.json; 4625 4246 } 4626 4247 4627 4248 let output_jsont = 4628 4249 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") 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") 4631 4252 |> 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) 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) 4633 4255 |> Jsont.Object.finish 4634 4256 4635 4257 end 4636 - module GetPosts = struct 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 4637 4274 type params = { 4638 - uris : string list; 4275 + actor : string; 4276 + others : string list option; 4639 4277 } 4640 4278 4641 4279 let params_jsont = 4642 4280 Jsont.Object.map ~kind:"Params" 4643 - (fun uris -> { 4644 - uris; 4281 + (fun actor others -> { 4282 + actor; 4283 + others; 4645 4284 }) 4646 - |> Jsont.Object.mem "uris" (Jsont.list Jsont.string) 4647 - ~enc:(fun r -> r.uris) 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) 4648 4289 |> Jsont.Object.finish 4649 4290 4650 4291 type output = { 4651 - posts : Jsont.json list; 4292 + actor : string option; 4293 + relationships : Jsont.json list; 4652 4294 } 4653 4295 4654 4296 let output_jsont = 4655 4297 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) 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) 4659 4302 |> Jsont.Object.finish 4660 4303 4661 4304 end 4662 - module GetTimeline = struct 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 + 4663 4319 type params = { 4664 - algorithm : string option; 4320 + actor : string; 4665 4321 cursor : string option; 4666 4322 limit : int option; 4323 + purposes : string list option; 4667 4324 } 4668 4325 4669 4326 let params_jsont = 4670 4327 Jsont.Object.map ~kind:"Params" 4671 - (fun algorithm cursor limit -> { 4672 - algorithm; 4328 + (fun actor cursor limit purposes -> { 4329 + actor; 4673 4330 cursor; 4674 4331 limit; 4332 + purposes; 4675 4333 }) 4676 - |> Jsont.Object.opt_mem "algorithm" Jsont.string 4677 - ~enc:(fun r -> r.algorithm) 4334 + |> Jsont.Object.mem "actor" Jsont.string 4335 + ~enc:(fun r -> r.actor) 4678 4336 |> Jsont.Object.opt_mem "cursor" Jsont.string 4679 4337 ~enc:(fun r -> r.cursor) 4680 4338 |> Jsont.Object.opt_mem "limit" Jsont.int 4681 4339 ~enc:(fun r -> r.limit) 4340 + |> Jsont.Object.opt_mem "purposes" (Jsont.list Jsont.string) 4341 + ~enc:(fun r -> r.purposes) 4682 4342 |> Jsont.Object.finish 4683 4343 4684 4344 type output = { 4685 4345 cursor : string option; 4686 - feed : Jsont.json list; 4346 + lists_with_membership : Jsont.json list; 4687 4347 } 4688 4348 4689 4349 let output_jsont = 4690 4350 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") 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") 4693 4353 |> 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) 4354 + |> Jsont.Object.mem "listsWithMembership" (Jsont.list Jsont.json) ~enc:(fun r -> r.lists_with_membership) 4695 4355 |> Jsont.Object.finish 4696 4356 4697 4357 end 4698 - end 4699 - module Bookmark = struct 4700 - module DeleteBookmark = struct 4701 - type input = { 4702 - uri : string; 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; 4703 4379 } 4704 4380 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) 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) 4710 4387 |> Jsont.Object.finish 4711 4388 4712 4389 end 4713 - module CreateBookmark = struct 4714 - type input = { 4715 - cid : string; 4716 - uri : string; 4390 + module GetActorStarterPacks = struct 4391 + type params = { 4392 + actor : string; 4393 + cursor : string option; 4394 + limit : int option; 4717 4395 } 4718 4396 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) 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) 4725 4423 |> Jsont.Object.finish 4726 4424 4727 4425 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; 4426 + module SearchStarterPacks = struct 4427 + type params = { 4428 + cursor : string option; 4429 + limit : int option; 4430 + q : string; 4733 4431 } 4734 4432 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) 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) 4742 4446 |> Jsont.Object.finish 4743 4447 4744 - type bookmark = { 4745 - subject : Com.Atproto.Repo.StrongRef.main; 4448 + type output = { 4449 + cursor : string option; 4450 + starter_packs : Jsont.json list; 4746 4451 } 4747 4452 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) 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) 4753 4459 |> Jsont.Object.finish 4754 4460 4755 4461 end 4756 - module GetBookmarks = struct 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 + 4757 4476 type params = { 4477 + actor : string; 4758 4478 cursor : string option; 4759 4479 limit : int option; 4760 4480 } 4761 4481 4762 4482 let params_jsont = 4763 4483 Jsont.Object.map ~kind:"Params" 4764 - (fun cursor limit -> { 4484 + (fun actor cursor limit -> { 4485 + actor; 4765 4486 cursor; 4766 4487 limit; 4767 4488 }) 4489 + |> Jsont.Object.mem "actor" Jsont.string 4490 + ~enc:(fun r -> r.actor) 4768 4491 |> Jsont.Object.opt_mem "cursor" Jsont.string 4769 4492 ~enc:(fun r -> r.cursor) 4770 4493 |> Jsont.Object.opt_mem "limit" Jsont.int ··· 4772 4495 |> Jsont.Object.finish 4773 4496 4774 4497 type output = { 4775 - bookmarks : Defs.bookmark_view list; 4776 4498 cursor : string option; 4499 + starter_packs_with_membership : Jsont.json list; 4777 4500 } 4778 4501 4779 4502 let output_jsont = 4780 4503 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) 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") 4784 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) 4785 4508 |> Jsont.Object.finish 4786 4509 4787 4510 end 4788 - end 4789 - module Unspecced = struct 4790 - module GetSuggestedUsersSkeleton = struct 4511 + module GetLists = struct 4791 4512 type params = { 4792 - category : string option; 4513 + actor : string; 4514 + cursor : string option; 4793 4515 limit : int option; 4794 - viewer : string option; 4516 + purposes : string list option; 4795 4517 } 4796 4518 4797 4519 let params_jsont = 4798 4520 Jsont.Object.map ~kind:"Params" 4799 - (fun category limit viewer -> { 4800 - category; 4521 + (fun actor cursor limit purposes -> { 4522 + actor; 4523 + cursor; 4801 4524 limit; 4802 - viewer; 4525 + purposes; 4803 4526 }) 4804 - |> Jsont.Object.opt_mem "category" Jsont.string 4805 - ~enc:(fun r -> r.category) 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) 4806 4531 |> Jsont.Object.opt_mem "limit" Jsont.int 4807 4532 ~enc:(fun r -> r.limit) 4808 - |> Jsont.Object.opt_mem "viewer" Jsont.string 4809 - ~enc:(fun r -> r.viewer) 4533 + |> Jsont.Object.opt_mem "purposes" (Jsont.list Jsont.string) 4534 + ~enc:(fun r -> r.purposes) 4810 4535 |> Jsont.Object.finish 4811 4536 4812 4537 type output = { 4813 - dids : string list; 4814 - rec_id : int option; 4538 + cursor : string option; 4539 + lists : Jsont.json list; 4815 4540 } 4816 4541 4817 4542 let output_jsont = 4818 4543 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) 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) 4823 4548 |> Jsont.Object.finish 4824 4549 4825 4550 end 4826 - module GetOnboardingSuggestedStarterPacks = struct 4551 + module GetStarterPack = struct 4827 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; 4828 4580 limit : int option; 4829 4581 } 4830 4582 4831 4583 let params_jsont = 4832 4584 Jsont.Object.map ~kind:"Params" 4833 - (fun limit -> { 4585 + (fun cursor limit -> { 4586 + cursor; 4834 4587 limit; 4835 4588 }) 4589 + |> Jsont.Object.opt_mem "cursor" Jsont.string 4590 + ~enc:(fun r -> r.cursor) 4836 4591 |> Jsont.Object.opt_mem "limit" Jsont.int 4837 4592 ~enc:(fun r -> r.limit) 4838 4593 |> Jsont.Object.finish 4839 4594 4840 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 = { 4841 4624 starter_packs : Jsont.json list; 4842 4625 } 4843 4626 4844 4627 let output_jsont = 4845 4628 Jsont.Object.map ~kind:"Output" 4846 4629 (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") 4630 + |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.graph.getStarterPacks#output" ~enc:(fun _ -> "app.bsky.graph.getStarterPacks#output") 4848 4631 |> Jsont.Object.mem "starterPacks" (Jsont.list Jsont.json) ~enc:(fun r -> r.starter_packs) 4849 4632 |> Jsont.Object.finish 4850 4633 4851 4634 end 4852 - module GetPopularFeedGenerators = struct 4635 + module GetList = struct 4853 4636 type params = { 4854 4637 cursor : string option; 4855 4638 limit : int option; 4856 - query : string option; 4639 + list_ : string; 4857 4640 } 4858 4641 4859 4642 let params_jsont = 4860 4643 Jsont.Object.map ~kind:"Params" 4861 - (fun cursor limit query -> { 4644 + (fun cursor limit list_ -> { 4862 4645 cursor; 4863 4646 limit; 4864 - query; 4647 + list_; 4865 4648 }) 4866 4649 |> Jsont.Object.opt_mem "cursor" Jsont.string 4867 4650 ~enc:(fun r -> r.cursor) 4868 4651 |> Jsont.Object.opt_mem "limit" Jsont.int 4869 4652 ~enc:(fun r -> r.limit) 4870 - |> Jsont.Object.opt_mem "query" Jsont.string 4871 - ~enc:(fun r -> r.query) 4653 + |> Jsont.Object.mem "list" Jsont.string 4654 + ~enc:(fun r -> r.list_) 4872 4655 |> Jsont.Object.finish 4873 4656 4874 4657 type output = { 4875 4658 cursor : string option; 4876 - feeds : Jsont.json list; 4659 + items : Jsont.json list; 4660 + list_ : Jsont.json; 4877 4661 } 4878 4662 4879 4663 let output_jsont = 4880 4664 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") 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") 4883 4667 |> 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) 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) 4885 4740 |> Jsont.Object.finish 4886 4741 4887 4742 end 4888 - module GetSuggestedStarterPacksSkeleton = struct 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 4889 4757 type params = { 4758 + cursor : string option; 4890 4759 limit : int option; 4891 - viewer : string option; 4892 4760 } 4893 4761 4894 4762 let params_jsont = 4895 4763 Jsont.Object.map ~kind:"Params" 4896 - (fun limit viewer -> { 4764 + (fun cursor limit -> { 4765 + cursor; 4897 4766 limit; 4898 - viewer; 4899 4767 }) 4768 + |> Jsont.Object.opt_mem "cursor" Jsont.string 4769 + ~enc:(fun r -> r.cursor) 4900 4770 |> Jsont.Object.opt_mem "limit" Jsont.int 4901 4771 ~enc:(fun r -> r.limit) 4902 - |> Jsont.Object.opt_mem "viewer" Jsont.string 4903 - ~enc:(fun r -> r.viewer) 4904 4772 |> Jsont.Object.finish 4905 4773 4906 4774 type output = { 4907 - starter_packs : string list; 4775 + bookmarks : Defs.bookmark_view list; 4776 + cursor : string option; 4908 4777 } 4909 4778 4910 4779 let output_jsont = 4911 4780 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) 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) 4915 4785 |> Jsont.Object.finish 4916 4786 4917 4787 end 4788 + end 4789 + module Unspecced = struct 4918 4790 module GetSuggestedFeeds = struct 4919 4791 type params = { 4920 4792 limit : int option; ··· 4941 4813 |> Jsont.Object.finish 4942 4814 4943 4815 end 4944 - module GetSuggestedFeedsSkeleton = struct 4816 + module GetSuggestedUsers = struct 4945 4817 type params = { 4818 + category : string option; 4946 4819 limit : int option; 4947 - viewer : string option; 4948 4820 } 4949 4821 4950 4822 let params_jsont = 4951 4823 Jsont.Object.map ~kind:"Params" 4952 - (fun limit viewer -> { 4824 + (fun category limit -> { 4825 + category; 4953 4826 limit; 4954 - viewer; 4955 4827 }) 4828 + |> Jsont.Object.opt_mem "category" Jsont.string 4829 + ~enc:(fun r -> r.category) 4956 4830 |> Jsont.Object.opt_mem "limit" Jsont.int 4957 4831 ~enc:(fun r -> r.limit) 4958 - |> Jsont.Object.opt_mem "viewer" Jsont.string 4959 - ~enc:(fun r -> r.viewer) 4960 4832 |> Jsont.Object.finish 4961 4833 4962 4834 type output = { 4963 - feeds : string list; 4835 + actors : Jsont.json list; 4836 + rec_id : int option; 4964 4837 } 4965 4838 4966 4839 let output_jsont = 4967 4840 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) 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) 4971 4845 |> Jsont.Object.finish 4972 4846 4973 4847 end 4974 - module GetConfig = struct 4975 - type live_now_config = { 4976 - did : string; 4977 - domains : string list; 4848 + module GetSuggestedUsersSkeleton = struct 4849 + type params = { 4850 + category : string option; 4851 + limit : int option; 4852 + viewer : string option; 4978 4853 } 4979 4854 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) 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) 4986 4868 |> Jsont.Object.finish 4987 4869 4988 4870 type output = { 4989 - check_email_confirmed : bool option; 4990 - live_now : live_now_config list option; 4871 + dids : string list; 4872 + rec_id : int option; 4991 4873 } 4992 4874 4993 4875 let output_jsont = 4994 4876 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) 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) 4999 4881 |> Jsont.Object.finish 5000 4882 5001 4883 end ··· 5025 4907 |> Jsont.Object.finish 5026 4908 5027 4909 end 5028 - module GetSuggestedUsers = struct 4910 + module GetOnboardingSuggestedStarterPacksSkeleton = struct 5029 4911 type params = { 5030 - category : string option; 5031 4912 limit : int option; 4913 + viewer : string option; 5032 4914 } 5033 4915 5034 4916 let params_jsont = 5035 4917 Jsont.Object.map ~kind:"Params" 5036 - (fun category limit -> { 5037 - category; 4918 + (fun limit viewer -> { 5038 4919 limit; 4920 + viewer; 5039 4921 }) 5040 - |> Jsont.Object.opt_mem "category" Jsont.string 5041 - ~enc:(fun r -> r.category) 5042 4922 |> Jsont.Object.opt_mem "limit" Jsont.int 5043 4923 ~enc:(fun r -> r.limit) 4924 + |> Jsont.Object.opt_mem "viewer" Jsont.string 4925 + ~enc:(fun r -> r.viewer) 5044 4926 |> Jsont.Object.finish 5045 4927 5046 4928 type output = { 5047 - actors : Jsont.json list; 5048 - rec_id : int option; 4929 + starter_packs : string list; 5049 4930 } 5050 4931 5051 4932 let output_jsont = 5052 4933 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) 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) 5057 4937 |> Jsont.Object.finish 5058 4938 5059 4939 end 5060 - module GetOnboardingSuggestedStarterPacksSkeleton = struct 4940 + module GetSuggestedFeedsSkeleton = struct 5061 4941 type params = { 5062 4942 limit : int option; 5063 4943 viewer : string option; ··· 5076 4956 |> Jsont.Object.finish 5077 4957 5078 4958 type output = { 5079 - starter_packs : string list; 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; 5080 4986 } 5081 4987 5082 4988 let output_jsont = 5083 4989 Jsont.Object.map ~kind:"Output" 5084 4990 (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) 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) 5087 4993 |> Jsont.Object.finish 5088 4994 5089 4995 end ··· 5267 5173 |> Jsont.Object.finish 5268 5174 5269 5175 end 5270 - module GetTaggedSuggestions = struct 5271 - type suggestion = { 5272 - subject : string; 5273 - subject_type : string; 5274 - tag : string; 5176 + module GetConfig = struct 5177 + type live_now_config = { 5178 + did : string; 5179 + domains : string list; 5275 5180 } 5276 5181 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) 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) 5284 5188 |> Jsont.Object.finish 5285 5189 5286 - type params = unit 5287 - 5288 - let params_jsont = Jsont.ignore 5289 - 5290 5190 type output = { 5291 - suggestions : suggestion list; 5191 + check_email_confirmed : bool option; 5192 + live_now : live_now_config list option; 5292 5193 } 5293 5194 5294 5195 let output_jsont = 5295 5196 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) 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) 5299 5201 |> Jsont.Object.finish 5300 5202 5301 5203 end 5302 - module SearchPostsSkeleton = struct 5204 + module GetPopularFeedGenerators = struct 5303 5205 type params = { 5304 - author : string option; 5305 5206 cursor : string option; 5306 - domain : string option; 5307 - lang : string option; 5308 5207 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; 5208 + query : string option; 5317 5209 } 5318 5210 5319 5211 let params_jsont = 5320 5212 Jsont.Object.map ~kind:"Params" 5321 - (fun author cursor domain lang limit mentions q since sort tag until url viewer -> { 5322 - author; 5213 + (fun cursor limit query -> { 5323 5214 cursor; 5324 - domain; 5325 - lang; 5326 5215 limit; 5327 - mentions; 5328 - q; 5329 - since; 5330 - sort; 5331 - tag; 5332 - until; 5333 - url; 5334 - viewer; 5216 + query; 5335 5217 }) 5336 - |> Jsont.Object.opt_mem "author" Jsont.string 5337 - ~enc:(fun r -> r.author) 5338 5218 |> Jsont.Object.opt_mem "cursor" Jsont.string 5339 5219 ~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 5220 |> Jsont.Object.opt_mem "limit" Jsont.int 5345 5221 ~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) 5222 + |> Jsont.Object.opt_mem "query" Jsont.string 5223 + ~enc:(fun r -> r.query) 5362 5224 |> Jsont.Object.finish 5363 5225 5364 5226 type output = { 5365 5227 cursor : string option; 5366 - hits_total : int option; 5367 - posts : Defs.skeleton_search_post list; 5228 + feeds : Jsont.json list; 5368 5229 } 5369 5230 5370 5231 let output_jsont = 5371 5232 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") 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") 5374 5235 |> 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) 5236 + |> Jsont.Object.mem "feeds" (Jsont.list Jsont.json) ~enc:(fun r -> r.feeds) 5377 5237 |> Jsont.Object.finish 5378 5238 5379 5239 end 5380 - module GetPostThreadV2 = struct 5381 - type thread_item = { 5382 - depth : int; 5383 - uri : string; 5384 - value : Jsont.json; 5240 + module GetTaggedSuggestions = struct 5241 + type suggestion = { 5242 + subject : string; 5243 + subject_type : string; 5244 + tag : string; 5385 5245 } 5386 5246 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) 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) 5394 5254 |> Jsont.Object.finish 5395 5255 5396 - type params = { 5397 - above : bool option; 5398 - anchor : string; 5399 - below : int option; 5400 - branching_factor : int option; 5401 - sort : string option; 5402 - } 5256 + type params = unit 5403 5257 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 5258 + let params_jsont = Jsont.ignore 5424 5259 5425 5260 type output = { 5426 - has_other_replies : bool; 5427 - thread : thread_item list; 5428 - threadgate : Jsont.json option; 5261 + suggestions : suggestion list; 5429 5262 } 5430 5263 5431 5264 let output_jsont = 5432 5265 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) 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) 5438 5269 |> Jsont.Object.finish 5439 5270 5440 5271 end 5441 - module GetTrendingTopics = struct 5272 + module GetSuggestedStarterPacksSkeleton = struct 5442 5273 type params = { 5443 5274 limit : int option; 5444 5275 viewer : string option; ··· 5457 5288 |> Jsont.Object.finish 5458 5289 5459 5290 type output = { 5460 - suggested : Defs.trending_topic list; 5461 - topics : Defs.trending_topic list; 5291 + starter_packs : string list; 5462 5292 } 5463 5293 5464 5294 let output_jsont = 5465 5295 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) 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) 5470 5316 |> Jsont.Object.finish 5471 5317 5318 + type output = Defs.age_assurance_state 5319 + 5320 + let output_jsont = Defs.age_assurance_state_jsont 5321 + 5472 5322 end 5473 - module GetTrendsSkeleton = struct 5323 + module GetTrendingTopics = struct 5474 5324 type params = { 5475 5325 limit : int option; 5476 5326 viewer : string option; ··· 5489 5339 |> Jsont.Object.finish 5490 5340 5491 5341 type output = { 5492 - trends : Defs.skeleton_trend list; 5342 + suggested : Defs.trending_topic list; 5343 + topics : Defs.trending_topic list; 5493 5344 } 5494 5345 5495 5346 let output_jsont = 5496 5347 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) 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) 5500 5352 |> Jsont.Object.finish 5501 5353 5502 5354 end ··· 5541 5393 |> Jsont.Object.finish 5542 5394 5543 5395 end 5544 - module InitAgeAssurance = struct 5545 - type input = { 5546 - country_code : string; 5547 - email : string; 5548 - language : string; 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; 5549 5402 } 5550 5403 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) 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) 5558 5420 |> Jsont.Object.finish 5559 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 5560 5441 type output = Defs.age_assurance_state 5561 5442 5562 5443 let output_jsont = Defs.age_assurance_state_jsont ··· 5604 5485 |> Jsont.Object.finish 5605 5486 5606 5487 end 5607 - module SearchActorsSkeleton = struct 5488 + module SearchPostsSkeleton = struct 5608 5489 type params = { 5490 + author : string option; 5609 5491 cursor : string option; 5492 + domain : string option; 5493 + lang : string option; 5610 5494 limit : int option; 5495 + mentions : string option; 5611 5496 q : string; 5612 - typeahead : bool option; 5497 + since : string option; 5498 + sort : string option; 5499 + tag : string list option; 5500 + until : string option; 5501 + url : string option; 5613 5502 viewer : string option; 5614 5503 } 5615 5504 5616 5505 let params_jsont = 5617 5506 Jsont.Object.map ~kind:"Params" 5618 - (fun cursor limit q typeahead viewer -> { 5507 + (fun author cursor domain lang limit mentions q since sort tag until url viewer -> { 5508 + author; 5619 5509 cursor; 5510 + domain; 5511 + lang; 5620 5512 limit; 5513 + mentions; 5621 5514 q; 5622 - typeahead; 5515 + since; 5516 + sort; 5517 + tag; 5518 + until; 5519 + url; 5623 5520 viewer; 5624 5521 }) 5522 + |> Jsont.Object.opt_mem "author" Jsont.string 5523 + ~enc:(fun r -> r.author) 5625 5524 |> Jsont.Object.opt_mem "cursor" Jsont.string 5626 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) 5627 5530 |> Jsont.Object.opt_mem "limit" Jsont.int 5628 5531 ~enc:(fun r -> r.limit) 5532 + |> Jsont.Object.opt_mem "mentions" Jsont.string 5533 + ~enc:(fun r -> r.mentions) 5629 5534 |> Jsont.Object.mem "q" Jsont.string 5630 5535 ~enc:(fun r -> r.q) 5631 - |> Jsont.Object.opt_mem "typeahead" Jsont.bool 5632 - ~enc:(fun r -> r.typeahead) 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) 5633 5546 |> Jsont.Object.opt_mem "viewer" Jsont.string 5634 5547 ~enc:(fun r -> r.viewer) 5635 5548 |> Jsont.Object.finish 5636 5549 5637 5550 type output = { 5638 - actors : Defs.skeleton_search_actor list; 5639 5551 cursor : string option; 5640 5552 hits_total : int option; 5553 + posts : Defs.skeleton_search_post list; 5641 5554 } 5642 5555 5643 5556 let output_jsont = 5644 5557 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) 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") 5648 5560 |> Jsont.Object.opt_mem "cursor" Jsont.string ~enc:(fun r -> r.cursor) 5649 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) 5650 5563 |> Jsont.Object.finish 5651 5564 5652 5565 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 5566 + module SearchActorsSkeleton = struct 5660 5567 type params = { 5661 5568 cursor : string option; 5662 5569 limit : int option; 5663 - relative_to_did : string option; 5570 + q : string; 5571 + typeahead : bool option; 5664 5572 viewer : string option; 5665 5573 } 5666 5574 5667 5575 let params_jsont = 5668 5576 Jsont.Object.map ~kind:"Params" 5669 - (fun cursor limit relative_to_did viewer -> { 5577 + (fun cursor limit q typeahead viewer -> { 5670 5578 cursor; 5671 5579 limit; 5672 - relative_to_did; 5580 + q; 5581 + typeahead; 5673 5582 viewer; 5674 5583 }) 5675 5584 |> Jsont.Object.opt_mem "cursor" Jsont.string 5676 5585 ~enc:(fun r -> r.cursor) 5677 5586 |> Jsont.Object.opt_mem "limit" Jsont.int 5678 5587 ~enc:(fun r -> r.limit) 5679 - |> Jsont.Object.opt_mem "relativeToDid" Jsont.string 5680 - ~enc:(fun r -> r.relative_to_did) 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) 5681 5592 |> Jsont.Object.opt_mem "viewer" Jsont.string 5682 5593 ~enc:(fun r -> r.viewer) 5683 5594 |> Jsont.Object.finish ··· 5685 5596 type output = { 5686 5597 actors : Defs.skeleton_search_actor list; 5687 5598 cursor : string option; 5688 - rec_id : int option; 5689 - relative_to_did : string option; 5599 + hits_total : int option; 5690 5600 } 5691 5601 5692 5602 let output_jsont = 5693 5603 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") 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") 5696 5606 |> Jsont.Object.mem "actors" (Jsont.list Defs.skeleton_search_actor_jsont) ~enc:(fun r -> r.actors) 5697 5607 |> 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) 5608 + |> Jsont.Object.opt_mem "hitsTotal" Jsont.int ~enc:(fun r -> r.hits_total) 5700 5609 |> Jsont.Object.finish 5701 5610 5702 5611 end ··· 5723 5632 (fun _typ trends -> { trends }) 5724 5633 |> Jsont.Object.mem "$type" Jsont.string ~dec_absent:"app.bsky.unspecced.getTrends#output" ~enc:(fun _ -> "app.bsky.unspecced.getTrends#output") 5725 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 5726 |> Jsont.Object.finish 5727 5727 5728 5728 end
+1641 -1641
ocaml-atp/lexicons/bsky/atp_lexicon_bsky.mli
··· 12 12 13 13 module Com : sig 14 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 15 63 module Label : sig 16 64 module Defs : sig 17 65 (** Metadata tag on an atproto record, published by the author within the record. Note that schemas should use #selfLabels, not #selfLabel. *) ··· 93 141 94 142 end 95 143 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 144 end 145 145 end 146 146 module App : sig 147 147 module Bsky : sig 148 - module AuthManageLabelerService : sig 148 + module AuthFullApp : sig 149 149 150 150 type main = unit 151 151 val main_jsont : main Jsont.t ··· 157 157 val main_jsont : main Jsont.t 158 158 159 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 160 module AuthManageFeedDeclarations : sig 218 161 219 162 type main = unit 220 163 val main_jsont : main Jsont.t 221 164 222 165 end 223 - module AuthFullApp : sig 166 + module AuthManageNotifications : sig 224 167 225 168 type main = unit 226 169 val main_jsont : main Jsont.t 227 170 228 171 end 229 - module AuthManageNotifications : sig 172 + module AuthManageModeration : sig 230 173 231 174 type main = unit 232 175 val main_jsont : main Jsont.t ··· 238 181 val main_jsont : main Jsont.t 239 182 240 183 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 184 + module AuthManageLabelerService : sig 527 185 528 186 type main = unit 529 187 val main_jsont : main Jsont.t 530 188 531 189 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. *) 190 + module Notification : sig 191 + module GetUnreadCount : sig 192 + (** Count the number of unread notifications for the requesting account. Requires auth. *) 583 193 584 194 (** Query/procedure parameters. *) 585 195 type params = { 586 - job_id : string; 196 + priority : bool option; 197 + seen_at : string option; 587 198 } 588 199 589 200 (** Jsont codec for {!type:params}. *) ··· 591 202 592 203 593 204 type output = { 594 - job_status : Defs.job_status; 205 + count : int; 595 206 } 596 207 597 208 (** Jsont codec for {!type:output}. *) 598 209 val output_jsont : output Jsont.t 599 210 600 211 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 212 module UpdateSeen : sig 816 213 (** Notify server that the requesting account has seen notifications. Requires auth. *) 817 214 ··· 824 221 val input_jsont : input Jsont.t 825 222 826 223 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 224 module ListNotifications : sig 844 225 845 226 type notification = { ··· 883 264 val output_jsont : output Jsont.t 884 265 885 266 end 886 - module GetUnreadCount : sig 887 - (** Count the number of unread notifications for the requesting account. Requires auth. *) 267 + module Declaration : sig 268 + (** A declaration of the user's choices related to notifications that can be produced by them. *) 888 269 889 - (** Query/procedure parameters. *) 890 - type params = { 891 - priority : bool option; 892 - seen_at : string option; 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'. *) 893 272 } 894 273 895 - (** Jsont codec for {!type:params}. *) 896 - val params_jsont : params Jsont.t 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. *) 897 280 898 281 899 - type output = { 900 - count : int; 282 + type input = { 283 + priority : bool; 901 284 } 902 285 903 - (** Jsont codec for {!type:output}. *) 904 - val output_jsont : output Jsont.t 286 + (** Jsont codec for {!type:input}. *) 287 + val input_jsont : input Jsont.t 905 288 906 289 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. *) 290 + module RegisterPush : sig 291 + (** Register to receive push notifications, via a specified service, for the requesting account. Requires auth. *) 909 292 910 293 911 294 type input = { 295 + age_restricted : bool option; (** Set to true when the actor is age restricted *) 912 296 app_id : string; 913 297 platform : string; 914 298 service_did : string; ··· 919 303 val input_jsont : input Jsont.t 920 304 921 305 end 922 - module PutPreferences : sig 923 - (** Set notification-related preferences for an account. Requires auth. *) 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. *) 924 308 925 309 926 310 type input = { 927 - priority : bool; 311 + app_id : string; 312 + platform : string; 313 + service_did : string; 314 + token : string; 928 315 } 929 316 930 317 (** Jsont codec for {!type:input}. *) ··· 1004 391 1005 392 (** Jsont codec for {!type:preferences}. *) 1006 393 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 394 1019 395 end 1020 396 module ListActivitySubscriptions : sig ··· 1112 488 1113 489 end 1114 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 1115 581 module Actor : sig 1116 582 module Status : sig 1117 583 (** Advertises an account as currently offering live content. *) ··· 1126 592 duration_minutes : int option; (** The duration of the status in minutes. Applications can choose to impose minimum and maximum limits. *) 1127 593 embed : Jsont.json option; (** An optional embed associated with the status. *) 1128 594 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 595 } 1150 596 1151 597 (** Jsont codec for {!type:main}. *) ··· 1515 961 val known_followers_jsont : known_followers Jsont.t 1516 962 1517 963 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. *) 964 + module Profile : sig 965 + (** A declaration of a Bluesky account profile. *) 1520 966 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; 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; 1530 978 } 1531 979 1532 - (** Jsont codec for {!type:output}. *) 1533 - val output_jsont : output Jsont.t 980 + (** Jsont codec for {!type:main}. *) 981 + val main_jsont : main Jsont.t 1534 982 1535 983 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. *) 984 + module GetProfiles : sig 985 + (** Get detailed profile views of multiple actors. *) 1538 986 1539 987 (** Query/procedure parameters. *) 1540 988 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. *) 989 + actors : string list; 1544 990 } 1545 991 1546 992 (** Jsont codec for {!type:params}. *) ··· 1548 994 1549 995 1550 996 type output = { 1551 - actors : Jsont.json list; 997 + profiles : Jsont.json list; 1552 998 } 1553 999 1554 1000 (** Jsont codec for {!type:output}. *) 1555 1001 val output_jsont : output Jsont.t 1556 1002 1557 1003 end 1558 - module GetProfile : sig 1559 - (** Get detailed profile view of an actor. Does not require auth, but contains relevant metadata with auth. *) 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. *) 1560 1006 1561 1007 (** Query/procedure parameters. *) 1562 - type params = { 1563 - actor : string; (** Handle or DID of account to fetch profile of. *) 1564 - } 1008 + type params = unit 1565 1009 1566 1010 (** Jsont codec for {!type:params}. *) 1567 1011 val params_jsont : params Jsont.t 1568 1012 1569 1013 1570 - type output = Jsont.json 1014 + type output = { 1015 + preferences : Jsont.json; 1016 + } 1571 1017 1572 1018 (** Jsont codec for {!type:output}. *) 1573 1019 val output_jsont : output Jsont.t 1574 1020 1575 1021 end 1576 - module SearchActors : sig 1577 - (** Find actors (profiles) matching search criteria. Does not require auth. *) 1022 + module GetSuggestions : sig 1023 + (** Get a list of suggested actors. Expected use is discovery of accounts to follow during new account onboarding. *) 1578 1024 1579 1025 (** Query/procedure parameters. *) 1580 1026 type params = { 1581 1027 cursor : string option; 1582 1028 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 1029 } 1586 1030 1587 1031 (** Jsont codec for {!type:params}. *) ··· 1591 1035 type output = { 1592 1036 actors : Jsont.json list; 1593 1037 cursor : string option; 1038 + rec_id : int option; (** Snowflake for this recommendation, use when submitting recommendation events. *) 1594 1039 } 1595 1040 1596 1041 (** Jsont codec for {!type:output}. *) 1597 1042 val output_jsont : output Jsont.t 1598 1043 1599 1044 end 1600 - module GetSuggestions : sig 1601 - (** Get a list of suggested actors. Expected use is discovery of accounts to follow during new account onboarding. *) 1045 + module GetProfile : sig 1046 + (** Get detailed profile view of an actor. Does not require auth, but contains relevant metadata with auth. *) 1602 1047 1603 1048 (** Query/procedure parameters. *) 1604 1049 type params = { 1605 - cursor : string option; 1606 - limit : int option; 1050 + actor : string; (** Handle or DID of account to fetch profile of. *) 1607 1051 } 1608 1052 1609 1053 (** Jsont codec for {!type:params}. *) 1610 1054 val params_jsont : params Jsont.t 1611 1055 1612 1056 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 - } 1057 + type output = Jsont.json 1618 1058 1619 1059 (** Jsont codec for {!type:output}. *) 1620 1060 val output_jsont : output Jsont.t 1621 1061 1622 1062 end 1623 - module GetProfiles : sig 1624 - (** Get detailed profile views of multiple actors. *) 1063 + module SearchActors : sig 1064 + (** Find actors (profiles) matching search criteria. Does not require auth. *) 1625 1065 1626 1066 (** Query/procedure parameters. *) 1627 1067 type params = { 1628 - actors : string list; 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. *) 1629 1072 } 1630 1073 1631 1074 (** Jsont codec for {!type:params}. *) ··· 1633 1076 1634 1077 1635 1078 type output = { 1636 - profiles : Jsont.json list; 1079 + actors : Jsont.json list; 1080 + cursor : string option; 1637 1081 } 1638 1082 1639 1083 (** Jsont codec for {!type:output}. *) ··· 1652 1096 val input_jsont : input Jsont.t 1653 1097 1654 1098 end 1655 - end 1656 - module Contact : sig 1657 - module Defs : sig 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. *) 1658 1101 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. *) 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. *) 1662 1107 } 1663 1108 1664 - (** Jsont codec for {!type:sync_status}. *) 1665 - val sync_status_jsont : sync_status Jsont.t 1109 + (** Jsont codec for {!type:params}. *) 1110 + val params_jsont : params Jsont.t 1666 1111 1667 - (** A stash object to be sent via bsync representing a notification to be created. *) 1668 1112 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. *) 1113 + type output = { 1114 + actors : Jsont.json list; 1682 1115 } 1683 1116 1684 - (** Jsont codec for {!type:match_and_contact_index}. *) 1685 - val match_and_contact_index_jsont : match_and_contact_index Jsont.t 1117 + (** Jsont codec for {!type:output}. *) 1118 + val output_jsont : output Jsont.t 1686 1119 1687 1120 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 1121 + end 1122 + module Video : sig 1123 + module GetUploadLimits : sig 1124 + (** Get video upload limits for the authenticated user. *) 1696 1125 1697 1126 1698 - type output = unit 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 + } 1699 1134 1700 1135 (** Jsont codec for {!type:output}. *) 1701 1136 val output_jsont : output Jsont.t 1702 1137 1703 1138 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 - 1139 + module Defs : sig 1707 1140 1708 - type input = { 1709 - subject : string; (** The subject's DID to dismiss the match with. *) 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. *) 1710 1149 } 1711 1150 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 1151 + (** Jsont codec for {!type:job_status}. *) 1152 + val job_status_jsont : job_status Jsont.t 1720 1153 1721 1154 end 1722 - module GetMatches : sig 1723 - (** Returns the matched contacts (contacts that were mutually imported). Excludes dismissed matches. Requires authentication. *) 1155 + module GetJobStatus : sig 1156 + (** Get status details for a video processing job. *) 1724 1157 1725 1158 (** Query/procedure parameters. *) 1726 1159 type params = { 1727 - cursor : string option; 1728 - limit : int option; 1160 + job_id : string; 1729 1161 } 1730 1162 1731 1163 (** Jsont codec for {!type:params}. *) ··· 1733 1165 1734 1166 1735 1167 type output = { 1736 - cursor : string option; 1737 - matches : Jsont.json list; 1168 + job_status : Defs.job_status; 1738 1169 } 1739 1170 1740 1171 (** Jsont codec for {!type:output}. *) 1741 1172 val output_jsont : output Jsont.t 1742 1173 1743 1174 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. *) 1175 + module UploadVideo : sig 1176 + (** Upload a video to be processed then stored on the PDS. *) 1746 1177 1747 1178 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}. *) 1179 + type input = unit 1754 1180 val input_jsont : input Jsont.t 1755 1181 1756 1182 1757 1183 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. *) 1184 + job_status : Defs.job_status; 1759 1185 } 1760 1186 1761 1187 (** Jsont codec for {!type:output}. *) 1762 1188 val output_jsont : output Jsont.t 1763 1189 1764 1190 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. *) 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'). *) 1767 1195 1196 + type tag = { 1197 + tag : string; 1198 + } 1768 1199 1769 - type input = { 1770 - phone : string; (** The phone number to receive the code via SMS. *) 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; 1771 1207 } 1772 1208 1773 - (** Jsont codec for {!type:input}. *) 1774 - val input_jsont : input Jsont.t 1209 + (** Jsont codec for {!type:mention}. *) 1210 + val mention_jsont : mention Jsont.t 1775 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. *) 1776 1213 1777 - type output = unit 1214 + type link = { 1215 + uri : string; 1216 + } 1778 1217 1779 - (** Jsont codec for {!type:output}. *) 1780 - val output_jsont : output Jsont.t 1218 + (** Jsont codec for {!type:link}. *) 1219 + val link_jsont : link Jsont.t 1781 1220 1782 - end 1783 - module SendNotification : sig 1784 - (** System endpoint to send notifications related to contact imports. Requires role authentication. *) 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. *) 1785 1222 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. *) 1223 + type byte_slice = { 1224 + byte_end : int; 1225 + byte_start : int; 1790 1226 } 1791 1227 1792 - (** Jsont codec for {!type:input}. *) 1793 - val input_jsont : input Jsont.t 1228 + (** Jsont codec for {!type:byte_slice}. *) 1229 + val byte_slice_jsont : byte_slice Jsont.t 1794 1230 1231 + (** Annotation of a sub-string within rich text. *) 1795 1232 1796 - type output = unit 1233 + type main = { 1234 + features : Jsont.json list; 1235 + index : byte_slice; 1236 + } 1797 1237 1798 - (** Jsont codec for {!type:output}. *) 1799 - val output_jsont : output Jsont.t 1238 + (** Jsont codec for {!type:main}. *) 1239 + val main_jsont : main Jsont.t 1800 1240 1801 1241 end 1802 - module GetSyncStatus : sig 1803 - (** Gets the user's current contact import status. Requires authentication. *) 1242 + end 1243 + module AuthCreatePosts : sig 1804 1244 1805 - (** Query/procedure parameters. *) 1806 - type params = unit 1245 + type main = unit 1246 + val main_jsont : main Jsont.t 1807 1247 1808 - (** Jsont codec for {!type:params}. *) 1809 - val params_jsont : params Jsont.t 1248 + end 1249 + module Ageassurance : sig 1250 + module Defs : sig 1251 + (** The status of the Age Assurance process. *) 1810 1252 1253 + type status = string 1254 + val status_jsont : status Jsont.t 1811 1255 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. *) 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. *) 1814 1260 } 1815 1261 1816 - (** Jsont codec for {!type:output}. *) 1817 - val output_jsont : output Jsont.t 1262 + (** Jsont codec for {!type:state_metadata}. *) 1263 + val state_metadata_jsont : state_metadata Jsont.t 1818 1264 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. *) 1265 + (** Object used to store Age Assurance data in stash. *) 1822 1266 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`. *) 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. *) 1827 1279 } 1828 1280 1829 - (** Jsont codec for {!type:input}. *) 1830 - val input_jsont : input Jsont.t 1281 + (** Jsont codec for {!type:event}. *) 1282 + val event_jsont : event Jsont.t 1831 1283 1284 + (** The Age Assurance configuration for a specific region. *) 1832 1285 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. *) 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. *) 1835 1291 } 1836 1292 1837 - (** Jsont codec for {!type:output}. *) 1838 - val output_jsont : output Jsont.t 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. *) 1839 1297 1840 - end 1841 - end 1842 - module Graph : sig 1843 - module Starterpack : sig 1298 + type access = string 1299 + val access_jsont : access Jsont.t 1300 + 1301 + (** The user's computed Age Assurance state. *) 1844 1302 1845 - type feed_item = { 1846 - uri : string; 1303 + type state = { 1304 + access : access; 1305 + last_initiated_at : string option; (** The timestamp when this state was last updated. *) 1306 + status : status; 1847 1307 } 1848 1308 1849 - (** Jsont codec for {!type:feed_item}. *) 1850 - val feed_item_jsont : feed_item Jsont.t 1309 + (** Jsont codec for {!type:state}. *) 1310 + val state_jsont : state Jsont.t 1851 1311 1852 - (** Record defining a starter pack of actors and feeds for new users. *) 1312 + (** Age Assurance rule that applies if the user has declared themselves under a certain age. *) 1853 1313 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. *) 1314 + type config_region_rule_if_declared_under_age = { 1315 + access : access; 1316 + age : int; (** The age threshold as a whole integer. *) 1861 1317 } 1862 1318 1863 - (** Jsont codec for {!type:main}. *) 1864 - val main_jsont : main Jsont.t 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 1865 1321 1866 - end 1867 - module GetFollows : sig 1868 - (** Enumerates accounts which a specified account (actor) follows. *) 1322 + (** Age Assurance rule that applies if the user has declared themselves equal-to or over a certain age. *) 1869 1323 1870 - (** Query/procedure parameters. *) 1871 - type params = { 1872 - actor : string; 1873 - cursor : string option; 1874 - limit : int option; 1324 + type config_region_rule_if_declared_over_age = { 1325 + access : access; 1326 + age : int; (** The age threshold as a whole integer. *) 1875 1327 } 1876 1328 1877 - (** Jsont codec for {!type:params}. *) 1878 - val params_jsont : params Jsont.t 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 1879 1331 1332 + (** Age Assurance rule that applies if the user has been assured to be under a certain age. *) 1880 1333 1881 - type output = { 1882 - cursor : string option; 1883 - follows : Jsont.json list; 1884 - subject : Jsont.json; 1334 + type config_region_rule_if_assured_under_age = { 1335 + access : access; 1336 + age : int; (** The age threshold as a whole integer. *) 1885 1337 } 1886 1338 1887 - (** Jsont codec for {!type:output}. *) 1888 - val output_jsont : output Jsont.t 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 1889 1341 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. *) 1342 + (** Age Assurance rule that applies if the user has been assured to be equal-to or over a certain age. *) 1893 1343 1894 - (** Query/procedure parameters. *) 1895 - type params = { 1896 - actor : string; 1344 + type config_region_rule_if_assured_over_age = { 1345 + access : access; 1346 + age : int; (** The age threshold as a whole integer. *) 1897 1347 } 1898 1348 1899 - (** Jsont codec for {!type:params}. *) 1900 - val params_jsont : params Jsont.t 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 1901 1351 1352 + (** Age Assurance rule that applies if the account is older than a certain date. *) 1902 1353 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; 1354 + type config_region_rule_if_account_older_than = { 1355 + access : access; 1356 + date : string; (** The date threshold as a datetime string. *) 1907 1357 } 1908 1358 1909 - (** Jsont codec for {!type:output}. *) 1910 - val output_jsont : output Jsont.t 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 1911 1361 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. *) 1362 + (** Age Assurance rule that applies if the account is equal-to or newer than a certain date. *) 1915 1363 1916 - type main = { 1917 - created_at : string; 1918 - subject : string; (** DID of the account to be blocked. *) 1364 + type config_region_rule_if_account_newer_than = { 1365 + access : access; 1366 + date : string; (** The date threshold as a datetime string. *) 1919 1367 } 1920 1368 1921 - (** Jsont codec for {!type:main}. *) 1922 - val main_jsont : main Jsont.t 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 1923 1371 1924 - end 1925 - module Listblock : sig 1926 - (** Record representing a block relationship against an entire an entire list of accounts (actors). *) 1372 + (** Age Assurance rule that applies by default. *) 1927 1373 1928 - type main = { 1929 - created_at : string; 1930 - subject : string; (** Reference (AT-URI) to the mod list record. *) 1374 + type config_region_rule_default = { 1375 + access : access; 1931 1376 } 1932 1377 1933 - (** Jsont codec for {!type:main}. *) 1934 - val main_jsont : main Jsont.t 1378 + (** Jsont codec for {!type:config_region_rule_default}. *) 1379 + val config_region_rule_default_jsont : config_region_rule_default Jsont.t 1935 1380 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 1381 1940 - 1941 - type input = { 1942 - root : string; 1382 + type config = { 1383 + regions : config_region list; (** The per-region Age Assurance configuration. *) 1943 1384 } 1944 1385 1945 - (** Jsont codec for {!type:input}. *) 1946 - val input_jsont : input Jsont.t 1386 + (** Jsont codec for {!type:config}. *) 1387 + val config_jsont : config Jsont.t 1947 1388 1948 1389 end 1949 - module GetFollowers : sig 1950 - (** Enumerates accounts which follow a specified account (actor). *) 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. *) 1951 1392 1952 1393 (** Query/procedure parameters. *) 1953 1394 type params = { 1954 - actor : string; 1955 - cursor : string option; 1956 - limit : int option; 1395 + country_code : string; 1396 + region_code : string option; 1957 1397 } 1958 1398 1959 1399 (** Jsont codec for {!type:params}. *) ··· 1961 1401 1962 1402 1963 1403 type output = { 1964 - cursor : string option; 1965 - followers : Jsont.json list; 1966 - subject : Jsont.json; 1404 + metadata : Defs.state_metadata; 1405 + state : Defs.state; 1967 1406 } 1968 1407 1969 1408 (** Jsont codec for {!type:output}. *) 1970 1409 val output_jsont : output Jsont.t 1971 1410 1972 1411 end 1973 - module UnmuteThread : sig 1974 - (** Unmutes the specified thread. Requires auth. *) 1412 + module Begin : sig 1413 + (** Initiate Age Assurance for an account. *) 1975 1414 1976 1415 1977 1416 type input = { 1978 - root : string; 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. *) 1979 1421 } 1980 1422 1981 1423 (** Jsont codec for {!type:input}. *) 1982 1424 val input_jsont : input Jsont.t 1983 1425 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 1426 1988 - type main = { 1989 - created_at : string; 1990 - subject : string; 1991 - via : Com.Atproto.Repo.StrongRef.main option; 1992 - } 1427 + type output = Defs.state 1993 1428 1994 - (** Jsont codec for {!type:main}. *) 1995 - val main_jsont : main Jsont.t 1429 + (** Jsont codec for {!type:output}. *) 1430 + val output_jsont : output Jsont.t 1996 1431 1997 1432 end 1998 - module UnmuteActor : sig 1999 - (** Unmutes the specified account. Requires auth. *) 1433 + module GetConfig : sig 1434 + (** Returns Age Assurance configuration for use on the client. *) 2000 1435 2001 1436 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 - } 1437 + type output = Defs.config 2017 1438 2018 - (** Jsont codec for {!type:input}. *) 2019 - val input_jsont : input Jsont.t 1439 + (** Jsont codec for {!type:output}. *) 1440 + val output_jsont : output Jsont.t 2020 1441 2021 1442 end 2022 - module UnmuteActorList : sig 2023 - (** Unmutes the specified list of accounts. Requires auth. *) 2024 - 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. *) 2025 1447 2026 - type input = { 2027 - list_ : string; 1448 + type aspect_ratio = { 1449 + height : int; 1450 + width : int; 2028 1451 } 2029 1452 2030 - (** Jsont codec for {!type:input}. *) 2031 - val input_jsont : input Jsont.t 1453 + (** Jsont codec for {!type:aspect_ratio}. *) 1454 + val aspect_ratio_jsont : aspect_ratio Jsont.t 2032 1455 2033 1456 end 2034 - module GetKnownFollowers : sig 2035 - (** Enumerates accounts which follow a specified account (actor) and are followed by the viewer. *) 1457 + module External : sig 2036 1458 2037 - (** Query/procedure parameters. *) 2038 - type params = { 2039 - actor : string; 2040 - cursor : string option; 2041 - limit : int option; 1459 + type view_external = { 1460 + description : string; 1461 + thumb : string option; 1462 + title : string; 1463 + uri : string; 2042 1464 } 2043 1465 2044 - (** Jsont codec for {!type:params}. *) 2045 - val params_jsont : params Jsont.t 1466 + (** Jsont codec for {!type:view_external}. *) 1467 + val view_external_jsont : view_external Jsont.t 2046 1468 2047 1469 2048 - type output = { 2049 - cursor : string option; 2050 - followers : Jsont.json list; 2051 - subject : Jsont.json; 1470 + type external_ = { 1471 + description : string; 1472 + thumb : Atp.Blob_ref.t option; 1473 + title : string; 1474 + uri : string; 2052 1475 } 2053 1476 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. *) 1477 + (** Jsont codec for {!type:external_}. *) 1478 + val external__jsont : external_ Jsont.t 2060 1479 2061 1480 2062 - type input = { 2063 - actor : string; 1481 + type view = { 1482 + external_ : Jsont.json; 2064 1483 } 2065 1484 2066 - (** Jsont codec for {!type:input}. *) 2067 - val input_jsont : input Jsont.t 1485 + (** Jsont codec for {!type:view}. *) 1486 + val view_jsont : view Jsont.t 2068 1487 2069 - end 2070 - module Listitem : sig 2071 - (** Record representing an account's inclusion on a specific list. The AppView will ignore duplicate listitem records. *) 1488 + (** A representation of some externally linked content (eg, a URL and 'card'), embedded in a Bluesky record (eg, a post). *) 2072 1489 2073 1490 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. *) 1491 + external_ : Jsont.json; 2077 1492 } 2078 1493 2079 1494 (** Jsont codec for {!type:main}. *) 2080 1495 val main_jsont : main Jsont.t 2081 1496 2082 1497 end 2083 - module Defs : sig 1498 + module Images : sig 2084 1499 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; 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. *) 2095 1505 } 2096 1506 2097 - (** Jsont codec for {!type:starter_pack_view_basic}. *) 2098 - val starter_pack_view_basic_jsont : starter_pack_view_basic Jsont.t 1507 + (** Jsont codec for {!type:view_image}. *) 1508 + val view_image_jsont : view_image Jsont.t 2099 1509 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 1510 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 *) 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; 2110 1515 } 2111 1516 2112 - (** Jsont codec for {!type:relationship}. *) 2113 - val relationship_jsont : relationship Jsont.t 1517 + (** Jsont codec for {!type:image}. *) 1518 + val image_jsont : image Jsont.t 2114 1519 2115 - (** A list of actors used for only for reference purposes such as within a starter pack. *) 2116 1520 2117 - type referencelist = string 2118 - val referencelist_jsont : referencelist Jsont.t 1521 + type view = { 1522 + images : Jsont.json list; 1523 + } 2119 1524 2120 - (** indicates that a handle or DID could not be resolved *) 1525 + (** Jsont codec for {!type:view}. *) 1526 + val view_jsont : view Jsont.t 2121 1527 2122 - type not_found_actor = { 2123 - actor : string; 2124 - not_found : bool; 1528 + 1529 + type main = { 1530 + images : Jsont.json list; 2125 1531 } 2126 1532 2127 - (** Jsont codec for {!type:not_found_actor}. *) 2128 - val not_found_actor_jsont : not_found_actor Jsont.t 1533 + (** Jsont codec for {!type:main}. *) 1534 + val main_jsont : main Jsont.t 1535 + 1536 + end 1537 + module Video : sig 2129 1538 2130 - (** A list of actors to apply an aggregate moderation action (mute/block) on. *) 1539 + type view = { 1540 + alt : string option; 1541 + aspect_ratio : Jsont.json option; 1542 + cid : string; 1543 + playlist : string; 1544 + thumbnail : string option; 1545 + } 2131 1546 2132 - type modlist = string 2133 - val modlist_jsont : modlist Jsont.t 1547 + (** Jsont codec for {!type:view}. *) 1548 + val view_jsont : view Jsont.t 2134 1549 2135 1550 2136 - type list_viewer_state = { 2137 - blocked : string option; 2138 - muted : bool option; 1551 + type caption = { 1552 + file : Atp.Blob_ref.t; 1553 + lang : string; 2139 1554 } 2140 1555 2141 - (** Jsont codec for {!type:list_viewer_state}. *) 2142 - val list_viewer_state_jsont : list_viewer_state Jsont.t 1556 + (** Jsont codec for {!type:caption}. *) 1557 + val caption_jsont : caption Jsont.t 2143 1558 2144 1559 2145 - type list_purpose = string 2146 - val list_purpose_jsont : list_purpose Jsont.t 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 + } 2147 1566 1567 + (** Jsont codec for {!type:main}. *) 1568 + val main_jsont : main Jsont.t 2148 1569 2149 - type list_item_view = { 2150 - subject : Jsont.json; 2151 - uri : string; 1570 + end 1571 + module RecordWithMedia : sig 1572 + 1573 + type view = { 1574 + media : Jsont.json; 1575 + record : Jsont.json; 2152 1576 } 2153 1577 2154 - (** Jsont codec for {!type:list_item_view}. *) 2155 - val list_item_view_jsont : list_item_view Jsont.t 1578 + (** Jsont codec for {!type:view}. *) 1579 + val view_jsont : view Jsont.t 1580 + 2156 1581 2157 - (** A list of actors used for curation purposes such as list feeds or interaction gating. *) 1582 + type main = { 1583 + media : Jsont.json; 1584 + record : Jsont.json; 1585 + } 2158 1586 2159 - type curatelist = string 2160 - val curatelist_jsont : curatelist Jsont.t 1587 + (** Jsont codec for {!type:main}. *) 1588 + val main_jsont : main Jsont.t 2161 1589 1590 + end 1591 + module Record : sig 2162 1592 2163 - type list_view_basic = { 2164 - avatar : string option; 1593 + type view_record = { 1594 + author : Jsont.json; 2165 1595 cid : string; 2166 - indexed_at : string option; 1596 + embeds : Jsont.json list option; 1597 + indexed_at : string; 2167 1598 labels : Com.Atproto.Label.Defs.label list option; 2168 - list_item_count : int option; 2169 - name : string; 2170 - purpose : Jsont.json; 1599 + like_count : int option; 1600 + quote_count : int option; 1601 + reply_count : int option; 1602 + repost_count : int option; 2171 1603 uri : string; 2172 - viewer : Jsont.json option; 1604 + value : Jsont.json; (** The record data itself. *) 2173 1605 } 2174 1606 2175 - (** Jsont codec for {!type:list_view_basic}. *) 2176 - val list_view_basic_jsont : list_view_basic Jsont.t 1607 + (** Jsont codec for {!type:view_record}. *) 1608 + val view_record_jsont : view_record Jsont.t 2177 1609 2178 1610 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; 1611 + type view_not_found = { 1612 + not_found : bool; 2190 1613 uri : string; 2191 - viewer : Jsont.json option; 2192 1614 } 2193 1615 2194 - (** Jsont codec for {!type:list_view}. *) 2195 - val list_view_jsont : list_view Jsont.t 1616 + (** Jsont codec for {!type:view_not_found}. *) 1617 + val view_not_found_jsont : view_not_found Jsont.t 2196 1618 2197 1619 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; 1620 + type view_detached = { 1621 + detached : bool; 2209 1622 uri : string; 2210 1623 } 2211 1624 2212 - (** Jsont codec for {!type:starter_pack_view}. *) 2213 - val starter_pack_view_jsont : starter_pack_view Jsont.t 1625 + (** Jsont codec for {!type:view_detached}. *) 1626 + val view_detached_jsont : view_detached Jsont.t 2214 1627 2215 - end 2216 - module GetBlocks : sig 2217 - (** Enumerates which accounts the requesting account is currently blocking. Requires auth. *) 2218 1628 2219 - (** Query/procedure parameters. *) 2220 - type params = { 2221 - cursor : string option; 2222 - limit : int option; 1629 + type view_blocked = { 1630 + author : Jsont.json; 1631 + blocked : bool; 1632 + uri : string; 2223 1633 } 2224 1634 2225 - (** Jsont codec for {!type:params}. *) 2226 - val params_jsont : params Jsont.t 1635 + (** Jsont codec for {!type:view_blocked}. *) 1636 + val view_blocked_jsont : view_blocked Jsont.t 2227 1637 2228 1638 2229 - type output = { 2230 - blocks : Jsont.json list; 2231 - cursor : string option; 1639 + type view = { 1640 + record : Jsont.json; 2232 1641 } 2233 1642 2234 - (** Jsont codec for {!type:output}. *) 2235 - val output_jsont : output Jsont.t 1643 + (** Jsont codec for {!type:view}. *) 1644 + val view_jsont : view Jsont.t 2236 1645 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 1646 2241 1647 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. *) 1648 + record : Com.Atproto.Repo.StrongRef.main; 2246 1649 } 2247 1650 2248 1651 (** Jsont codec for {!type:main}. *) 2249 1652 val main_jsont : main Jsont.t 2250 1653 2251 1654 end 2252 - module GetMutes : sig 2253 - (** Enumerates accounts that the requesting account (actor) currently has muted. Requires auth. *) 1655 + end 1656 + module Contact : sig 1657 + module SendNotification : sig 1658 + (** System endpoint to send notifications related to contact imports. Requires role authentication. *) 2254 1659 2255 - (** Query/procedure parameters. *) 2256 - type params = { 2257 - cursor : string option; 2258 - limit : int option; 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. *) 2259 1664 } 2260 1665 2261 - (** Jsont codec for {!type:params}. *) 2262 - val params_jsont : params Jsont.t 1666 + (** Jsont codec for {!type:input}. *) 1667 + val input_jsont : input Jsont.t 2263 1668 2264 1669 2265 - type output = { 2266 - cursor : string option; 2267 - mutes : Jsont.json list; 2268 - } 1670 + type output = unit 2269 1671 2270 1672 (** Jsont codec for {!type:output}. *) 2271 1673 val output_jsont : output Jsont.t 2272 1674 2273 1675 end 2274 - module GetRelationships : sig 2275 - (** Enumerates public relationships between one account, and a list of other accounts. Does not require auth. *) 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 + 2276 1679 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. *) 1680 + type input = { 1681 + phone : string; (** The phone number to receive the code via SMS. *) 2281 1682 } 2282 1683 2283 - (** Jsont codec for {!type:params}. *) 2284 - val params_jsont : params Jsont.t 1684 + (** Jsont codec for {!type:input}. *) 1685 + val input_jsont : input Jsont.t 2285 1686 2286 1687 2287 - type output = { 2288 - actor : string option; 2289 - relationships : Jsont.json list; 2290 - } 1688 + type output = unit 2291 1689 2292 1690 (** Jsont codec for {!type:output}. *) 2293 1691 val output_jsont : output Jsont.t 2294 1692 2295 1693 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. *) 1694 + module GetMatches : sig 1695 + (** Returns the matched contacts (contacts that were mutually imported). Excludes dismissed matches. Requires authentication. *) 2308 1696 2309 1697 (** Query/procedure parameters. *) 2310 1698 type params = { 2311 - actor : string; (** The account (actor) to check for membership. *) 2312 1699 cursor : string option; 2313 1700 limit : int option; 2314 1701 } ··· 2319 1706 2320 1707 type output = { 2321 1708 cursor : string option; 2322 - starter_packs_with_membership : Jsont.json list; 1709 + matches : Jsont.json list; 2323 1710 } 2324 1711 2325 1712 (** Jsont codec for {!type:output}. *) 2326 1713 val output_jsont : output Jsont.t 2327 1714 2328 1715 end 2329 - module GetActorStarterPacks : sig 2330 - (** Get a list of starter packs created by the actor. *) 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 + 2331 1719 2332 - (** Query/procedure parameters. *) 2333 - type params = { 2334 - actor : string; 2335 - cursor : string option; 2336 - limit : int option; 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`. *) 2337 1723 } 2338 1724 2339 - (** Jsont codec for {!type:params}. *) 2340 - val params_jsont : params Jsont.t 1725 + (** Jsont codec for {!type:input}. *) 1726 + val input_jsont : input Jsont.t 2341 1727 2342 1728 2343 1729 type output = { 2344 - cursor : string option; 2345 - starter_packs : Jsont.json list; 1730 + token : string; (** JWT to be used in a call to `app.bsky.contact.importContacts`. It is only valid for a single call. *) 2346 1731 } 2347 1732 2348 1733 (** Jsont codec for {!type:output}. *) 2349 1734 val output_jsont : output Jsont.t 2350 1735 2351 1736 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 - } 1737 + module RemoveData : sig 1738 + (** Removes all stored hashes used for contact matching, existing matches, and sync status. Requires authentication. *) 2364 1739 2365 - (** Jsont codec for {!type:main}. *) 2366 - val main_jsont : main Jsont.t 2367 1740 2368 - end 2369 - module SearchStarterPacks : sig 2370 - (** Find starter packs matching search criteria. Does not require auth. *) 1741 + type input = unit 2371 1742 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 1743 + (** Jsont codec for {!type:input}. *) 1744 + val input_jsont : input Jsont.t 2381 1745 2382 1746 2383 - type output = { 2384 - cursor : string option; 2385 - starter_packs : Jsont.json list; 2386 - } 1747 + type output = unit 2387 1748 2388 1749 (** Jsont codec for {!type:output}. *) 2389 1750 val output_jsont : output Jsont.t 2390 1751 2391 1752 end 2392 - module GetList : sig 2393 - (** Gets a 'view' (with additional context) of a specified list. *) 1753 + module Defs : sig 2394 1754 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. *) 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. *) 2400 1768 } 2401 1769 2402 - (** Jsont codec for {!type:params}. *) 2403 - val params_jsont : params Jsont.t 1770 + (** Jsont codec for {!type:notification}. *) 1771 + val notification_jsont : notification Jsont.t 2404 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. *) 2405 1774 2406 - type output = { 2407 - cursor : string option; 2408 - items : Jsont.json list; 2409 - list_ : Jsont.json; 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. *) 2410 1778 } 2411 1779 2412 - (** Jsont codec for {!type:output}. *) 2413 - val output_jsont : output Jsont.t 1780 + (** Jsont codec for {!type:match_and_contact_index}. *) 1781 + val match_and_contact_index_jsont : match_and_contact_index Jsont.t 2414 1782 2415 1783 end 2416 - module GetListBlocks : sig 2417 - (** Get mod lists that the requesting account (actor) is blocking. Requires auth. *) 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 + 2418 1787 2419 - (** Query/procedure parameters. *) 2420 - type params = { 2421 - cursor : string option; 2422 - limit : int option; 1788 + type input = { 1789 + subject : string; (** The subject's DID to dismiss the match with. *) 2423 1790 } 2424 1791 2425 - (** Jsont codec for {!type:params}. *) 2426 - val params_jsont : params Jsont.t 1792 + (** Jsont codec for {!type:input}. *) 1793 + val input_jsont : input Jsont.t 2427 1794 2428 1795 2429 - type output = { 2430 - cursor : string option; 2431 - lists : Jsont.json list; 2432 - } 1796 + type output = unit 2433 1797 2434 1798 (** Jsont codec for {!type:output}. *) 2435 1799 val output_jsont : output Jsont.t 2436 1800 2437 1801 end 2438 - module GetStarterPack : sig 2439 - (** Gets a view of a starter pack. *) 1802 + module GetSyncStatus : sig 1803 + (** Gets the user's current contact import status. Requires authentication. *) 2440 1804 2441 1805 (** Query/procedure parameters. *) 2442 - type params = { 2443 - starter_pack : string; (** Reference (AT-URI) of the starter pack record. *) 2444 - } 1806 + type params = unit 2445 1807 2446 1808 (** Jsont codec for {!type:params}. *) 2447 1809 val params_jsont : params Jsont.t 2448 1810 2449 1811 2450 1812 type output = { 2451 - starter_pack : Jsont.json; 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. *) 2452 1814 } 2453 1815 2454 1816 (** Jsont codec for {!type:output}. *) 2455 1817 val output_jsont : output Jsont.t 2456 1818 2457 1819 end 2458 - module GetListsWithMembership : sig 2459 - (** A list and an optional list item indicating membership of a target user to that list. *) 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. *) 2460 1822 2461 - type list_with_membership = { 2462 - list_ : Jsont.json; 2463 - list_item : Jsont.json option; 2464 - } 2465 1823 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. *) 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`. *) 2477 1827 } 2478 1828 2479 - (** Jsont codec for {!type:params}. *) 2480 - val params_jsont : params Jsont.t 1829 + (** Jsont codec for {!type:input}. *) 1830 + val input_jsont : input Jsont.t 2481 1831 2482 1832 2483 1833 type output = { 2484 - cursor : string option; 2485 - lists_with_membership : Jsont.json list; 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. *) 2486 1835 } 2487 1836 2488 1837 (** Jsont codec for {!type:output}. *) 2489 1838 val output_jsont : output Jsont.t 2490 1839 2491 1840 end 2492 - module GetListMutes : sig 2493 - (** Enumerates mod lists that the requesting account (actor) currently has muted. Requires auth. *) 1841 + end 1842 + module Feed : sig 1843 + module Repost : sig 1844 + (** Record representing a 'repost' of an existing Bluesky post. *) 2494 1845 2495 - (** Query/procedure parameters. *) 2496 - type params = { 2497 - cursor : string option; 2498 - limit : int option; 1846 + type main = { 1847 + created_at : string; 1848 + subject : Com.Atproto.Repo.StrongRef.main; 1849 + via : Com.Atproto.Repo.StrongRef.main option; 2499 1850 } 2500 1851 2501 - (** Jsont codec for {!type:params}. *) 2502 - val params_jsont : params Jsont.t 1852 + (** Jsont codec for {!type:main}. *) 1853 + val main_jsont : main Jsont.t 2503 1854 1855 + end 1856 + module DescribeFeedGenerator : sig 2504 1857 2505 - type output = { 2506 - cursor : string option; 2507 - lists : Jsont.json list; 1858 + type links = { 1859 + privacy_policy : string option; 1860 + terms_of_service : string option; 2508 1861 } 2509 1862 2510 - (** Jsont codec for {!type:output}. *) 2511 - val output_jsont : output Jsont.t 1863 + (** Jsont codec for {!type:links}. *) 1864 + val links_jsont : links Jsont.t 2512 1865 2513 - end 2514 - module GetStarterPacks : sig 2515 - (** Get views for a list of starter packs. *) 2516 1866 2517 - (** Query/procedure parameters. *) 2518 - type params = { 2519 - uris : string list; 1867 + type feed = { 1868 + uri : string; 2520 1869 } 2521 1870 2522 - (** Jsont codec for {!type:params}. *) 2523 - val params_jsont : params Jsont.t 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). *) 2524 1875 2525 1876 2526 1877 type output = { 2527 - starter_packs : Jsont.json list; 1878 + did : string; 1879 + feeds : Jsont.json list; 1880 + links : Jsont.json option; 2528 1881 } 2529 1882 2530 1883 (** Jsont codec for {!type:output}. *) 2531 1884 val output_jsont : output Jsont.t 2532 1885 2533 1886 end 2534 - module GetLists : sig 2535 - (** Enumerates the lists created by a specified account (actor). *) 1887 + module Threadgate : sig 1888 + (** Allow replies from actors mentioned in your post. *) 2536 1889 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 - } 1890 + type mention_rule = unit 2544 1891 2545 - (** Jsont codec for {!type:params}. *) 2546 - val params_jsont : params Jsont.t 1892 + (** Jsont codec for {!type:mention_rule}. *) 1893 + val mention_rule_jsont : mention_rule Jsont.t 2547 1894 1895 + (** Allow replies from actors on a list. *) 2548 1896 2549 - type output = { 2550 - cursor : string option; 2551 - lists : Jsont.json list; 1897 + type list_rule = { 1898 + list_ : string; 2552 1899 } 2553 1900 2554 - (** Jsont codec for {!type:output}. *) 2555 - val output_jsont : output Jsont.t 1901 + (** Jsont codec for {!type:list_rule}. *) 1902 + val list_rule_jsont : list_rule Jsont.t 2556 1903 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. *) 1904 + (** Allow replies from actors you follow. *) 2562 1905 2563 - type text_slice = { 2564 - end_ : int; 2565 - start : int; 2566 - } 1906 + type following_rule = unit 2567 1907 2568 - (** Jsont codec for {!type:text_slice}. *) 2569 - val text_slice_jsont : text_slice Jsont.t 1908 + (** Jsont codec for {!type:following_rule}. *) 1909 + val following_rule_jsont : following_rule Jsont.t 2570 1910 1911 + (** Allow replies from actors who follow you. *) 2571 1912 2572 - type reply_ref = { 2573 - parent : Com.Atproto.Repo.StrongRef.main; 2574 - root : Com.Atproto.Repo.StrongRef.main; 2575 - } 1913 + type follower_rule = unit 2576 1914 2577 - (** Jsont codec for {!type:reply_ref}. *) 2578 - val reply_ref_jsont : reply_ref Jsont.t 1915 + (** Jsont codec for {!type:follower_rule}. *) 1916 + val follower_rule_jsont : follower_rule Jsont.t 2579 1917 2580 - (** Deprecated: use facets instead. *) 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. *) 2581 1919 2582 - type entity = { 2583 - index : Jsont.json; 2584 - type_ : string; (** Expected values are 'mention' and 'link'. *) 2585 - value : string; 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. *) 2586 1925 } 2587 1926 2588 - (** Jsont codec for {!type:entity}. *) 2589 - val entity_jsont : entity Jsont.t 1927 + (** Jsont codec for {!type:main}. *) 1928 + val main_jsont : main Jsont.t 2590 1929 2591 - (** Record containing a Bluesky post. *) 1930 + end 1931 + module Like : sig 1932 + (** Record declaring a 'like' of a piece of subject content. *) 2592 1933 2593 1934 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. *) 1935 + created_at : string; 1936 + subject : Com.Atproto.Repo.StrongRef.main; 1937 + via : Com.Atproto.Repo.StrongRef.main option; 2603 1938 } 2604 1939 2605 1940 (** Jsont codec for {!type:main}. *) ··· 2642 1977 val output_jsont : output Jsont.t 2643 1978 2644 1979 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 1980 module GetRepostedBy : sig 2667 1981 (** Get a list of reposts for a given post. *) 2668 1982 ··· 2689 2003 val output_jsont : output Jsont.t 2690 2004 2691 2005 end 2692 - module DescribeFeedGenerator : sig 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. *) 2693 2008 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 = { 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; 2714 2016 did : string; 2715 - feeds : Jsont.json list; 2716 - links : Jsont.json option; 2017 + display_name : string; 2018 + labels : Com.Atproto.Label.Defs.self_labels option; (** Self-label values *) 2717 2019 } 2718 2020 2719 - (** Jsont codec for {!type:output}. *) 2720 - val output_jsont : output Jsont.t 2021 + (** Jsont codec for {!type:main}. *) 2022 + val main_jsont : main Jsont.t 2721 2023 2722 2024 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 2025 + module Postgate : sig 2026 + (** Disables embedding of this post. *) 2746 2027 2747 - (** Allow replies from actors who follow you. *) 2028 + type disable_rule = unit 2748 2029 2749 - type follower_rule = unit 2030 + (** Jsont codec for {!type:disable_rule}. *) 2031 + val disable_rule_jsont : disable_rule Jsont.t 2750 2032 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. *) 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. *) 2755 2034 2756 2035 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 2036 created_at : string; 2759 - hidden_replies : string list option; (** List of hidden reply URIs. *) 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. *) 2760 2039 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 2040 } 2775 2041 2776 2042 (** Jsont codec for {!type:main}. *) ··· 3048 2314 val feed_view_post_jsont : feed_view_post Jsont.t 3049 2315 3050 2316 end 3051 - module Repost : sig 3052 - (** Record representing a 'repost' of an existing Bluesky post. *) 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. *) 3053 2349 3054 2350 type main = { 3055 - created_at : string; 3056 - subject : Com.Atproto.Repo.StrongRef.main; 3057 - via : Com.Atproto.Repo.StrongRef.main option; 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. *) 3058 2360 } 3059 2361 3060 2362 (** Jsont codec for {!type:main}. *) 3061 2363 val main_jsont : main Jsont.t 3062 2364 3063 2365 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. *) 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'. *) 3066 2368 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 *) 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; 3077 2380 } 3078 2381 3079 - (** Jsont codec for {!type:main}. *) 3080 - val main_jsont : main Jsont.t 2382 + (** Jsont codec for {!type:output}. *) 2383 + val output_jsont : output Jsont.t 3081 2384 3082 2385 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. *) 2386 + module GetQuotes : sig 2387 + (** Get a list of quotes for a given post. *) 3085 2388 3086 2389 (** Query/procedure parameters. *) 3087 2390 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. *) 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 *) 3091 2395 } 3092 2396 3093 2397 (** Jsont codec for {!type:params}. *) ··· 3095 2399 3096 2400 3097 2401 type output = { 3098 - thread : Jsont.json; 3099 - threadgate : Jsont.json option; 2402 + cid : string option; 2403 + cursor : string option; 2404 + posts : Jsont.json list; 2405 + uri : string; 3100 2406 } 3101 2407 3102 2408 (** Jsont codec for {!type:output}. *) 3103 2409 val output_jsont : output Jsont.t 3104 2410 3105 2411 end 3106 - module GetFeed : sig 3107 - (** Get a hydrated feed from an actor's selected feed generator. Implemented by App View. *) 2412 + module GetAuthorFeed : sig 2413 + (** Get a view of an actor's 'author feed' (post and reposts by the author). Does not require auth. *) 3108 2414 3109 2415 (** Query/procedure parameters. *) 3110 2416 type params = { 2417 + actor : string; 3111 2418 cursor : string option; 3112 - feed : string; 2419 + filter : string option; (** Combinations of post/repost types to include in response. *) 2420 + include_pins : bool option; 3113 2421 limit : int option; 3114 2422 } 3115 2423 ··· 3126 2434 val output_jsont : output Jsont.t 3127 2435 3128 2436 end 3129 - module GetQuotes : sig 3130 - (** Get a list of quotes for a given post. *) 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. *) 3131 2439 3132 2440 (** Query/procedure parameters. *) 3133 2441 type params = { 3134 - cid : string option; (** If supplied, filters to quotes of specific version (by CID) of the post record. *) 2442 + algorithm : string option; (** Variant 'algorithm' for timeline. Implementation-specific. NOTE: most feed flexibility has been moved to feed generator mechanism. *) 3135 2443 cursor : string option; 3136 2444 limit : int option; 3137 - uri : string; (** Reference (AT-URI) of post record *) 3138 2445 } 3139 2446 3140 2447 (** Jsont codec for {!type:params}. *) ··· 3142 2449 3143 2450 3144 2451 type output = { 3145 - cid : string option; 3146 2452 cursor : string option; 3147 - posts : Jsont.json list; 3148 - uri : string; 2453 + feed : Jsont.json list; 3149 2454 } 3150 2455 3151 2456 (** Jsont codec for {!type:output}. *) ··· 3175 2480 val output_jsont : output Jsont.t 3176 2481 3177 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 3178 2505 module GetActorLikes : sig 3179 2506 (** Get a list of posts liked by an actor. Requires auth, actor must be the requesting account. *) 3180 2507 ··· 3198 2525 val output_jsont : output Jsont.t 3199 2526 3200 2527 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. *) 2528 + module GetActorFeeds : sig 2529 + (** Get a list of feeds (feed generator records) created by the actor (in the actor's repo). *) 3203 2530 3204 2531 (** Query/procedure parameters. *) 3205 2532 type params = { 2533 + actor : string; 3206 2534 cursor : string option; 3207 - feed : string; (** Reference to feed generator record describing the specific feed being requested. *) 3208 2535 limit : int option; 3209 2536 } 3210 2537 ··· 3214 2541 3215 2542 type output = { 3216 2543 cursor : string option; 3217 - feed : Jsont.json list; 3218 - req_id : string option; (** Unique identifier per request that may be passed back alongside interactions. *) 2544 + feeds : Jsont.json list; 3219 2545 } 3220 2546 3221 2547 (** Jsont codec for {!type:output}. *) ··· 3255 2581 val output_jsont : output Jsont.t 3256 2582 3257 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 3258 2654 module GetFeedGenerators : sig 3259 2655 (** Get information about a list of feed generators. *) 3260 2656 ··· 3293 2689 val output_jsont : output Jsont.t 3294 2690 3295 2691 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. *) 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). *) 3298 2910 3299 2911 (** Query/procedure parameters. *) 3300 2912 type params = { 3301 2913 actor : string; 3302 2914 cursor : string option; 3303 - filter : string option; (** Combinations of post/repost types to include in response. *) 3304 - include_pins : bool option; 3305 2915 limit : int option; 3306 2916 } 3307 2917 ··· 3311 2921 3312 2922 type output = { 3313 2923 cursor : string option; 3314 - feed : Jsont.json list; 2924 + followers : Jsont.json list; 2925 + subject : Jsont.json; 3315 2926 } 3316 2927 3317 2928 (** Jsont codec for {!type:output}. *) 3318 2929 val output_jsont : output Jsont.t 3319 2930 3320 2931 end 3321 - module GetFeedGenerator : sig 3322 - (** Get information about a feed generator. Implemented by AppView. *) 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. *) 3323 2958 3324 2959 (** Query/procedure parameters. *) 3325 2960 type params = { 3326 - feed : string; (** AT-URI of the feed generator record. *) 2961 + cursor : string option; 2962 + limit : int option; 3327 2963 } 3328 2964 3329 2965 (** Jsont codec for {!type:params}. *) ··· 3331 2967 3332 2968 3333 2969 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; 2970 + blocks : Jsont.json list; 2971 + cursor : string option; 3337 2972 } 3338 2973 3339 2974 (** Jsont codec for {!type:output}. *) 3340 2975 val output_jsont : output Jsont.t 3341 2976 3342 2977 end 3343 - module GetSuggestedFeeds : sig 3344 - (** Get a list of suggested feeds (feed generators) for the requesting account. *) 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. *) 3345 3041 3346 3042 (** Query/procedure parameters. *) 3347 3043 type params = { 3044 + actor : string; 3348 3045 cursor : string option; 3349 3046 limit : int option; 3350 3047 } ··· 3355 3052 3356 3053 type output = { 3357 3054 cursor : string option; 3358 - feeds : Jsont.json list; 3055 + follows : Jsont.json list; 3056 + subject : Jsont.json; 3359 3057 } 3360 3058 3361 3059 (** Jsont codec for {!type:output}. *) 3362 3060 val output_jsont : output Jsont.t 3363 3061 3364 3062 end 3365 - module GetActorFeeds : sig 3366 - (** Get a list of feeds (feed generator records) created by the actor (in the actor's repo). *) 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. *) 3367 3113 3368 3114 (** Query/procedure parameters. *) 3369 3115 type params = { ··· 3378 3124 3379 3125 type output = { 3380 3126 cursor : string option; 3381 - feeds : Jsont.json list; 3127 + followers : Jsont.json list; 3128 + subject : Jsont.json; 3382 3129 } 3383 3130 3384 3131 (** Jsont codec for {!type:output}. *) 3385 3132 val output_jsont : output Jsont.t 3386 3133 3387 3134 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'. *) 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. *) 3390 3149 3391 3150 (** Query/procedure parameters. *) 3392 3151 type params = { 3393 - uris : string list; (** List of post AT-URIs to return hydrated views for. *) 3152 + actor : string; (** Primary account requesting relationships for. *) 3153 + others : string list option; (** List of 'other' accounts to be related back to the primary. *) 3394 3154 } 3395 3155 3396 3156 (** Jsont codec for {!type:params}. *) ··· 3398 3158 3399 3159 3400 3160 type output = { 3401 - posts : Jsont.json list; 3161 + actor : string option; 3162 + relationships : Jsont.json list; 3402 3163 } 3403 3164 3404 3165 (** Jsont codec for {!type:output}. *) 3405 3166 val output_jsont : output Jsont.t 3406 3167 3407 3168 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. *) 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. *) 3410 3181 3411 3182 (** Query/procedure parameters. *) 3412 3183 type params = { 3413 - algorithm : string option; (** Variant 'algorithm' for timeline. Implementation-specific. NOTE: most feed flexibility has been moved to feed generator mechanism. *) 3184 + actor : string; (** The account (actor) to check for membership. *) 3414 3185 cursor : string option; 3415 3186 limit : int option; 3187 + purposes : string list option; (** Optional filter by list purpose. If not specified, all supported types are returned. *) 3416 3188 } 3417 3189 3418 3190 (** Jsont codec for {!type:params}. *) ··· 3421 3193 3422 3194 type output = { 3423 3195 cursor : string option; 3424 - feed : Jsont.json list; 3196 + lists_with_membership : Jsont.json list; 3425 3197 } 3426 3198 3427 3199 (** Jsont codec for {!type:output}. *) 3428 3200 val output_jsont : output Jsont.t 3429 3201 3430 3202 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. *) 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 + } 3435 3211 3212 + (** Jsont codec for {!type:params}. *) 3213 + val params_jsont : params Jsont.t 3436 3214 3437 - type input = { 3438 - uri : string; 3215 + 3216 + type output = { 3217 + cursor : string option; 3218 + lists : Jsont.json list; 3439 3219 } 3440 3220 3441 - (** Jsont codec for {!type:input}. *) 3442 - val input_jsont : input Jsont.t 3221 + (** Jsont codec for {!type:output}. *) 3222 + val output_jsont : output Jsont.t 3443 3223 3444 3224 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. *) 3225 + module GetActorStarterPacks : sig 3226 + (** Get a list of starter packs created by the actor. *) 3447 3227 3228 + (** Query/procedure parameters. *) 3229 + type params = { 3230 + actor : string; 3231 + cursor : string option; 3232 + limit : int option; 3233 + } 3448 3234 3449 - type input = { 3450 - cid : string; 3451 - uri : string; 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; 3452 3242 } 3453 3243 3454 - (** Jsont codec for {!type:input}. *) 3455 - val input_jsont : input Jsont.t 3244 + (** Jsont codec for {!type:output}. *) 3245 + val output_jsont : output Jsont.t 3456 3246 3457 3247 end 3458 - module Defs : sig 3248 + module SearchStarterPacks : sig 3249 + (** Find starter packs matching search criteria. Does not require auth. *) 3459 3250 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. *) 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. *) 3464 3256 } 3465 3257 3466 - (** Jsont codec for {!type:bookmark_view}. *) 3467 - val bookmark_view_jsont : bookmark_view Jsont.t 3258 + (** Jsont codec for {!type:params}. *) 3259 + val params_jsont : params Jsont.t 3468 3260 3469 - (** Object used to store bookmark data in stash. *) 3470 3261 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. *) 3262 + type output = { 3263 + cursor : string option; 3264 + starter_packs : Jsont.json list; 3473 3265 } 3474 3266 3475 - (** Jsont codec for {!type:bookmark}. *) 3476 - val bookmark_jsont : bookmark Jsont.t 3267 + (** Jsont codec for {!type:output}. *) 3268 + val output_jsont : output Jsont.t 3477 3269 3478 3270 end 3479 - module GetBookmarks : sig 3480 - (** Gets views of records bookmarked by the authenticated user. Requires authentication. *) 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. *) 3481 3283 3482 3284 (** Query/procedure parameters. *) 3483 3285 type params = { 3286 + actor : string; (** The account (actor) to check for membership. *) 3484 3287 cursor : string option; 3485 3288 limit : int option; 3486 3289 } ··· 3490 3293 3491 3294 3492 3295 type output = { 3493 - bookmarks : Defs.bookmark_view list; 3494 3296 cursor : string option; 3297 + starter_packs_with_membership : Jsont.json list; 3495 3298 } 3496 3299 3497 3300 (** Jsont codec for {!type:output}. *) 3498 3301 val output_jsont : output Jsont.t 3499 3302 3500 3303 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 *) 3304 + module GetLists : sig 3305 + (** Enumerates the lists created by a specified account (actor). *) 3505 3306 3506 3307 (** Query/procedure parameters. *) 3507 3308 type params = { 3508 - category : string option; (** Category of users to get suggestions for. *) 3309 + actor : string; (** The account (actor) to enumerate lists from. *) 3310 + cursor : string option; 3509 3311 limit : int option; 3510 - viewer : string option; (** DID of the account making the request (not included for public/unauthenticated queries). *) 3312 + purposes : string list option; (** Optional filter by list purpose. If not specified, all supported types are returned. *) 3511 3313 } 3512 3314 3513 3315 (** Jsont codec for {!type:params}. *) ··· 3515 3317 3516 3318 3517 3319 type output = { 3518 - dids : string list; 3519 - rec_id : int option; (** Snowflake for this recommendation, use when submitting recommendation events. *) 3320 + cursor : string option; 3321 + lists : Jsont.json list; 3520 3322 } 3521 3323 3522 3324 (** Jsont codec for {!type:output}. *) 3523 3325 val output_jsont : output Jsont.t 3524 3326 3525 3327 end 3526 - module GetOnboardingSuggestedStarterPacks : sig 3527 - (** Get a list of suggested starterpacks for onboarding *) 3328 + module GetStarterPack : sig 3329 + (** Gets a view of a starter pack. *) 3528 3330 3529 3331 (** Query/procedure parameters. *) 3530 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; 3531 3354 limit : int option; 3532 3355 } 3533 3356 ··· 3536 3359 3537 3360 3538 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 = { 3539 3383 starter_packs : Jsont.json list; 3540 3384 } 3541 3385 ··· 3543 3387 val output_jsont : output Jsont.t 3544 3388 3545 3389 end 3546 - module GetPopularFeedGenerators : sig 3547 - (** An unspecced view of globally popular feed generators. *) 3390 + module GetList : sig 3391 + (** Gets a 'view' (with additional context) of a specified list. *) 3548 3392 3549 3393 (** Query/procedure parameters. *) 3550 3394 type params = { 3551 3395 cursor : string option; 3552 3396 limit : int option; 3553 - query : string option; 3397 + list_ : string; (** Reference (AT-URI) of the list record to hydrate. *) 3554 3398 } 3555 3399 3556 3400 (** Jsont codec for {!type:params}. *) ··· 3559 3403 3560 3404 type output = { 3561 3405 cursor : string option; 3562 - feeds : Jsont.json list; 3406 + items : Jsont.json list; 3407 + list_ : Jsont.json; 3563 3408 } 3564 3409 3565 3410 (** Jsont codec for {!type:output}. *) 3566 3411 val output_jsont : output Jsont.t 3567 3412 3568 3413 end 3569 - module GetSuggestedStarterPacksSkeleton : sig 3570 - (** Get a skeleton of suggested starterpacks. Intended to be called and hydrated by app.bsky.unspecced.getSuggestedStarterpacks *) 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. *) 3571 3481 3572 3482 (** Query/procedure parameters. *) 3573 3483 type params = { 3484 + cursor : string option; 3574 3485 limit : int option; 3575 - viewer : string option; (** DID of the account making the request (not included for public/unauthenticated queries). *) 3576 3486 } 3577 3487 3578 3488 (** Jsont codec for {!type:params}. *) ··· 3580 3490 3581 3491 3582 3492 type output = { 3583 - starter_packs : string list; 3493 + bookmarks : Defs.bookmark_view list; 3494 + cursor : string option; 3584 3495 } 3585 3496 3586 3497 (** Jsont codec for {!type:output}. *) 3587 3498 val output_jsont : output Jsont.t 3588 3499 3589 3500 end 3501 + end 3502 + module Unspecced : sig 3590 3503 module GetSuggestedFeeds : sig 3591 3504 (** Get a list of suggested feeds *) 3592 3505 ··· 3607 3520 val output_jsont : output Jsont.t 3608 3521 3609 3522 end 3610 - module GetSuggestedFeedsSkeleton : sig 3611 - (** Get a skeleton of suggested feeds. Intended to be called and hydrated by app.bsky.unspecced.getSuggestedFeeds *) 3523 + module GetSuggestedUsers : sig 3524 + (** Get a list of suggested users *) 3612 3525 3613 3526 (** Query/procedure parameters. *) 3614 3527 type params = { 3528 + category : string option; (** Category of users to get suggestions for. *) 3615 3529 limit : int option; 3616 - viewer : string option; (** DID of the account making the request (not included for public/unauthenticated queries). *) 3617 3530 } 3618 3531 3619 3532 (** Jsont codec for {!type:params}. *) ··· 3621 3534 3622 3535 3623 3536 type output = { 3624 - feeds : string list; 3537 + actors : Jsont.json list; 3538 + rec_id : int option; (** Snowflake for this recommendation, use when submitting recommendation events. *) 3625 3539 } 3626 3540 3627 3541 (** Jsont codec for {!type:output}. *) 3628 3542 val output_jsont : output Jsont.t 3629 3543 3630 3544 end 3631 - module GetConfig : sig 3545 + module GetSuggestedUsersSkeleton : sig 3546 + (** Get a skeleton of suggested users. Intended to be called and hydrated by app.bsky.unspecced.getSuggestedUsers *) 3632 3547 3633 - type live_now_config = { 3634 - did : string; 3635 - domains : string list; 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). *) 3636 3553 } 3637 3554 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. *) 3555 + (** Jsont codec for {!type:params}. *) 3556 + val params_jsont : params Jsont.t 3642 3557 3643 3558 3644 3559 type output = { 3645 - check_email_confirmed : bool option; 3646 - live_now : live_now_config list option; 3560 + dids : string list; 3561 + rec_id : int option; (** Snowflake for this recommendation, use when submitting recommendation events. *) 3647 3562 } 3648 3563 3649 3564 (** Jsont codec for {!type:output}. *) ··· 3670 3585 val output_jsont : output Jsont.t 3671 3586 3672 3587 end 3673 - module GetSuggestedUsers : sig 3674 - (** Get a list of suggested users *) 3588 + module GetOnboardingSuggestedStarterPacksSkeleton : sig 3589 + (** Get a skeleton of suggested starterpacks for onboarding. Intended to be called and hydrated by app.bsky.unspecced.getOnboardingSuggestedStarterPacks *) 3675 3590 3676 3591 (** Query/procedure parameters. *) 3677 3592 type params = { 3678 - category : string option; (** Category of users to get suggestions for. *) 3679 3593 limit : int option; 3594 + viewer : string option; (** DID of the account making the request (not included for public/unauthenticated queries). *) 3680 3595 } 3681 3596 3682 3597 (** Jsont codec for {!type:params}. *) ··· 3684 3599 3685 3600 3686 3601 type output = { 3687 - actors : Jsont.json list; 3688 - rec_id : int option; (** Snowflake for this recommendation, use when submitting recommendation events. *) 3602 + starter_packs : string list; 3689 3603 } 3690 3604 3691 3605 (** Jsont codec for {!type:output}. *) 3692 3606 val output_jsont : output Jsont.t 3693 3607 3694 3608 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 *) 3609 + module GetSuggestedFeedsSkeleton : sig 3610 + (** Get a skeleton of suggested feeds. Intended to be called and hydrated by app.bsky.unspecced.getSuggestedFeeds *) 3697 3611 3698 3612 (** Query/procedure parameters. *) 3699 3613 type params = { ··· 3706 3620 3707 3621 3708 3622 type output = { 3709 - starter_packs : string list; 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; 3710 3644 } 3711 3645 3712 3646 (** Jsont codec for {!type:output}. *) ··· 3839 3773 val age_assurance_event_jsont : age_assurance_event Jsont.t 3840 3774 3841 3775 end 3842 - module GetTaggedSuggestions : sig 3776 + module GetConfig : sig 3843 3777 3844 - type suggestion = { 3845 - subject : string; 3846 - subject_type : string; 3847 - tag : string; 3778 + type live_now_config = { 3779 + did : string; 3780 + domains : string list; 3848 3781 } 3849 3782 3850 - (** Jsont codec for {!type:suggestion}. *) 3851 - val suggestion_jsont : suggestion Jsont.t 3783 + (** Jsont codec for {!type:live_now_config}. *) 3784 + val live_now_config_jsont : live_now_config Jsont.t 3852 3785 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 3786 + (** Get miscellaneous runtime configuration. *) 3860 3787 3861 3788 3862 3789 type output = { 3863 - suggestions : suggestion list; 3790 + check_email_confirmed : bool option; 3791 + live_now : live_now_config list option; 3864 3792 } 3865 3793 3866 3794 (** Jsont codec for {!type:output}. *) 3867 3795 val output_jsont : output Jsont.t 3868 3796 3869 3797 end 3870 - module SearchPostsSkeleton : sig 3871 - (** Backend Posts search, returns only skeleton *) 3798 + module GetPopularFeedGenerators : sig 3799 + (** An unspecced view of globally popular feed generators. *) 3872 3800 3873 3801 (** Query/procedure parameters. *) 3874 3802 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. *) 3803 + cursor : string option; 3879 3804 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. *) 3805 + query : string option; 3888 3806 } 3889 3807 3890 3808 (** Jsont codec for {!type:params}. *) ··· 3893 3811 3894 3812 type output = { 3895 3813 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; 3814 + feeds : Jsont.json list; 3898 3815 } 3899 3816 3900 3817 (** Jsont codec for {!type:output}. *) 3901 3818 val output_jsont : output Jsont.t 3902 3819 3903 3820 end 3904 - module GetPostThreadV2 : sig 3821 + module GetTaggedSuggestions : sig 3905 3822 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; 3823 + type suggestion = { 3824 + subject : string; 3825 + subject_type : string; 3826 + tag : string; 3910 3827 } 3911 3828 3912 - (** Jsont codec for {!type:thread_item}. *) 3913 - val thread_item_jsont : thread_item Jsont.t 3829 + (** Jsont codec for {!type:suggestion}. *) 3830 + val suggestion_jsont : suggestion Jsont.t 3914 3831 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. *) 3832 + (** Get a list of suggestions (feeds and users) tagged with categories *) 3916 3833 3917 3834 (** 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 - } 3835 + type params = unit 3925 3836 3926 3837 (** Jsont codec for {!type:params}. *) 3927 3838 val params_jsont : params Jsont.t 3928 3839 3929 3840 3930 3841 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; 3842 + suggestions : suggestion list; 3934 3843 } 3935 3844 3936 3845 (** Jsont codec for {!type:output}. *) 3937 3846 val output_jsont : output Jsont.t 3938 3847 3939 3848 end 3940 - module GetTrendingTopics : sig 3941 - (** Get a list of trending topics *) 3849 + module GetSuggestedStarterPacksSkeleton : sig 3850 + (** Get a skeleton of suggested starterpacks. Intended to be called and hydrated by app.bsky.unspecced.getSuggestedStarterpacks *) 3942 3851 3943 3852 (** Query/procedure parameters. *) 3944 3853 type params = { 3945 3854 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. *) 3855 + viewer : string option; (** DID of the account making the request (not included for public/unauthenticated queries). *) 3947 3856 } 3948 3857 3949 3858 (** Jsont codec for {!type:params}. *) ··· 3951 3860 3952 3861 3953 3862 type output = { 3954 - suggested : Defs.trending_topic list; 3955 - topics : Defs.trending_topic list; 3863 + starter_packs : string list; 3956 3864 } 3957 3865 3958 3866 (** Jsont codec for {!type:output}. *) 3959 3867 val output_jsont : output Jsont.t 3960 3868 3961 3869 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 *) 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 *) 3964 3892 3965 3893 (** Query/procedure parameters. *) 3966 3894 type params = { 3967 3895 limit : int option; 3968 - viewer : string option; (** DID of the account making the request (not included for public/unauthenticated queries). *) 3896 + viewer : string option; (** DID of the account making the request (not included for public/unauthenticated queries). Used to boost followed accounts in ranking. *) 3969 3897 } 3970 3898 3971 3899 (** Jsont codec for {!type:params}. *) ··· 3973 3901 3974 3902 3975 3903 type output = { 3976 - trends : Defs.skeleton_trend list; 3904 + suggested : Defs.trending_topic list; 3905 + topics : Defs.trending_topic list; 3977 3906 } 3978 3907 3979 3908 (** Jsont codec for {!type:output}. *) ··· 4010 3939 val output_jsont : output Jsont.t 4011 3940 4012 3941 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. *) 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 + } 4015 3952 3953 + (** Jsont codec for {!type:params}. *) 3954 + val params_jsont : params Jsont.t 4016 3955 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. *) 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. *) 4021 3962 } 4022 3963 4023 - (** Jsont codec for {!type:input}. *) 4024 - val input_jsont : input Jsont.t 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. *) 4025 3970 4026 3971 4027 3972 type output = Defs.age_assurance_state ··· 4055 4000 val output_jsont : output Jsont.t 4056 4001 4057 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 4058 4037 module SearchActorsSkeleton : sig 4059 4038 (** Backend Actors (profile) search, returns only skeleton. *) 4060 4039 ··· 4081 4060 val output_jsont : output Jsont.t 4082 4061 4083 4062 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. *) 4063 + module GetTrends : sig 4064 + (** Get the current trends on the network *) 4086 4065 4066 + (** Query/procedure parameters. *) 4067 + type params = { 4068 + limit : int option; 4069 + } 4087 4070 4088 - type output = Defs.age_assurance_state 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 + } 4089 4078 4090 4079 (** Jsont codec for {!type:output}. *) 4091 4080 val output_jsont : output Jsont.t 4092 4081 4093 4082 end 4094 - module GetSuggestionsSkeleton : sig 4095 - (** Get a skeleton of suggested actors. Intended to be called and then hydrated through app.bsky.actor.getSuggestions *) 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. *) 4096 4095 4097 4096 (** Query/procedure parameters. *) 4098 4097 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. *) 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 4103 } 4104 4104 4105 4105 (** Jsont codec for {!type:params}. *) ··· 4107 4107 4108 4108 4109 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. *) 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; 4114 4113 } 4115 4114 4116 4115 (** Jsont codec for {!type:output}. *) 4117 4116 val output_jsont : output Jsont.t 4118 4117 4119 4118 end 4120 - module GetTrends : sig 4121 - (** Get the current trends on the network *) 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 *) 4122 4121 4123 4122 (** Query/procedure parameters. *) 4124 4123 type params = { 4125 4124 limit : int option; 4125 + viewer : string option; (** DID of the account making the request (not included for public/unauthenticated queries). *) 4126 4126 } 4127 4127 4128 4128 (** Jsont codec for {!type:params}. *) ··· 4130 4130 4131 4131 4132 4132 type output = { 4133 - trends : Defs.trend_view list; 4133 + trends : Defs.skeleton_trend list; 4134 4134 } 4135 4135 4136 4136 (** Jsont codec for {!type:output}. *)
+15 -15
ocaml-atp/lexicons/standard-site/atp_lexicon_standard_site.ml
··· 36 36 end 37 37 module Site = struct 38 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 39 module Document = struct 55 40 type main = { 56 41 bsky_post_ref : Com.Atproto.Repo.StrongRef.main option; ··· 135 120 |> Jsont.Object.mem "accentForeground" Color.rgb_jsont ~enc:(fun r -> r.accent_foreground) 136 121 |> Jsont.Object.mem "background" Color.rgb_jsont ~enc:(fun r -> r.background) 137 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 138 |> Jsont.Object.finish 139 139 140 140 end
+13 -13
ocaml-atp/lexicons/standard-site/atp_lexicon_standard_site.mli
··· 30 30 end 31 31 module Site : sig 32 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 33 module Document : sig 47 34 (** A document record representing a published article, blog post, or other content. Documents can belong to a publication or exist independently. *) 48 35 ··· 96 83 accent_foreground : Color.rgb; (** Color used for button text. *) 97 84 background : Color.rgb; (** Color used for content background. *) 98 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 99 } 100 100 101 101 (** Jsont codec for {!type:main}. *)
+963 -963
ocaml-atp/lexicons/tangled/atp_lexicon_tangled.ml
··· 15 15 16 16 module Sh = struct 17 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 18 58 module Spindle = struct 19 59 type main = { 20 60 created_at : string; ··· 45 85 46 86 end 47 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 48 480 module Git = struct 49 481 module RefUpdate = struct 50 482 type individual_language_size = { ··· 135 567 136 568 end 137 569 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 570 module String = struct 166 571 type main = { 167 572 contents : string; ··· 181 586 |> Jsont.Object.finish 182 587 183 588 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 589 module Repo = struct 219 590 type main = { 220 591 created_at : string; ··· 243 614 |> Jsont.Object.opt_mem "website" Jsont.string ~enc:(fun r -> r.website) 244 615 |> Jsont.Object.finish 245 616 246 - module Artifact = struct 617 + module Issue = struct 247 618 type main = { 248 - artifact : Atp.Blob_ref.t; 619 + body : string option; 249 620 created_at : string; 250 - name : string; 621 + mentions : string list option; 622 + references : string list option; 251 623 repo : string; 252 - tag : string; 624 + title : string; 253 625 } 254 626 255 627 let main_jsont = 256 628 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) 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) 260 632 |> Jsont.Object.mem "createdAt" Jsont.string ~enc:(fun r -> r.created_at) 261 - |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 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) 262 635 |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 263 - |> Jsont.Object.mem "tag" Jsont.binary_string ~enc:(fun r -> r.tag) 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) 264 674 |> Jsont.Object.finish 265 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 266 687 end 267 - module MergeCheck = struct 268 - type conflict_info = { 269 - filename : string; 270 - reason : string; 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; 271 751 } 272 752 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) 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) 279 762 |> Jsont.Object.finish 280 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 281 797 type input = { 282 - branch : string; 283 - did : string; 284 - name : string; 285 - patch : string; 798 + default_branch : string; 799 + repo : string; 286 800 } 287 801 288 802 let input_jsont = 289 803 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) 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) 294 823 |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 295 - |> Jsont.Object.mem "patch" Jsont.string ~enc:(fun r -> r.patch) 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) 296 838 |> Jsont.Object.finish 297 839 298 840 type output = { 299 - conflicts : conflict_info list option; 300 - error : string option; 301 - is_conflicted : bool; 841 + author : signature option; 842 + hash : string; 302 843 message : string option; 844 + name : string; 845 + short_hash : string option; 846 + when_ : string; 303 847 } 304 848 305 849 let output_jsont = 306 850 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) 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) 312 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) 313 891 |> Jsont.Object.finish 314 892 315 893 end ··· 400 978 |> Jsont.Object.finish 401 979 402 980 end 403 - module SetDefaultBranch = struct 981 + module AddSecret = struct 404 982 type input = { 405 - default_branch : string; 983 + key : string; 406 984 repo : string; 985 + value : string; 407 986 } 408 987 409 988 let input_jsont = 410 989 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) 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) 414 993 |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 994 + |> Jsont.Object.mem "value" Jsont.string ~enc:(fun r -> r.value) 415 995 |> Jsont.Object.finish 416 996 417 997 end 418 - module Compare = struct 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 + 419 1014 type params = { 1015 + name : string; 420 1016 repo : string; 421 - rev1 : string; 422 - rev2 : string; 423 1017 } 424 1018 425 1019 let params_jsont = 426 1020 Jsont.Object.map ~kind:"Params" 427 - (fun repo rev1 rev2 -> { 1021 + (fun name repo -> { 1022 + name; 428 1023 repo; 429 - rev1; 430 - rev2; 431 1024 }) 1025 + |> Jsont.Object.mem "name" Jsont.string 1026 + ~enc:(fun r -> r.name) 432 1027 |> Jsont.Object.mem "repo" Jsont.string 433 1028 ~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 1029 |> Jsont.Object.finish 439 1030 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; 1031 + type output = { 1032 + author : signature option; 1033 + hash : string; 1034 + is_default : bool option; 1035 + message : string option; 452 1036 name : string; 453 - patch : string; 1037 + short_hash : string option; 1038 + when_ : string; 454 1039 } 455 1040 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) 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) 466 1049 |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 467 - |> Jsont.Object.mem "patch" Jsont.string ~enc:(fun r -> r.patch) 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_) 468 1052 |> Jsont.Object.finish 469 1053 470 1054 end 471 - module Tags = struct 1055 + module Log = struct 472 1056 type params = { 473 1057 cursor : string option; 474 1058 limit : int option; 1059 + path : string option; 1060 + ref_ : string; 475 1061 repo : string; 476 1062 } 477 1063 478 1064 let params_jsont = 479 1065 Jsont.Object.map ~kind:"Params" 480 - (fun cursor limit repo -> { 1066 + (fun cursor limit path ref_ repo -> { 481 1067 cursor; 482 1068 limit; 1069 + path; 1070 + ref_; 483 1071 repo; 484 1072 }) 485 1073 |> Jsont.Object.opt_mem "cursor" Jsont.string 486 1074 ~enc:(fun r -> r.cursor) 487 1075 |> Jsont.Object.opt_mem "limit" Jsont.int 488 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_) 489 1081 |> Jsont.Object.mem "repo" Jsont.string 490 1082 ~enc:(fun r -> r.repo) 491 1083 |> Jsont.Object.finish ··· 494 1086 let output_jsont = Jsont.ignore 495 1087 496 1088 end 497 - module Collaborator = struct 498 - type main = { 1089 + module ListSecrets = struct 1090 + type secret = { 499 1091 created_at : string; 1092 + created_by : string; 1093 + key : string; 500 1094 repo : string; 501 - subject : string; 502 1095 } 503 1096 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") 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") 508 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) 509 1104 |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 510 - |> Jsont.Object.mem "subject" Jsont.string ~enc:(fun r -> r.subject) 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) 511 1129 |> Jsont.Object.finish 512 1130 513 1131 end 514 - module Branches = struct 1132 + module Tags = struct 515 1133 type params = { 516 1134 cursor : string option; 517 1135 limit : int option; ··· 537 1155 let output_jsont = Jsont.ignore 538 1156 539 1157 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 - 1158 + module Diff = struct 556 1159 type params = { 1160 + ref_ : string; 557 1161 repo : string; 558 1162 } 559 1163 560 1164 let params_jsont = 561 1165 Jsont.Object.map ~kind:"Params" 562 - (fun repo -> { 1166 + (fun ref_ repo -> { 1167 + ref_; 563 1168 repo; 564 1169 }) 1170 + |> Jsont.Object.mem "ref" Jsont.string 1171 + ~enc:(fun r -> r.ref_) 565 1172 |> Jsont.Object.mem "repo" Jsont.string 566 1173 ~enc:(fun r -> r.repo) 567 1174 |> Jsont.Object.finish 568 1175 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; 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; 576 1185 } 577 1186 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_) 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) 588 1194 |> Jsont.Object.finish 589 1195 590 1196 end ··· 605 1211 |> Jsont.Object.finish 606 1212 607 1213 end 608 - module ForkStatus = struct 609 - type input = { 610 - branch : string; 611 - did : string; 612 - hidden_ref : string; 1214 + module Artifact = struct 1215 + type main = { 1216 + artifact : Atp.Blob_ref.t; 1217 + created_at : string; 613 1218 name : string; 614 - source : string; 1219 + repo : string; 1220 + tag : string; 615 1221 } 616 1222 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) 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) 624 1229 |> 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) 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) 637 1232 |> Jsont.Object.finish 638 1233 639 1234 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 - 1235 + module Archive = struct 656 1236 type params = { 657 - name : string; 1237 + format : string option; 1238 + prefix : string option; 1239 + ref_ : string; 658 1240 repo : string; 659 1241 } 660 1242 661 1243 let params_jsont = 662 1244 Jsont.Object.map ~kind:"Params" 663 - (fun name repo -> { 664 - name; 1245 + (fun format prefix ref_ repo -> { 1246 + format; 1247 + prefix; 1248 + ref_; 665 1249 repo; 666 1250 }) 667 - |> Jsont.Object.mem "name" Jsont.string 668 - ~enc:(fun r -> r.name) 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_) 669 1257 |> Jsont.Object.mem "repo" Jsont.string 670 1258 ~enc:(fun r -> r.repo) 671 1259 |> Jsont.Object.finish 672 1260 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 1261 + type output = unit 1262 + let output_jsont = Jsont.ignore 695 1263 696 1264 end 697 - module DeleteBranch = struct 1265 + module RemoveSecret = struct 698 1266 type input = { 699 - branch : string; 1267 + key : string; 700 1268 repo : string; 701 1269 } 702 1270 703 1271 let input_jsont = 704 1272 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) 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) 708 1276 |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 709 1277 |> Jsont.Object.finish 710 1278 711 1279 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; 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; 719 1290 } 720 1291 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) 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) 740 1304 |> Jsont.Object.finish 741 - 742 - type output = unit 743 - let output_jsont = Jsont.ignore 744 1305 745 1306 end 746 1307 module Blob = struct ··· 846 1407 |> Jsont.Object.finish 847 1408 848 1409 end 849 - module RemoveSecret = struct 1410 + module HiddenRef = struct 850 1411 type input = { 851 - key : string; 1412 + fork_ref : string; 1413 + remote_ref : string; 852 1414 repo : string; 853 1415 } 854 1416 855 1417 let input_jsont = 856 1418 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) 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) 860 1423 |> Jsont.Object.mem "repo" Jsont.string ~enc:(fun r -> r.repo) 861 1424 |> Jsont.Object.finish 862 1425 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 1426 type output = { 904 - languages : language list; 905 - ref_ : string; 906 - total_files : int option; 907 - total_size : int option; 1427 + error : string option; 1428 + ref_ : string option; 1429 + success : bool; 908 1430 } 909 1431 910 1432 let output_jsont = 911 1433 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) 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) 918 1439 |> Jsont.Object.finish 919 1440 920 1441 end 921 - module Diff = struct 1442 + module Compare = struct 922 1443 type params = { 923 - ref_ : string; 924 1444 repo : string; 1445 + rev1 : string; 1446 + rev2 : string; 925 1447 } 926 1448 927 1449 let params_jsont = 928 1450 Jsont.Object.map ~kind:"Params" 929 - (fun ref_ repo -> { 930 - ref_; 1451 + (fun repo rev1 rev2 -> { 931 1452 repo; 1453 + rev1; 1454 + rev2; 932 1455 }) 933 - |> Jsont.Object.mem "ref" Jsont.string 934 - ~enc:(fun r -> r.ref_) 935 1456 |> Jsont.Object.mem "repo" Jsont.string 936 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) 937 1462 |> Jsont.Object.finish 938 1463 939 1464 type output = unit 940 1465 let output_jsont = Jsont.ignore 941 1466 942 1467 end 943 - module ForkSync = struct 1468 + module ForkStatus = struct 944 1469 type input = { 945 1470 branch : string; 946 1471 did : string; 1472 + hidden_ref : string; 947 1473 name : string; 948 1474 source : string; 949 1475 } 950 1476 951 1477 let input_jsont = 952 1478 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") 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") 955 1481 |> Jsont.Object.mem "branch" Jsont.string ~enc:(fun r -> r.branch) 956 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) 957 1484 |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name) 958 1485 |> Jsont.Object.mem "source" Jsont.string ~enc:(fun r -> r.source) 959 1486 |> Jsont.Object.finish 960 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 + 961 1499 end 962 - module AddSecret = struct 963 - type input = { 964 - key : string; 965 - repo : string; 966 - value : string; 1500 + module MergeCheck = struct 1501 + type conflict_info = { 1502 + filename : string; 1503 + reason : string; 967 1504 } 968 1505 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) 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) 976 1512 |> Jsont.Object.finish 977 1513 978 - end 979 - module Delete = struct 980 1514 type input = { 1515 + branch : string; 981 1516 did : string; 982 1517 name : string; 983 - rkey : string; 1518 + patch : string; 984 1519 } 985 1520 986 1521 let input_jsont = 987 1522 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") 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) 990 1526 |> Jsont.Object.mem "did" Jsont.string ~enc:(fun r -> r.did) 991 1527 |> 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) 1528 + |> Jsont.Object.mem "patch" Jsont.string ~enc:(fun r -> r.patch) 1025 1529 |> Jsont.Object.finish 1026 1530 1027 1531 type output = { 1028 - secrets : secret list; 1532 + conflicts : conflict_info list option; 1533 + error : string option; 1534 + is_conflicted : bool; 1535 + message : string option; 1029 1536 } 1030 1537 1031 1538 let output_jsont = 1032 1539 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) 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) 1036 1546 |> Jsont.Object.finish 1037 1547 1038 1548 end 1039 - module Archive = struct 1549 + module Branches = struct 1040 1550 type params = { 1041 - format : string option; 1042 - prefix : string option; 1043 - ref_ : string; 1551 + cursor : string option; 1552 + limit : int option; 1044 1553 repo : string; 1045 1554 } 1046 1555 1047 1556 let params_jsont = 1048 1557 Jsont.Object.map ~kind:"Params" 1049 - (fun format prefix ref_ repo -> { 1050 - format; 1051 - prefix; 1052 - ref_; 1558 + (fun cursor limit repo -> { 1559 + cursor; 1560 + limit; 1053 1561 repo; 1054 1562 }) 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_) 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) 1061 1567 |> Jsont.Object.mem "repo" Jsont.string 1062 1568 ~enc:(fun r -> r.repo) 1063 1569 |> Jsont.Object.finish ··· 1066 1572 let output_jsont = Jsont.ignore 1067 1573 1068 1574 end 1069 - module HiddenRef = struct 1575 + module ForkSync = struct 1070 1576 type input = { 1071 - fork_ref : string; 1072 - remote_ref : string; 1073 - repo : string; 1577 + branch : string; 1578 + did : string; 1579 + name : string; 1580 + source : string; 1074 1581 } 1075 1582 1076 1583 let input_jsont = 1077 1584 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") 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") 1125 1587 |> 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) 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) 1155 1591 |> Jsont.Object.finish 1156 1592 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 1593 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 = { 1594 + module Languages = struct 1595 + type language = { 1299 1596 color : string option; 1300 - created_at : string; 1301 - multiple : bool option; 1597 + extensions : string list option; 1598 + file_count : int option; 1302 1599 name : string; 1303 - scope : string list; 1304 - value_type : value_type; 1600 + percentage : int; 1601 + size : int; 1305 1602 } 1306 1603 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") 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") 1311 1608 |> 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) 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) 1314 1611 |> 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) 1612 + |> Jsont.Object.mem "percentage" Jsont.int ~enc:(fun r -> r.percentage) 1613 + |> Jsont.Object.mem "size" Jsont.int ~enc:(fun r -> r.size) 1413 1614 |> Jsont.Object.finish 1414 1615 1415 1616 type params = { 1416 - cursor : string option; 1417 - limit : int option; 1617 + ref_ : string option; 1618 + repo : string; 1418 1619 } 1419 1620 1420 1621 let params_jsont = 1421 1622 Jsont.Object.map ~kind:"Params" 1422 - (fun cursor limit -> { 1423 - cursor; 1424 - limit; 1623 + (fun ref_ repo -> { 1624 + ref_; 1625 + repo; 1425 1626 }) 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) 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) 1456 1631 |> Jsont.Object.finish 1457 1632 1458 - end 1459 - end 1460 - module Owner = struct 1461 1633 type output = { 1462 - owner : string; 1634 + languages : language list; 1635 + ref_ : string; 1636 + total_files : int option; 1637 + total_size : int option; 1463 1638 } 1464 1639 1465 1640 let output_jsont = 1466 1641 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) 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) 1520 1645 |> 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) 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 1648 |> Jsont.Object.finish 1649 1649 1650 1650 end
+639 -639
ocaml-atp/lexicons/tangled/atp_lexicon_tangled.mli
··· 12 12 13 13 module Sh : sig 14 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 15 46 module Spindle : sig 16 47 17 48 type main = { ··· 34 65 35 66 end 36 67 end 37 - module Git : sig 38 - module RefUpdate : sig 68 + module Pipeline : sig 39 69 40 - type individual_language_size = { 41 - lang : string; 42 - size : int; 70 + type trigger_repo = { 71 + default_branch : string; 72 + did : string; 73 + knot : string; 74 + repo : string; 43 75 } 44 76 45 - (** Jsont codec for {!type:individual_language_size}. *) 46 - val individual_language_size_jsont : individual_language_size Jsont.t 77 + (** Jsont codec for {!type:trigger_repo}. *) 78 + val trigger_repo_jsont : trigger_repo Jsont.t 47 79 48 80 49 - type individual_email_commit_count = { 50 - count : int; 51 - email : string; 81 + type push_trigger_data = { 82 + new_sha : string; 83 + old_sha : string; 84 + ref_ : string; 52 85 } 53 86 54 - (** Jsont codec for {!type:individual_email_commit_count}. *) 55 - val individual_email_commit_count_jsont : individual_email_commit_count Jsont.t 87 + (** Jsont codec for {!type:push_trigger_data}. *) 88 + val push_trigger_data_jsont : push_trigger_data Jsont.t 56 89 57 90 58 - type lang_breakdown = { 59 - inputs : individual_language_size list option; 91 + type pull_request_trigger_data = { 92 + action : string; 93 + source_branch : string; 94 + source_sha : string; 95 + target_branch : string; 60 96 } 61 97 62 - (** Jsont codec for {!type:lang_breakdown}. *) 63 - val lang_breakdown_jsont : lang_breakdown Jsont.t 98 + (** Jsont codec for {!type:pull_request_trigger_data}. *) 99 + val pull_request_trigger_data_jsont : pull_request_trigger_data Jsont.t 64 100 65 101 66 - type commit_count_breakdown = { 67 - by_email : individual_email_commit_count list option; 102 + type pair = { 103 + key : string; 104 + value : string; 68 105 } 69 106 70 - (** Jsont codec for {!type:commit_count_breakdown}. *) 71 - val commit_count_breakdown_jsont : commit_count_breakdown Jsont.t 107 + (** Jsont codec for {!type:pair}. *) 108 + val pair_jsont : pair Jsont.t 72 109 73 110 74 - type meta = { 75 - commit_count : commit_count_breakdown; 76 - is_default_ref : bool; 77 - lang_breakdown : lang_breakdown option; 111 + type clone_opts = { 112 + depth : int; 113 + skip : bool; 114 + submodules : bool; 78 115 } 79 116 80 - (** Jsont codec for {!type:meta}. *) 81 - val meta_jsont : meta Jsont.t 117 + (** Jsont codec for {!type:clone_opts}. *) 118 + val clone_opts_jsont : clone_opts Jsont.t 82 119 83 - (** An update to a git repository, emitted by knots. *) 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 + 84 151 85 152 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 *) 153 + trigger_metadata : trigger_metadata; 154 + workflows : workflow list; 93 155 } 94 156 95 157 (** Jsont codec for {!type:main}. *) 96 158 val main_jsont : main Jsont.t 97 159 98 - end 99 - end 100 - module Actor : sig 101 - module Profile : sig 102 - (** A declaration of a Tangled account profile. *) 160 + module Status : sig 103 161 104 162 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; 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 *) 112 169 } 113 170 114 171 (** Jsont codec for {!type:main}. *) ··· 116 173 117 174 end 118 175 end 119 - module String : sig 176 + module Knot : sig 120 177 121 178 type main = { 122 - contents : string; 123 179 created_at : string; 124 - description : string; 125 - filename : string; 126 180 } 127 181 128 182 (** Jsont codec for {!type:main}. *) 129 183 val main_jsont : main Jsont.t 130 184 131 - end 132 - module Feed : sig 133 - module Star : sig 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 134 230 135 231 type main = { 136 232 created_at : string; 233 + domain : string; (** domain that this member now belongs to *) 137 234 subject : string; 138 235 } 139 236 ··· 141 238 val main_jsont : main Jsont.t 142 239 143 240 end 144 - module Reaction : sig 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 + 145 253 146 254 type main = { 147 - created_at : string; 148 - reaction : string; 149 - subject : string; 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. *) 150 259 } 151 260 152 261 (** Jsont codec for {!type:main}. *) 153 262 val main_jsont : main Jsont.t 154 263 155 264 end 156 - end 157 - module Repo : sig 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 + 158 276 159 277 type main = { 278 + color : string option; (** The hex value for the background color for the label. Appviews may choose to respect this. *) 160 279 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 *) 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. *) 169 284 } 170 285 171 286 (** Jsont codec for {!type:main}. *) 172 287 val main_jsont : main Jsont.t 173 288 174 - module Artifact : sig 289 + end 290 + end 291 + module Feed : sig 292 + module Reaction : sig 175 293 176 294 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) *) 295 + created_at : string; 296 + reaction : string; 297 + subject : string; 182 298 } 183 299 184 300 (** Jsont codec for {!type:main}. *) 185 301 val main_jsont : main Jsont.t 186 302 187 303 end 188 - module MergeCheck : sig 304 + module Star : sig 189 305 190 - type conflict_info = { 191 - filename : string; (** Name of the conflicted file *) 192 - reason : string; (** Reason for the conflict *) 306 + type main = { 307 + created_at : string; 308 + subject : string; 193 309 } 194 310 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 *) 311 + (** Jsont codec for {!type:main}. *) 312 + val main_jsont : main Jsont.t 199 313 314 + end 315 + end 316 + module PublicKey : sig 200 317 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 *) 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 *) 206 322 } 207 323 208 - (** Jsont codec for {!type:input}. *) 209 - val input_jsont : input Jsont.t 324 + (** Jsont codec for {!type:main}. *) 325 + val main_jsont : main Jsont.t 210 326 327 + end 328 + module Graph : sig 329 + module Follow : sig 211 330 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 *) 331 + type main = { 332 + created_at : string; 333 + subject : string; 217 334 } 218 335 219 - (** Jsont codec for {!type:output}. *) 220 - val output_jsont : output Jsont.t 336 + (** Jsont codec for {!type:main}. *) 337 + val main_jsont : main Jsont.t 221 338 222 339 end 223 - module Tree : sig 340 + end 341 + module Git : sig 342 + module RefUpdate : sig 224 343 225 - type readme = { 226 - contents : string; (** Contents of the readme file *) 227 - filename : string; (** Name of the readme file *) 344 + type individual_language_size = { 345 + lang : string; 346 + size : int; 228 347 } 229 348 230 - (** Jsont codec for {!type:readme}. *) 231 - val readme_jsont : readme Jsont.t 349 + (** Jsont codec for {!type:individual_language_size}. *) 350 + val individual_language_size_jsont : individual_language_size Jsont.t 232 351 233 352 234 - type last_commit = { 235 - hash : string; (** Commit hash *) 236 - message : string; (** Commit message *) 237 - when_ : string; (** Commit timestamp *) 353 + type individual_email_commit_count = { 354 + count : int; 355 + email : string; 238 356 } 239 357 240 - (** Jsont codec for {!type:last_commit}. *) 241 - val last_commit_jsont : last_commit Jsont.t 358 + (** Jsont codec for {!type:individual_email_commit_count}. *) 359 + val individual_email_commit_count_jsont : individual_email_commit_count Jsont.t 242 360 243 361 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 *) 362 + type lang_breakdown = { 363 + inputs : individual_language_size list option; 249 364 } 250 365 251 - (** Jsont codec for {!type:tree_entry}. *) 252 - val tree_entry_jsont : tree_entry Jsont.t 366 + (** Jsont codec for {!type:lang_breakdown}. *) 367 + val lang_breakdown_jsont : lang_breakdown Jsont.t 253 368 254 369 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' *) 370 + type commit_count_breakdown = { 371 + by_email : individual_email_commit_count list option; 260 372 } 261 373 262 - (** Jsont codec for {!type:params}. *) 263 - val params_jsont : params Jsont.t 374 + (** Jsont codec for {!type:commit_count_breakdown}. *) 375 + val commit_count_breakdown_jsont : commit_count_breakdown Jsont.t 264 376 265 377 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 *) 378 + type meta = { 379 + commit_count : commit_count_breakdown; 380 + is_default_ref : bool; 381 + lang_breakdown : lang_breakdown option; 272 382 } 273 383 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 *) 384 + (** Jsont codec for {!type:meta}. *) 385 + val meta_jsont : meta Jsont.t 280 386 387 + (** An update to a git repository, emitted by knots. *) 281 388 282 - type input = { 283 - default_branch : string; 284 - repo : string; 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 *) 285 397 } 286 398 287 - (** Jsont codec for {!type:input}. *) 288 - val input_jsont : input Jsont.t 399 + (** Jsont codec for {!type:main}. *) 400 + val main_jsont : main Jsont.t 289 401 290 402 end 291 - module Compare : sig 403 + end 404 + module String : sig 292 405 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) *) 406 + type main = { 407 + contents : string; 408 + created_at : string; 409 + description : string; 410 + filename : string; 298 411 } 299 412 300 - (** Jsont codec for {!type:params}. *) 301 - val params_jsont : params Jsont.t 413 + (** Jsont codec for {!type:main}. *) 414 + val main_jsont : main Jsont.t 302 415 303 - (** Compare output in application/json *) 416 + end 417 + module Repo : sig 304 418 305 - type output = unit 306 - val output_jsont : output Jsont.t 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 + } 307 430 308 - end 309 - module Merge : sig 310 - (** Merge a patch into a repository branch *) 431 + (** Jsont codec for {!type:main}. *) 432 + val main_jsont : main Jsont.t 311 433 434 + module Issue : sig 312 435 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 *) 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; 322 443 } 323 444 324 - (** Jsont codec for {!type:input}. *) 325 - val input_jsont : input Jsont.t 445 + (** Jsont codec for {!type:main}. *) 446 + val main_jsont : main Jsont.t 326 447 327 - end 328 - module Tags : sig 448 + module Comment : sig 329 449 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' *) 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; 335 457 } 336 458 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 459 + (** Jsont codec for {!type:main}. *) 460 + val main_jsont : main Jsont.t 343 461 344 - end 345 - module Collaborator : sig 462 + end 463 + module State : sig 346 464 347 465 type main = { 348 - created_at : string; 349 - repo : string; (** repo to add this user to *) 350 - subject : string; 466 + issue : string; 467 + state : string; (** state of the issue *) 351 468 } 352 469 353 470 (** Jsont codec for {!type:main}. *) 354 471 val main_jsont : main Jsont.t 355 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 356 488 end 357 - module Branches : sig 489 + module Pull : sig 358 490 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' *) 491 + type target = { 492 + branch : string; 493 + repo : string; 364 494 } 365 495 366 - (** Jsont codec for {!type:params}. *) 367 - val params_jsont : params Jsont.t 496 + (** Jsont codec for {!type:target}. *) 497 + val target_jsont : target Jsont.t 368 498 369 499 370 - type output = unit 371 - val output_jsont : output Jsont.t 500 + type source = { 501 + branch : string; 502 + repo : string option; 503 + sha : string; 504 + } 372 505 373 - end 374 - module GetDefaultBranch : sig 506 + (** Jsont codec for {!type:source}. *) 507 + val source_jsont : source Jsont.t 375 508 376 - type signature = { 377 - email : string; (** Author email *) 378 - name : string; (** Author name *) 379 - when_ : string; (** Author timestamp *) 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; 380 520 } 381 521 382 - (** Jsont codec for {!type:signature}. *) 383 - val signature_jsont : signature Jsont.t 522 + (** Jsont codec for {!type:main}. *) 523 + val main_jsont : main Jsont.t 384 524 525 + module Comment : sig 385 526 386 - (** Query/procedure parameters. *) 387 - type params = { 388 - repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 527 + type main = { 528 + body : string; 529 + created_at : string; 530 + mentions : string list option; 531 + pull : string; 532 + references : string list option; 389 533 } 390 534 391 - (** Jsont codec for {!type:params}. *) 392 - val params_jsont : params Jsont.t 535 + (** Jsont codec for {!type:main}. *) 536 + val main_jsont : main Jsont.t 393 537 538 + end 539 + module Status : sig 394 540 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 *) 541 + type main = { 542 + pull : string; 543 + status : string; (** status of the pull request *) 402 544 } 403 545 404 - (** Jsont codec for {!type:output}. *) 405 - val output_jsont : output Jsont.t 546 + (** Jsont codec for {!type:main}. *) 547 + val main_jsont : main Jsont.t 406 548 407 - end 408 - module Create : sig 409 - (** Create a new repository *) 549 + module Merged : sig 550 + (** merged pull request *) 410 551 552 + type main = string 553 + val main_jsont : main Jsont.t 411 554 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 - } 555 + end 556 + module Closed : sig 557 + (** closed pull request *) 417 558 418 - (** Jsont codec for {!type:input}. *) 419 - val input_jsont : input Jsont.t 559 + type main = string 560 + val main_jsont : main Jsont.t 420 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 421 571 end 422 - module ForkStatus : sig 423 - (** Check fork status relative to upstream source *) 572 + module SetDefaultBranch : sig 573 + (** Set the default branch for a repository *) 424 574 425 575 426 576 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 *) 577 + default_branch : string; 578 + repo : string; 432 579 } 433 580 434 581 (** Jsont codec for {!type:input}. *) 435 582 val input_jsont : input Jsont.t 436 583 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 584 end 446 - module Branch : sig 585 + module GetDefaultBranch : sig 447 586 448 587 type signature = { 449 588 email : string; (** Author email *) ··· 457 596 458 597 (** Query/procedure parameters. *) 459 598 type params = { 460 - name : string; (** Branch name to get information for *) 461 599 repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 462 600 } 463 601 ··· 467 605 468 606 type output = { 469 607 author : signature option; 470 - hash : string; (** Latest commit hash on this branch *) 471 - is_default : bool option; (** Whether this is the default branch *) 608 + hash : string; (** Latest commit hash on default branch *) 472 609 message : string option; (** Latest commit message *) 473 - name : string; (** Branch name *) 610 + name : string; (** Default branch name *) 474 611 short_hash : string option; (** Short commit hash *) 475 612 when_ : string; (** Timestamp of latest commit *) 476 613 } ··· 492 629 val input_jsont : input Jsont.t 493 630 494 631 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 632 + module Delete : sig 633 + (** Delete a repository *) 512 634 513 - end 514 - module Blob : sig 515 635 516 - type submodule = { 517 - branch : string option; (** Branch to track in the submodule *) 518 - name : string; (** Submodule name *) 519 - url : string; (** Submodule repository URL *) 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 *) 520 640 } 521 641 522 - (** Jsont codec for {!type:submodule}. *) 523 - val submodule_jsont : submodule Jsont.t 642 + (** Jsont codec for {!type:input}. *) 643 + val input_jsont : input Jsont.t 524 644 645 + end 646 + module Tree : sig 525 647 526 - type signature = { 527 - email : string; (** Author email *) 528 - name : string; (** Author name *) 529 - when_ : string; (** Author timestamp *) 648 + type readme = { 649 + contents : string; (** Contents of the readme file *) 650 + filename : string; (** Name of the readme file *) 530 651 } 531 652 532 - (** Jsont codec for {!type:signature}. *) 533 - val signature_jsont : signature Jsont.t 653 + (** Jsont codec for {!type:readme}. *) 654 + val readme_jsont : readme Jsont.t 534 655 535 656 536 657 type last_commit = { 537 - author : signature option; 538 658 hash : string; (** Commit hash *) 539 659 message : string; (** Commit message *) 540 - short_hash : string option; (** Short commit hash *) 541 660 when_ : string; (** Commit timestamp *) 542 661 } 543 662 ··· 545 664 val last_commit_jsont : last_commit Jsont.t 546 665 547 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 + 548 678 (** Query/procedure parameters. *) 549 679 type params = { 550 - path : string; (** Path to the file within the repository *) 551 - raw : bool option; (** Return raw file content instead of JSON response *) 680 + path : string option; (** Path within the repository tree *) 552 681 ref_ : string; (** Git reference (branch, tag, or commit SHA) *) 553 682 repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 554 683 } ··· 558 687 559 688 560 689 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 *) 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 *) 567 694 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 695 } 571 696 572 697 (** Jsont codec for {!type:output}. *) 573 698 val output_jsont : output Jsont.t 574 699 575 700 end 576 - module RemoveSecret : sig 577 - (** Remove a CI secret *) 701 + module AddSecret : sig 702 + (** Add a CI secret *) 578 703 579 704 580 705 type input = { 581 706 key : string; 582 707 repo : string; 708 + value : string; 583 709 } 584 710 585 711 (** Jsont codec for {!type:input}. *) 586 712 val input_jsont : input Jsont.t 587 713 588 714 end 589 - module Languages : sig 715 + module Branch : sig 590 716 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) *) 717 + type signature = { 718 + email : string; (** Author email *) 719 + name : string; (** Author name *) 720 + when_ : string; (** Author timestamp *) 598 721 } 599 722 600 - (** Jsont codec for {!type:language}. *) 601 - val language_jsont : language Jsont.t 723 + (** Jsont codec for {!type:signature}. *) 724 + val signature_jsont : signature Jsont.t 602 725 603 726 604 727 (** Query/procedure parameters. *) 605 728 type params = { 606 - ref_ : string option; (** Git reference (branch, tag, or commit SHA) *) 729 + name : string; (** Branch name to get information for *) 607 730 repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 608 731 } 609 732 ··· 612 735 613 736 614 737 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 *) 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 *) 619 745 } 620 746 621 747 (** Jsont codec for {!type:output}. *) 622 748 val output_jsont : output Jsont.t 623 749 624 750 end 625 - module Diff : sig 751 + module Log : sig 626 752 627 753 (** Query/procedure parameters. *) 628 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 *) 629 758 ref_ : string; (** Git reference (branch, tag, or commit SHA) *) 630 759 repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 631 760 } ··· 638 767 val output_jsont : output Jsont.t 639 768 640 769 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 770 module ListSecrets : sig 685 771 686 772 type secret = { ··· 711 797 val output_jsont : output Jsont.t 712 798 713 799 end 714 - module Archive : sig 800 + module Tags : sig 715 801 716 802 (** Query/procedure parameters. *) 717 803 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) *) 804 + cursor : string option; (** Pagination cursor *) 805 + limit : int option; (** Maximum number of tags to return *) 721 806 repo : string; (** Repository identifier in format 'did:plc:.../repoName' *) 722 807 } 723 808 724 809 (** Jsont codec for {!type:params}. *) 725 810 val params_jsont : params Jsont.t 726 811 727 - (** Binary archive data *) 728 812 729 813 type output = unit 730 814 val output_jsont : output Jsont.t 731 815 732 816 end 733 - module HiddenRef : sig 734 - (** Create a hidden ref in a repository *) 817 + module Diff : sig 735 818 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 *) 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' *) 741 823 } 742 824 743 - (** Jsont codec for {!type:input}. *) 744 - val input_jsont : input Jsont.t 825 + (** Jsont codec for {!type:params}. *) 826 + val params_jsont : params Jsont.t 745 827 746 828 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}. *) 829 + type output = unit 754 830 val output_jsont : output Jsont.t 755 831 756 832 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 - 833 + module Collaborator : sig 777 834 778 835 type main = { 779 - body : string option; 780 836 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; 837 + repo : string; (** repo to add this user to *) 838 + subject : string; 788 839 } 789 840 790 841 (** Jsont codec for {!type:main}. *) 791 842 val main_jsont : main Jsont.t 792 843 793 - module Comment : sig 844 + end 845 + module Create : sig 846 + (** Create a new repository *) 794 847 795 - type main = { 796 - body : string; 797 - created_at : string; 798 - mentions : string list option; 799 - pull : string; 800 - references : string list option; 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. *) 801 853 } 802 854 803 - (** Jsont codec for {!type:main}. *) 804 - val main_jsont : main Jsont.t 855 + (** Jsont codec for {!type:input}. *) 856 + val input_jsont : input Jsont.t 805 857 806 - end 807 - module Status : sig 858 + end 859 + module Artifact : sig 808 860 809 861 type main = { 810 - pull : string; 811 - status : string; (** status of the pull request *) 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) *) 812 867 } 813 868 814 869 (** Jsont codec for {!type:main}. *) 815 870 val main_jsont : main Jsont.t 816 871 817 - module Closed : sig 818 - (** closed pull request *) 819 - 820 - type main = string 821 - val main_jsont : main Jsont.t 872 + end 873 + module Archive : sig 822 874 823 - end 824 - module Open : sig 825 - (** open pull request *) 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 + } 826 882 827 - type main = string 828 - val main_jsont : main Jsont.t 883 + (** Jsont codec for {!type:params}. *) 884 + val params_jsont : params Jsont.t 829 885 830 - end 831 - module Merged : sig 832 - (** merged pull request *) 886 + (** Binary archive data *) 833 887 834 - type main = string 835 - val main_jsont : main Jsont.t 888 + type output = unit 889 + val output_jsont : output Jsont.t 836 890 837 - end 838 - end 839 891 end 840 - module Issue : sig 892 + module RemoveSecret : sig 893 + (** Remove a CI secret *) 841 894 842 - type main = { 843 - body : string option; 844 - created_at : string; 845 - mentions : string list option; 846 - references : string list option; 895 + 896 + type input = { 897 + key : string; 847 898 repo : string; 848 - title : string; 849 899 } 850 900 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 - } 901 + (** Jsont codec for {!type:input}. *) 902 + val input_jsont : input Jsont.t 864 903 865 - (** Jsont codec for {!type:main}. *) 866 - val main_jsont : main Jsont.t 904 + end 905 + module Merge : sig 906 + (** Merge a patch into a repository branch *) 867 907 868 - end 869 - module State : sig 870 908 871 - type main = { 872 - issue : string; 873 - state : string; (** state of the issue *) 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 *) 874 918 } 875 919 876 - (** Jsont codec for {!type:main}. *) 877 - val main_jsont : main Jsont.t 878 - 879 - module Closed : sig 880 - (** closed issue *) 920 + (** Jsont codec for {!type:input}. *) 921 + val input_jsont : input Jsont.t 881 922 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 923 end 895 - end 896 - module Label : sig 897 - module Definition : sig 924 + module Blob : sig 898 925 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. *) 926 + type submodule = { 927 + branch : string option; (** Branch to track in the submodule *) 928 + name : string; (** Submodule name *) 929 + url : string; (** Submodule repository URL *) 903 930 } 904 931 905 - (** Jsont codec for {!type:value_type}. *) 906 - val value_type_jsont : value_type Jsont.t 932 + (** Jsont codec for {!type:submodule}. *) 933 + val submodule_jsont : submodule Jsont.t 907 934 908 935 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. *) 936 + type signature = { 937 + email : string; (** Author email *) 938 + name : string; (** Author name *) 939 + when_ : string; (** Author timestamp *) 916 940 } 917 941 918 - (** Jsont codec for {!type:main}. *) 919 - val main_jsont : main Jsont.t 942 + (** Jsont codec for {!type:signature}. *) 943 + val signature_jsont : signature Jsont.t 920 944 921 - end 922 - module Op : sig 923 945 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. *) 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 *) 927 952 } 928 953 929 - (** Jsont codec for {!type:operand}. *) 930 - val operand_jsont : operand Jsont.t 954 + (** Jsont codec for {!type:last_commit}. *) 955 + val last_commit_jsont : last_commit Jsont.t 931 956 932 957 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. *) 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' *) 938 964 } 939 965 940 - (** Jsont codec for {!type:main}. *) 941 - val main_jsont : main Jsont.t 966 + (** Jsont codec for {!type:params}. *) 967 + val params_jsont : params Jsont.t 942 968 943 - end 944 - end 945 - module Graph : sig 946 - module Follow : sig 947 969 948 - type main = { 949 - created_at : string; 950 - subject : string; 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 *) 951 980 } 952 981 953 - (** Jsont codec for {!type:main}. *) 954 - val main_jsont : main Jsont.t 982 + (** Jsont codec for {!type:output}. *) 983 + val output_jsont : output Jsont.t 955 984 956 985 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 986 + module HiddenRef : sig 987 + (** Create a hidden ref in a repository *) 966 988 967 - module Member : sig 968 989 969 - type main = { 970 - created_at : string; 971 - domain : string; (** domain that this member now belongs to *) 972 - subject : string; 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 *) 973 994 } 974 995 975 - (** Jsont codec for {!type:main}. *) 976 - val main_jsont : main Jsont.t 996 + (** Jsont codec for {!type:input}. *) 997 + val input_jsont : input Jsont.t 977 998 978 - end 979 - module ListKeys : sig 980 999 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 *) 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 *) 985 1004 } 986 1005 987 - (** Jsont codec for {!type:public_key}. *) 988 - val public_key_jsont : public_key Jsont.t 1006 + (** Jsont codec for {!type:output}. *) 1007 + val output_jsont : output Jsont.t 989 1008 990 - (** List all public keys stored in the knot server *) 1009 + end 1010 + module Compare : sig 991 1011 992 1012 (** Query/procedure parameters. *) 993 1013 type params = { 994 - cursor : string option; (** Pagination cursor *) 995 - limit : int option; (** Maximum number of keys to return *) 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) *) 996 1017 } 997 1018 998 1019 (** Jsont codec for {!type:params}. *) 999 1020 val params_jsont : params Jsont.t 1000 1021 1001 - 1002 - type output = { 1003 - cursor : string option; (** Pagination cursor for next page *) 1004 - keys : public_key list; 1005 - } 1022 + (** Compare output in application/json *) 1006 1023 1007 - (** Jsont codec for {!type:output}. *) 1024 + type output = unit 1008 1025 val output_jsont : output Jsont.t 1009 1026 1010 1027 end 1011 - module Version : sig 1012 - (** Get the version of a knot *) 1028 + module ForkStatus : sig 1029 + (** Check fork status relative to upstream source *) 1013 1030 1014 1031 1015 - type output = { 1016 - version : string; 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 *) 1017 1038 } 1018 1039 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 *) 1040 + (** Jsont codec for {!type:input}. *) 1041 + val input_jsont : input Jsont.t 1026 1042 1027 1043 1028 1044 type output = { 1029 - owner : string; 1045 + status : int; (** Fork status: 0=UpToDate, 1=FastForwardable, 2=Conflict, 3=MissingBranch *) 1030 1046 } 1031 1047 1032 1048 (** Jsont codec for {!type:output}. *) 1033 1049 val output_jsont : output Jsont.t 1034 1050 1035 - end 1036 - module PublicKey : sig 1051 + end 1052 + module MergeCheck : sig 1037 1053 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 *) 1054 + type conflict_info = { 1055 + filename : string; (** Name of the conflicted file *) 1056 + reason : string; (** Reason for the conflict *) 1042 1057 } 1043 1058 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 - } 1059 + (** Jsont codec for {!type:conflict_info}. *) 1060 + val conflict_info_jsont : conflict_info Jsont.t 1056 1061 1057 - (** Jsont codec for {!type:trigger_repo}. *) 1058 - val trigger_repo_jsont : trigger_repo Jsont.t 1062 + (** Check if a merge is possible between two branches *) 1059 1063 1060 1064 1061 - type push_trigger_data = { 1062 - new_sha : string; 1063 - old_sha : string; 1064 - ref_ : string; 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 *) 1065 1070 } 1066 1071 1067 - (** Jsont codec for {!type:push_trigger_data}. *) 1068 - val push_trigger_data_jsont : push_trigger_data Jsont.t 1072 + (** Jsont codec for {!type:input}. *) 1073 + val input_jsont : input Jsont.t 1069 1074 1070 1075 1071 - type pull_request_trigger_data = { 1072 - action : string; 1073 - source_branch : string; 1074 - source_sha : string; 1075 - target_branch : string; 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 *) 1076 1081 } 1077 1082 1078 - (** Jsont codec for {!type:pull_request_trigger_data}. *) 1079 - val pull_request_trigger_data_jsont : pull_request_trigger_data Jsont.t 1083 + (** Jsont codec for {!type:output}. *) 1084 + val output_jsont : output Jsont.t 1080 1085 1086 + end 1087 + module Branches : sig 1081 1088 1082 - type pair = { 1083 - key : string; 1084 - value : string; 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' *) 1085 1094 } 1086 1095 1087 - (** Jsont codec for {!type:pair}. *) 1088 - val pair_jsont : pair Jsont.t 1096 + (** Jsont codec for {!type:params}. *) 1097 + val params_jsont : params Jsont.t 1089 1098 1090 1099 1091 - type clone_opts = { 1092 - depth : int; 1093 - skip : bool; 1094 - submodules : bool; 1095 - } 1100 + type output = unit 1101 + val output_jsont : output Jsont.t 1096 1102 1097 - (** Jsont codec for {!type:clone_opts}. *) 1098 - val clone_opts_jsont : clone_opts Jsont.t 1103 + end 1104 + module ForkSync : sig 1105 + (** Sync a forked repository with its upstream source *) 1099 1106 1100 1107 1101 - type workflow = { 1102 - clone : clone_opts; 1103 - engine : string; 1104 - name : string; 1105 - raw : string; 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 *) 1106 1113 } 1107 1114 1108 - (** Jsont codec for {!type:workflow}. *) 1109 - val workflow_jsont : workflow Jsont.t 1115 + (** Jsont codec for {!type:input}. *) 1116 + val input_jsont : input Jsont.t 1110 1117 1118 + end 1119 + module Languages : sig 1111 1120 1112 - type manual_trigger_data = { 1113 - inputs : pair list option; 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) *) 1114 1128 } 1115 1129 1116 - (** Jsont codec for {!type:manual_trigger_data}. *) 1117 - val manual_trigger_data_jsont : manual_trigger_data Jsont.t 1130 + (** Jsont codec for {!type:language}. *) 1131 + val language_jsont : language Jsont.t 1118 1132 1119 1133 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; 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' *) 1126 1138 } 1127 1139 1128 - (** Jsont codec for {!type:trigger_metadata}. *) 1129 - val trigger_metadata_jsont : trigger_metadata Jsont.t 1140 + (** Jsont codec for {!type:params}. *) 1141 + val params_jsont : params Jsont.t 1130 1142 1131 1143 1132 - type main = { 1133 - trigger_metadata : trigger_metadata; 1134 - workflows : workflow list; 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 *) 1135 1149 } 1136 1150 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 1151 + (** Jsont codec for {!type:output}. *) 1152 + val output_jsont : output Jsont.t 1153 1153 1154 1154 end 1155 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 570 571 571 let search t ?charset criteria = 572 572 require_selected t; 573 - let tag = send_command t (Command.Search { charset; criteria }) in 573 + let tag = send_command t (Command.Search { charset; criteria; return_opts = None }) in 574 574 let untagged, final = receive_responses t tag in 575 575 check_ok tag untagged final; 576 576 (* Extract search results from untagged responses *) ··· 582 582 583 583 let uid_search t ?charset criteria = 584 584 require_selected t; 585 - let tag = send_command t (Command.Uid (Uid_search { charset; criteria })) in 585 + let tag = send_command t (Command.Uid (Uid_search { charset; criteria; return_opts = None })) in 586 586 let untagged, final = receive_responses t tag in 587 587 check_ok tag untagged final; 588 588 (* Extract UID search results from untagged responses - UIDs are returned as int64 *) ··· 685 685 (function Response.Enabled exts -> enabled := exts | _ -> ()) 686 686 untagged; 687 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 247 248 248 val enable : t -> string list -> string list 249 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 24 | Expired 25 25 | Expungeissued 26 26 | Haschildren 27 + | Highestmodseq of int64 (** Highest MODSEQ in mailbox - RFC 7162 CONDSTORE *) 27 28 | Inuse 28 29 | Limit 30 + | Modified of Seq.t (** Messages modified since UNCHANGEDSINCE - RFC 7162 CONDSTORE *) 31 + | Nomodseq (** Mailbox doesn't support MODSEQ - RFC 7162 CONDSTORE *) 29 32 | Nonexistent 30 33 | Noperm 31 34 | Overquota ··· 61 64 | Expired -> Fmt.string ppf "EXPIRED" 62 65 | Expungeissued -> Fmt.string ppf "EXPUNGEISSUED" 63 66 | Haschildren -> Fmt.string ppf "HASCHILDREN" 67 + | Highestmodseq m -> Fmt.pf ppf "HIGHESTMODSEQ %Ld" m 64 68 | Inuse -> Fmt.string ppf "INUSE" 65 69 | Limit -> Fmt.string ppf "LIMIT" 70 + | Modified s -> Fmt.pf ppf "MODIFIED %a" Seq.pp s 71 + | Nomodseq -> Fmt.string ppf "NOMODSEQ" 66 72 | Nonexistent -> Fmt.string ppf "NONEXISTENT" 67 73 | Noperm -> Fmt.string ppf "NOPERM" 68 74 | Overquota -> Fmt.string ppf "OVERQUOTA"
+3
ocaml-imap/lib/imap/code.mli
··· 24 24 | Expired 25 25 | Expungeissued 26 26 | Haschildren 27 + | Highestmodseq of int64 (** Highest MODSEQ in mailbox - RFC 7162 CONDSTORE *) 27 28 | Inuse 28 29 | Limit 30 + | Modified of Seq.t (** Messages modified since UNCHANGEDSINCE - RFC 7162 CONDSTORE *) 31 + | Nomodseq (** Mailbox doesn't support MODSEQ - RFC 7162 CONDSTORE *) 29 32 | Nonexistent 30 33 | Noperm 31 34 | Overquota
+13 -2
ocaml-imap/lib/imap/command.ml
··· 7 7 8 8 Client-to-server commands as specified in RFC 9051. *) 9 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 + 10 17 type t = 11 18 | Capability 12 19 | Noop ··· 35 42 | Close 36 43 | Unselect 37 44 | Expunge 38 - | Search of { charset : string option; criteria : Search.t } 45 + | Search of { charset : string option; criteria : Search.t; return_opts : search_return_opt list option } 39 46 | Sort of { charset : string; criteria : Sort.t; search : Search.t } 47 + | Thread of { algorithm : Thread.algorithm; charset : string; search : Search.t } 40 48 | Fetch of { sequence : Seq.t; items : Fetch.request list; changedsince : int64 option } 41 49 | Store of { 42 50 sequence : Seq.t; ··· 61 69 } 62 70 | Uid_copy of { sequence : Seq.t; mailbox : Mailbox.t } 63 71 | Uid_move of { sequence : Seq.t; mailbox : Mailbox.t } 64 - | Uid_search of { charset : string option; criteria : Search.t } 72 + | Uid_search of { charset : string option; criteria : Search.t; return_opts : search_return_opt list option } 65 73 | Uid_sort of { charset : string; criteria : Sort.t; search : Search.t } 74 + | Uid_thread of { algorithm : Thread.algorithm; charset : string; search : Search.t } 66 75 | Uid_expunge of Seq.t 67 76 68 77 type tagged = { tag : string; command : t } ··· 95 104 | Expunge -> Fmt.string ppf "EXPUNGE" 96 105 | Search _ -> Fmt.string ppf "SEARCH (...)" 97 106 | Sort _ -> Fmt.string ppf "SORT (...)" 107 + | Thread _ -> Fmt.string ppf "THREAD (...)" 98 108 | Fetch { sequence; _ } -> Fmt.pf ppf "FETCH %a (...)" Seq.pp sequence 99 109 | Store { sequence; action; _ } -> 100 110 let action_str = match action with Store.Set -> "FLAGS" | Store.Add -> "+FLAGS" | Store.Remove -> "-FLAGS" in ··· 113 123 | Uid_move { sequence; mailbox } -> Fmt.pf ppf "MOVE %a %s" Seq.pp sequence mailbox 114 124 | Uid_search _ -> Fmt.string ppf "SEARCH (...)" 115 125 | Uid_sort _ -> Fmt.string ppf "SORT (...)" 126 + | Uid_thread _ -> Fmt.string ppf "THREAD (...)" 116 127 | Uid_expunge seq -> Fmt.pf ppf "EXPUNGE %a" Seq.pp seq
+11 -2
ocaml-imap/lib/imap/command.mli
··· 7 7 8 8 Client-to-server commands as specified in RFC 9051. *) 9 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 + 10 17 type t = 11 18 | Capability 12 19 | Noop ··· 35 42 | Close 36 43 | Unselect 37 44 | Expunge 38 - | Search of { charset : string option; criteria : Search.t } 45 + | Search of { charset : string option; criteria : Search.t; return_opts : search_return_opt list option } 39 46 | Sort of { charset : string; criteria : Sort.t; search : Search.t } 47 + | Thread of { algorithm : Thread.algorithm; charset : string; search : Search.t } 40 48 | Fetch of { sequence : Seq.t; items : Fetch.request list; changedsince : int64 option } 41 49 | Store of { 42 50 sequence : Seq.t; ··· 61 69 } 62 70 | Uid_copy of { sequence : Seq.t; mailbox : Mailbox.t } 63 71 | Uid_move of { sequence : Seq.t; mailbox : Mailbox.t } 64 - | Uid_search of { charset : string option; criteria : Search.t } 72 + | Uid_search of { charset : string option; criteria : Search.t; return_opts : search_return_opt list option } 65 73 | Uid_sort of { charset : string; criteria : Sort.t; search : Search.t } 74 + | Uid_thread of { algorithm : Thread.algorithm; charset : string; search : Search.t } 66 75 | Uid_expunge of Seq.t 67 76 68 77 type tagged = { tag : string; command : t }
+1
ocaml-imap/lib/imap/dune
··· 9 9 base64 10 10 fmt 11 11 logs 12 + mail-flag 12 13 unix))
+2
ocaml-imap/lib/imap/fetch.ml
··· 25 25 | Binary of string * (int * int) option 26 26 | Binary_peek of string * (int * int) option 27 27 | Binary_size of string 28 + | Modseq (** Request MODSEQ value - RFC 7162 CONDSTORE *) 28 29 29 30 let pp_request ppf = function 30 31 | Envelope -> Fmt.string ppf "ENVELOPE" ··· 42 43 | Binary (s, _) -> Fmt.pf ppf "BINARY[%s]" s 43 44 | Binary_peek (s, _) -> Fmt.pf ppf "BINARY.PEEK[%s]" s 44 45 | Binary_size s -> Fmt.pf ppf "BINARY.SIZE[%s]" s 46 + | Modseq -> Fmt.string ppf "MODSEQ" 45 47 46 48 (** {1 Response Items} *) 47 49
+1
ocaml-imap/lib/imap/fetch.mli
··· 25 25 | Binary of string * (int * int) option 26 26 | Binary_peek of string * (int * int) option 27 27 | Binary_size of string 28 + | Modseq (** Request MODSEQ value - RFC 7162 CONDSTORE *) 28 29 29 30 val pp_request : Format.formatter -> request -> unit 30 31
+52 -1
ocaml-imap/lib/imap/flag.ml
··· 5 5 6 6 (** Message Flags 7 7 8 - IMAP message flags as specified in RFC 9051 Section 2.3.2. *) 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} *) 9 12 10 13 type system = 11 14 | Seen (** Message has been read *) ··· 20 23 | Flagged -> Fmt.string ppf "\\Flagged" 21 24 | Deleted -> Fmt.string ppf "\\Deleted" 22 25 | Draft -> Fmt.string ppf "\\Draft" 26 + 27 + (** {1 Flags} *) 23 28 24 29 type t = 25 30 | System of system ··· 47 52 | "\\DRAFT" -> Some (System Draft) 48 53 | _ -> 49 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 5 6 6 (** Message Flags 7 7 8 - IMAP message flags as specified in RFC 9051 Section 2.3.2. *) 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}. *) 9 10 10 11 (** {1 System Flags} *) 11 12 ··· 36 37 val pp : Format.formatter -> t -> unit 37 38 val to_string : t -> string 38 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 57 - {!module:Fetch} - FETCH request/response items 58 58 - {!module:Search} - SEARCH criteria 59 59 - {!module:Sort} - SORT criteria (RFC 5256) 60 + - {!module:Subject} - Base subject extraction (RFC 5256) 60 61 - {!module:Store} - STORE actions 61 62 - {!module:Status} - STATUS items 62 63 - {!module:List_attr} - LIST mailbox attributes ··· 99 100 module Store = Store 100 101 module Status = Status 101 102 module List_attr = List_attr 103 + module Subject = Subject 104 + module Thread = Thread 102 105 103 106 (** {1 Client} *) 104 107
+3
ocaml-imap/lib/imap/imap.mli
··· 57 57 - {!module:Fetch} - FETCH request/response items 58 58 - {!module:Search} - SEARCH criteria 59 59 - {!module:Sort} - SORT criteria (RFC 5256) 60 + - {!module:Subject} - Base subject extraction (RFC 5256) 60 61 - {!module:Store} - STORE actions 61 62 - {!module:Status} - STATUS items 62 63 - {!module:List_attr} - LIST mailbox attributes ··· 99 100 module Store = Store 100 101 module Status = Status 101 102 module List_attr = List_attr 103 + module Subject = Subject 104 + module Thread = Thread 102 105 103 106 (** {1 Client} *) 104 107
+102 -1
ocaml-imap/lib/imap/list_attr.ml
··· 5 5 6 6 (** LIST Command Attributes 7 7 8 - Mailbox attributes returned by LIST command. 8 + Re-exports from {!Mail_flag.Mailbox_attr}. 9 9 See RFC 9051 Section 7.2.2. *) 10 10 11 11 type t = ··· 43 43 | Extension s -> Fmt.string ppf s 44 44 45 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 5 6 6 (** LIST Command Attributes 7 7 8 - Mailbox attributes returned by LIST command. 8 + Re-exports from {!Mail_flag.Mailbox_attr}. 9 9 See RFC 9051 Section 7.2.2. *) 10 10 11 11 type t = ··· 27 27 28 28 val pp : Format.formatter -> t -> unit 29 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 106 in 107 107 loop [] 108 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 + 109 140 (** {1 Flags} *) 110 141 111 142 let system_flag r = ··· 175 206 in 176 207 loop [] 177 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 + 178 312 (** {1 Response Codes} *) 179 313 180 314 let response_code r = ··· 184 318 match String.uppercase_ascii name with 185 319 | "ALERT" -> Code.Alert 186 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) 187 327 | "AUTHENTICATIONFAILED" -> Code.Authenticationfailed 188 328 | "AUTHORIZATIONFAILED" -> Code.Authorizationfailed 189 329 | "CANNOT" -> Code.Cannot ··· 191 331 | "CLIENTBUG" -> Code.Clientbug 192 332 | "CLOSED" -> Code.Closed 193 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) 194 342 | "CORRUPTION" -> Code.Corruption 195 343 | "EXPIRED" -> Code.Expired 196 344 | "EXPUNGEISSUED" -> Code.Expungeissued 197 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) 198 352 | "INUSE" -> Code.Inuse 199 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 200 365 | "NONEXISTENT" -> Code.Nonexistent 201 366 | "NOPERM" -> Code.Noperm 202 367 | "OVERQUOTA" -> Code.Overquota ··· 286 451 R.char ')' r; 287 452 Envelope.{ date; subject; from; sender; reply_to; to_; cc; bcc; in_reply_to; message_id } 288 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 + 289 671 (** {1 FETCH Response Items} *) 290 672 291 673 let fetch_item r = ··· 333 715 | Some '[' -> 334 716 (* BODY[section]<origin> literal-or-nil *) 335 717 R.char '[' r; 336 - let _section = R.take_while (fun c -> c <> ']') r in 718 + let section_str = R.take_while (fun c -> c <> ']') r in 337 719 R.char ']' r; 338 - (* Skip optional origin <n> *) 720 + let section = parse_section_spec section_str in 721 + (* Parse optional origin <n> *) 339 722 let origin = 340 723 if R.peek_char r = Some '<' then ( 341 724 R.char '<' r; ··· 346 729 in 347 730 sp r; 348 731 let data = nstring r in 349 - Fetch.Item_body_section { section = None; origin; data } 732 + Fetch.Item_body_section { section; origin; data } 350 733 | _ -> 351 - (* BODY without [] means bodystructure - skip for now *) 734 + (* BODY without [] means basic bodystructure (no extensions) *) 352 735 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) 736 + let parsed_body = body r in 737 + Fetch.Item_body parsed_body) 390 738 | "BODYSTRUCTURE" -> 739 + (* BODYSTRUCTURE includes extension data *) 391 740 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 741 + let parsed_body = body r in 742 + Fetch.Item_bodystructure parsed_body 429 743 | _ -> Fetch.Item_flags [] 430 744 431 745 let fetch_items r = parse_paren_list ~parse_item:fetch_item r ··· 444 758 | "UNSEEN" -> Status.Unseen 445 759 | "DELETED" -> Status.Deleted 446 760 | "SIZE" -> Status.Size 761 + | "HIGHESTMODSEQ" -> Status.Highestmodseq (* RFC 7162 CONDSTORE *) 447 762 | _ -> Status.Messages 448 763 in 449 764 (item, value) ··· 488 803 let shared = namespace_list r in 489 804 Response.{ personal; other; shared } 490 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 + 491 876 (** {1 ID Response} *) 492 877 493 878 let id_params r = ··· 509 894 loop ((k, v) :: acc) 510 895 in 511 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 [] 512 942 513 943 (** {1 Main Response Parser} *) 514 944 ··· 631 1061 done; 632 1062 crlf r; 633 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 634 1086 | _ -> 635 1087 let _ = rest_of_line r in 636 1088 Response.Ok { tag = None; code = None; text = "" })
+2
ocaml-imap/lib/imap/response.ml
··· 45 45 | Esearch of { tag : string option; uid : bool; results : esearch_result list } 46 46 | Search of int list 47 47 | Sort of int64 list 48 + | Thread of int Thread.t 48 49 | Flags of Flag.t list 49 50 | Exists of int 50 51 | Recent of int ··· 83 84 | Esearch _ -> Fmt.string ppf "* ESEARCH ..." 84 85 | Search seqs -> Fmt.pf ppf "* SEARCH %a" Fmt.(list ~sep:sp int) seqs 85 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 86 88 | Flags flags -> Fmt.pf ppf "* FLAGS (%a)" Fmt.(list ~sep:sp Flag.pp) flags 87 89 | Exists n -> Fmt.pf ppf "* %d EXISTS" n 88 90 | Recent n -> Fmt.pf ppf "* %d RECENT" n
+1
ocaml-imap/lib/imap/response.mli
··· 45 45 | Esearch of { tag : string option; uid : bool; results : esearch_result list } 46 46 | Search of int list 47 47 | Sort of int64 list 48 + | Thread of int Thread.t 48 49 | Flags of Flag.t list 49 50 | Exists of int 50 51 | Recent of int
+2
ocaml-imap/lib/imap/status.ml
··· 14 14 | Unseen 15 15 | Deleted 16 16 | Size 17 + | Highestmodseq (** RFC 7162 CONDSTORE *) 17 18 18 19 let pp_item ppf = function 19 20 | Messages -> Fmt.string ppf "MESSAGES" ··· 22 23 | Unseen -> Fmt.string ppf "UNSEEN" 23 24 | Deleted -> Fmt.string ppf "DELETED" 24 25 | Size -> Fmt.string ppf "SIZE" 26 + | Highestmodseq -> Fmt.string ppf "HIGHESTMODSEQ" 25 27 26 28 type t = { 27 29 mailbox : string;
+1
ocaml-imap/lib/imap/status.mli
··· 14 14 | Unseen 15 15 | Deleted 16 16 | Size 17 + | Highestmodseq (** RFC 7162 CONDSTORE *) 17 18 18 19 val pp_item : Format.formatter -> item -> unit 19 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 116 flags; 117 117 W.char w ')' 118 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 + 119 135 (** {1 Search Keys} *) 120 136 121 137 let rec search_key w = function ··· 245 261 write_partial w partial 246 262 | Fetch.Binary_size section -> 247 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" 248 267 249 268 let fetch_items w = function 250 269 | [ item ] -> fetch_item w item ··· 266 285 | Status.Unseen -> W.string w "UNSEEN" 267 286 | Status.Deleted -> W.string w "DELETED" 268 287 | Status.Size -> W.string w "SIZE" 288 + | Status.Highestmodseq -> W.string w "HIGHESTMODSEQ" (* RFC 7162 CONDSTORE *) 269 289 270 290 let status_items w items = 271 291 W.char w '('; ··· 307 327 criteria; 308 328 W.char w ')' 309 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 + 310 337 (** {1 ID Parameters} *) 311 338 312 339 let id_params w = function ··· 324 351 325 352 (** {1 Commands} *) 326 353 327 - let write_search w charset criteria = 354 + let write_search w charset criteria return_opts = 328 355 W.string w "SEARCH"; 356 + Option.iter (fun opts -> sp w; search_return_opts w opts) return_opts; 329 357 Option.iter (fun cs -> W.string w " CHARSET "; astring w cs) charset; 330 358 sp w; 331 359 search_key w criteria ··· 333 361 let write_sort w charset criteria search = 334 362 W.string w "SORT "; 335 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; 336 372 sp w; 337 373 astring w charset; 338 374 sp w; ··· 403 439 | Command.Close -> W.string w "CLOSE" 404 440 | Command.Unselect -> W.string w "UNSELECT" 405 441 | Command.Expunge -> W.string w "EXPUNGE" 406 - | Command.Search { charset; criteria } -> 407 - write_search w charset criteria 442 + | Command.Search { charset; criteria; return_opts } -> 443 + write_search w charset criteria return_opts 408 444 | Command.Sort { charset; criteria; search } -> 409 445 write_sort w charset criteria search 446 + | Command.Thread { algorithm; charset; search } -> 447 + write_thread w algorithm charset search 410 448 | Command.Fetch { sequence; items; changedsince } -> 411 449 W.string w "FETCH "; 412 450 sequence_set w sequence; ··· 476 514 sequence_set w sequence; 477 515 sp w; 478 516 astring w mailbox 479 - | Command.Uid_search { charset; criteria } -> 480 - write_search w charset criteria 517 + | Command.Uid_search { charset; criteria; return_opts } -> 518 + write_search w charset criteria return_opts 481 519 | Command.Uid_sort { charset; criteria; search } -> 482 520 write_sort w charset criteria search 521 + | Command.Uid_thread { algorithm; charset; search } -> 522 + write_thread w algorithm charset search 483 523 | Command.Uid_expunge set -> 484 524 W.string w "EXPUNGE "; 485 525 sequence_set w set)
+4
ocaml-imap/lib/imap/write.mli
··· 43 43 val fetch_item : t -> Fetch.request -> unit 44 44 val fetch_items : t -> Fetch.request list -> unit 45 45 46 + (** {1 Thread} *) 47 + 48 + val thread_algorithm : t -> Thread.algorithm -> unit 49 + 46 50 (** {1 Commands} *) 47 51 48 52 val command : t -> tag:string -> Command.t -> unit
+2 -2
ocaml-imap/lib/imapd/client.ml
··· 132 132 | Flags_response f -> flags := f 133 133 | Capability_response c -> caps := c 134 134 | Enabled e -> enabled := e 135 - | List_response { flags = f; delimiter; name } -> 135 + | List_response { flags = f; delimiter; name; _ } -> 136 136 list_entries := { flags = f; delimiter; name } :: !list_entries 137 137 | Status_response { mailbox; items } -> 138 138 let messages = ··· 554 554 555 555 let list t ~reference ~pattern = 556 556 require_authenticated t; 557 - let responses = run_command t (List { reference; pattern }) in 557 + let responses = run_command t (List (List_basic { reference; pattern })) in 558 558 let _, _, _, _, _, _, _, _, entries, _, _, _, _, _, _, _ = 559 559 process_untagged responses 560 560 in
+91 -1
ocaml-imap/lib/imapd/grammar.mly
··· 61 61 %token CHARSET MIME PEEK HEADER_FIELDS HEADER_FIELDS_NOT SILENT 62 62 %token RETURN SUBSCRIBED CHILDREN REMOTE RECURSIVEMATCH DONE 63 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 + 64 70 (* Entry point *) 65 71 %start <Protocol.tagged_command> command 66 72 %start <Protocol.response> response_parser ··· 382 388 | RENAME SP old_mb = mailbox SP new_mb = mailbox { Rename { old_name = old_mb; new_name = new_mb } } 383 389 | SUBSCRIBE SP mb = mailbox { Subscribe mb } 384 390 | UNSUBSCRIBE SP mb = mailbox { Unsubscribe mb } 385 - | LIST SP ref = astring SP pat = list_mailbox { List { reference = ref; pattern = pat } } 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 }) } 386 400 | NAMESPACE { Namespace } 387 401 | STATUS SP mb = mailbox SP LPAREN atts = status_att_list RPAREN { Status { mailbox = mb; items = atts } } 388 402 | APPEND SP mb = mailbox SP fl = flag_list SP dt = date_time SP msg = append_message ··· 392 406 | APPEND SP mb = mailbox SP msg = append_message 393 407 { Append { mailbox = mb; flags = []; date = None; message = msg } } 394 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 } 395 430 ; 396 431 397 432 enable_caps: ··· 402 437 list_mailbox: 403 438 | s = astring { s } 404 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 } 405 495 ; 406 496 407 497 append_message:
+10
ocaml-imap/lib/imapd/lexer.mll
··· 123 123 ("REMOTE", REMOTE); 124 124 ("RECURSIVEMATCH", RECURSIVEMATCH); 125 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 *) 126 136 ] 127 137 128 138 let lookup_keyword s =
+116 -3
ocaml-imap/lib/imapd/parser.ml
··· 12 12 open Protocol 13 13 14 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 + 15 26 type command = Protocol.command = 16 27 | Capability 17 28 | Noop ··· 27 38 | Rename of { old_name : mailbox_name; new_name : mailbox_name } 28 39 | Subscribe of mailbox_name 29 40 | Unsubscribe of mailbox_name 30 - | List of { reference : string; pattern : string } 41 + | List of list_command (** LIST command - RFC 9051, RFC 5258 LIST-EXTENDED *) 31 42 | Namespace 32 43 | Status of { mailbox : mailbox_name; items : status_item list } 33 44 | Append of { mailbox : mailbox_name; flags : flag list; date : string option; message : string } ··· 42 53 | Move of { sequence : sequence_set; mailbox : mailbox_name } 43 54 | Uid of uid_command 44 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 } 45 62 46 63 type uid_command = Protocol.uid_command = 47 64 | Uid_fetch of { sequence : sequence_set; items : fetch_item list } ··· 50 67 | Uid_move of { sequence : sequence_set; mailbox : mailbox_name } 51 68 | Uid_search of { charset : string option; criteria : search_key } 52 69 | Uid_expunge of sequence_set 70 + | Uid_thread of { algorithm : thread_algorithm; charset : string; criteria : search_key } 53 71 54 72 type tagged_command = Protocol.tagged_command = { 55 73 tag : string; ··· 64 82 | Bye of { code : response_code option; text : string } 65 83 | Capability_response of string list 66 84 | Enabled of string list 67 - | List_response of { flags : list_flag list; delimiter : char option; name : mailbox_name } 85 + | List_response of list_response_data (** RFC 9051, RFC 5258 LIST-EXTENDED *) 68 86 | Namespace_response of namespace_data 69 87 | Status_response of { mailbox : mailbox_name; items : (status_item * int64) list } 70 88 | Esearch of { tag : string option; uid : bool; results : esearch_result list } ··· 74 92 | Fetch_response of { seq : int; items : fetch_response_item list } 75 93 | Continuation of string option 76 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 77 100 78 101 (* ===== Menhir Parser Interface ===== *) 79 102 ··· 113 136 write_string f "}\r\n"; 114 137 write_string f s 115 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 + 116 147 let write_flag f flag = 117 148 write_string f (flag_to_string flag) 118 149 ··· 219 250 List.iter (fun c -> write_sp f; write_string f c) caps; 220 251 write_crlf f 221 252 222 - | List_response { flags; delimiter; name } -> 253 + | List_response { flags; delimiter; name; extended } -> 254 + (* LIST response per RFC 9051 Section 7.3.1, RFC 5258 Section 3.4 *) 223 255 write_string f "* LIST ("; 224 256 List.iteri (fun i flag -> 225 257 if i > 0 then write_sp f; ··· 231 263 | List_subscribed -> write_string f "\\Subscribed" 232 264 | List_haschildren -> write_string f "\\HasChildren" 233 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 *) 234 268 | List_all -> write_string f "\\All" 235 269 | List_archive -> write_string f "\\Archive" 236 270 | List_drafts -> write_string f "\\Drafts" ··· 246 280 | None -> write_string f "NIL"); 247 281 write_sp f; 248 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; 249 296 write_crlf f 250 297 251 298 | Namespace_response { personal; other; shared } -> ··· 371 418 write_quoted_string f value 372 419 ) pairs; 373 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; 374 487 write_crlf f 375 488 376 489 let response_to_string resp =
+19 -2
ocaml-imap/lib/imapd/parser.mli
··· 15 15 16 16 Types are defined in {!Protocol} and re-exported here for convenience. *) 17 17 18 + type thread_algorithm = Protocol.thread_algorithm = 19 + | Thread_orderedsubject 20 + | Thread_references 21 + | Thread_extension of string 22 + 18 23 type command = Protocol.command = 19 24 | Capability 20 25 | Noop ··· 30 35 | Rename of { old_name : mailbox_name; new_name : mailbox_name } 31 36 | Subscribe of mailbox_name 32 37 | Unsubscribe of mailbox_name 33 - | List of { reference : string; pattern : string } 38 + | List of list_command 34 39 | Namespace 35 40 | Status of { mailbox : mailbox_name; items : status_item list } 36 41 | Append of { mailbox : mailbox_name; flags : flag list; date : string option; message : string } ··· 45 50 | Move of { sequence : sequence_set; mailbox : mailbox_name } 46 51 | Uid of uid_command 47 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 } 48 59 49 60 type uid_command = Protocol.uid_command = 50 61 | Uid_fetch of { sequence : sequence_set; items : fetch_item list } ··· 53 64 | Uid_move of { sequence : sequence_set; mailbox : mailbox_name } 54 65 | Uid_search of { charset : string option; criteria : search_key } 55 66 | Uid_expunge of sequence_set 67 + | Uid_thread of { algorithm : thread_algorithm; charset : string; criteria : search_key } 56 68 57 69 type tagged_command = Protocol.tagged_command = { 58 70 tag : string; ··· 67 79 | Bye of { code : response_code option; text : string } 68 80 | Capability_response of string list 69 81 | Enabled of string list 70 - | List_response of { flags : list_flag list; delimiter : char option; name : mailbox_name } 82 + | List_response of list_response_data 71 83 | Namespace_response of namespace_data 72 84 | Status_response of { mailbox : mailbox_name; items : (status_item * int64) list } 73 85 | Esearch of { tag : string option; uid : bool; results : esearch_result list } ··· 77 89 | Fetch_response of { seq : int; items : fetch_response_item list } 78 90 | Continuation of string option 79 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 80 97 81 98 (** {1 Parsing} *) 82 99
+127 -3
ocaml-imap/lib/imapd/protocol.ml
··· 183 183 | Status_deleted 184 184 | Status_size 185 185 186 - (* LIST flags - RFC 9051 Section 7.3.1 *) 186 + (* LIST flags - RFC 9051 Section 7.3.1, RFC 5258 Section 3.4 *) 187 187 type list_flag = 188 188 | List_noinferiors 189 189 | List_noselect ··· 192 192 | List_subscribed 193 193 | List_haschildren 194 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 *) 195 197 | List_all 196 198 | List_archive 197 199 | List_drafts ··· 200 202 | List_sent 201 203 | List_trash 202 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 + } 203 254 204 255 (* Connection state - RFC 9051 Section 3 *) 205 256 type connection_state = ··· 334 385 else 335 386 None 336 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 + 337 437 (* === Commands - RFC 9051 Section 6 === *) 338 438 339 439 type command = ··· 351 451 | Rename of { old_name : mailbox_name; new_name : mailbox_name } 352 452 | Subscribe of mailbox_name 353 453 | Unsubscribe of mailbox_name 354 - | List of { reference : string; pattern : string } 454 + | List of list_command (** LIST command - RFC 9051, RFC 5258 LIST-EXTENDED *) 355 455 | Namespace 356 456 | Status of { mailbox : mailbox_name; items : status_item list } 357 457 | Append of { mailbox : mailbox_name; flags : flag list; date : string option; message : string } ··· 366 466 | Move of { sequence : sequence_set; mailbox : mailbox_name } 367 467 | Uid of uid_command 368 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}. *) 369 480 370 481 and uid_command = 371 482 | Uid_fetch of { sequence : sequence_set; items : fetch_item list } ··· 374 485 | Uid_move of { sequence : sequence_set; mailbox : mailbox_name } 375 486 | Uid_search of { charset : string option; criteria : search_key } 376 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. *) 377 490 378 491 type tagged_command = { 379 492 tag : string; ··· 419 532 | Bye of { code : response_code option; text : string } 420 533 | Capability_response of string list 421 534 | Enabled of string list 422 - | List_response of { flags : list_flag list; delimiter : char option; name : mailbox_name } 535 + | List_response of list_response_data (** RFC 9051, RFC 5258 LIST-EXTENDED *) 423 536 | Namespace_response of namespace_data 424 537 | Status_response of { mailbox : mailbox_name; items : (status_item * int64) list } 425 538 | Esearch of { tag : string option; uid : bool; results : esearch_result list } ··· 429 542 | Fetch_response of { seq : int; items : fetch_response_item list } 430 543 | Continuation of string option 431 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 245 | List_subscribed (** \Subscribed *) 246 246 | List_haschildren (** \HasChildren *) 247 247 | List_hasnochildren (** \HasNoChildren *) 248 + | List_nonexistent (** \NonExistent - RFC 5258 Section 3.4 *) 249 + | List_remote (** \Remote - RFC 5258 Section 3.4 *) 248 250 | List_all (** \All - special-use *) 249 251 | List_archive (** \Archive *) 250 252 | List_drafts (** \Drafts *) ··· 253 255 | List_sent (** \Sent *) 254 256 | List_trash (** \Trash *) 255 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 + } 256 296 257 297 (** {1 Connection State} 258 298 ··· 332 372 | Code_unknown_cte 333 373 | Code_other of string * string option 334 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 + 335 424 (** {1 Commands} 336 425 337 426 See {{:https://datatracker.ietf.org/doc/html/rfc9051#section-6}RFC 9051 Section 6}. *) ··· 351 440 | Rename of { old_name : mailbox_name; new_name : mailbox_name } 352 441 | Subscribe of mailbox_name 353 442 | Unsubscribe of mailbox_name 354 - | List of { reference : string; pattern : string } 443 + | List of list_command (** LIST command - RFC 9051, RFC 5258 LIST-EXTENDED *) 355 444 | Namespace 356 445 | Status of { mailbox : mailbox_name; items : status_item list } 357 446 | Append of { mailbox : mailbox_name; flags : flag list; date : string option; message : string } ··· 366 455 | Move of { sequence : sequence_set; mailbox : mailbox_name } 367 456 | Uid of uid_command 368 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}. *) 369 469 370 470 and uid_command = 371 471 | Uid_fetch of { sequence : sequence_set; items : fetch_item list } ··· 374 474 | Uid_move of { sequence : sequence_set; mailbox : mailbox_name } 375 475 | Uid_search of { charset : string option; criteria : search_key } 376 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. *) 377 479 378 480 type tagged_command = { 379 481 tag : string; ··· 421 523 | Bye of { code : response_code option; text : string } 422 524 | Capability_response of string list 423 525 | Enabled of string list 424 - | List_response of { flags : list_flag list; delimiter : char option; name : mailbox_name } 526 + | List_response of list_response_data (** RFC 9051, RFC 5258 LIST-EXTENDED *) 425 527 | Namespace_response of namespace_data 426 528 | Status_response of { mailbox : mailbox_name; items : (status_item * int64) list } 427 529 | Esearch of { tag : string option; uid : bool; results : esearch_result list } ··· 431 533 | Fetch_response of { seq : int; items : fetch_response_item list } 432 534 | Continuation of string option 433 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}. *) 434 547 435 548 (** {1 Utility Functions} *) 436 549
+1 -1
ocaml-imap/lib/imapd/read.ml
··· 870 870 sp r; 871 871 let name = astring r in 872 872 crlf r; 873 - List_response { flags; delimiter; name } 873 + List_response { flags; delimiter; name; extended = [] } 874 874 | "STATUS" -> 875 875 sp r; 876 876 let mailbox = astring r in
+172 -49
ocaml-imap/lib/imapd/server.ml
··· 13 13 (* Module alias to access Storage types without conflicting with functor parameter *) 14 14 module Storage_types = Storage 15 15 16 - (* Base capabilities per RFC 9051 *) 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 *) 17 19 let base_capabilities_pre_tls = [ 18 20 "IMAP4rev2"; 19 21 "IMAP4rev1"; (* For compatibility *) ··· 26 28 "ENABLE"; 27 29 "LITERAL+"; 28 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 *) 29 44 ] 30 45 31 46 let base_capabilities_post_tls = [ ··· 39 54 "ENABLE"; 40 55 "LITERAL+"; 41 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 *) 42 70 ] 43 71 44 72 (* Server configuration *) ··· 62 90 (Storage : Storage.STORAGE) 63 91 (Auth : Auth.AUTH) = struct 64 92 93 + (** Connection state with UTF-8 mode tracking. 94 + @see <https://datatracker.ietf.org/doc/html/rfc6855#section-3> RFC 6855 Section 3 *) 65 95 type connection_state = 66 96 | Not_authenticated 67 - | Authenticated of { username : string } 68 - | Selected of { username : string; mailbox : string; readonly : bool } 97 + | Authenticated of { username : string; utf8_enabled : bool } 98 + | Selected of { username : string; mailbox : string; readonly : bool; utf8_enabled : bool } 69 99 | Logout 70 100 71 101 (* Action returned by command handlers *) ··· 151 181 code = Some (Code_capability caps); 152 182 text = "LOGIN completed" 153 183 }); 154 - Authenticated { username } 184 + Authenticated { username; utf8_enabled = false } 155 185 end else begin 156 186 send_response flow (No { 157 187 tag = Some tag; ··· 170 200 171 201 (* Process SELECT/EXAMINE command - only valid in Authenticated/Selected state *) 172 202 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 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 177 207 in 178 208 match username with 179 209 | None -> ··· 191 221 code = None; 192 222 text = "Invalid mailbox name" 193 223 }); 194 - Authenticated { username } 224 + Authenticated { username; utf8_enabled } 195 225 end else 196 226 match Storage.select_mailbox t.storage ~username mailbox ~readonly with 197 227 | Error _ -> ··· 200 230 code = Some Code_nonexistent; 201 231 text = "Mailbox does not exist" 202 232 }); 203 - Authenticated { username } 233 + Authenticated { username; utf8_enabled } 204 234 | Ok mb_state -> 205 235 (* Send untagged responses *) 206 236 send_response flow (Flags_response mb_state.flags); ··· 227 257 code; 228 258 text = if readonly then "EXAMINE completed" else "SELECT completed" 229 259 }); 230 - Selected { username; mailbox; readonly } 260 + Selected { username; mailbox; readonly; utf8_enabled } 231 261 232 - (* Process LIST command *) 233 - let handle_list t flow tag ~reference ~pattern state = 262 + (* Process LIST command - RFC 9051, RFC 5258 LIST-EXTENDED *) 263 + let handle_list t flow tag list_cmd state = 234 264 let username = match state with 235 - | Authenticated { username } -> Some username 265 + | Authenticated { username; _ } -> Some username 236 266 | Selected { username; _ } -> Some username 237 267 | _ -> None 238 268 in ··· 245 275 }); 246 276 state 247 277 | Some username -> 248 - let mailboxes = Storage.list_mailboxes t.storage ~username ~reference ~pattern in 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 *) 249 288 List.iter (fun (mb : Storage_types.mailbox_info) -> 250 289 send_response flow (List_response { 251 290 flags = mb.flags; 252 291 delimiter = mb.delimiter; 253 292 name = mb.name; 293 + extended = []; (* Extended data can be populated based on return options *) 254 294 }) 255 - ) mailboxes; 295 + ) all_mailboxes; 256 296 send_response flow (Ok { tag = Some tag; code = None; text = "LIST completed" }); 257 297 state 258 298 ··· 264 304 state 265 305 end else 266 306 let username = match state with 267 - | Authenticated { username } -> Some username 307 + | Authenticated { username; _ } -> Some username 268 308 | Selected { username; _ } -> Some username 269 309 | _ -> None 270 310 in ··· 320 360 (* Process STORE command *) 321 361 let handle_store t flow tag ~sequence ~silent ~action ~flags state = 322 362 match state with 323 - | Selected { username; mailbox; readonly } -> 363 + | Selected { username; mailbox; readonly; _ } -> 324 364 if readonly then begin 325 365 send_response flow (No { tag = Some tag; code = None; text = "Mailbox is read-only" }); 326 366 state ··· 351 391 (* Process EXPUNGE command *) 352 392 let handle_expunge t flow tag state = 353 393 match state with 354 - | Selected { username; mailbox; readonly } -> 394 + | Selected { username; mailbox; readonly; _ } -> 355 395 if readonly then begin 356 396 send_response flow (No { tag = Some tag; code = None; text = "Mailbox is read-only" }); 357 397 state ··· 376 416 (* Process CLOSE command *) 377 417 let handle_close t flow tag state = 378 418 match state with 379 - | Selected { username; mailbox; readonly } -> 419 + | Selected { username; mailbox; readonly; utf8_enabled } -> 380 420 (* Silently expunge if not readonly *) 381 421 if not readonly then 382 422 ignore (Storage.expunge t.storage ~username ~mailbox); 383 423 send_response flow (Ok { tag = Some tag; code = None; text = "CLOSE completed" }); 384 - Authenticated { username } 424 + Authenticated { username; utf8_enabled } 385 425 | _ -> 386 426 send_response flow (Bad { 387 427 tag = Some tag; ··· 393 433 (* Process UNSELECT command *) 394 434 let handle_unselect flow tag state = 395 435 match state with 396 - | Selected { username; _ } -> 436 + | Selected { username; utf8_enabled; _ } -> 397 437 send_response flow (Ok { tag = Some tag; code = None; text = "UNSELECT completed" }); 398 - Authenticated { username } 438 + Authenticated { username; utf8_enabled } 399 439 | _ -> 400 440 send_response flow (Bad { 401 441 tag = Some tag; ··· 412 452 state 413 453 end else 414 454 let username = match state with 415 - | Authenticated { username } -> Some username 455 + | Authenticated { username; _ } -> Some username 416 456 | Selected { username; _ } -> Some username 417 457 | _ -> None 418 458 in ··· 448 488 state 449 489 end else 450 490 let username = match state with 451 - | Authenticated { username } -> Some username 491 + | Authenticated { username; _ } -> Some username 452 492 | Selected { username; _ } -> Some username 453 493 | _ -> None 454 494 in ··· 485 525 state 486 526 end else 487 527 let username = match state with 488 - | Authenticated { username } -> Some username 528 + | Authenticated { username; _ } -> Some username 489 529 | Selected { username; _ } -> Some username 490 530 | _ -> None 491 531 in ··· 567 607 state 568 608 end else 569 609 match state with 570 - | Selected { username; mailbox = src_mailbox; readonly } -> 610 + | Selected { username; mailbox = src_mailbox; readonly; _ } -> 571 611 if readonly then begin 572 612 send_response flow (No { tag = Some tag; code = None; text = "Mailbox is read-only" }); 573 613 state ··· 605 645 }); 606 646 state 607 647 608 - (* Process SEARCH command *) 609 - let handle_search t flow tag ~charset:_ ~criteria state = 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 = 610 652 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 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 625 678 | _ -> 626 679 send_response flow (Bad { 627 680 tag = Some tag; ··· 630 683 }); 631 684 state 632 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 + 633 719 (* Process APPEND command *) 634 720 let handle_append t flow tag ~mailbox ~flags ~date ~message state = 635 721 (* Security: Validate mailbox name *) ··· 638 724 state 639 725 end else 640 726 let username = match state with 641 - | Authenticated { username } -> Some username 727 + | Authenticated { username; _ } -> Some username 642 728 | Selected { username; _ } -> Some username 643 729 | _ -> None 644 730 in ··· 694 780 }); 695 781 state 696 782 697 - (* Process ENABLE command - RFC 5161 *) 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 *) 698 787 let handle_enable flow tag ~capabilities state = 699 788 match state with 700 - | Authenticated _ -> 789 + | Authenticated { username; utf8_enabled } -> 701 790 (* Filter to capabilities we actually support *) 702 791 let enabled = List.filter (fun cap -> 703 792 let cap_upper = String.uppercase_ascii cap in 704 793 cap_upper = "IMAP4REV2" || cap_upper = "UTF8=ACCEPT" 705 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 706 799 if List.length enabled > 0 then 707 800 send_response flow (Enabled enabled); 708 801 send_response flow (Ok { tag = Some tag; code = None; text = "ENABLE completed" }); 709 - state 802 + Authenticated { username; utf8_enabled = new_utf8_enabled } 710 803 | _ -> 711 804 send_response flow (Bad { 712 805 tag = Some tag; ··· 779 872 | Login { username; password } -> (handle_login t flow tag ~username ~password ~tls_active state, Continue) 780 873 | Select mailbox -> (handle_select t flow tag mailbox ~readonly:false state, Continue) 781 874 | 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) 875 + | List list_cmd -> (handle_list t flow tag list_cmd state, Continue) 783 876 | Status { mailbox; items } -> (handle_status t flow tag mailbox ~items state, Continue) 784 877 | Fetch { sequence; items } -> (handle_fetch t flow tag ~sequence ~items state, Continue) 785 878 | Store { sequence; silent; action; flags } -> (handle_store t flow tag ~sequence ~silent ~action ~flags state, Continue) ··· 792 885 | Copy { sequence; mailbox } -> (handle_copy t flow tag ~sequence ~mailbox state, Continue) 793 886 | Move { sequence; mailbox } -> (handle_move t flow tag ~sequence ~mailbox state, Continue) 794 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) 795 889 | Append { mailbox; flags; date; message } -> (handle_append t flow tag ~mailbox ~flags ~date ~message state, Continue) 796 890 | Namespace -> (handle_namespace flow tag state, Continue) 797 891 | Enable caps -> (handle_enable flow tag ~capabilities:caps state, Continue) ··· 816 910 | Authenticate _ -> 817 911 send_response flow (No { tag = Some tag; code = None; text = "Use LOGIN instead" }); 818 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) 819 939 820 940 (* Handle UID prefixed commands *) 821 941 and handle_uid_command t flow tag ~read_line_fn:_ uid_cmd state = ··· 834 954 | Uid_expunge _sequence -> 835 955 (* UID EXPUNGE only expunges messages in the given UID set *) 836 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 837 960 838 961 (* Maximum line length to prevent DoS attacks via memory exhaustion. 839 962 RFC 9051 Section 4 recommends supporting lines up to 8192 octets. *) ··· 990 1113 text = "LOGIN completed" 991 1114 }); 992 1115 (* Continue session as authenticated user *) 993 - let state = Authenticated { username } in 1116 + let state = Authenticated { username; utf8_enabled = false } in 994 1117 ignore (command_loop t flow state tls_active) 995 1118 end else begin 996 1119 (* Failed to drop privileges *)
+14 -2
ocaml-imap/lib/imapd/storage.ml
··· 60 60 flags : list_flag list; 61 61 } 62 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 + 63 73 (* Storage backend signature *) 64 74 module type STORAGE = sig 65 75 type t ··· 168 178 ensure_inbox user; 169 179 Hashtbl.fold (fun name _mb acc -> 170 180 if matches_pattern ~pattern name then 171 - { name; delimiter = Some '/'; flags = [] } :: acc 181 + let flags = get_special_use_for_mailbox name in 182 + { name; delimiter = Some '/'; flags } :: acc 172 183 else acc 173 184 ) user.mailboxes [] 174 185 ··· 700 711 let name = String.sub entry 1 (String.length entry - 1) in 701 712 let name = String.map (fun c -> if c = '.' then '/' else c) name in 702 713 if Memory_storage.matches_pattern ~pattern name then 703 - { name; delimiter = Some '/'; flags = [] } :: acc 714 + let flags = get_special_use_for_mailbox name in 715 + { name; delimiter = Some '/'; flags } :: acc 704 716 else acc 705 717 else acc 706 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 350 | Unsubscribe mailbox -> 351 351 W.string w "UNSUBSCRIBE "; 352 352 astring w mailbox 353 - | List { reference; pattern } -> 353 + | List list_cmd -> 354 354 W.string w "LIST "; 355 - astring w reference; 356 - sp w; 357 - astring w pattern 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 ')')) 358 399 | Namespace -> W.string w "NAMESPACE" 359 400 | Status { mailbox; items } -> 360 401 W.string w "STATUS "; ··· 449 490 search_key w criteria 450 491 | Uid_expunge set -> 451 492 W.string w "EXPUNGE "; 452 - sequence_set w set) 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) 453 504 | Id params -> 454 505 W.string w "ID "; 455 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 456 541 457 542 let command w ~tag cmd = 458 543 atom w tag;
+8
ocaml-imap/test/dune
··· 29 29 (test 30 30 (name test_client) 31 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 64 65 65 let test_parse_list () = 66 66 match parse_command "A008 LIST \"\" \"*\"\r\n" with 67 - | Ok { tag; command = List { reference; pattern } } -> 67 + | Ok { tag; command = List (List_basic { reference; pattern }) } -> 68 68 Alcotest.(check string) "tag" "A008" tag; 69 69 Alcotest.(check string) "reference" "" reference; 70 70 Alcotest.(check string) "pattern" "*" pattern
+449
ocaml-imap/test/test_read.ml
··· 81 81 let is_enabled = function Imap.Response.Enabled _ -> true | _ -> false 82 82 let is_id = function Imap.Response.Id _ -> true | _ -> false 83 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 84 86 85 87 let test_response_ok_tagged () = 86 88 let result = with_reader "A001 OK Success\r\n" (fun r -> Imap.Read.response r) in ··· 288 290 Alcotest.(check int) "untagged count" 2 (List.length untagged); 289 291 Alcotest.(check bool) "final is OK" true (is_ok final) 290 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 + 291 711 let () = 292 712 let open Alcotest in 293 713 run "imap_read" ··· 337 757 test_case "ENABLED" `Quick test_response_enabled; 338 758 test_case "ID" `Quick test_response_id; 339 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; 340 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; 341 790 ] ); 342 791 ]
+3 -2
ocaml-imap/test/test_server.ml
··· 66 66 (contains_substring ~substring:"STARTTLS" serialized) 67 67 68 68 let test_list_response () = 69 - let response = List_response { flags = []; delimiter = Some '/'; name = "INBOX" } in 69 + let response = List_response { flags = []; delimiter = Some '/'; name = "INBOX"; extended = [] } in 70 70 let serialized = response_to_string response in 71 71 Alcotest.(check bool) "has LIST" true 72 72 (contains_substring ~substring:"LIST" serialized); ··· 172 172 | Result.Ok cmd -> 173 173 Alcotest.(check string) "tag" "A005" cmd.tag; 174 174 (match cmd.command with 175 - | List { reference; pattern } -> 175 + | List (List_basic { reference; pattern }) -> 176 176 Alcotest.(check string) "reference" "" reference; 177 177 Alcotest.(check string) "pattern" "*" pattern 178 + | List (List_extended _) -> Alcotest.fail "Expected basic List command" 178 179 | _ -> Alcotest.fail "Expected List command") 179 180 | Result.Error msg -> Alcotest.fail ("Parse failed: " ^ msg) 180 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 195 let result = 196 196 serialize (fun w -> 197 197 Imap.Write.command w ~tag:"A014" 198 - (Imap.Command.Search { charset = None; criteria = Imap.Search.Unseen })) 198 + (Imap.Command.Search { charset = None; criteria = Imap.Search.Unseen; return_opts = None })) 199 199 in 200 200 Alcotest.(check string) "search" "A014 SEARCH UNSEEN\r\n" result 201 201 ··· 209 209 { 210 210 charset = None; 211 211 criteria = Imap.Search.And [ Imap.Search.Unseen; Imap.Search.From "alice@example.com" ]; 212 + return_opts = None; 212 213 })) 213 214 in 214 215 Alcotest.(check string) "search complex"
+75 -145
ocaml-jmap/lib/core/jmap_types.ml
··· 82 82 (** {1 Keyword Type} *) 83 83 84 84 module Keyword = struct 85 - (** RFC 8621 standard keywords *) 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. *) 86 92 type standard = [ 87 93 | `Seen 88 94 | `Flagged ··· 95 101 ] 96 102 97 103 (** 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 - ] 104 + type extended = Mail_flag.Keyword.extended 114 105 115 106 (** Apple Mail flag color keywords *) 116 - type flag_bits = [ 117 - | `MailFlagBit0 118 - | `MailFlagBit1 119 - | `MailFlagBit2 120 - ] 107 + type flag_bits = Mail_flag.Keyword.flag_bit 121 108 109 + (** Unified keyword type for JMAP. 110 + This is compatible with mail-flag's keyword type but excludes [`Deleted]. *) 122 111 type t = [ 123 112 | standard 124 113 | extended ··· 126 115 | `Custom of string 127 116 ] 128 117 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 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 159 123 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 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) 190 131 191 132 let pp ppf k = Format.pp_print_string ppf (to_string k) 192 133 193 134 (** Apple Mail flag colors *) 194 - type flag_color = [ 195 - | `Red 196 - | `Orange 197 - | `Yellow 198 - | `Green 199 - | `Blue 200 - | `Purple 201 - | `Gray 202 - ] 135 + type flag_color = Mail_flag.Keyword.flag_color 203 136 204 137 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 138 + let mail_flag_keywords = List.map to_mail_flag keywords in 139 + Mail_flag.Keyword.flag_color_of_keywords mail_flag_keywords 218 140 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] 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 227 144 end 228 145 229 146 (** {1 Mailbox Role Type} *) 230 147 231 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 + 232 152 (** RFC 8621 standard roles *) 233 153 type standard = [ 234 154 | `Inbox ··· 250 170 | `Memos 251 171 ] 252 172 173 + (** JMAP role type - corresponds to mail-flag's special_use type *) 253 174 type t = [ 254 175 | standard 255 176 | extended 256 177 | `Custom of string 257 178 ] 258 179 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 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 276 195 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" 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 293 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) 294 224 295 225 let pp ppf r = Format.pp_print_string ppf (to_string r) 296 226 end
+1 -1
ocaml-jmap/lib/dune
··· 3 3 (library 4 4 (name jmap) 5 5 (public_name jmap) 6 - (libraries jsont json-pointer ptime) 6 + (libraries jsont json-pointer ptime mail-flag) 7 7 (modules 8 8 ; Core unified interface 9 9 jmap