diff --git a/packages/docs/docs/getting-started/dashboard.md b/packages/docs/docs/getting-started/dashboard.md index f8e361f..daf2e40 100644 --- a/packages/docs/docs/getting-started/dashboard.md +++ b/packages/docs/docs/getting-started/dashboard.md @@ -83,6 +83,10 @@ Manage installed plugins and configure plugin secrets. Plugins extend HappyView Configure labeler subscriptions for content labeling. See [Labelers](../guides/features/labelers.md) for details. +### XRPC Proxy + +Control which unrecognized XRPC methods are forwarded to their resolved authority. Choose from four modes: **Disabled** (block all proxy requests), **Open** (proxy everything — the default), **Allowlist** (only proxy NSIDs matching your patterns), or **Blocklist** (proxy everything except matching patterns). Allowlist and blocklist modes accept NSID patterns with trailing wildcards (e.g. `com.example.*`). Locally registered lexicons are always served regardless of this setting. See [XRPC Proxy](../reference/admin/xrpc-proxy.md) for the full API reference. + ### Environment Variables View the current values of all environment variables that affect HappyView's behavior. This is a read-only view — values are set via your deployment environment, not the dashboard. diff --git a/packages/docs/docs/reference/admin/xrpc-proxy.md b/packages/docs/docs/reference/admin/xrpc-proxy.md new file mode 100644 index 0000000..1a98f29 --- /dev/null +++ b/packages/docs/docs/reference/admin/xrpc-proxy.md @@ -0,0 +1,93 @@ +# Admin API: XRPC Proxy + +Control which unrecognized XRPC methods HappyView forwards to their resolved authority. Locally registered lexicons are always served regardless of this setting. + +All endpoints require the `settings:manage` permission. + +```sh +# All examples assume $TOKEN is an API key (hv_...) +AUTH="Authorization: Bearer $TOKEN" +``` + +## Get proxy config + +``` +GET /admin/settings/xrpc-proxy +``` + +```sh +curl http://127.0.0.1:3000/admin/settings/xrpc-proxy -H "$AUTH" +``` + +**Response**: `200 OK` + +```json +{ + "mode": "allowlist", + "nsids": ["com.example.feed.*", "games.gamesgamesgamesgames.*"] +} +``` + +Returns `{"mode": "open", "nsids": []}` when no config has been saved. + +## Update proxy config + +``` +PUT /admin/settings/xrpc-proxy +``` + +```sh +curl -X PUT http://127.0.0.1:3000/admin/settings/xrpc-proxy \ + -H "$AUTH" \ + -H "Content-Type: application/json" \ + -d '{ + "mode": "allowlist", + "nsids": ["com.example.feed.*"] + }' +``` + +**Response**: `204 No Content` + +Changes take effect immediately — no restart needed. + +### Modes + +| Mode | Behavior | +|------|----------| +| `disabled` | Block all proxy requests. Return `403` for every unrecognized NSID. | +| `open` | Proxy everything (default). Current behavior on a fresh install. | +| `allowlist` | Proxy only NSIDs matching a pattern in `nsids`. Return `403` for the rest. | +| `blocklist` | Proxy everything except NSIDs matching a pattern in `nsids`. | + +When mode is `disabled` or `open`, any `nsids` in the request body are ignored and stored as `[]`. + +### NSID patterns + +Patterns are dotted NSID identifiers. Trailing wildcards are supported: + +- `com.example.feed.getHot` — exact match +- `com.example.feed.*` — matches any NSID starting with `com.example.feed.` +- `games.gamesgamesgamesgames.*` — matches the entire namespace + +Mid-segment wildcards (e.g., `com.*.feed`) are not supported. + +### Validation errors + +| Status | Cause | +|--------|-------| +| `400` | An NSID pattern is empty, has fewer than two segments, contains invalid characters, or uses an unsupported wildcard | +| `422` | `mode` is not one of `disabled`, `open`, `allowlist`, `blocklist` | + +## Blocked request response + +When the proxy denies a request, the client receives: + +``` +403 Forbidden +``` + +```json +{ + "error": "NSID not allowed by proxy policy" +} +``` diff --git a/packages/docs/docs/reference/xrpc-api.md b/packages/docs/docs/reference/xrpc-api.md index 8fd6644..c6aeb65 100644 --- a/packages/docs/docs/reference/xrpc-api.md +++ b/packages/docs/docs/reference/xrpc-api.md @@ -177,6 +177,10 @@ HappyView proxies this to the user's PDS as `com.atproto.repo.putRecord`, then u **Response** for both: proxied from the user's PDS. +## XRPC proxy + +When a request targets an NSID that has no locally registered lexicon, HappyView resolves the NSID's authority via DNS and forwards the request. Admins can restrict which NSIDs are proxied — see [XRPC Proxy settings](admin/xrpc-proxy.md). + ## Errors All error responses return JSON with an `error` field: diff --git a/packages/docs/sidebars.ts b/packages/docs/sidebars.ts index c64e5d1..f9925df 100644 --- a/packages/docs/sidebars.ts +++ b/packages/docs/sidebars.ts @@ -357,6 +357,11 @@ const sidebars: SidebarsConfig = { id: "reference/admin/settings", label: "Instance Settings", }, + { + type: "doc", + id: "reference/admin/xrpc-proxy", + label: "XRPC Proxy", + }, { type: "doc", id: "reference/admin/domains",