# atproto_core

The shared sans-io core of the gleam-atproto client packages: the XRPC
error vocabulary and response handling, plus the OAuth effect kernel that
`atproto_client` (sync, erlang) and `atproto_browser` (async, javascript)
both interpret with their own runners.

This package performs no IO and depends on no HTTP backend. Unless you are
building a runner for a new target, you want [`atproto_client`](https://hex.pm/packages/atproto_client)
or `atproto_browser` instead; they re-surface everything here behind their
own entry points.

## Modules

| Module                         | What it does                                                    |
| ------------------------------ | --------------------------------------------------------------- |
| `atproto_core/xrpc`            | `TransportError`, `XrpcError`, `describe`, `parse`, `check_ok`  |
| `atproto_core/oauth/effect`    | The `Effect` type: `Fetch`/`FetchBits`/`DpopProof`/`Done` steps |
| `atproto_core/oauth/transport` | Form POST with DPoP proof and the single `use_dpop_nonce` retry |
| `atproto_core/oauth/metadata`  | Authorization server / resource metadata discovery              |
| `atproto_core/oauth/flow`      | PAR: identity resolution through pushed authorization request   |
| `atproto_core/oauth/tokens`    | Token exchange, refresh, and revocation                         |
| `atproto_core/oauth/resource`  | DPoP-signed resource requests bound to an access token          |

## The effect kernel in one paragraph

Every OAuth operation is a pure `Effect` value: a step asking for a fetch,
a bit-array fetch, or a DPoP proof, with a continuation for the answer. A
runner walks the value, performing real IO per step; the kernel never sees
a socket or a key. That is what lets one implementation of the nonce-retry
and token-exchange logic serve both a sync erlang client and an async
browser client, and it is why the whole kernel is unit-testable by stepping
effects by hand (see `test/oauth_effect_test.gleam`).
