SIGN IN SIGN UP

feat(core): name the zone host in discovery and read rejected tokens as Unauthenticated (#106)

## Summary

Issues 110 and the core half of 109. Discovery names the provider whose
nameservers serve an unconnected domain, and a token Cloudflare or
Vercel rejects while connecting reads as `Unauthenticated` instead of
`ProviderRejected`.

## Discovery

```ts
Provider.Definition.nameservers?: ReadonlyArray<string>   // cloudflare: ["ns.cloudflare.com"], vercel: ["vercel-dns.com"]

const discovery = yield* Connect.discover("app.example.com");
// { _tag: "NotFound", nameservers: ["ada.ns.cloudflare.com", "bob.ns.cloudflare.com"], host: { provider: "cloudflare" } }
```

| Authoritative nameservers | Registered suffixes | `host` |
| ------------------------------------------- |
------------------------------------------------------- |
---------------------------- |
| `ada.ns.cloudflare.com`, `bob.ns.cloudflare.com` | cloudflare
`ns.cloudflare.com`, vercel `vercel-dns.com` | `{ provider: "cloudflare"
}` |
| `ada.ns.cloudflare.com`, `ns1.elsewhere.test` | same | `null` |
| `ada.ns.alpha.test` | alpha `ns.alpha.test`, reseller `alpha.test` |
`null` (two match) |
| `fakens.alpha.test` | alpha `ns.alpha.test` | `null` (trailing labels
only) |

- Match is case-insensitive with the trailing dot stripped; a suffix
matches on whole trailing labels.
- `GET /domains/:domain/discovery` and `Transport.connection.discover`
carry `host` on `NotFound`. Additive on the wire: 0.9.1 clients ignore
it.
- `Testing.provider({ nameserverSuffixes })` sets the fake definition's
suffixes.

## Rejected token

| Provider answer during token verification | Before | After |
| ------------------------------------------------------ |
------------------ | ----------------- |
| Cloudflare 400 code 6003 / 6111 (malformed token) | `ProviderRejected`
| `Unauthenticated` |
| Cloudflare 403 on verify | `Forbidden` | `Unauthenticated` |
| Vercel 403 `forbidden` on `/v2/user` | `Forbidden` | `Unauthenticated`
|
| Cloudflare 401 | `Unauthenticated` | unchanged |

The reason keeps the provider's message (`Invalid request headers`), so
the React catalog can name the provider; the server answers 401.
`Testing.conformance.provider` gains a `rejected-token` case that
authenticates an empty token and expects `Unauthenticated`; the offline
Cloudflare and Vercel fixtures reject any bearer other than the recorded
one.

## Validation

- `packages/domainkit`: typecheck, 141 tests, root `lint`, `lint:rules`,
`format:check`, `git diff --check`
- Root `bun run release:check` (typecheck, tests, build, examples
typecheck, packed artifacts for domainkit, capsuledb, react)
- Docs: `reference:check`, `blume validate --strict`, `audit --strict`,
`typecheck`, `test`, `build`
- Live provider runs are user-owned and were not run

https://claude.ai/code/session_017P54ng7iisz1dsk18u1w1x
S
Saatvik Arya committed
887f487565051e236d8dd74e9adafcc06383661d
Parent: 07ae0c0
Committed by GitHub <noreply@github.com> on 9/4/2026, 8:21:27 AM