Next.js
Web-standard helpers for Next App Router route handlers — streamStitchSse streams a stitch as text/event-stream, and stitchErrorResponse maps a StitchError to a Response.
Next App Router route handlers are Web-standard: they take a Request and return
a Response. So a stitch already runs in one directly — define a seam
once and call it in the handler. @stitchapi/next adds the two bits you'd otherwise
hand-roll on the Web platform: streaming a stitch as Server-Sent Events, and mapping a
StitchError to a Response.
It's built on Web standards only (Response, ReadableStream, TextEncoder) — no
next import — so the same helpers also work in Remix, SvelteKit endpoints, Bun,
Deno, and Workers.
Example
npm install @stitchapi/next@rc stitchapi@rcstitchapi is the only peer dependency.
A route handler
A non-streaming endpoint is the stitch plus the error helper — no per-route
try/catch shape to invent:
// app/api/users/[id]/route.ts
import { getUser } from '@/lib/api';
import { stitchErrorResponse } from '@stitchapi/next';
export async function GET(
_req: Request,
{ params }: { params: Promise<{ id: string }> },
) {
const { id } = await params;
try {
return Response.json(await getUser({ params: { id } }));
} catch (err) {
const mapped = stitchErrorResponse(err);
if (mapped) return mapped;
throw err;
}
}stitchErrorResponse returns a Response for a StitchError and undefined for
anything else — map the stitch failure, rethrow the rest, no instanceof dance.
It maps to 502 by default — the safe choice that never leaks the
upstream's 401/404 semantics. Pass { status: (e) => e.status ?? 502 } to
propagate the upstream status instead.
Streaming with SSE
streamStitchSse streams a stitch's events as text/event-stream. Each delta
becomes one frame; an error event ends the stream with a named event: error
frame whose data is a generic error token by default (opt in to a client-facing
message with error); the terminal result closes it:
// app/api/chat/route.ts
import { chat } from '@/lib/api';
import { streamStitchSse } from '@stitchapi/next';
export async function POST(request: Request) {
const { prompt } = await request.json();
return streamStitchSse(chat({ body: { prompt } }).stream(), {
delta: (c) => String(c), // pull text out of each chunk
signal: request.signal, // abort the upstream if the client leaves
});
}Pass request.signal so a client disconnect aborts the upstream iterator rather than
leaving it running.
On the client, pair a streaming route with
useStitchStream (or the Vue / Svelte / Angular
binding) to render tokens as they arrive.
See also
NestJS
Wire stitches into a NestJS app with StitchModule — injectable stitches, a Logger trace bridge, ConfigService-backed secrets, and request-scoped multi-tenancy.
Angular
injectStitch and injectStitchStream expose a stitch's lifecycle as both Angular signals and an RxJS observable over the framework-agnostic @stitchapi/query-core store — plus an optional TanStack Query adapter.