# `ExWapp.Session.JIDUtils`
[🔗](https://github.com/elchemista/ex_wapp/blob/v0.1.5/lib/ex_wapp/session/jid_utils.ex#L1)

Pure JID helpers used by session send/decrypt flows.

Keeping these helpers isolated makes the session orchestration code easier
to reason about and test.

# `build_dm_target_specs`

```elixir
@spec build_dm_target_specs([String.t()], [String.t()]) :: [
  %{jid: String.t(), payload_kind: :recipient | :own}
]
```

# `build_self_chat_fallback_target_specs`

```elixir
@spec build_self_chat_fallback_target_specs([String.t()], [String.t()], String.t()) ::
  [
    %{jid: String.t(), payload_kind: :recipient | :own}
  ]
```

Fallback self-chat strategy used when a DSM-only send appears silently dropped.

It keeps one primary target as `:recipient` payload and uses `:own` payload for
the remaining fanout targets.

# `build_self_chat_target_specs`

```elixir
@spec build_self_chat_target_specs([String.t()], [String.t()], String.t()) :: [
  %{jid: String.t(), payload_kind: :recipient | :own}
]
```

Builds target specs for self-chat fanout.

WhatsMeow parity: for self-chat, every non-current target gets the DSM payload.
There is no plain "recipient payload" branch in self-chat fanout.

# `current_device_target?`

```elixir
@spec current_device_target?(term(), integer()) :: boolean()
```

# `device_id`

```elixir
@spec device_id(term()) :: non_neg_integer() | nil
```

# `has_explicit_device?`

```elixir
@spec has_explicit_device?(term()) :: boolean()
```

# `identity`

```elixir
@spec identity(term()) :: {String.t(), String.t()}
```

# `lid_jid?`

```elixir
@spec lid_jid?(term()) :: boolean()
```

# `map_to_preferred_family`

```elixir
@spec map_to_preferred_family(term(), term(), map() | nil) :: String.t()
```

# `normalize_for_signal`

```elixir
@spec normalize_for_signal(term()) :: String.t()
```

# `normalize_target_list`

```elixir
@spec normalize_target_list(term()) :: [String.t()]
```

# `normalize_with_device`

```elixir
@spec normalize_with_device(term()) :: String.t()
```

# `related_bases`

```elixir
@spec related_bases(term(), map() | nil) :: [String.t()]
```

# `resolve_signal_encryption_jid`

```elixir
@spec resolve_signal_encryption_jid(term(), map() | nil) :: String.t()
```

# `strip_device`

```elixir
@spec strip_device(term()) :: String.t()
```

# `user_part`

```elixir
@spec user_part(term()) :: String.t()
```

---

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