# `Tink.RateLimiter`
[🔗](https://github.com/iamkanishka/tink.ex/blob/v0.1.1/lib/tink/rate_limiter.ex#L1)

Rate limiting for Tink API requests using Hammer 7.2.

Uses a private `Tink.RateLimiter.Backend` module backed by Hammer's
fixed-window ETS algorithm. The backend process is supervised by
`Tink.Application` and must be running before any rate-limit functions
are called.

## Algorithm

Fixed window (`Hammer.ETS.FixWindow`) is used because Tink's rate limits
are expressed as "N requests per hour" — exactly what a fixed window
enforces with minimal overhead.

## Configuration

    config :tink,
      enable_rate_limiting: true

Optionally tune the cleanup interval (default: every 5 minutes):

    config :tink, Tink.RateLimiter.Backend,
      clean_period: :timer.minutes(5)

## Hammer 7.2 API used

`Backend.hit(key, scale_ms, limit)` — increments the counter and checks
the limit atomically. Returns `{:allow, count}` or `{:deny, ms_to_reset}`.

`Backend.get(key, scale_ms)` — returns the current count without incrementing.

## Telemetry

Emits:
- `[:tink, :rate_limit, :checked]` — check performed
- `[:tink, :rate_limit, :exceeded]` — limit exceeded

# `check`

```elixir
@spec check(
  String.t(),
  keyword()
) :: :ok | {:error, :rate_limited}
```

Checks whether a request is within the configured rate limit.

Increments the counter for `key` in the current window. Returns `:ok` if
the request is allowed, or `{:error, :rate_limited}` if the limit is exceeded.

## Parameters

  * `key` - Bucket identifier, e.g. a user ID or operation name
  * `opts` - Options:
    * `:limit` - Maximum requests per window (default: 100)
    * `:period` - Window duration in milliseconds (default: 1 hour)

## Examples

    iex> Tink.RateLimiter.check("user_123")
    :ok

    iex> Tink.RateLimiter.check("user_123", limit: 50, period: :timer.minutes(30))
    :ok

# `info`

```elixir
@spec info(
  String.t(),
  keyword()
) :: {:ok, map()}
```

Returns detailed rate limit information for `key`.

## Returns

  * `{:ok, map}` — Map with `:count`, `:limit`, `:remaining`
  * `{:ok, map}` — With `:resets_in_ms` set to `0` when rate limiting is off

## Examples

    iex> Tink.RateLimiter.info("user_123")
    {:ok, %{count: 5, limit: 100, remaining: 95}}

# `remaining`

```elixir
@spec remaining(
  String.t(),
  keyword()
) :: {:ok, non_neg_integer() | :infinity}
```

Returns the number of requests remaining in the current window for `key`.

Does **not** increment the counter. Returns `{:ok, :infinity}` when rate
limiting is disabled.

## Examples

    iex> Tink.RateLimiter.remaining("user_123")
    {:ok, 95}

    iex> Tink.RateLimiter.remaining("unknown_key")
    {:ok, 100}

---

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