# `Image.Plug`
[🔗](https://github.com/elixir-image/image_plug/blob/v0.1.0/lib/image/plug.ex#L1)

The library's request entry point.

Mount this plug under whatever path your host application uses (e.g.
`forward "/img", to: Image.Plug, init_opts: [...]` for
`Plug.Router`, or `plug Image.Plug, [...]` from a Phoenix
endpoint).

### Request lifecycle

Each request flows through:

1. `provider.parse/2` — produces either a fully-formed pipeline +
   source, a variant lookup + source, or a passthrough source.

2. Variant resolution against the configured
   `Image.Plug.VariantStore`. Variant URLs of the form
   `/<account>/<image-id>/<variant-name>` are expanded to the
   stored pipeline; ad-hoc URLs skip this step.

3. `Image.Plug.Pipeline.Normaliser.normalise/1`.

4. `source_resolver.load/2` — opens the source as a
   `Vix.Vips.Image`, preferring streaming decode.

5. `Image.Plug.Pipeline.Interpreter.execute/2`.

6. `Image.Plug.Pipeline.Encoder.encode/3` — produces a streaming
   body when possible.

7. The plug pipes the body to the client via
   `Plug.Conn.send_chunked/2` + `Plug.Conn.chunk/2`. Buffered bytes
   bodies use `Plug.Conn.send_resp/3`.

# `call`

```elixir
@spec call(Plug.Conn.t(), Image.Plug.Options.t()) :: Plug.Conn.t()
```

Handles a single request end-to-end.

# `default_telemetry_prefix`

```elixir
@spec default_telemetry_prefix() :: [atom(), ...]
```

Returns the default telemetry prefix used by the request plug.

### Returns

* The list of atoms `[:image_plug]`.

### Examples

    iex> Image.Plug.default_telemetry_prefix()
    [:image_plug]

# `delete_variant`

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

Deletes a variant by name.

### Returns

* `:ok` on success.

* `{:error, :not_found}` if the variant does not exist.

# `get_variant`

```elixir
@spec get_variant(
  String.t(),
  keyword()
) :: {:ok, Image.Plug.Variant.t()} | {:error, :not_found}
```

Fetches a variant by name.

Returns `{:ok, variant}` or `{:error, :not_found}`.

### Examples

    iex> case Image.Plug.get_variant("public") do
    ...>   {:ok, variant} -> variant.name
    ...>   {:error, _} -> nil
    ...> end
    "public"

# `init`

```elixir
@spec init(keyword()) :: Image.Plug.Options.t()
```

Validates configuration and returns an opaque options struct passed
through to every `call/2` invocation.

Raises `ArgumentError` if required configuration is missing or
malformed. Configuration errors are programmer errors and must surface
at boot time, not per-request.

# `list_variants`

```elixir
@spec list_variants(keyword()) :: {:ok, [Image.Plug.Variant.t()]}
```

Lists every variant in the store.

### Returns

* `{:ok, [variant]}` — the order is store-defined (the default ETS
  store sorts by name).

# `put_variant`

```elixir
@spec put_variant(Image.Plug.Variant.t() | String.t(), term(), keyword()) ::
  {:ok, Image.Plug.Variant.t()} | {:error, term()}
```

Inserts or updates a variant.

### Arguments

* `name_or_variant` is either a variant name string or a complete
  `Image.Plug.Variant` struct.

* When the first argument is a name, the second argument is either
  a Cloudflare-style options string, an `Image.Plug.Pipeline`
  struct, or a `{provider_module, options_string}` tuple.

### Options

* `:store` — `{module, options}` tuple identifying the store.
  Defaults to `{Image.Plug.VariantStore.ETS, []}`.

* `:metadata` — arbitrary metadata map stored on the variant.

* `:never_require_signed_urls?` — boolean, defaults to `false`.

### Returns

* `{:ok, variant}` on success.

* `{:error, reason}` on failure (e.g. invalid options string).

# `version`

```elixir
@spec version() :: String.t()
```

Returns the library version as a string.

### Returns

* A semver-like version string such as `"0.1.0-dev"`.

### Examples

    iex> is_binary(Image.Plug.version())
    true

---

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