# `Macaw.Layers.Bundle`
[🔗](https://github.com/dcoai/macaw_layers/blob/v0.2.2/lib/macaw/layers/bundle.ex#L1)

A portable set of documents (spec/03 §3): the transitive closure of what a page needs,
with where it came from, in a map form and a JSON form so it can leave the node it was
made on, and imported into another store as a relocation (`Macaw.Layers.Store.relocate/3`).

    %Macaw.Layers.Bundle{
      provenance: %{store: "metresis", exported_at: ~U[2026-10-20 09:30:00.000000Z], version: 1},
      entries: [%{id: {:style, 11}, name: "Styles:thick", fragment: %{style: %{width: 3}}}],
      snapshot: nil
    }

A bundle is read through the kernel's gates (spec/01 §5) with its own version line:
this module is a `Macaw.Layers.Version` and a `Macaw.Layers.Document`, whose `validate/1`
judges the envelope; each entry's fragment is then read by its own type, at the type's
own version where the type has a line.

Ported from visualize's `Visualize.Chart.Builder.Bundle` and its codec, without boards.

# `provenance`

```elixir
@type provenance() :: %{
  store: String.t() | atom(),
  exported_at: DateTime.t(),
  version: pos_integer()
}
```

Where a bundle came from, when, and the bundle version it was exported at.

# `t`

```elixir
@type t() :: %Macaw.Layers.Bundle{
  entries: [Macaw.Layers.Store.entry()],
  provenance: provenance(),
  snapshot: map() | nil
}
```

# `export`

```elixir
@spec export(
  Macaw.Layers.Store.assign(),
  Macaw.Layers.Store.id() | [Macaw.Layers.Store.id()],
  String.t() | atom()
) :: t()
```

The closure of `ids` through a store (§3.1): each entry, and every entry it refers to
(`Macaw.Layers.Fragment.refs/2`, use sites included), transitively, each once, in
dependency order. An id the store no longer holds is skipped. `source` is the host's
name for the store, written in the provenance.

# `from_json`

```elixir
@spec from_json(String.t(), [module()], keyword()) ::
  {:ok, t()} | {:error, [Macaw.Layers.Fault.t(), ...]}
```

The bundle a JSON document holds, as `from_map/3` reads it, every gate first.

# `from_map`

```elixir
@spec from_map(term(), [module()], keyword()) ::
  {:ok, t()} | {:error, [Macaw.Layers.Fault.t(), ...]}
```

The bundle a map form holds (§3.2), read through the kernel's gates with this module's
version line — the stamp, the limits, then the envelope — and then each entry's fragment
through the type its id names, given as a store's: `{:ok, bundle}` or every fault by path.
`limits:` as `Macaw.Layers.Document.read/3` takes them.

# `to_json`

```elixir
@spec to_json(t(), [module()]) ::
  {:ok, String.t()} | {:error, [Macaw.Layers.Fault.t(), ...]}
```

The bundle's JSON form.

# `to_map`

```elixir
@spec to_map(t(), [module()]) ::
  {:ok, map()} | {:error, [Macaw.Layers.Fault.t(), ...]}
```

The bundle's map form (§3.2), each entry's fragment in its type's map form, stamped with
the type's version where the type has a line: `{:ok, map}`, or every value without a
form, by path.

---

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