Skip to main content

src/langfuse_client@client.erl

-module(langfuse_client@client).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/langfuse_client/client.gleam").
-export([new/3, send_get/4]).
-export_type([client/0, error/0]).

-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.

?MODULEDOC(
    " HTTP client for a Langfuse project. Holds the base URL and API key pair\n"
    " used to authenticate against `/api/public/*` endpoints. Domain-specific\n"
    " modules (e.g. `langfuse_client/score`) drive the actual requests via `send_get`.\n"
    "\n"
    " The pure pieces (types, `new`) compile on both the Erlang and JavaScript\n"
    " targets; the HTTP-issuing pieces are Erlang-only because they depend on\n"
    " `gleam_httpc`.\n"
).

-type client() :: {client, binary(), binary(), binary()}.

-type error() :: {http_error, binary()} |
    {bad_status, integer(), binary()} |
    {bad_url, binary()} |
    {decode_error, gleam@json:decode_error()}.

-file("src/langfuse_client/client.gleam", 50).
?DOC(
    " Build a client. Trailing slashes on `base_url` are stripped so callers\n"
    " can pass either form.\n"
).
-spec new(binary(), binary(), binary()) -> client().
new(Base_url, Public_key, Secret_key) ->
    gleam@bool:guard(
        not gleam_stdlib:string_ends_with(Base_url, <<"/"/utf8>>),
        ({client, Base_url, Public_key, Secret_key}),
        fun() ->
            {client, gleam@string:drop_end(Base_url, 1), Public_key, Secret_key}
        end
    ).

-file("src/langfuse_client/client.gleam", 114).
-spec decode_body(
    gleam@http@response:response(binary()),
    gleam@dynamic@decode:decoder(FFC)
) -> {ok, FFC} | {error, error()}.
decode_body(Resp, Decoder) ->
    gleam@bool:guard(
        (erlang:element(2, Resp) < 200) orelse (erlang:element(2, Resp) >= 300),
        {error, {bad_status, erlang:element(2, Resp), erlang:element(4, Resp)}},
        fun() -> _pipe = gleam@json:parse(erlang:element(4, Resp), Decoder),
            gleam@result:map_error(
                _pipe,
                fun(Field@0) -> {decode_error, Field@0} end
            ) end
    ).

-file("src/langfuse_client/client.gleam", 108).
-spec send_raw(gleam@http@request:request(binary())) -> {ok,
        gleam@http@response:response(binary())} |
    {error, error()}.
send_raw(Req) ->
    _pipe = gleam@httpc:send(Req),
    gleam@result:map_error(
        _pipe,
        fun(E) -> {http_error, gleam@string:inspect(E)} end
    ).

-file("src/langfuse_client/client.gleam", 102).
-spec auth_header(client()) -> binary().
auth_header(Client) ->
    Creds = <<<<(erlang:element(3, Client))/binary, ":"/utf8>>/binary,
        (erlang:element(4, Client))/binary>>,
    <<"Basic "/utf8,
        (gleam_stdlib:base64_encode(gleam_stdlib:identity(Creds), true))/binary>>.

-file("src/langfuse_client/client.gleam", 85).
-spec build_request(client(), binary()) -> {ok,
        gleam@http@request:request(binary())} |
    {error, error()}.
build_request(Client, Path) ->
    Url = <<(erlang:element(2, Client))/binary, Path/binary>>,
    gleam@result:'try'(
        begin
            _pipe = gleam_stdlib:uri_parse(Url),
            gleam@result:replace_error(_pipe, {bad_url, Url})
        end,
        fun(Parsed) ->
            gleam@result:'try'(
                begin
                    _pipe@1 = gleam@http@request:from_uri(Parsed),
                    gleam@result:replace_error(_pipe@1, {bad_url, Url})
                end,
                fun(Req) -> _pipe@2 = Req,
                    _pipe@3 = gleam@http@request:set_method(_pipe@2, get),
                    _pipe@4 = gleam@http@request:prepend_header(
                        _pipe@3,
                        <<"authorization"/utf8>>,
                        auth_header(Client)
                    ),
                    _pipe@5 = gleam@http@request:prepend_header(
                        _pipe@4,
                        <<"accept"/utf8>>,
                        <<"application/json"/utf8>>
                    ),
                    {ok, _pipe@5} end
            )
        end
    ).

-file("src/langfuse_client/client.gleam", 70).
?DOC(false).
-spec send_get(
    client(),
    binary(),
    list({binary(), binary()}),
    gleam@dynamic@decode:decoder(FEQ)
) -> {ok, FEQ} | {error, error()}.
send_get(Client, Path, Query, Decoder) ->
    gleam@result:'try'(
        build_request(Client, Path),
        fun(Req) ->
            Req@1 = gleam@http@request:set_query(Req, Query),
            gleam@result:'try'(
                send_raw(Req@1),
                fun(Resp) -> decode_body(Resp, Decoder) end
            )
        end
    ).