Elysia
An Elysia plugin for StitchAPI — a principal-bound seam on the request context, an SSE bridge with streamStitchSse returning a Response, and stitch errors mapped to HTTP via the plugin's onError.
Use @stitchapi/elysia when you serve an API with Elysia.
.use() the plugin and every request gets a principal-bound seam on its context,
plus two bridges into Elysia's Web-standard world: an SSE writer and a stitch-error
→ HTTP mapping.
Web-standard by construction. Elysia is Bun-first, but the plugin
imports only elysia and stitchapi — there are no node:* imports,
so it runs unchanged on Bun, Node, Deno, and the edge.
Example
Install the package alongside core and Elysia:
npm install @stitchapi/elysia stitchapi elysiaBuild (and own) the seam once at startup, then .use() the plugin. With a
principal resolver, each request's context stitch is a seam.as(id) handle — a
principal-bound seam with separate auth sessions per principal over one shared
throttle. A .derive runs per request and puts it on the context, so a handler
reads it straight off the destructured context:
import { stitch } from '@stitchapi/elysia';
import { Elysia } from 'elysia';
import { seam } from 'stitchapi';
import { z } from 'zod';
const api = seam({ baseUrl: 'https://api.example.com' });
const app = new Elysia()
.use(
stitch({
seam: api,
principal: ({ request }) =>
request.headers.get('x-tenant') ?? undefined,
}),
)
.get('/me', ({ stitch }) =>
stitch.stitch({
path: '/me',
output: z.object({ id: z.string(), name: z.string() }),
})(),
);The principal lives in the closure, never in a call argument, so a handler can
never name another identity. Returning undefined falls back to the unbound root
seam for that request (e.g. anonymous). Borrow, don't own: the plugin never
calls seam.close() — you build the seam at startup and await api.close() on
shutdown.
Streaming — streamStitchSse
Stream a streaming/SSE stitch's .stream() to the client by returning the
text/event-stream Response streamStitchSse builds. Each delta becomes a
data: message; a terminal error (or a throw) becomes a final event: error
message; control events are consumed but not forwarded; and a client disconnect
cancels the body and aborts the upstream stitch stream.
import { stitch, streamStitchSse } from '@stitchapi/elysia';
import { Elysia } from 'elysia';
import { seam } from 'stitchapi';
import { sseSurface } from 'stitchapi/sse';
const api = seam({ baseUrl: 'https://api.example.com' });
const app = new Elysia()
.use(stitch({ seam: api }))
.get('/chat', ({ stitch, query }) => {
const chat = stitch.stitch({ kind: sseSurface, path: '/v1/messages' });
return streamStitchSse(chat.stream({ body: { prompt: query.q } }), {
data: (chunk) => (chunk as { data: string }).data,
});
});Anti-pattern: return the streamStitchSse Response as the handler's
result — don't also set set.status / set.headers or return a second
value from the same handler. The helper builds the complete
text/event-stream response (status, headers, and the frame body); a
competing write corrupts the stream.
Errors
A failed stitch throws a StitchError carrying the upstream status. The plugin
registers an .onError that maps it to an HTTP response (502 by default, so an
upstream's status is never leaked) and lets every other error fall through to
Elysia's default handling — so handlers need no try/catch:
import { stitch } from '@stitchapi/elysia';
import { Elysia } from 'elysia';
import { seam } from 'stitchapi';
const api = seam({ baseUrl: 'https://api.example.com' });
const app = new Elysia().use(
stitch({
seam: api,
// the default is a safe 502; propagate the upstream status instead:
errorHandler: { status: (e) => e.status ?? 502 },
}),
);Set errorHandler: false to register none and wire your own with stitchOnError
(an .onError-compatible mapper) or stitchErrorResponse(err, options) (a one-off
StitchError → Response); isStitchError narrows an unknown error first.
On Bun clusters and other multi-runtime deployments, pair the seam with a shared store so throttle and sessions are fleet-wide rather than per-process.
See also
Hono
Edge-ready Hono middleware for StitchAPI — a principal-bound seam on c.var.stitch, an SSE bridge with streamStitchSse, and stitch errors mapped to HTTPException.
Express
Express 4/5 middleware for StitchAPI — a principal-bound seam on req.stitch, an SSE bridge with streamStitchSse, and stitch errors mapped to JSON by a 4-arg error handler.