# `Ankusa`
[🔗](https://github.com/jamescarr/ankusa/blob/ankusa-v0.7.0/packages/ankusa/lib/ankusa.ex#L1)

A loosely coupled, high-throughput webhook ingestion framework.

## Core invariant

Never return `2xx` until the hook is durably stored. The edge acks only after
the group-commit batcher's store commit returns.

## Layers (all pluggable behaviours)

  * `Ankusa.Queue`       — the durable hook queue: hooks, delivery rows, DLQ, replay.
  * `Ankusa.Verifier`    — signature/timestamp checks (Standard Webhooks, Stripe…).
  * `Ankusa.SourceStore` — per-source config, secrets, and failure policy.
  * `Ankusa.Sink`        — what happens to a delivered hook.
  * `Ankusa.RetryPolicy` — dispatch backoff and give-up rules.
  * `Ankusa.BlobStore` / `Ankusa.Codec` — long-term segment storage.

Every process is instance-scoped through `Ankusa.Registry`, so two independent
instances can run in one VM. Read-mostly config lives in `:persistent_term`.

# `config`

```elixir
@spec config(atom()) :: Ankusa.Config.t()
```

Fetch the instance config.

# `fetch_config`

```elixir
@spec fetch_config(atom()) :: {:ok, Ankusa.Config.t()} | :error
```

Fetch the instance config, or `:error` when the instance has none (it never started).

# `put_config`

```elixir
@spec put_config(Ankusa.Config.t()) :: :ok
```

Store the instance config in `:persistent_term` for read-mostly access.

# `via`

```elixir
@spec via(atom(), term()) :: {:via, Registry, {module(), {atom(), term()}}}
```

Register/lookup name for an instance-scoped process.

# `whereis`

```elixir
@spec whereis(atom(), term()) :: pid() | nil
```

Look up the running pid for an instance-scoped process, if any.

---

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