# `Arcana.CollectionScope`
[🔗](https://github.com/georgeguimaraes/arcana/blob/main/lib/arcana/collection_scope.ex#L1)

Represents the collections included in a read.

Public inputs are normalized before they reach query code:

  * `:all` includes every collection
  * a collection name includes only that collection
  * a list of names includes those collections
  * an empty list matches no collections

Collection names must be non-empty binaries. Normalization preserves their
order while removing duplicates.

# `error_reason`

```elixir
@type error_reason() ::
  {:invalid_collection_scope, term()} | {:unsupported_collection_option, atom()}
```

# `input`

```elixir
@type input() :: :all | name() | [name()]
```

# `name`

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

# `t`

```elixir
@type t() :: :all | {:only, [name()]}
```

# `from_opts`

```elixir
@spec from_opts(keyword(), input()) :: {:ok, t()} | {:error, error_reason()}
```

Reads a collection scope from keyword options.

The `:collection` option accepts every public scope shape. When it is absent,
`default` is normalized instead. The removed `:collections` alias is rejected
so an outdated scoped caller cannot silently widen to the default.

# `from_opts!`

```elixir
@spec from_opts!(keyword(), input()) :: t()
```

Reads and normalizes a collection scope from options or raises `ArgumentError`.

# `intersect`

```elixir
@spec intersect(t(), t()) :: t()
```

Returns the intersection of two normalized collection scopes.

When both scopes list names, their order follows the first scope.

# `normalize`

```elixir
@spec normalize(term()) :: {:ok, t()} | {:error, error_reason()}
```

Normalizes a public collection scope.

Returns `{:error, {:invalid_collection_scope, input}}` when a name is blank
or an input has an unsupported shape.

# `normalize!`

```elixir
@spec normalize!(term()) :: t()
```

Normalizes a collection scope or raises `ArgumentError`.

# `subset?`

```elixir
@spec subset?(t(), t()) :: boolean()
```

Returns whether every collection in `scope` is included in `allowed`.

This is useful at authorization boundaries where silently intersecting an
explicit request would accept only part of a forged scope.

---

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