# `AshAuthzed`
[🔗](https://github.com/boxxxie/ash_authzed/blob/v0.2.0/lib/ash_authzed.ex#L1)

Standalone Ash Framework extension for Zanzibar / ReBAC authorization
backed by `Licet` (embedded Postgres/Ecto), `SpiceDB` / `Authzed` (HTTP via `Req`),
or `AshAuthzed.Adapters.Memory` (in-memory `Licet` engine).

## Usage

    defmodule MyApp.Accounts.User do
      use Ash.Resource,
        domain: MyApp.Accounts,
        data_layer: AshPostgres.DataLayer,
        authorizers: [Ash.Policy.Authorizer],
        extensions: [AshAuthzed]

      authzed do
        object_type "user_profile"
        adapter :licet
        adapter_opts [instance: MyApp.Licet]

        relation :owner, subject_type: "user", subject_id: :id
        relation :platform, static_subject: "platform:main"
        external_role :role, target: "platform:main", subject_type: "user", subject_id: :id

        conditional_wildcard :is_protected_admin,
          subject_type: "user",
          attribute: :role,
          in: [:admin, :super_admin]
      end

      policies do
        policy action(:read) do
          authorize_if rebac_can(:view)
        end

        policy action(:update_profile) do
          authorize_if rebac_can(:edit)
        end
      end
    end

# `adapter_config`

```elixir
@spec adapter_config(Ash.Resource.t(), keyword()) :: keyword()
```

Builds the adapter options keyword list for a given Ash resource, merging any call-site overrides.

# `apply_schema`

```elixir
@spec apply_schema(String.t(), keyword()) :: :ok | {:ok, term()} | {:error, term()}
```

Applies the given `.zed` or YAML schema (file path or raw string) to the configured ReBAC adapter.

# `authzed`
*macro* 

# `backfill`

```elixir
@spec backfill(Ash.Resource.t() | Ash.Query.t(), keyword()) ::
  {:ok,
   %{
     records: non_neg_integer(),
     operations: non_neg_integer(),
     batches: non_neg_integer()
   }}
  | {:error, term()}
```

Streams an Ash Resource or `Ash.Query` in keyset-paginated batches and writes
its relationship tuples via `AshAuthzed.Adapter.write_tuples/2`.

## Options
  * `:batch_size` - Number of records per chunk (default: `500`)
  * `:reconcile?` - Whether to also emit `:delete` ops for non-matching enum roles (default: `true`)
  * `:dry_run?` - If `true`, computes operations and returns counts without writing to the adapter (default: `false`)
  * `:tenant` - Optional tenant passed to `Ash.stream!/2`
  * `:stream_opts` - Additional options forwarded to `Ash.stream!/2`
  * `:adapter_opts` - Additional options forwarded to `AshAuthzed.Adapter.write_tuples/2`
  * `:on_batch` - Optional callback invoked with running stats after each batch

# `backfill_all`

```elixir
@spec backfill_all(atom() | [Ash.Domain.t()], keyword()) ::
  {:ok, %{optional(Ash.Resource.t()) =&gt; map()}}
  | {:error, {Ash.Resource.t(), term()}}
```

Backfills all `AshAuthzed`-enabled resources in the given OTP app or domain list.

# `get_entities`

```elixir
@spec get_entities(Ash.Resource.t()) :: [
  AshAuthzed.Relation.t()
  | AshAuthzed.ExternalRole.t()
  | AshAuthzed.ConditionalWildcard.t()
]
```

Returns all ReBAC entities declared in the resource's `authzed` and `rebac` DSL sections.

# `get_opt`

```elixir
@spec get_opt(Ash.Resource.t(), atom(), term()) :: term()
```

Fetches a configuration option from the resource's `authzed` or `rebac` DSL section.

# `rebac`
*macro* 

# `registered_resources`

```elixir
@spec registered_resources(atom() | [Ash.Domain.t()]) :: [Ash.Resource.t()]
```

Discovers all Ash resources in the given OTP app (or list of Ash domains)
that use the `AshAuthzed` extension.

---

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