# hrafn — fleet browser-fetch service. Copy to `.env` and set HRAFN_TOKEN.
# This file is the canonical config surface (contract § Configuration).

# ── auth (required) ──────────────────────────────────────────────────
# Shared bearer token required on POST /v1/fetch. Provision via the
# vault (secrets-broker); rotation = rotate the vault entry + recycle.
HRAFN_TOKEN=CHANGE_ME

# ── network ──────────────────────────────────────────────────────────
HRAFN_BIND=0.0.0.0
HRAFN_PORT=8080

# ── fetch limits ─────────────────────────────────────────────────────
# Max post-content-decoding body bytes of the main navigation response;
# oversize is rejected (413), never truncated. Both raw and dom modes.
HRAFN_MAX_BODY_BYTES=10485760
# Whole-request budget default + hard cap (seconds). timeout_s INCLUDES
# politeness-queue wait. A request may not exceed the cap.
HRAFN_DEFAULT_TIMEOUT_S=30
HRAFN_MAX_TIMEOUT_S=120
# Default dom-mode wait state: load | domcontentloaded | networkidle.
HRAFN_DEFAULT_WAIT_UNTIL=domcontentloaded

# ── concurrency + browser lifecycle ──────────────────────────────────
# Global in-flight cap (acquired on leaving the politeness queue).
HRAFN_CONCURRENCY=4
# Recycle the browser after N requests or M seconds of age.
HRAFN_BROWSER_MAX_REQUESTS=200
HRAFN_BROWSER_MAX_AGE_S=1800

# ── politeness gate (per registrable domain) ─────────────────────────
# Minimum seconds between fetch STARTS per domain (0 = no throttle).
HRAFN_DOMAIN_MIN_INTERVAL_S=5
# Per-domain interval overrides: comma-separated domain=seconds pairs.
# HRAFN_DOMAIN_OVERRIDES=reddit.com=10, example.com=2
HRAFN_DOMAIN_OVERRIDES=
# Waiting-request queue depth per domain (excludes the in-flight fetch;
# 0 = no queue). Overflow → 429 queue_full.
HRAFN_QUEUE_DEPTH=4
# Upstream Retry-After (on 429/503) embargoes the domain; clamped to
# this many seconds so a hostile Retry-After can't lock a domain for a day.
HRAFN_MAX_EMBARGO_S=300

# ── SSRF ─────────────────────────────────────────────────────────────
# Private/reserved targets are DENIED by default. To permit specific
# internal targets, list IPs/CIDRs (comma-separated). Empty = deny all
# private ranges (the safe default). Write entries in IPv4 form for IPv4
# targets: resolved IPv4-mapped IPv6 addresses are canonicalised to IPv4
# before matching, so an IPv6-mapped CIDR (::ffff:10.0.0.0/120) will not
# match them.
# HRAFN_PRIVATE_ALLOWLIST=10.0.0.0/8, 192.168.1.5
HRAFN_PRIVATE_ALLOWLIST=

# ── live smoke (dev only) ────────────────────────────────────────────
# Set to 1 to enable the opt-in Reddit RSS smoke test. Off in CI.
# HRAFN_LIVE_SMOKE=1
