domainkit
Every namespace the package root exports, what each one owns, how the composed layer is built, and the failure shape every operation raises.
The package root is one module per concept. A service module exposes Service (the tag) and
Interface (its shape); a value module exposes Model (the schema).
import { DnsRecord, DomainKit, Provision, Verify } from "domainkit";
Every namespace below is also its own subpath, for a package that emits declarations or wants a narrow import: see entry points.
Lifecycle services
Each one is a Service tag, an Interface, a layer, and free accessors that read the service
from context (Provision.plan(...)). Policy values are Context.References with defaults.
| Namespace | Owns |
|---|---|
Connect |
inspect, discover, zones, start, reconnect, complete, completeOutcome, attach, detach, disconnect, refresh, session |
Provision |
plan, approve, reject, apply, get, latest over durable attempts, and batch over many at once |
Cleanup |
The same verbs over a plan built from an apply receipt |
Verify |
observe, attachEvidence, latest, summary, requirementKey, Observer (readinessChanged({ ownerId, domain, readiness, cause })), Policy, and the evidence classes they produce |
Host seams
| Namespace | Owns |
|---|---|
Principal |
{ ownerId, actorId } per request; every Storage query is scoped by it |
Storage |
Every durable row, the row schemas, layerMemory, and layerFromAsync |
Custody |
Sealing credentials: layer, layerConfig, layerFromAsync, and generateKey |
Providers
| Namespace | Owns |
|---|---|
Provider |
Definition, make, tokenAuth, Session, Dns, Target, Resolution, fromAsync |
Providers |
The registry of enabled definitions, built by DomainKit.layer |
Cloudflare |
provider, AccountContext, TokenFields, and the OAuth server metadata |
Vercel |
provider, TeamContext, and TokenFields |
Values
| Namespace | Owns |
|---|---|
DomainName |
A normalized, IDN-aware hostname, its zone candidates, and isWithin |
DnsRecord |
Record constructors including txt and spf, Model, Observed, Opaque, data, equals, sameSet |
Plan |
Model, the four operations, writes, conflicts, isApplicable, renderInstructions |
Approval |
Consent bound to one plan digest and an explicit operation set |
Receipt |
What an apply actually wrote: Applied, Skipped, Failed, applied, isComplete |
Everything else
| Namespace | Owns |
|---|---|
DomainKit |
layer, layerMemory, Error, ErrorCategory, and isError |
Reason |
The seventeen failure reasons and their union, Reason.Model |
Resolver |
The public DNS pool: layer (Cloudflare and Google DoH), layerWith, Outcome |
VERSION |
The installed package version, read from the package manifest |
Composing the layer
DomainKit.layer({ providers, resolver? }) provides every lifecycle service and requires Storage
and Custody beneath it. DomainKit.layerMemory adds the in-memory pair and a throwaway custody
key for tests and playgrounds.
/**
* `PgStorage.layer()` prepares at boot: it creates CapsuleDB's ledger, applies pending migrations,
* and only then provides `Storage`. Nothing can observe a database whose tables are missing.
*/
export const DomainKitLive = DomainKit.layer({
providers: [
Cloudflare.provider({
oauth: {
clientId: Config.String("CF_CLIENT_ID"),
clientSecret: Config.Redacted("CF_CLIENT_SECRET"),
},
}),
Vercel.provider(),
],
}).pipe(
// `provideMerge`, not `provide`: the route handlers read attempts and receipts straight from
// Storage, so the layer they are given has to still carry it.
Layer.provideMerge(Layer.mergeAll(PgStorage.layer(), Custody.layerConfig())),
Layer.provide(PgClient.layerConfig({ url: Config.Redacted("DATABASE_URL") })),
);Failures
Every operation fails with DomainKit.Error. It carries one Reason, and category,
isRetryable, and httpStatus derive from it.
| Property | Values |
|---|---|
reason |
One member of Reason.Model |
category |
request, auth, plan, provider, storage, internal |
isRetryable |
true for Busy, ProviderUnavailable, and StorageFailed |
httpStatus |
The status domainkit/server answers with |
Failure reasons lists every reason with its status and the next step.
Completion outcomes
Connect.completeOutcome({ continuationId, callbackUrl, provider? }) shares the completion lock,
exchange, persistence, and spending path with Connect.complete. Its Connect.Completion tagged
value is Connected { started }, Cancelled { error }, or Failed { error, recovery }.
started contains a connection and either an attachment or zone candidates; no redirect is produced.
error is the original DomainKit.Error for server-side handling. Do not send this value to a
browser: Server callback outcomes omit those errors
and storage rows.
The operation verifies the live continuation and its owner and actor inside the lock before
classifying callback parameters. provider, when supplied, also binds the stored flow to that
provider route. Invalid flows fail without an outcome; direct missing/expired reads retain
NotFound/Expired. Connect.complete returns the same Started result or original completion
error for ordinary callers. Neither operation spends cancellation or failure; persistence can be
partial, and recovery: "inspect" requires inspecting durable state before deciding whether to
restart. A provider code can be single-use even when the continuation is still live.