# `X402.Utils`
[🔗](https://github.com/cardotrejos/x402/blob/v0.9.0/lib/x402/utils.ex#L1)

Shared utility functions for the X402 library.

Centralises helpers for Base64 decoding, map access, decimal parsing,
and decimal comparison that are used across payment processing modules.

# `compare_decimal`
*since 0.1.0* 

```elixir
@spec compare_decimal(
  {non_neg_integer(), non_neg_integer()},
  {non_neg_integer(), non_neg_integer()}
) ::
  :lt | :eq | :gt
```

Compares two `{value, scale}` decimal tuples.

Returns `:lt`, `:eq`, or `:gt`.

## Examples

    iex> X402.Utils.compare_decimal({10, 1}, {1, 0})
    :eq

    iex> X402.Utils.compare_decimal({5, 1}, {1, 0})
    :lt

    iex> X402.Utils.compare_decimal({15, 1}, {1, 0})
    :gt

# `decode_base64`
*since 0.1.0* 

```elixir
@spec decode_base64(String.t()) :: {:ok, String.t()} | {:error, :invalid_base64}
```

Decodes a Base64 string with or without padding.

## Examples

    iex> X402.Utils.decode_base64("")
    {:error, :invalid_base64}

    iex> X402.Utils.decode_base64("aGVsbG8=")
    {:ok, "hello"}

    iex> X402.Utils.decode_base64("not-valid-!!!")
    {:error, :invalid_base64}

# `first_present`
*since 0.1.0* 

```elixir
@spec first_present([term()]) :: term() | nil
```

Finds the first non-nil value in a list.

## Examples

    iex> X402.Utils.first_present([nil, nil, "found"])
    "found"

    iex> X402.Utils.first_present([nil, nil])
    nil

    iex> X402.Utils.first_present([false, "other"])
    false

# `map_delete`
*since 0.1.0* 

```elixir
@spec map_delete(
  map(),
  {String.t(), atom()}
) :: map()
```

Deletes both string and atom versions of a key from a map.

# `map_put`
*since 0.1.0* 

```elixir
@spec map_put(map(), {String.t(), atom()}, term()) :: map()
```

Puts a value into a map, preferring the existing key type (string over atom).

# `map_value`
*since 0.1.0* 

```elixir
@spec map_value(
  map(),
  {String.t(), atom()}
) :: term()
```

Retrieves a value from a map using either a string or atom key.

Prefers the string key if present, falls back to atom key.

## Examples

    iex> X402.Utils.map_value(%{"key" => "string_val"}, {"key", :key})
    "string_val"

    iex> X402.Utils.map_value(%{key: "atom_val"}, {"key", :key})
    "atom_val"

    iex> X402.Utils.map_value(%{}, {"key", :key})
    nil

# `nested_map_value`
*since 0.1.0* 

```elixir
@spec nested_map_value(map(), [{String.t(), atom()}]) :: term()
```

Retrieves a nested value from a map using a list of string/atom key pairs.

# `parse_decimal`
*since 0.1.0* 

```elixir
@spec parse_decimal(term()) :: {:ok, {non_neg_integer(), non_neg_integer()}} | :error
```

Parses a decimal value (integer or string) into a `{value, scale}` tuple
where `value / 10^scale` equals the original number.

Returns `:error` for negative integers, non-numeric strings, or strings
without a leading digit (e.g. `".5"`).

## Examples

    iex> X402.Utils.parse_decimal(42)
    {:ok, {42, 0}}

    iex> X402.Utils.parse_decimal("12.50")
    {:ok, {125, 1}}

    iex> X402.Utils.parse_decimal("0.001")
    {:ok, {1, 3}}

    iex> X402.Utils.parse_decimal(".5")
    :error

    iex> X402.Utils.parse_decimal("")
    :error

    iex> X402.Utils.parse_decimal(-1)
    :error

---

*Consult [api-reference.md](api-reference.md) for complete listing*
