Server API
Mount provider connection routes in Effect-native or async hosts while retaining application ownership of identity, persistence, and policy.
domainkit/server supplies one provider-connection HTTP seam for Effect-native and async hosts.
Identity, tenancy, credentials, short-lived continuations, durable authorization storage, and audit
policy remain host-owned.
Async hosts
Use createDomainKit in a conventional async application. It accepts Promise-based host
capabilities and returns a standard Web handler:
import { createDomainKit } from "domainkit/server";
export const domainKit = await createDomainKit({
baseURL: "https://app.example.com",
basePath: "/api/domainkit",
defaultReturnTo: "/domains",
identity: hostIdentity,
connectionPolicy: hostConnectionPolicy,
providers: [cloudflare],
pendingAuthorizations: redisPendingAuthorizations,
persistence: managedDnsConnections,
});
The host supplies persistence; DomainKit does not choose a database, run migrations, or dispose
the host’s database client. The optional @domainkit/capsuledb package remains an Effect-native
implementation rather than an implicit dependency of this factory.
Effect-native hosts
Use Server.make in an existing Effect program or provide it as a Layer with Server.layer:
import { Server } from "domainkit/server";
import { Layer } from "effect";
const dependencies = Layer.mergeAll(
IdentityLive,
ConnectionPolicyLive,
ProvidersLive,
PendingAuthorizationsLive,
ManagedDnsConnectionsLive,
CryptoLive,
);
const DomainKitServerLive = Server.layer({
baseURL: "https://app.example.com",
basePath: "/api/domainkit",
defaultReturnTo: "/domains",
}).pipe(Layer.provide(dependencies));
export const domainKit = Server.toWebHandler(DomainKitServerLive);
Both paths use the same route program. Server.make leaves Effect requirements visible;
createDomainKit adapts Promise capabilities at the foreign-runtime boundary.
Mount the handler
The returned fetch(Request) works directly with Web-standard server frameworks.
app.all("/api/domainkit/*", (context) => domainKit.fetch(context.req.raw));
// app/api/domainkit/[...path]/route.ts
export const GET = domainKit.fetch;
export const POST = domainKit.fetch;
// routes/api/domainkit/$.ts
export const Route = createFileRoute("/api/domainkit/$")({
server: {
handlers: {
GET: ({ request }) => domainKit.fetch(request),
POST: ({ request }) => domainKit.fetch(request),
},
},
});
Dispose the DomainKit handler during a long-lived host’s shutdown. This releases only the runtime
created by DomainKit; the host still owns its persistence lifecycle. The default base path is
/api/domainkit. When baseURL is omitted, the start request’s origin constructs the callback URL;
configure it explicitly behind a reverse proxy or custom domain.
Routes
| Method | Path | Behavior |
|---|---|---|
POST |
/api/domainkit/connection/start |
Authenticates the host principal and returns an authorization URL |
GET |
/api/domainkit/callback/:providerId |
Consumes state once, commits the connection, and redirects |
The start body accepts providerId, method, an optional provider-selection domain, an optional
existing authorizationId, and a same-origin returnTo. When authorizationId is present,
Server.ConnectionPolicy must authorize that exact aggregate for the authenticated principal
before DomainKit can reuse it. Callback redirects append
domainkit=connected and the public connectionId so the host UI can continue its setup flow.
Host services
| Export | Purpose |
|---|---|
Server |
Routes, configuration, host service tags, errors, and the Web handler adapter |
| Service | Host responsibility |
|---|---|
Server.Identity |
Authenticate a start request and return tenant-owned principal identifiers |
Server.ConnectionPolicy |
Authorize an exact existing aggregate before connection reuse |
Server.Providers |
Build a configured interactive provider flow for the selected domain and callback |
Server.PendingAuthorizations |
Persist the opaque continuation and safe callback context until one-time consume |
ManagedDnsConnections.Service |
Persist the durable authorization, credential, connection, and attachment aggregate |
Crypto.Crypto |
Generate continuation, authorization, and connection identifiers |
createDomainKit is also a named export for Promise hosts. Its identity, connectionPolicy,
providers, pendingAuthorizations, and persistence options correspond to these Effect
services. Build Effect sibling implementations with Layer.mergeAll, then provide the completed
dependency graph to Server.layer once.
Failure behavior
Failures are returned as JSON with category, message, operation, and retry. Start requests
without a host identity return 401, and denied aggregate reuse returns 403. Invalid provider
input, unsafe return URLs, mismatched callbacks, expired state, and replayed state return 400.
Configuration failures return 500, provider infrastructure failures return 502, and storage
failures return 503. Provider tokens and opaque continuation payloads are never serialized to the
browser response.