# `Portals.Protocol`
[🔗](https://github.com/Ziinc/portals/blob/v0.1.0/lib/portals/protocol.ex#L1)

Portals wire protocol v1: frame tags, default limits, and the frame
validation rules shared by every SDK implementation.

See `protocol/v1.md` for the full specification. This module encodes
the frame tag registry and default limits as authoritative Elixir
constants; `protocol/v1.md` must stay in sync with these values.

# `frame_name`

```elixir
@type frame_name() ::
  :hello
  | :ready
  | :call
  | :return
  | :error
  | :cancel
  | :callback
  | :callback_return
  | :callback_error
  | :message
  | :stream_data
  | :credit
  | :half_close
  | :ping
  | :pong
  | :shutdown
```

# `limits`

```elixir
@type limits() :: %{
  max_frame_size: pos_integer(),
  max_nesting_depth: pos_integer(),
  max_collection_length: pos_integer(),
  max_metadata_size: pos_integer(),
  max_callback_depth: pos_integer(),
  max_in_flight_callbacks: pos_integer(),
  max_in_flight_requests: pos_integer(),
  max_stream_byte_credit: pos_integer(),
  max_queued_stream_frames: pos_integer()
}
```

# `arity`

```elixir
@spec arity(frame_name()) :: {non_neg_integer(), non_neg_integer() | :infinity}
```

Required and optional field arity for each frame, used to validate a decoded envelope.

# `default_limits`

```elixir
@spec default_limits() :: limits()
```

# `frame_name`

```elixir
@spec frame_name(pos_integer()) :: {:ok, frame_name()} | :error
```

# `frame_tag`

```elixir
@spec frame_tag(frame_name()) :: pos_integer()
```

# `validate_envelope`

```elixir
@spec validate_envelope(list()) :: {:ok, {frame_name(), list()}} | {:error, term()}
```

Validate a decoded frame envelope: `[tag | fields]`.

Returns `{:ok, {frame_name, fields}}` or `{:error, reason}`. Does not
interpret field semantics beyond arity and the tag itself; that is the
responsibility of `Portals.Connection` and its equivalents in each SDK.

# `version`

```elixir
@spec version() :: pos_integer()
```

---

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