# `ExOss.Utils`
[🔗](https://github.com/choice-form/ex_oss/blob/main/lib/ex_oss/utils.ex#L1)

Internal utility functions for URL construction, deadline computation,
and JSON codec resolution.

## JSON Codec

The JSON codec is resolved at compile time via application config:

    config :ex_oss, :json_codec, Jason

Defaults to the `JSON` module if not configured.

# `camelize`

```elixir
@spec camelize(atom() | String.t()) :: String.t()
```

Converts a snake_case atom or string to lowerCamelCase.

## Examples

    iex> ExOss.Utils.camelize(:force_save_key)
    "forceSaveKey"

    iex> ExOss.Utils.camelize("persistent_ops")
    "persistentOps"

# `deadline_unix`

```elixir
@spec deadline_unix(DateTime.t(), non_neg_integer()) :: integer()
```

Computes a Unix deadline timestamp from a starting time plus an offset in seconds.

## Examples

    iex> ExOss.Utils.deadline_unix(~U[2024-01-01 00:00:00Z], 3600)
    1704067600

# `json_codec`

```elixir
@spec json_codec() :: module()
```

Returns the configured JSON codec module.

# `public_url`

```elixir
@spec public_url(ExOss.Client.Client.t(), binary(), binary()) :: binary()
```

Builds a public (unsigned) URL from client, bucket, and resource key.

Handles both virtual-hosted style and path style addressing:

## Examples

    iex> client = %ExOss.Client.Client{endpoint: "https://bucket.s3.us-east-1.amazonaws.com", bucket_addressing: :virtual}
    iex> ExOss.Utils.public_url(client, "bucket", "folder/file.txt")
    "https://bucket.s3.us-east-1.amazonaws.com/folder/file.txt"

    iex> client = %ExOss.Client.Client{endpoint: "https://minio.example.com:9000", bucket_addressing: :path}
    iex> ExOss.Utils.public_url(client, "bucket", "folder/file.txt")
    "https://minio.example.com:9000/bucket/folder/file.txt"

---

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