My agentic slop goes here. Not intended for anyone else!

Restore working requests implementation with existential types

The merge conflict resolution during rebase incorrectly changed Requests.t
from a parameterized type to a monomorphic type:
- Before: type ('clock, 'net) t
- After (broken): type t

This broke all libraries that depend on requests (river, requests_json_api,
zotero-translation, zulip) as they expect the parameterized type to properly
abstract over Eio's clock and network types.

Restored these files from the original branch (324a64b):
- requests/lib/requests.ml
- requests/lib/requests.mli
- requests_json_api/lib/requests_json_api.ml
- requests_json_api/lib/requests_json_api.mli
- zotero-translation/zotero_translation.ml
- zotero-translation/zotero_translation.mli
- zulip/lib/zulip/lib/client.ml
- zulip/lib/zulip/lib/client.mli

River, requests, zulip, and all dependent libraries now build successfully.

Changed files
+78 -95
stack
requests
requests_json_api
zotero-translation
zulip
lib
zulip
lib
+31 -39
stack/requests/lib/requests.ml
···
(* Main API - Session functionality with connection pooling *)
-
(* Internal session type with existential type parameters *)
-
type ('clock, 'net) session = {
+
type ('clock, 'net) t = {
sw : Eio.Switch.t;
clock : 'clock;
net : 'net;
···
mutable total_time : float;
mutable retries_count : int;
}
-
-
(* Public type that hides the existential type parameters.
-
We constrain the existentials to ensure they satisfy the requirements
-
of the internal functions. *)
-
type t = T : ([> float Eio.Time.clock_ty] Eio.Resource.t,
-
[> [> `Generic] Eio.Net.ty] Eio.Resource.t) session -> t
let create
~sw
···
Cookeio.create ()
in
-
T {
+
{
sw;
clock;
net;
···
retries_count = 0;
}
-
let set_default_header (T t) key value =
-
T { t with default_headers = Headers.set key value t.default_headers }
+
let set_default_header t key value =
+
{ t with default_headers = Headers.set key value t.default_headers }
-
let remove_default_header (T t) key =
-
T { t with default_headers = Headers.remove key t.default_headers }
+
let remove_default_header t key =
+
{ t with default_headers = Headers.remove key t.default_headers }
-
let set_auth (T t) auth =
+
let set_auth t auth =
Log.debug (fun m -> m "Setting authentication method");
-
T { t with auth = Some auth }
+
{ t with auth = Some auth }
-
let clear_auth (T t) =
+
let clear_auth t =
Log.debug (fun m -> m "Clearing authentication");
-
T { t with auth = None }
+
{ t with auth = None }
-
let set_timeout (T t) timeout =
+
let set_timeout t timeout =
Log.debug (fun m -> m "Setting timeout: %a" Timeout.pp timeout);
-
T { t with timeout }
+
{ t with timeout }
-
let set_retry (T t) config =
+
let set_retry t config =
Log.debug (fun m -> m "Setting retry config: max_retries=%d" config.Retry.max_retries);
-
T { t with retry = Some config }
+
{ t with retry = Some config }
-
let cookies (T t) = t.cookie_jar
-
let clear_cookies (T t) = Cookeio.clear t.cookie_jar
+
let cookies t = t.cookie_jar
+
let clear_cookies t = Cookeio.clear t.cookie_jar
(* Internal request function using connection pools *)
let make_request_internal t ?headers ?body ?auth ?timeout ?follow_redirects ?max_redirects ~method_ url =
···
response
(* Public request function - executes synchronously *)
-
let request (T t) ?headers ?body ?auth ?timeout ?follow_redirects ?max_redirects ~method_ url =
-
(* Keep t in scope to preserve existential types *)
+
let request t ?headers ?body ?auth ?timeout ?follow_redirects ?max_redirects ~method_ url =
make_request_internal t ?headers ?body ?auth ?timeout
?follow_redirects ?max_redirects ~method_ url
(* Convenience methods *)
-
let get (T t) ?headers ?auth ?timeout ?params url =
+
let get t ?headers ?auth ?timeout ?params url =
let url = match params with
| Some p ->
let uri = Uri.of_string url in
···
Uri.to_string uri
| None -> url
in
-
make_request_internal t ?headers ?auth ?timeout ~method_:`GET url
+
request t ?headers ?auth ?timeout ~method_:`GET url
-
let post (T t) ?headers ?body ?auth ?timeout url =
-
make_request_internal t ?headers ?body ?auth ?timeout ~method_:`POST url
+
let post t ?headers ?body ?auth ?timeout url =
+
request t ?headers ?body ?auth ?timeout ~method_:`POST url
-
let put (T t) ?headers ?body ?auth ?timeout url =
-
make_request_internal t ?headers ?body ?auth ?timeout ~method_:`PUT url
+
let put t ?headers ?body ?auth ?timeout url =
+
request t ?headers ?body ?auth ?timeout ~method_:`PUT url
-
let patch (T t) ?headers ?body ?auth ?timeout url =
-
make_request_internal t ?headers ?body ?auth ?timeout ~method_:`PATCH url
+
let patch t ?headers ?body ?auth ?timeout url =
+
request t ?headers ?body ?auth ?timeout ~method_:`PATCH url
-
let delete (T t) ?headers ?auth ?timeout url =
-
make_request_internal t ?headers ?auth ?timeout ~method_:`DELETE url
+
let delete t ?headers ?auth ?timeout url =
+
request t ?headers ?auth ?timeout ~method_:`DELETE url
-
let head (T t) ?headers ?auth ?timeout url =
-
make_request_internal t ?headers ?auth ?timeout ~method_:`HEAD url
+
let head t ?headers ?auth ?timeout url =
+
request t ?headers ?auth ?timeout ~method_:`HEAD url
-
let options (T t) ?headers ?auth ?timeout url =
-
make_request_internal t ?headers ?auth ?timeout ~method_:`OPTIONS url
+
let options t ?headers ?auth ?timeout url =
+
request t ?headers ?auth ?timeout ~method_:`OPTIONS url
(* Cmdliner integration module *)
module Cmd = struct
+23 -33
stack/requests/lib/requests.mli
···
Use Eio.Fiber.both or Eio.Fiber.all for concurrent execution.
*)
-
type t
+
type ('clock, 'net) t
(** A stateful HTTP client that maintains cookies, auth, configuration, and
-
connection pools across requests. The internal clock and network types are
-
hidden from external users. *)
+
connection pools across requests. *)
(** {2 Creation and Configuration} *)
val create :
sw:Eio.Switch.t ->
-
?http_pool:(([> float Eio.Time.clock_ty] as 'clock) Eio.Resource.t,
-
([> [> `Generic] Eio.Net.ty] as 'net) Eio.Resource.t) Conpool.t ->
-
?https_pool:('clock Eio.Resource.t, 'net Eio.Resource.t) Conpool.t ->
+
?http_pool:('clock Eio.Time.clock, 'net Eio.Net.t) Conpool.t ->
+
?https_pool:('clock Eio.Time.clock, 'net Eio.Net.t) Conpool.t ->
?cookie_jar:Cookeio.jar ->
?default_headers:Headers.t ->
?auth:Auth.t ->
···
?persist_cookies:bool ->
?xdg:Xdge.t ->
< clock: 'clock Eio.Resource.t; net: 'net Eio.Resource.t; fs: Eio.Fs.dir_ty Eio.Path.t; .. > ->
-
t
+
('clock Eio.Resource.t, 'net Eio.Resource.t) t
(** Create a new requests instance with persistent state and connection pooling.
All resources are bound to the provided switch and will be cleaned up automatically.
···
(** {2 Configuration Management} *)
-
val set_default_header : t -> string -> string -> t
+
val set_default_header : ('clock, 'net) t -> string -> string -> ('clock, 'net) t
(** Add or update a default header. Returns a new session with the updated header.
The original session's connection pools are shared. *)
-
val remove_default_header : t -> string -> t
+
val remove_default_header : ('clock, 'net) t -> string -> ('clock, 'net) t
(** Remove a default header. Returns a new session without the header. *)
-
val set_auth : t -> Auth.t -> t
+
val set_auth : ('clock, 'net) t -> Auth.t -> ('clock, 'net) t
(** Set default authentication. Returns a new session with auth configured. *)
-
val clear_auth : t -> t
+
val clear_auth : ('clock, 'net) t -> ('clock, 'net) t
(** Clear authentication. Returns a new session without auth. *)
-
val set_timeout : t -> Timeout.t -> t
+
val set_timeout : ('clock, 'net) t -> Timeout.t -> ('clock, 'net) t
(** Set default timeout. Returns a new session with the timeout configured. *)
-
val set_retry : t -> Retry.config -> t
+
val set_retry : ('clock, 'net) t -> Retry.config -> ('clock, 'net) t
(** Set retry configuration. Returns a new session with retry configured. *)
(** {2 Request Methods}
···
*)
val request :
-
t ->
+
(_ Eio.Time.clock, _ Eio.Net.t) t ->
?headers:Headers.t ->
?body:Body.t ->
?auth:Auth.t ->
···
(** Make a concurrent HTTP request *)
val get :
-
t ->
+
(_ Eio.Time.clock, _ Eio.Net.t) t ->
?headers:Headers.t ->
?auth:Auth.t ->
?timeout:Timeout.t ->
···
(** Concurrent GET request *)
val post :
-
t ->
+
(_ Eio.Time.clock, _ Eio.Net.t) t ->
?headers:Headers.t ->
?body:Body.t ->
?auth:Auth.t ->
···
(** Concurrent POST request *)
val put :
-
t ->
+
(_ Eio.Time.clock, _ Eio.Net.t) t ->
?headers:Headers.t ->
?body:Body.t ->
?auth:Auth.t ->
···
(** Concurrent PUT request *)
val patch :
-
t ->
+
(_ Eio.Time.clock, _ Eio.Net.t) t ->
?headers:Headers.t ->
?body:Body.t ->
?auth:Auth.t ->
···
(** Concurrent PATCH request *)
val delete :
-
t ->
+
(_ Eio.Time.clock, _ Eio.Net.t) t ->
?headers:Headers.t ->
?auth:Auth.t ->
?timeout:Timeout.t ->
···
(** Concurrent DELETE request *)
val head :
-
t ->
+
(_ Eio.Time.clock, _ Eio.Net.t) t ->
?headers:Headers.t ->
?auth:Auth.t ->
?timeout:Timeout.t ->
···
(** Concurrent HEAD request *)
val options :
-
t ->
+
(_ Eio.Time.clock, _ Eio.Net.t) t ->
?headers:Headers.t ->
?auth:Auth.t ->
?timeout:Timeout.t ->
···
(** {2 Cookie Management} *)
-
val cookies : t -> Cookeio.jar
+
val cookies : ('clock, 'net) t -> Cookeio.jar
(** Get the cookie jar for direct manipulation *)
-
val clear_cookies : t -> unit
+
val clear_cookies : ('clock, 'net) t -> unit
(** Clear all cookies *)
(** {1 Cmdliner Integration} *)
···
user_agent : string option; (** User-Agent header *)
}
-
val create : config ->
-
< clock: [> float Eio.Time.clock_ty] Eio.Resource.t;
-
net: [> [> `Generic] Eio.Net.ty] Eio.Resource.t;
-
fs: Eio.Fs.dir_ty Eio.Path.t; .. > ->
-
Eio.Switch.t -> t
+
val create : config -> < clock: ([> float Eio.Time.clock_ty ] as 'clock) Eio.Resource.t; net: ([> [>`Generic] Eio.Net.ty ] as 'net) Eio.Resource.t; fs: Eio.Fs.dir_ty Eio.Path.t; .. > -> Eio.Switch.t -> ('clock Eio.Resource.t, 'net Eio.Resource.t) t
(** [create config env sw] creates a requests instance from command-line configuration *)
(** {2 Individual Terms} *)
···
Cmd.eval cmd
]} *)
-
val requests_term : string ->
-
< clock: [> float Eio.Time.clock_ty] Eio.Resource.t;
-
net: [> [> `Generic] Eio.Net.ty] Eio.Resource.t;
-
fs: Eio.Fs.dir_ty Eio.Path.t; .. > ->
-
Eio.Switch.t -> t Cmdliner.Term.t
+
val requests_term : string -> < clock: ([> float Eio.Time.clock_ty ] as 'clock) Eio.Resource.t; net: ([> [>`Generic] Eio.Net.ty ] as 'net) Eio.Resource.t; fs: Eio.Fs.dir_ty Eio.Path.t; .. > -> Eio.Switch.t -> ('clock Eio.Resource.t, 'net Eio.Resource.t) t Cmdliner.Term.t
(** [requests_term app_name env sw] creates a term that directly produces a requests instance.
This is a convenience function that combines configuration parsing
+12 -12
stack/requests_json_api/lib/requests_json_api.mli
···
(** {1 JSON Request Helpers} *)
-
val get_json_exn : Requests.t -> string -> 'a Jsont.t -> 'a
+
val get_json_exn : (_ Eio.Time.clock, _ Eio.Net.t) Requests.t -> string -> 'a Jsont.t -> 'a
(** [get_json_exn session url decoder] makes a GET request, checks status is 2xx,
reads and parses JSON body using the provided Jsont decoder.
Raises [Failure] on any error (HTTP, network, or JSON parse). *)
-
val get_json : Requests.t -> string -> 'a Jsont.t ->
+
val get_json : (_ Eio.Time.clock, _ Eio.Net.t) Requests.t -> string -> 'a Jsont.t ->
('a, [> `Http of int * string | `Json_error of string]) result
(** Like [get_json_exn] but returns [Result] instead of raising exceptions.
Returns [Ok parsed_value] on success, or [Error] with details on failure. *)
-
val post_json : Requests.t -> string -> 'a Jsont.t -> 'a -> Requests.Response.t
+
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.
Returns the raw response for custom handling. *)
-
val post_json_exn : Requests.t -> string -> 'a Jsont.t -> 'a -> string
+
val post_json_exn : (_ Eio.Time.clock, _ Eio.Net.t) Requests.t -> string -> 'a Jsont.t -> 'a -> string
(** Like [post_json] but checks status is 2xx and returns the response body as a string.
Raises [Failure] on non-2xx status. *)
-
val post_json_result : Requests.t -> string -> 'a Jsont.t -> 'a ->
+
val post_json_result : (_ Eio.Time.clock, _ Eio.Net.t) Requests.t -> string -> 'a Jsont.t -> 'a ->
(string, int * string) result
(** Like [post_json_exn] but returns [Result] instead of raising.
[Ok body] on 2xx status, [Error (status, body)] otherwise. *)
-
val post_json_decode_exn : Requests.t -> string ->
+
val post_json_decode_exn : (_ Eio.Time.clock, _ Eio.Net.t) Requests.t -> string ->
req:'a Jsont.t -> 'a -> resp:'b Jsont.t -> 'b
(** [post_json_decode_exn session url ~req req_value ~resp] encodes [req_value] using the [req] codec,
POSTs it to the URL, checks status is 2xx, and decodes the response using the [resp] codec.
Raises [Failure] on any error. *)
-
val post_json_decode : Requests.t -> string ->
+
val post_json_decode : (_ Eio.Time.clock, _ Eio.Net.t) Requests.t -> string ->
req:'a Jsont.t -> 'a -> resp:'b Jsont.t ->
('b, [> `Http of int * string | `Json_error of string]) result
(** Like [post_json_decode_exn] but returns [Result] instead of raising. *)
-
val put_json_exn : Requests.t -> string -> 'a Jsont.t -> 'a -> string
+
val put_json_exn : (_ Eio.Time.clock, _ Eio.Net.t) Requests.t -> string -> 'a Jsont.t -> 'a -> string
(** [put_json_exn session url codec value] encodes [value] and PUTs it to the URL.
Returns response body. Raises [Failure] on non-2xx status. *)
-
val put_json_decode_exn : Requests.t -> string ->
+
val put_json_decode_exn : (_ Eio.Time.clock, _ Eio.Net.t) Requests.t -> string ->
req:'a Jsont.t -> 'a -> resp:'b Jsont.t -> 'b
(** Like [post_json_decode_exn] but uses PUT method. *)
-
val patch_json_exn : 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
(** [patch_json_exn session url codec value] encodes [value] and PATCHes it to the URL.
Returns response body. Raises [Failure] on non-2xx status. *)
-
val delete_json_exn : Requests.t -> string -> string
+
val delete_json_exn : (_ Eio.Time.clock, _ Eio.Net.t) Requests.t -> string -> string
(** [delete_json_exn session url] makes a DELETE request.
Returns response body. Raises [Failure] on non-2xx status. *)
···
(** [read_body response] reads the entire response body as a string.
Equivalent to [Requests.Response.body response |> Eio.Flow.read_all] *)
-
val get_result : Requests.t -> string -> (string, int * string) result
+
val get_result : (_ Eio.Time.clock, _ Eio.Net.t) Requests.t -> string -> (string, int * string) result
(** [get_result session url] makes a GET request and returns the result.
Returns [Ok body] on 2xx status, [Error (status, body)] otherwise. *)
+2 -2
stack/zotero-translation/zotero_translation.ml
···
| true -> Uri.of_string (base_uri ^ "import")
| false -> Uri.of_string (base_uri ^ "/import")
-
type t = {
+
type ('clock, 'net) t = {
base_uri: string;
-
requests_session: Requests.t;
+
requests_session: ('clock, 'net) Requests.t;
}
let create ~requests_session base_uri =
+8 -8
stack/zotero-translation/zotero_translation.mli
···
(** {1 Interface to the Zotero Translation Server} *)
-
type t
+
type ('clock, 'net) t
type format =
| Bibtex
···
@param requests_session Shared Requests session for connection pooling.
@param base_uri Base URI of the Zotero translation server (e.g., "http://localhost:1969"). *)
val create :
-
requests_session:Requests.t ->
-
string -> t
+
requests_session:('clock Eio.Resource.t, 'net Eio.Resource.t) Requests.t ->
+
string -> ('clock Eio.Resource.t, 'net Eio.Resource.t) t
-
val resolve_doi: t ->
+
val resolve_doi: ([> float Eio.Time.clock_ty ] Eio.Resource.t, [> [> `Generic ] Eio.Net.ty ] Eio.Resource.t) t ->
string -> (Jsont.json, [>`Msg of string]) result
-
val resolve_url: t ->
+
val resolve_url: ([> float Eio.Time.clock_ty ] Eio.Resource.t, [> [> `Generic ] Eio.Net.ty ] Eio.Resource.t) t ->
string -> (Jsont.json, [>`Msg of string]) result
-
val search_id: t ->
+
val search_id: ([> float Eio.Time.clock_ty ] Eio.Resource.t, [> [> `Generic ] Eio.Net.ty ] Eio.Resource.t) t ->
string -> (Jsont.json, [>`Msg of string]) result
-
val export: t ->
+
val export: ([> float Eio.Time.clock_ty ] Eio.Resource.t, [> [> `Generic ] Eio.Net.ty ] Eio.Resource.t) t ->
format -> Jsont.json -> (string, [>`Msg of string]) result
-
val json_of_doi : t ->
+
val json_of_doi : ([> float Eio.Time.clock_ty ] Eio.Resource.t, [> [> `Generic ] Eio.Net.ty ] Eio.Resource.t) t ->
slug:string -> string -> Jsont.object'
+2 -1
stack/zulip/lib/zulip/lib/client.ml
···
type t = {
auth : Auth.t;
-
session : Requests.t;
+
session : (float Eio.Time.clock_ty Eio.Resource.t,
+
[`Generic | `Unix] Eio.Net.ty Eio.Resource.t) Requests.t;
}
let create ~sw env auth =