Skip to main content
SvelteKit keeps server work in +page.server.ts. A load function fetches, +page.svelte renders, and form actions mutate. Corsair drops straight into that flow, with load reading from .db and form actions writing through .api, and the handler itself living in a Web-standard endpoint.

Install

The adapters ship inside core corsair; add one plugin package per service you connect.

Create the instance

Build the instance once. The handler and your read/write code both import it.
corsair.ts
The handler and every .db / .api call on this page import this corsair. multiTenancy: true is what makes corsair.withTenant(id) available, and a tenant.github.* call resolves to the github() entry here. Add a service by installing its @corsair-dev/* package and dropping it into plugins. Database choices and the Hub keys are in Quick Start.

Project layout

Mount the handler

An endpoint receives a Request and returns a Response, which is exactly the adapter’s shape. Add a rest-parameter route and export the pair.
src/routes/api/corsair/[...rest]/+server.ts
$lib/server/corsair is your createCorsair({ ... }) instance. The [...rest] segment catches /api/corsair and every path beneath it.

Resolve the tenant

Set the signed-in user on event.locals in hooks.server.ts, which is your auth’s job, not Corsair’s. Then load and form actions read it off locals and hand the id to withTenant.

Read and write

load reads .db and hands the data to the page, with no network on navigation. A form action writes through .api; because Corsair upserts the response into your database as part of the call, the next load sees the row already current.
src/routes/issues/+page.server.ts
The page renders data.issues and posts to the action. Entity fields live on .data in camelCase:
src/routes/issues/+page.svelte

Refresh after a write

A form action that returns nothing makes SvelteKit re-run the page’s load, so the closed issue drops off on its own. When a write happens outside a form, such as a button handler or a websocket message, call invalidate to re-run load yourself; the .api upsert means the re-read is already current.

Connect a tenant

A tenant connects GitHub before load has anything to read. Svelte isn’t React, so use the vanilla client from a component, a load function, or a script.
1

Create the client

corsair-client.ts
createCorsairClient is a typed fetch wrapper over the management API, no React required. Use it from your frontend, a worker, or a script. Every route is typed against its response. Full surface on the Vanilla Client reference.
2

Read what's connected

connections.ts
connectionStatus.get returns a map of plugin id to connected | missing_credentials | not_connected, so you can show what’s live and what still needs connecting.
3

Mint a connect link

connect.ts
Hub hosts the consent screen and runs the OAuth handshake. When the user returns, the tokens are already encrypted in your own database. You never saw them, and neither did Hub. Swap "github" for any plugin you configured.

Go green

The first request to /api/corsair registers your delivery URL with Hub and turns the App sync dot in the dashboard header green.

Deploy

Pick the SvelteKit adapter for your target (adapter-node, adapter-vercel, and so on) and deploy as usual. The endpoint runs server-side under every adapter, so in production /api/corsair is the delivery URL Hub calls.

Next

Build a dashboard

The .db read / .api write pattern in full, with refresh and webhooks.

Vanilla client

Every management-API method the client exposes, fully typed.

Connect / OAuth

The full connect flow, error codes, and retry.

Multi-tenancy

One flag and every user gets their own data and credentials.