@ownsi/sdk is a thin layer over Eden Treaty, which
infers the whole surface from the API’s exported App type. There is no code-generation step and
nothing to keep in sync.
A route that changes shape becomes a type error at the call site, in the same commit.
Install
Create the client
api/ownsi.client.ts
fetch if you
need to route the calls somewhere else — a test, a worker, a proxy.
Claim a domain
Three resources — a domain is a name, a claim is an episode, a verification is a process — and one sentence over them.findOrCreate is idempotent on the name: asking twice returns the same domain. domain.claim()
answers already_claimed while one is still open — use the one you have, its token is the one
that will verify.
claim.record is singular because there is one record to write. It comes from the claim alone —
so the write this record screen renders with no verification loaded — and it is null once the
claim has ended, because there is nothing left to put in a panel.
Follow the verification
The claim knows which process is running against it, so you never carry the id yourself.diagnosis and waitEstimate is set while a verification is still running. One is
your reader’s problem and one is not, which is
the split the product exists for.
verification.attempts() is every read it has made, newest first — the evidence a proof rests on.
Every act, in one table
Every read answers with a handle: the fields the API sent, plus the acts reachable from them.
ownsi.api is the Eden client underneath, for a route the package does not cover yet.
list() answers with Claim; get() and create() answer with ClaimDetail, which adds
coexistence. The list does not carry a field it did not fetch.
The two dates a proof states
proofOf(claims) is the same function if you already hold the list.
Reading a zone
The public read streams, so it is a generator rather than a value.Extract on the discriminant narrows any of the tagged unions in this API — zone steps on step,
diagnoses on code, wait estimates on reason. ZoneDelegation and ZonePublishing are exported
already narrowed.
Errors
Everything throws anOwnsiError, carrying the API’s own code and docsUrl untouched.
RETRYABLE is the set worth trying again. unreachable is in it, and it is the one code the API
never sends: it means no answer arrived, or the answer was not ours. A request that never arrived
and a request that failed are both our side of the line, so both read as unreachable rather than
as something about somebody’s domain.
With TanStack Query
Keep the call in a hook rather than in a component, and let the error’scode drive the retry.
hooks/useVerificationState.ts
proved; keep polling while a waitEstimate says the wait is real. Forcing runs
in a loop does not make DNS answer faster — the verification’s own secondsRemaining is the
honest interval.
Authentication
Sessions are better-auth, not the SDK. It publishes its own typed client, and wrapping it would buy a second name for every method and nothing else.api/auth.client.ts
inferAdditionalFields<Auth>() types the session off the server’s configured instance, the same
way Treaty types the routes.