Transport
Implement the DomainKit React transport with authenticated app endpoints. Provider credentials and API clients stay on the server.
DomainKit.Root receives a Layer<Transport.Service>. Its controllers run through Effect Atom, which owns request interruption, stale result suppression, and disposal for the React subtree. The service is intentionally application-facing rather than a browser wrapper around provider APIs.
The host integration guide shows where the transport belongs in a complete browser, application server, and provider architecture.
import { Transport } from "domainkit";
import * as Layer from "effect/Layer";
const service = Transport.Service.of({
connection: {
inspect: (input) => api.connections.inspect(input),
connect: (input) => api.connections.connect(input),
reuse: (input) => api.connections.reuse(input),
removeDomain: (input) => api.connections.removeDomain(input),
},
provisioning: {
plan: (input) => api.provisioning.plan(input),
apply: (input) => api.provisioning.apply(input),
},
verification: {
observe: (input) => api.verification.observe(input),
},
cleanup: {
plan: (input) => api.cleanup.plan(input),
apply: (input) => api.cleanup.apply(input),
},
});
export const transport = Layer.succeed(Transport.Service, service);
When an authenticated client already returns Promises, adapt it at that foreign-runtime boundary rather than recreating a second React transport contract:
import { Transport } from "domainkit";
export const transport = Transport.layerFromAsync({
connection: api.connections,
provisioning: api.provisioning,
verification: api.verification,
cleanup: api.cleanup,
});
@domainkit/react
-> authenticated host endpoint
-> durable connection + receipt state
-> domainkit
-> Cloudflare / Vercel
Successful outcomes use schema-backed tagged models. Failures use Transport.Failure in the Effect error channel. Decode untrusted request, database, and provider data at your server boundary before mapping it into these browser-safe wire types.
Custom UI can consume Connection.useModel(domain) with useAtomValue(model.state) and
useAtomSet(model.command). Dispatch commands with Connection.Command.Connect, Reuse, and
Retry; the packaged controller and flow use the same atoms.
Correlate browser operations with durable attempts
Treat every plan application as a server-side attempt. Persist the plan and its digest before returning it to the browser, then require the browser to submit that digest when it asks the server to apply the plan.
browser requests plan
-> server plans and persists { attemptId, planDigest, plan }
-> browser reviews plan
-> browser submits { attemptId, planDigest }
-> server authorizes and applies the persisted plan
-> server stores the receipt
This keeps retries, authorization decisions, and support investigations attached to one durable record instead of trusting a mutable plan sent back by the browser.
Use product-owned verification when needed
Transport exposes provider-backed operations. Public DNS verification is a separate product
decision: your server can use Verification.observe with public resolvers, expose a dedicated
endpoint, and map its result into your product state without giving the browser resolver or provider
credentials.
See the Transport reference for every service method and Observe DNS for verification policy choices.