# `Stevedore.Registry`
[🔗](https://github.com/oshlabs/stevedore/blob/v0.2.0/lib/stevedore/registry.ex#L1)

A daemonless client for the OCI/Docker Distribution v2 API (the `docker://` transport).

Fetches and pushes manifests and blobs: it performs the bearer-token handshake (a `401`
challenge exchanged at the token endpoint, requesting `pull`/`push` scope as the server asks),
negotiates manifest media types via `Accept`, honors `Docker-Content-Digest`, and verifies
every blob against its digest. Manifest bytes move **raw** so their digest stays stable.

This module requires the optional `:req` dependency; calling it without `req` raises a clear
error. The functions return the shapes a runtime (e.g. Tank) consumes directly.

By default each call re-runs the token handshake. Pass a `Stevedore.Auth.Cache` as the
`:token_cache` option to reuse a bearer token across a pull's manifest + blob fetches.

Spec: [OCI distribution-spec](https://github.com/opencontainers/distribution-spec/blob/main/spec.md)
(pull, push, blob uploads, cross-repo mount).

# `blob`

```elixir
@spec blob(Stevedore.Reference.t(), Stevedore.Digest.t(), keyword()) ::
  {:ok, binary()} | {:error, Stevedore.Registry.Error.t()}
```

Fetches a blob (config or layer) for `ref` by `digest`, verifying the bytes against it.

Survives CDN redirects without leaking the registry token: `req` strips the `Authorization`
header on any cross-host redirect.

# `delete_manifest`

```elixir
@spec delete_manifest(Stevedore.Reference.t(), String.t(), keyword()) ::
  :ok | {:error, Stevedore.Registry.Error.t()}
```

Deletes a manifest by tag or digest.

# `has_blob?`

```elixir
@spec has_blob?(Stevedore.Reference.t(), Stevedore.Digest.t(), keyword()) :: boolean()
```

Whether the registry already has the blob for `digest` (a `HEAD` on the blob).

# `list_tags`

```elixir
@spec list_tags(
  Stevedore.Reference.t(),
  keyword()
) :: {:ok, [String.t()]} | {:error, Stevedore.Registry.Error.t()}
```

Lists all tags for `ref`'s repository, following `Link` pagination.

# `manifest`

```elixir
@spec manifest(
  Stevedore.Reference.t(),
  keyword()
) ::
  {:ok,
   %{
     media_type: String.t(),
     digest: Stevedore.Digest.t(),
     raw: binary(),
     json: map()
   }}
  | {:error, Stevedore.Registry.Error.t()}
```

Fetches a manifest (or index) for `ref`, by its tag or digest.

Returns the raw bytes, decoded JSON, resolved media type, and digest. When the registry sends
`Docker-Content-Digest`, the bytes are verified against it.

Options: `:creds` (`t:Stevedore.Auth.creds/0`, default `:anonymous`), `:scheme` (default
`"https"`), `:token_cache` (a `Stevedore.Auth.Cache` to reuse bearer tokens), `:max_retries`,
and `:req_options` (a keyword merged into the `Req` request, e.g. an `:adapter` for tests).

# `mount_blob`

```elixir
@spec mount_blob(Stevedore.Reference.t(), Stevedore.Digest.t(), String.t(), keyword()) ::
  :ok | :not_mounted
```

Attempts a cross-repo blob mount (`POST ?mount=&from=`). Returns `:not_mounted` (rather than an
error) when the registry declines, so the caller can fall back to a normal upload.

# `put_blob`

```elixir
@spec put_blob(Stevedore.Reference.t(), Stevedore.Digest.t(), iodata(), keyword()) ::
  :ok | {:error, Stevedore.Registry.Error.t()}
```

Uploads a blob via a monolithic upload session (`POST` an upload, then `PUT` the bytes with
`?digest=`).

# `put_manifest`

```elixir
@spec put_manifest(Stevedore.Reference.t(), binary(), String.t(), keyword()) ::
  {:ok, Stevedore.Digest.t()} | {:error, Stevedore.Registry.Error.t()}
```

Pushes raw manifest bytes, tagged or by digest (`ref` is a tag, a `t:Stevedore.Digest.t/0`, or
`nil` to use the computed digest). Returns the manifest digest.

# `referrers`

```elixir
@spec referrers(Stevedore.Reference.t(), Stevedore.Digest.t(), keyword()) ::
  {:ok, %{raw: binary(), json: map()}} | {:error, Stevedore.Registry.Error.t()}
```

Lists referrers to `digest` via the OCI 1.1 Referrers API, falling back to the tag-schema
(`<algo>-<hex>`) referrers index for registries without the API. Returns the referrers index as
raw bytes + decoded JSON.

---

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