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

Reference to a source image. Produced by a provider, consumed by a
source resolver.

A source is intentionally a thin tagged reference. The provider names
*what* the source is (an absolute path, an absolute URL, or a hosted
asset id) and the source resolver decides *where the bytes come from*.

Sources never hold image bytes themselves.

# `kind`

```elixir
@type kind() :: :path | :url | :hosted
```

The kind of source. Determines which `Image.Plug.SourceResolver`
implementation handles it.

* `:path` — `ref` is an absolute path string. Resolved against a
  configured root directory by `Image.Plug.SourceResolver.File`.

* `:url` — `ref` is an absolute `http(s)://` URL. Resolved by
  `Image.Plug.SourceResolver.HTTP` against an allow-list.

* `:hosted` — `ref` is a `{account_hash, image_id}` tuple. Resolved
  by `Image.Plug.SourceResolver.Hosted` against a host-supplied
  asset table.

# `ref`

```elixir
@type ref() :: String.t() | {String.t(), String.t()}
```

# `t`

```elixir
@type t() :: %Image.Plug.Source{
  headers: %{optional(String.t()) =&gt; String.t()},
  kind: kind(),
  ref: ref()
}
```

# `hosted`

```elixir
@spec hosted(String.t(), String.t()) :: t()
```

Builds a `:hosted` source.

### Arguments

* `account_hash` is an opaque account identifier string.

* `image_id` is an opaque image identifier string.

### Returns

* An `Image.Plug.Source` struct (always succeeds).

### Examples

    iex> source = Image.Plug.Source.hosted("acct123", "img456")
    iex> source.kind
    :hosted
    iex> source.ref
    {"acct123", "img456"}

# `path`

```elixir
@spec path(String.t()) :: {:ok, t()} | {:error, Image.Plug.Error.t()}
```

Builds a `:path` source.

### Arguments

* `path` is an absolute path string (must start with `/`).

### Returns

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

* `{:error, %Image.Plug.Error{tag: :invalid_option}}` if the path is
  not absolute or contains `..` segments.

### Examples

    iex> {:ok, source} = Image.Plug.Source.path("/foo/bar.jpg")
    iex> source.kind
    :path

    iex> {:error, error} = Image.Plug.Source.path("relative.jpg")
    iex> error.tag
    :invalid_option

# `url`

```elixir
@spec url(String.t()) :: {:ok, t()} | {:error, Image.Plug.Error.t()}
```

Builds a `:url` source.

### Arguments

* `url` is an absolute `http://` or `https://` URL.

### Returns

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

* `{:error, %Image.Plug.Error{tag: :invalid_option}}` if the URL is
  missing a scheme or host.

### Examples

    iex> {:ok, source} = Image.Plug.Source.url("https://example.com/a.jpg")
    iex> source.kind
    :url

    iex> {:error, error} = Image.Plug.Source.url("not-a-url")
    iex> error.tag
    :invalid_option

---

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