# `AshGrant.Introspect`
[🔗](https://github.com/jhlee111/ash_grant/blob/v0.14.1/lib/ash_grant/introspect.ex#L1)

Permission introspection helpers for various use cases.

This module provides functions to query and inspect permissions
at runtime, useful for:

- **Admin UI**: Display what permissions a user has
- **Permission Management**: List all available permissions for a resource
- **Debugging**: Check why access is allowed or denied
- **API Responses**: Return allowed actions to clients

## Functions Overview

| Function | Use Case | Returns |
|----------|----------|---------|
| `actor_permissions/3` | Admin UI | All permissions with status |
| `available_permissions/1` | Permission management | All possible permissions |
| `can?/4` | Debugging | `:allow` or `:deny` with details |
| `allowed_actions/3` | API response | List of allowed actions |
| `permissions_for/3` | Raw access | Permission strings from resolver |

## Examples

    # Admin UI: What can this user do?
    Introspect.actor_permissions(Post, current_user)
    # => [%{action: "read", allowed: true, scope: "always", field_groups: []}, ...]

    # Permission management: What permissions exist?
    Introspect.available_permissions(Post)
    # => [%{permission_string: "post:*:read:always", action: "read", scope: "always", field_group: nil}, ...]

    # Debugging: Can user do this?
    Introspect.can?(Post, :update, user)
    # => {:allow, %{scope: "own", instance_ids: nil, field_groups: []}}

    # API: What actions are available?
    Introspect.allowed_actions(Post, user)
    # => [:read, :create, :update]

# `available_permission`

```elixir
@type available_permission() :: %{
  permission_string: String.t(),
  action: String.t(),
  scope: String.t(),
  scope_description: String.t() | nil,
  field_group: String.t() | nil
}
```

# `permission_status`

```elixir
@type permission_status() :: %{
  action: String.t(),
  allowed: boolean(),
  denied: boolean(),
  scope: String.t() | nil,
  instance_ids: [String.t()] | nil,
  field_groups: [String.t()]
}
```

# `actor_permissions`

```elixir
@spec actor_permissions(module(), term(), keyword()) :: [permission_status()]
```

Returns all permissions for a resource with their status for a given actor.

Useful for Admin UI to display what a user can or cannot do.

## Options

- `:context` - Additional context to pass to the resolver

## Examples

    iex> Introspect.actor_permissions(Post, %{role: :editor})
    [
      %{action: "read", allowed: true, scope: "always", denied: false, instance_ids: nil, field_groups: []},
      %{action: "update", allowed: true, scope: "own", denied: false, instance_ids: nil, field_groups: []},
      %{action: "destroy", allowed: false, scope: nil, denied: false, instance_ids: nil, field_groups: []}
    ]

# `allowed_actions`

```elixir
@spec allowed_actions(module(), term(), keyword()) :: [atom()] | [map()]
```

Returns list of allowed actions for an actor.

Useful for API responses to tell clients what they can do.

## Options

- `:context` - Additional context to pass to the resolver
- `:detailed` - When `true`, returns detailed info instead of just action names

## Examples

    iex> Introspect.allowed_actions(Post, %{role: :editor})
    [:read, :create, :update]

    iex> Introspect.allowed_actions(Post, %{role: :editor}, detailed: true)
    [
      %{action: :read, scope: "always", instance_ids: nil, field_groups: []},
      %{action: :create, scope: "always", instance_ids: nil, field_groups: []},
      %{action: :update, scope: "own", instance_ids: nil, field_groups: []}
    ]

# `available_permissions`

```elixir
@spec available_permissions(module()) :: [available_permission()]
```

Returns all available permissions for a resource.

Useful for permission management UI to show what permissions can be assigned.

## Examples

    iex> Introspect.available_permissions(Post)
    [
      %{permission_string: "post:*:read:always", action: "read", scope: "always", scope_description: nil, field_group: nil},
      %{permission_string: "post:*:read:own", action: "read", scope: "own", scope_description: "...", field_group: nil},
      ...
    ]

# `can?`

```elixir
@spec can?(module(), atom(), term(), keyword()) :: {:allow, map()} | {:deny, map()}
```

Simple permission check returning `:allow` or `:deny` with details.

Useful for debugging authorization issues.

## Options

- `:context` - Additional context to pass to the resolver

## Examples

    iex> Introspect.can?(Post, :read, %{role: :editor})
    {:allow, %{scope: "always", instance_ids: nil, field_groups: []}}

    iex> Introspect.can?(Post, :destroy, %{role: :viewer})
    {:deny, %{reason: :no_permission}}

    iex> Introspect.can?(Post, :read, nil)
    {:deny, %{reason: :no_actor}}

# `permissions_for`

```elixir
@spec permissions_for(module(), term(), keyword()) :: [String.t()]
```

Returns raw permissions from the resolver for an actor.

Useful when you need direct access to permission strings.

## Options

- `:context` - Additional context to pass to the resolver

## Examples

    iex> Introspect.permissions_for(Post, %{role: :editor})
    ["post:*:read:always", "post:*:update:own", "post:*:create:always"]

---

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