Skip to main content

src/aion_client@error.erl

-module(aion_client@error).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/aion_client/error.gleam").
-export([from_wire/2, from_http_status/2, transport_failure/0]).
-export_type([error/0, wire_error_code/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(" Shared caller-side SDK error taxonomy.\n").

-type error() :: not_found |
    already_exists |
    query_failed |
    query_timeout |
    cancelled |
    unavailable |
    unauthenticated |
    {namespace_denied, binary()} |
    invalid_argument |
    {server, binary()}.

-type wire_error_code() :: wire_not_found |
    wire_namespace_denied |
    wire_sequence_conflict |
    wire_unknown_query |
    wire_query_timeout |
    wire_not_running |
    wire_lagged |
    wire_invalid_input |
    wire_backend |
    wire_query_failed |
    {wire_unknown, binary()}.

-file("src/aion_client/error.gleam", 47).
?DOC(
    " Map an AW wire error code into the shared client taxonomy.\n"
    "\n"
    " `WireSequenceConflict` is the server's internal double-writer-bug signal\n"
    " (a single-writer invariant violation), never an idempotency outcome, so it\n"
    " surfaces as `Server` rather than `AlreadyExists`.\n"
).
-spec from_wire(wire_error_code(), binary()) -> error().
from_wire(Code, Detail) ->
    case Code of
        wire_not_found ->
            not_found;

        wire_namespace_denied ->
            {namespace_denied, Detail};

        wire_sequence_conflict ->
            {server, Detail};

        wire_unknown_query ->
            invalid_argument;

        wire_query_timeout ->
            query_timeout;

        wire_not_running ->
            invalid_argument;

        wire_lagged ->
            unavailable;

        wire_invalid_input ->
            invalid_argument;

        wire_backend ->
            {server, Detail};

        wire_query_failed ->
            query_failed;

        {wire_unknown, _} ->
            {server, Detail}
    end.

-file("src/aion_client/error.gleam", 68).
?DOC(
    " Map HTTP status codes used by aion-server into the shared taxonomy.\n"
    " aion-server returns 401 exclusively for credential failure and 403\n"
    " exclusively for namespace denial. Gateway statuses 502/503/504 signal\n"
    " transient unreachability and map to the retryable `Unavailable`; 500 and\n"
    " any unrecognised status are server faults.\n"
).
-spec from_http_status(integer(), binary()) -> error().
from_http_status(Status, Detail) ->
    case Status of
        400 ->
            invalid_argument;

        401 ->
            unauthenticated;

        403 ->
            {namespace_denied, Detail};

        404 ->
            not_found;

        408 ->
            query_timeout;

        409 ->
            already_exists;

        412 ->
            invalid_argument;

        429 ->
            unavailable;

        499 ->
            cancelled;

        500 ->
            {server, Detail};

        502 ->
            unavailable;

        503 ->
            unavailable;

        504 ->
            unavailable;

        _ ->
            {server, Detail}
    end.

-file("src/aion_client/error.gleam", 87).
?DOC(
    " Transport, DNS, TLS, socket, and transient stream failures are retryable\n"
    " availability failures in the contract.\n"
).
-spec transport_failure() -> error().
transport_failure() ->
    unavailable.