# `Hyper.Img`
[🔗](https://github.com/harmont-dev/hyper/blob/main/lib/hyper/img.ex#L1)

A content-addressed image: an ordered stack of layers, and the entry point for
putting one into the cluster.

`create/2` ingests a prepared image file -- e.g. the ext4 rootfs produced by
`Hyper.Img.OciLoader` -- into the shared media store and the image database. It
content-addresses the file (sha256 of its bytes = the image id), publishes it
into `Hyper.Cfg.Dirs.layer_dir/0` at `layer_<id>.img`, then records it as a
one-layer base image (`blobs` + `images` + `image_layers`). Producers of image
files stay decoupled from the store and DB: they hand a path to `create/2`.

# `id`

```elixir
@type id() :: String.t()
```

# `create`

```elixir
@spec create(
  Path.t(),
  keyword()
) :: {:ok, id()} | {:error, term()}
```

Ingest the image file at `path` into the cluster and return its
content-addressed id.

Content-addresses `path` (sha256 of its bytes = the id), publishes it into the
media store at `layer_<id>.img`, and records it as a one-layer base image. The
file at `path` is consumed -- moved into the store on success, removed on
failure -- so the caller hands off ownership.

`opts[:label]` sets the human-readable `images.label` (defaults to the basename
of `path`).

Idempotent: creating identical bytes again is a no-op that returns the same id.

# `create_derived`

```elixir
@spec create_derived(id(), Path.t(), keyword()) :: {:ok, id()} | {:error, term()}
```

Ingest the dm-snapshot COW file at `delta_path` as a new delta layer over
`parent_img_id`, returning the derived image's id. The file is consumed, like
`create/2`. Idempotent for identical bytes over the same parent.

`opts[:label]` sets the derived image's label (defaults to the file basename).

# `derived_image_id`

```elixir
@spec derived_image_id(id(), String.t()) :: id()
```

The id of the image derived from `parent_img_id` by applying delta blob
`delta_blob_id`: a digest of the *pair*, so re-publishing the same fork is
idempotent while identical delta bytes over different parents still get
distinct image rows.

# `derived_layer_rows`

```elixir
@spec derived_layer_rows(id(), [String.t()], String.t()) :: [
  %{image_id: id(), position: non_neg_integer(), blob_id: String.t()}
]
```

The `image_layers` rows of a derived image: the parent's blob chain in order
at positions `0..n-1`, the delta blob at position `n`.

---

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