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

A library-first, daemonless OCI toolkit for Elixir — everything you can do to a container
image **except run it**.

Stevedore handles OCI artifacts *at rest* (as bytes): fetch, inspect, copy, mirror, build,
modify, analyze, sign, verify, and serve images. Running them (namespaces, mounts, cgroups)
is out of scope.

## Layers

The library is a pure core with optional shells:

  * **Core data types** — `Stevedore.Reference`, `Stevedore.Digest`, `Stevedore.MediaType`,
    `Stevedore.Descriptor`, `Stevedore.Manifest`, `Stevedore.Config`, and `Stevedore.Archive`.
  * **The `docker://` client** — `Stevedore.Registry` (requires the optional `:req` dep) plus
    `Stevedore.Auth` for the bearer-token flow.
  * **The `Stevedore.Store` seam** — content-addressed blob I/O, with `Store.Local` and
    `Store.Memory`.

The functions below are the high-level verbs. See `docs/EXAMPLES.md` for a cookbook of
task-oriented recipes.

Nothing here starts a process; adding `:stevedore` as a dependency is weightless.

# `copy`

```elixir
@spec copy(Stevedore.Copy.endpoint(), Stevedore.Copy.endpoint(), keyword()) ::
  {:ok, %{digest: Stevedore.Digest.t()}} | {:error, term()}
```

Copies an image from `source` to `dest`, preserving digests. Returns `{:ok, %{digest: ...}}`.

Endpoints are transport-prefixed strings (`docker://`, `oci:`, `dir:`, `docker-archive:`,
`oci-archive:`, `static:`) or `{transport, ref}` tuples. Options: `:all` (copy a whole index),
`:platform`/`:platforms` (select from an index), plus transport options like `:creds`.

## Examples

    Stevedore.copy("docker://alpine:3.20", "oci:./alpine:3.20")
    Stevedore.copy("docker://alpine:3.20", "docker://ghcr.io/me/alpine:3.20", all: true)

# `delete`

```elixir
@spec delete(
  Stevedore.Copy.endpoint(),
  keyword()
) :: :ok | {:error, term()}
```

Deletes the manifest named by `endpoint` (a transport-prefixed string or `{transport, ref}`).

# `inspect`

```elixir
@spec inspect(
  Stevedore.Reference.t(),
  keyword()
) ::
  {:ok, Stevedore.Manifest.t() | binary() | Stevedore.Config.t()}
  | {:error, term()}
```

Fetches and parses the manifest for `ref` from its registry.

Options:

  * `:raw` — return the raw manifest bytes instead of a `t:Stevedore.Manifest.t/0`.
  * `:config` — fetch and parse the image config, returning a `t:Stevedore.Config.t/0`
    (selecting the host platform, or `:platform`, when `ref` is a multi-arch index).
  * `:platform` — a keyword (`os`/`architecture`/`variant`) used with `:config` on an index.
  * plus any `Stevedore.Registry` option (`:creds`, `:scheme`, …).

# `list_tags`

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

Lists the tags in `ref`'s repository.

# `manifest_digest`

```elixir
@spec manifest_digest(binary() | Stevedore.Manifest.t()) :: Stevedore.Digest.t()
```

Computes the digest of a manifest from its raw bytes (or a `t:Stevedore.Manifest.t/0`).

## Examples

    iex> digest = Stevedore.manifest_digest(~s({"schemaVersion":2}))
    iex> digest.algorithm
    :sha256

# `start_link`

```elixir
@spec start_link(keyword()) :: Supervisor.on_start()
```

Starts the standalone `/v2` registry server (`Stevedore.Server`).

The only thing in Stevedore that boots a process tree, and only when called. Requires the
optional `:bandit`/`:plug` deps. See `Stevedore.Server` for options (`:store`, `:port`,
`:authorize`, …).

# `sync`

```elixir
@spec sync(
  [{Stevedore.Copy.endpoint(), Stevedore.Copy.endpoint()} | map()],
  keyword()
) :: {:ok, [{term(), term()}]}
```

Copies many images from a declarative list of jobs. Each job is `{source, dest}` or a map with
`:source`/`:dest` (and optional per-job `:opts`). Returns a result per job.

---

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