+1
stack/.gitignore
+1
stack/.gitignore
···
···
+2
-1
stack/cacheio/cacheio.opam
+2
-1
stack/cacheio/cacheio.opam
+2
-1
stack/cacheio/dune-project
+2
-1
stack/cacheio/dune-project
+1
-1
stack/cacheio/lib/dune
+1
-1
stack/cacheio/lib/dune
+23
-1
stack/cacheio/lib/entry.ml
+23
-1
stack/cacheio/lib/entry.ml
···
+6
-1
stack/cacheio/lib/entry.mli
+6
-1
stack/cacheio/lib/entry.mli
+31
-1
stack/cacheio/lib/flags.ml
+31
-1
stack/cacheio/lib/flags.ml
···
+6
-1
stack/cacheio/lib/flags.mli
+6
-1
stack/cacheio/lib/flags.mli
+26
-1
stack/cacheio/lib/stats.ml
+26
-1
stack/cacheio/lib/stats.ml
···
+6
-1
stack/cacheio/lib/stats.mli
+6
-1
stack/cacheio/lib/stats.mli
+1
-1
stack/immich/dune
+1
-1
stack/immich/dune
+2
-1
stack/immich/dune-project
+2
-1
stack/immich/dune-project
+44
-36
stack/immich/immich.ml
+44
-36
stack/immich/immich.ml
·········
·········
+2
stack/immich/immich.mli
+2
stack/immich/immich.mli
······
+2
-1
stack/immich/immich.opam
+2
-1
stack/immich/immich.opam
+42
-37
stack/karakeep/bin/karakeep_cli.ml
+42
-37
stack/karakeep/bin/karakeep_cli.ml
···············
···············
+1
-1
stack/karakeep/dune
+1
-1
stack/karakeep/dune
-1
stack/karakeep/dune-project
-1
stack/karakeep/dune-project
+313
-271
stack/karakeep/karakeep.ml
+313
-271
stack/karakeep/karakeep.ml
···························failwith (Fmt.str "Failed to create bookmark. HTTP error: %d. Details: %s" status_code error_body)
······+Log.debug (fun m -> m "Successfully parsed format 1: %d bookmarks" (List.length response.data));+Log.debug (fun m -> m "Successfully parsed format 2: %d bookmarks" (List.length response.data));··················+| Error e -> failwith (Fmt.str "Failed to parse created bookmark: %s" (Jsont.Error.to_string e))···failwith (Fmt.str "Failed to create bookmark. HTTP error: %d. Details: %s" status_code error_body)
+23
-28
stack/karakeep/karakeep.mli
+23
-28
stack/karakeep/karakeep.mli
······
······
-1
stack/karakeep/karakeep.opam
-1
stack/karakeep/karakeep.opam
+8
-4
stack/peertubee/bin/peertubee_cli.ml
+8
-4
stack/peertubee/bin/peertubee_cli.ml
······
······
+1
-1
stack/peertubee/dune
+1
-1
stack/peertubee/dune
-1
stack/peertubee/dune-project
-1
stack/peertubee/dune-project
+85
-55
stack/peertubee/peertubee.ml
+85
-55
stack/peertubee/peertubee.ml
············
······+|> Jsont.Object.opt_mem "originallyPublishedAt" Rfc3339.jsont ~enc:video_originally_published_at······
+33
-5
stack/peertubee/peertubee.mli
+33
-5
stack/peertubee/peertubee.mli
···
···
-1
stack/peertubee/peertubee.opam
-1
stack/peertubee/peertubee.opam
+1
-1
stack/requests/bin/dune
+1
-1
stack/requests/bin/dune
+12
-3
stack/requests/bin/ocurl.ml
+12
-3
stack/requests/bin/ocurl.ml
···
···
-1
stack/requests/dune-project
-1
stack/requests/dune-project
+28
-150
stack/requests/lib/body.ml
+28
-150
stack/requests/lib/body.ml
···
···+let content = match Jsont_bytesrw.encode_string' ~format:Jsont.Minify Jsont.json json_value with+let content = match Jsont_bytesrw.encode_string' ~format:Jsont.Minify Jsont.json json_value with
+14
-31
stack/requests/lib/body.mli
+14
-31
stack/requests/lib/body.mli
···
···
+98
-30
stack/requests/lib/cache.ml
+98
-30
stack/requests/lib/cache.ml
······
······+let make_cacheio_stats total_entries total_bytes expired_entries pinned_entries temporary_entries =+let make memory_cache_entries cache_backend enabled cache_get_requests cache_range_requests cacheio_stats =+{ memory_cache_entries; cache_backend; enabled; cache_get_requests; cache_range_requests; cacheio_stats }
+2
-3
stack/requests/lib/dune
+2
-3
stack/requests/lib/dune
-1
stack/requests/requests.opam
-1
stack/requests/requests.opam
-18
stack/requests/test/dune
-18
stack/requests/test/dune
···
···
-52
stack/requests/test/test_connection_pool.ml
-52
stack/requests/test/test_connection_pool.ml
···
···
-899
stack/requests/test/test_requests.ml
-899
stack/requests/test/test_requests.ml
···-let response = Requests.request req ~follow_redirects:false ~method_:`GET (base_url ^ "/redirect") in
···
+2
-1
stack/requests_json_api/dune-project
+2
-1
stack/requests_json_api/dune-project
+1
-1
stack/requests_json_api/lib/dune
+1
-1
stack/requests_json_api/lib/dune
+83
-15
stack/requests_json_api/lib/requests_json_api.ml
+83
-15
stack/requests_json_api/lib/requests_json_api.ml
···
···
+50
-12
stack/requests_json_api/lib/requests_json_api.mli
+50
-12
stack/requests_json_api/lib/requests_json_api.mli
···-val get_json_exn : (_ Eio.Time.clock, _ Eio.Net.t) Requests.t -> string -> (Ezjsonm.value -> 'a) -> 'a-val get_json : (_ Eio.Time.clock, _ Eio.Net.t) Requests.t -> string -> (Ezjsonm.value -> 'a) ->-val post_json : (_ Eio.Time.clock, _ Eio.Net.t) Requests.t -> string -> Ezjsonm.value -> Requests.Response.t-val post_json_exn : (_ Eio.Time.clock, _ Eio.Net.t) Requests.t -> string -> Ezjsonm.value -> string-val post_json_result : (_ Eio.Time.clock, _ Eio.Net.t) Requests.t -> string -> Ezjsonm.value ->
···+val post_json : (_ Eio.Time.clock, _ Eio.Net.t) Requests.t -> string -> 'a Jsont.t -> 'a -> Requests.Response.t+(** [post_json session url codec value] encodes [value] using the Jsont codec and POSTs it to the URL.+val post_json_exn : (_ Eio.Time.clock, _ Eio.Net.t) Requests.t -> string -> 'a Jsont.t -> 'a -> string+val post_json_result : (_ Eio.Time.clock, _ Eio.Net.t) Requests.t -> string -> 'a Jsont.t -> 'a ->+(** [post_json_decode_exn session url ~req req_value ~resp] encodes [req_value] using the [req] codec,+val put_json_exn : (_ Eio.Time.clock, _ Eio.Net.t) Requests.t -> string -> 'a Jsont.t -> 'a -> string+val patch_json_exn : (_ Eio.Time.clock, _ Eio.Net.t) Requests.t -> string -> 'a Jsont.t -> 'a -> string
+2
-1
stack/requests_json_api/requests_json_api.opam
+2
-1
stack/requests_json_api/requests_json_api.opam
+1
-1
stack/river/bin/dune
+1
-1
stack/river/bin/dune
+36
-38
stack/river/bin/river_cli.ml
+36
-38
stack/river/bin/river_cli.ml
···
···
+1
-2
stack/river/dune-project
+1
-2
stack/river/dune-project
+1
-1
stack/river/lib/dune
+1
-1
stack/river/lib/dune
+264
-189
stack/river/lib/river_store.ml
+264
-189
stack/river/lib/river_store.ml
······························-| Some t -> List.filter (fun e -> Ptime.is_later e.updated ~than:t || Ptime.equal e.updated t) entries-| Some t -> List.filter (fun e -> Ptime.is_earlier e.updated ~than:t || Ptime.equal e.updated t) entries························let feed_id = Uri.of_string ("urn:river:archive:" ^ (Digest.string feed_url |> Digest.to_hex)) in···-Format.fprintf fmt "Link: %s@," (match entry.link with Some u -> Uri.to_string u | None -> "none");···
············+Some (Uri.to_string (List.find (fun l -> l.Syndic.Atom.rel = Syndic.Atom.Alternate) atom_entry.links).href)·······································+let updated = Jsonfeed.Item.date_modified item |> Option.value ~default:entry.meta.stored_at in···let feed_id = Uri.of_string ("urn:river:archive:" ^ (Digest.string feed_url |> Digest.to_hex)) in···+Format.fprintf fmt "Title: %s@," (Jsonfeed.Item.title item |> Option.value ~default:"(no title)");···
+13
-38
stack/river/lib/river_store.mli
+13
-38
stack/river/lib/river_store.mli
···
···
+1
-2
stack/river/river.opam
+1
-2
stack/river/river.opam
+1
-1
stack/typesense-client/dune
+1
-1
stack/typesense-client/dune
+2
-1
stack/typesense-client/dune-project
+2
-1
stack/typesense-client/dune-project
+2
-1
stack/typesense-client/typesense-client.opam
+2
-1
stack/typesense-client/typesense-client.opam
+175
-94
stack/typesense-client/typesense_client.ml
+175
-94
stack/typesense-client/typesense_client.ml
·········-(match Requests_json_api.parse_json_result (parse_search_response collection_name) response_str with······-let body = Ezjsonm.dict [("searches", Ezjsonm.list (fun x -> x) searches)] |> Ezjsonm.value_to_string inlet combine_multisearch_results (multisearch_resp : multisearch_response) ?(limit=10) ?(offset=0) () =···
···············let combine_multisearch_results (multisearch_resp : multisearch_response) ?(limit=10) ?(offset=0) () =···
+12
-5
stack/typesense-client/typesense_client.mli
+12
-5
stack/typesense-client/typesense_client.mli
······
······
+1
-1
stack/zotero-translation/dune
+1
-1
stack/zotero-translation/dune
+2
-1
stack/zotero-translation/dune-project
+2
-1
stack/zotero-translation/dune-project
+2
-1
stack/zotero-translation/zotero-translation.opam
+2
-1
stack/zotero-translation/zotero-translation.opam
+105
-58
stack/zotero-translation/zotero_translation.ml
+105
-58
stack/zotero-translation/zotero_translation.ml
···(* From the ZTS source code: https://github.com/zotero/translation-server/blob/master/src/formats.js···-failwith "Zotero_translation.v is deprecated. Use Zotero_translation.create ~sw ~env base_uri instead"············let f = Bibtex.fields bib |> Bibtex.SM.bindings |> List.map (fun (k,v) -> k, (unescape_bibtex v)) in-let authors m = add_if_present "author" (fun j -> J.get_list J.get_string j |> String.concat " and ") m inlet fields = authors fields |> string "title" |> string "doi" |> string "month" |> string "year" |> string "url" in···
···(* From the ZTS source code: https://github.com/zotero/translation-server/blob/master/src/formats.js···············let f = Bibtex.fields bib |> Bibtex.SM.bindings |> List.map (fun (k,v) -> k, (unescape_bibtex v)) in+let v = List.fold_left (fun acc (k,v) -> ((k, Jsont.Meta.none), Jsont.String (v, Jsont.Meta.none))::acc)+(match keywords with [] -> None | _ -> Some (Jsont.Array (keywords, Jsont.Meta.none))) json' in+let authors m = add_if_present "author" (fun j -> get_list get_string j |> String.concat " and ") m inlet fields = authors fields |> string "title" |> string "doi" |> string "month" |> string "year" |> string "url" in···
+8
-16
stack/zotero-translation/zotero_translation.mli
+8
-16
stack/zotero-translation/zotero_translation.mli
···val resolve_doi: ([> float Eio.Time.clock_ty ] Eio.Resource.t, [> [> `Generic ] Eio.Net.ty ] Eio.Resource.t) t ->val resolve_url: ([> float Eio.Time.clock_ty ] Eio.Resource.t, [> [> `Generic ] Eio.Net.ty ] Eio.Resource.t) t ->val search_id: ([> float Eio.Time.clock_ty ] Eio.Resource.t, [> [> `Generic ] Eio.Net.ty ] Eio.Resource.t) t ->val export: ([> float Eio.Time.clock_ty ] Eio.Resource.t, [> [> `Generic ] Eio.Net.ty ] Eio.Resource.t) t ->val json_of_doi : ([> float Eio.Time.clock_ty ] Eio.Resource.t, [> [> `Generic ] Eio.Net.ty ] Eio.Resource.t) t ->
···val resolve_doi: ([> float Eio.Time.clock_ty ] Eio.Resource.t, [> [> `Generic ] Eio.Net.ty ] Eio.Resource.t) t ->val resolve_url: ([> float Eio.Time.clock_ty ] Eio.Resource.t, [> [> `Generic ] Eio.Net.ty ] Eio.Resource.t) t ->val search_id: ([> float Eio.Time.clock_ty ] Eio.Resource.t, [> [> `Generic ] Eio.Net.ty ] Eio.Resource.t) t ->val export: ([> float Eio.Time.clock_ty ] Eio.Resource.t, [> [> `Generic ] Eio.Net.ty ] Eio.Resource.t) t ->val json_of_doi : ([> float Eio.Time.clock_ty ] Eio.Resource.t, [> [> `Generic ] Eio.Net.ty ] Eio.Resource.t) t ->
+217
stack/zulip/ARCHITECTURE.md
+217
stack/zulip/ARCHITECTURE.md
···
···+The Zulip OCaml library follows a clean, layered architecture that separates protocol types, encoding concerns, and HTTP communication.+|> Jsont.Object.mem "history_public_to_subscribers" Jsont.bool ~enc:history_public_to_subscribers+The `Encode` module provides clean utilities for converting between OCaml types and wire formats:
-689
stack/zulip/CLAUDE.md
-689
stack/zulip/CLAUDE.md
···-The library follows OCaml best practices with abstract types (`type t`) per module, comprehensive constructors/accessors, and proper pretty printers. Each core concept gets its own module with a clean interface.-val edit : Client.t -> message_id:int -> ?content:string -> ?topic:string -> unit -> (unit, Error.t) result-val get_events : t -> Client.t -> ?last_event_id:int -> unit -> (Event.t list, Error.t) result-- https://github.com/zulip/python-zulip-api/blob/main/zulip_botserver/zulip_botserver/server.py-Bot handlers require direct access to the EIO environment for legitimate I/O operations beyond HTTP requests to Zulip:-Based on analysis, the current EIO environment plumbing is **essential** and should be cleaned up:-val handle_message : t -> #Eio.Env.t -> Message_context.t -> (Response.t, Zulip.Error.t) result-This design maintains flexibility for real-world bot functionality while providing clean, type-safe interfaces.-- Bot framework: https://github.com/zulip/python-zulip-api/blob/main/zulip_bots/zulip_bots/lib.py-- Bot server: https://github.com/zulip/python-zulip-api/blob/main/zulip_botserver/zulip_botserver/server.py-The design adapts these Python patterns to idiomatic OCaml with abstract types, proper error handling, and EIO's structured concurrency for robust, type-safe Zulip integration.
···
+2
-2
stack/zulip/dune-project
+2
-2
stack/zulip/dune-project
+2
-5
stack/zulip/examples/example.ml
+2
-5
stack/zulip/examples/example.ml
···
+4
-3
stack/zulip/examples/test_client.ml
+4
-3
stack/zulip/examples/test_client.ml
···
···
+25
-33
stack/zulip/lib/zulip/lib/channel.ml
+25
-33
stack/zulip/lib/zulip/lib/channel.ml
···-Error (Zulip_types.create_error ~code:(Other "json_parse_error") ~msg:"Channel JSON must be an object" ())-Error (Zulip_types.create_error ~code:(Other "json_parse_error") ~msg:("Channel JSON parsing failed: " ^ Printexc.to_string exn) ())
···+|> Jsont.Object.mem "history_public_to_subscribers" Jsont.bool ~enc:history_public_to_subscribers
+17
-6
stack/zulip/lib/zulip/lib/channel.mli
+17
-6
stack/zulip/lib/zulip/lib/channel.mli
···
···
+53
-43
stack/zulip/lib/zulip/lib/channels.ml
+53
-43
stack/zulip/lib/zulip/lib/channels.ml
···-| _ -> Error (Zulip_types.create_error ~code:(Other "api_error") ~msg:"Invalid streams response format" ()))-| _ -> Error (Zulip_types.create_error ~code:(Other "api_error") ~msg:"Streams response must be an object" ()))-match Client.request client ~method_:`POST ~path:"/api/v1/users/me/subscriptions" ~body () with-match Client.request client ~method_:`DELETE ~path:"/api/v1/users/me/subscriptions" ~body () with
···+match Client.request client ~method_:`POST ~path:"/api/v1/users/me/subscriptions" ~body ~content_type () with+match Client.request client ~method_:`DELETE ~path:"/api/v1/users/me/subscriptions" ~body ~content_type () with
+16
-14
stack/zulip/lib/zulip/lib/client.ml
+16
-14
stack/zulip/lib/zulip/lib/client.ml
······
······
+1
-1
stack/zulip/lib/zulip/lib/dune
+1
-1
stack/zulip/lib/zulip/lib/dune
+56
stack/zulip/lib/zulip/lib/encode.ml
+56
stack/zulip/lib/zulip/lib/encode.ml
···
···
+21
stack/zulip/lib/zulip/lib/encode.mli
+21
stack/zulip/lib/zulip/lib/encode.mli
···
···
+35
-24
stack/zulip/lib/zulip/lib/event.ml
+35
-24
stack/zulip/lib/zulip/lib/event.ml
···-Error (Zulip_types.create_error ~code:(Other "json_parse_error") ~msg:"Event JSON must be an object" ())-Error (Zulip_types.create_error ~code:(Other "json_parse_error") ~msg:("Event JSON parsing failed: " ^ Printexc.to_string exn) ())
···
+79
-42
stack/zulip/lib/zulip/lib/event_queue.ml
+79
-42
stack/zulip/lib/zulip/lib/event_queue.ml
···-| _ -> Error (Zulip_types.create_error ~code:(Other "api_error") ~msg:"Invalid register response: missing queue_id" ()))-| _ -> Error (Zulip_types.create_error ~code:(Other "api_error") ~msg:"Register response must be an object" ()))-Error (Zulip_types.create_error ~code:(Other "api_error") ~msg:"Invalid events response format" ())-| _ -> Error (Zulip_types.create_error ~code:(Other "api_error") ~msg:"Events response must be an object" ()))
···+| Some types -> Log.debug (fun m -> m "Registering with event_types: %s" (String.concat "," types))+match Client.request client ~method_:`POST ~path:"/api/v1/register" ~body ~content_type () with
-206
stack/zulip/lib/zulip/lib/jsonu.ml
-206
stack/zulip/lib/zulip/lib/jsonu.ml
···-| Some _ -> Error (Zulip_types.create_error ~code:(Other "json_type_error") ~msg:(Printf.sprintf "Field '%s' is not a string" key) ())-| None -> Error (Zulip_types.create_error ~code:(Other "json_missing_field") ~msg:(Printf.sprintf "Field '%s' not found" key) ())-| None -> Error (Zulip_types.create_error ~code:(Other "json_missing_field") ~msg:(Printf.sprintf "Field '%s' not found" key) ())-| _ -> Error (Zulip_types.create_error ~code:(Other "json_type_error") ~msg:(Printf.sprintf "Field '%s' is not a valid float" key) ()))-| Some _ -> Error (Zulip_types.create_error ~code:(Other "json_type_error") ~msg:(Printf.sprintf "Field '%s' is not a float" key) ())-| None -> Error (Zulip_types.create_error ~code:(Other "json_missing_field") ~msg:(Printf.sprintf "Field '%s' not found" key) ())-| Some _ -> Error (Zulip_types.create_error ~code:(Other "json_type_error") ~msg:(Printf.sprintf "Field '%s' is not a boolean" key) ())-| None -> Error (Zulip_types.create_error ~code:(Other "json_missing_field") ~msg:(Printf.sprintf "Field '%s' not found" key) ())-| Some _ -> Error (Zulip_types.create_error ~code:(Other "json_type_error") ~msg:(Printf.sprintf "Field '%s' is not an object" key) ())-| None -> Error (Zulip_types.create_error ~code:(Other "json_missing_field") ~msg:(Printf.sprintf "Field '%s' not found" key) ())-| Some _ -> Error (Zulip_types.create_error ~code:(Other "json_type_error") ~msg:(Printf.sprintf "Field '%s' is not an array" key) ())-| None -> Error (Zulip_types.create_error ~code:(Other "json_missing_field") ~msg:(Printf.sprintf "Field '%s' not found" key) ())-| _ -> Error (Zulip_types.create_error ~code:(Other "json_type_error") ~msg:(Printf.sprintf "%s: expected JSON object" context) ())-| _ -> Error (Zulip_types.create_error ~code:(Other "json_type_error") ~msg:(Printf.sprintf "%s: expected JSON array" context) ())-Zulip_types.create_error ~code:(Other "json_missing_field") ~msg:(Printf.sprintf "Required field '%s' not found" field) ()-Zulip_types.create_error ~code:(Other "json_type_error") ~msg:(Printf.sprintf "Field '%s' type mismatch: expected %s" field expected) ()-| Failure msg -> Error (Zulip_types.create_error ~code:(Other "json_parse_error") ~msg:(Printf.sprintf "%s: %s" context msg) ())-| exn -> Error (Zulip_types.create_error ~code:(Other "json_parse_error") ~msg:(Printf.sprintf "%s: %s" context (Printexc.to_string exn)) ())
···
-117
stack/zulip/lib/zulip/lib/jsonu.mli
-117
stack/zulip/lib/zulip/lib/jsonu.mli
···-val get_object : (string * json) list -> string -> ((string * json) list, Zulip_types.zerror) result-val with_object : string -> ((string * json) list -> ('a, Zulip_types.zerror) result) -> json -> ('a, Zulip_types.zerror) result-val with_array : string -> (json -> ('a, Zulip_types.zerror) result) -> json -> ('a list, Zulip_types.zerror) result-val parse_with_error : string -> (unit -> ('a, Zulip_types.zerror) result) -> ('a, Zulip_types.zerror) result
···
-144
stack/zulip/lib/zulip/lib/jsonu_syntax.ml
-144
stack/zulip/lib/zulip/lib/jsonu_syntax.ml
···-| None -> Error (Zulip_types.create_error ~code:(Other "missing_field") ~msg:(Printf.sprintf "Required field '%s' not found" name) ())-with _ -> Error (Zulip_types.create_error ~code:(Other "type_error") ~msg:"Expected integer" ()))-with _ -> Error (Zulip_types.create_error ~code:(Other "type_error") ~msg:"Expected float" ()))-| Error e -> Error (Zulip_types.create_error ~code:(Zulip_types.error_code e) ~msg:(Printf.sprintf "%s: %s" ctx (Zulip_types.error_message e)) ())
···
-96
stack/zulip/lib/zulip/lib/jsonu_syntax.mli
-96
stack/zulip/lib/zulip/lib/jsonu_syntax.mli
···-val ( and+++ ) : ('a * 'b * 'c, 'e) result -> ('d, 'e) result -> ('a * 'b * 'c * 'd, 'e) result-val ( and++++ ) : ('a * 'b * 'c * 'd, 'e) result -> ('f, 'e) result -> ('a * 'b * 'c * 'd * 'f, 'e) result-val field_opt : (string * json) list -> string -> 'a parser -> ('a option, Zulip_types.zerror) result-val field_or : (string * json) list -> string -> 'a parser -> 'a -> ('a, Zulip_types.zerror) result-val traverse : ('a -> ('b, Zulip_types.zerror) result) -> 'a list -> ('b list, Zulip_types.zerror) result
···
+35
-21
stack/zulip/lib/zulip/lib/message.ml
+35
-21
stack/zulip/lib/zulip/lib/message.ml
···
···
+18
-9
stack/zulip/lib/zulip/lib/message.mli
+18
-9
stack/zulip/lib/zulip/lib/message.mli
······
······
+20
-8
stack/zulip/lib/zulip/lib/message_response.ml
+20
-8
stack/zulip/lib/zulip/lib/message_response.ml
···-let automatic_new_visibility_policy = Jsonu.get_string_opt fields "automatic_new_visibility_policy" in
···+|> Jsont.Object.opt_mem "automatic_new_visibility_policy" Jsont.string ~enc:automatic_new_visibility_policy
+5
stack/zulip/lib/zulip/lib/message_response.mli
+5
stack/zulip/lib/zulip/lib/message_response.mli
···
+15
-62
stack/zulip/lib/zulip/lib/messages.ml
+15
-62
stack/zulip/lib/zulip/lib/messages.ml
···match Client.request client ~method_:`PATCH ~path:("/api/v1/messages/" ^ string_of_int message_id) ~params () with···-Buffer.add_string body ("Content-Disposition: form-data; name=\"file\"; filename=\"" ^ basename ^ "\"\r\n");-| _ -> Error (Zulip_types.create_error ~code:(Zulip_types.Other "upload_error") ~msg:"Failed to parse upload response" ()))
···match Client.request client ~method_:`PATCH ~path:("/api/v1/messages/" ^ string_of_int message_id) ~params () with···
+25
-18
stack/zulip/lib/zulip/lib/user.ml
+25
-18
stack/zulip/lib/zulip/lib/user.ml
···
···
+18
-7
stack/zulip/lib/zulip/lib/user.mli
+18
-7
stack/zulip/lib/zulip/lib/user.mli
······
······
+32
-28
stack/zulip/lib/zulip/lib/users.ml
+32
-28
stack/zulip/lib/zulip/lib/users.ml
···-| _ -> Error (Zulip_types.create_error ~code:(Other "api_error") ~msg:"Invalid users response format" ()))-| _ -> Error (Zulip_types.create_error ~code:(Other "api_error") ~msg:"Users response must be an object" ()))···
······
+1
-5
stack/zulip/lib/zulip/lib/zulip.ml
+1
-5
stack/zulip/lib/zulip/lib/zulip.ml
+2
-10
stack/zulip/lib/zulip/lib/zulip.mli
+2
-10
stack/zulip/lib/zulip/lib/zulip.mli
···
+32
-15
stack/zulip/lib/zulip/lib/zulip_types.ml
+32
-15
stack/zulip/lib/zulip/lib/zulip_types.ml
···-type json = [`Null | `Bool of bool | `Float of float | `String of string | `A of json list | `O of (string * json) list]···
······
+6
-1
stack/zulip/lib/zulip/lib/zulip_types.mli
+6
-1
stack/zulip/lib/zulip/lib/zulip_types.mli
···-type json = [`Null | `Bool of bool | `Float of float | `String of string | `A of json list | `O of (string * json) list]···
······
+6
-5
stack/zulip/lib/zulip_bot/lib/bot_runner.ml
+6
-5
stack/zulip/lib/zulip_bot/lib/bot_runner.ml
······
······
+81
-29
stack/zulip/lib/zulip_bot/lib/bot_storage.ml
+81
-29
stack/zulip/lib/zulip_bot/lib/bot_storage.ml
·····················
·····················
+1
-1
stack/zulip/lib/zulip_bot/lib/dune
+1
-1
stack/zulip/lib/zulip_bot/lib/dune
+277
-88
stack/zulip/lib/zulip_bot/lib/message.ml
+277
-88
stack/zulip/lib/zulip_bot/lib/message.ml
··················-let submessages = Zulip.Jsonu.get_array_opt fields "submessages" |> Option.value ~default:[] in-Log.warn (fun m -> m "Failed to parse user in display_recipient: %s" (Zulip.error_message err));···
···············+k <> "emoji_name" && k <> "emoji_code" && k <> "reaction_type" && k <> "user_id" && k <> "user"···+(match (get_int "id", get_int "sender_id", get_string "sender_email", get_string "sender_full_name") with+| _ -> Error (Zulip.create_error ~code:(Other "json_parse_error") ~msg:"Missing required message fields" ()))+| _ -> Error (Zulip.create_error ~code:(Other "json_parse_error") ~msg:"Expected JSON object for message" ())+Log.warn (fun m -> m "Failed to parse user in display_recipient: %s" (Zulip.error_message err));···
+10
stack/zulip/lib/zulip_bot/lib/message.mli
+10
stack/zulip/lib/zulip_bot/lib/message.mli
······
······
+30
stack/zulip/zulip.opam
+30
stack/zulip/zulip.opam
···
···
+26
stack/zulip/zulip_bot.opam
+26
stack/zulip/zulip_bot.opam
···
···
+29
stack/zulip/zulip_botserver.opam
+29
stack/zulip/zulip_botserver.opam
···
···