Current section
Files
Jump to
Current section
Files
src/atproto/oauth/runner.gleam
//// The sync runner for the OAuth effect kernel: a tail-recursive loop that
//// interprets an `Effect` against a synchronous `xrpc.Client` and a `gose`
//// DPoP key. `run_readonly` is for fetch-only flows (metadata discovery) that
//// never sign a proof, so they need no key.
import atproto/oauth/core/effect.{type Effect}
import atproto/oauth/dpop
import atproto/xrpc.{type Client}
import gose
pub fn run(effect: Effect(a), client: Client, key: gose.Key(String)) -> a {
case effect {
effect.Done(value) -> value
effect.Fetch(request, next) ->
run(next(xrpc.send_text(client, request)), client, key)
effect.FetchBits(request, next) ->
run(next(client.send(request)), client, key)
effect.DpopProof(method, url, nonce, ath, next) ->
run(next(dpop.proof(key, method:, url:, nonce:, ath:)), client, key)
}
}
/// Interpret a fetch-only effect (no `DpopProof` steps). The `DpopProof` branch
/// is unreachable for such flows; it fails defensively rather than panicking.
pub fn run_readonly(effect: Effect(a), client: Client) -> a {
case effect {
effect.Done(value) -> value
effect.Fetch(request, next) ->
run_readonly(next(xrpc.send_text(client, request)), client)
effect.FetchBits(request, next) ->
run_readonly(next(client.send(request)), client)
effect.DpopProof(_, _, _, _, next) ->
run_readonly(next(Error("dpop proof required in read-only flow")), client)
}
}