# `Electric.Shapes.EventRouter`
[🔗](https://github.com/electric-sql/electric/tree/%40core/sync-service%401.6.2/packages/sync-service/lib/electric/shapes/event_router.ex#L1)

Routes replication events to shapes, returning per-shape transaction fragments.

The EventRouter wraps a Filter and adds transaction-aware routing:
- For Relation events, returns the relation for all affected shapes
- For TransactionFragment events, returns per-shape TransactionFragments
  with only the changes that affect each shape.

Transaction state is tracked to ensure:
- Each shape receives Begin only once per transaction (on first relevant operation)
- Each shape receives Commit only if it received operations in the transaction
- Shapes added mid-transaction are skipped for that transaction
- Shapes removed mid-transaction stop receiving events immediately

# `shape_id`

```elixir
@type shape_id() :: any()
```

# `t`

```elixir
@type t() :: %Electric.Shapes.EventRouter{
  current_xid: term(),
  filter: term(),
  in_txn: term(),
  shapes_added_mid_txn: term(),
  shapes_in_txn: term(),
  shapes_seen_begin: term()
}
```

# `active_shapes`

```elixir
@spec active_shapes(t()) :: MapSet.t(shape_id())
```

# `add_shape`

```elixir
@spec add_shape(t(), shape_id(), Electric.Shapes.Shape.t()) :: t()
```

# `event_by_shape_handle`

```elixir
@spec event_by_shape_handle(
  t(),
  Electric.Replication.Changes.Relation.t()
  | Electric.Replication.Changes.TransactionFragment.t()
) ::
  {%{
     required(shape_id()) =&gt;
       Electric.Replication.Changes.Relation.t()
       | Electric.Replication.Changes.TransactionFragment.t()
   }, t()}
```

# `has_shape?`

```elixir
@spec has_shape?(t(), shape_id()) :: boolean()
```

# `new`

```elixir
@spec new(keyword()) :: t()
```

# `remove_shape`

```elixir
@spec remove_shape(t(), shape_id()) :: t()
```

---

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