Release candidate — 1.0.0-rc.1
StitchAPI
Concepts

The seam

The shared-runtime primitive a set of stitches belong to — one store, vault, throttle bucket, and trace sink behind a shared base config and a trusted principal boundary.

A seam is the second primitive StitchAPI is built on: a long-lived surface that stitches belong to. Where a stitch is one call, a seam is the shared runtime behind a whole set of them — one store, one auth vault, one throttle bucket, one trace sink — fronted by a shared base config and a trusted principal boundary.

Why it's shaped this way

A single API is rarely one call. You wrap a handful of endpoints against the same host, with the same auth, the same rate limit, and the same place you want traces to land. The question a seam answers is what those stitches should share — and the answer is more than configuration.

A fragment shares config; a seam shares runtime. A plain object folded in through extends is data: every stitch that extends it gets its own copy — its own throttle counter, its own cookie jar, its own cached tokens. That is the right default, but it can't express "these five stitches draw from one rate budget" or "these share a login". A seam can, because it isn't a fragment the stitches copy — it is the live runtime they all point at. One throttle bucket pools the budget across every member; one vault lets a session captured by one stitch serve the next call; one trace sink sees the whole surface as a single stream.

import { , ,  } from 'stitchapi';
import {  } from 'zod';

const  = .({
    : .(),
    : .(),
    : .(),
    : .(['admin', 'member', 'viewer']),
});

// One seam: the shared base every member inherits, and the runtime they share.
const  = ({
    : 'https://demo.stitchapi.dev',
    : (('API_TOKEN')),
    : { : 3, : [429, 503] },
});

// Members are stitches that belong to the seam — they extend its config and
// share its store, throttle bucket, vault, and trace sink.
const  = .({
    : '/users/{id}',
    : 'data',
    : ,
});
const  = .({
    : '/users',
    : 'data',
    : .(),
});

The decisive job is the trusted principal boundary. seam.as(id) derives a handle whose members carry that principal — and the principal lives in the closure, never in a call's input. A caller invokes a stitch the same way it always does; it cannot name a different principal, because there is no field on the call to name one. Auth is scoped per principal (separate sessions, no bleed between tenants), while the throttle stays shared (one bucket across every principal, so the whole surface still honours one rate limit). That split — isolated identity, pooled budget — is exactly what a multi-tenant server wants, and the seam enforces it by where it holds the principal, not by a check the caller could forget.

Lifecycle belongs to the root, not the per-request handle. flush, close, and invalidate act on the runtime every principal shares, so they live on the root seam alone. A handle from seam.as(...) is deliberately lifecycle-free: the least-trusted, per-request caller can derive its own identity but can never flush the trace sink, close the shared store, or bust the cache out from under the rest of the surface.

How it relates

A seam is the surface-scale companion to the per-call stitch: you still author and call stitches the same way, but they now belong to something.

It owns the fragment that extends composes — reach for a plain fragment when stitches share only config, and a seam when they share runtime. Building and using one is the job of the seam guide.

Its principal boundary is capability, not credential at surface scale: the secret never leaves the runtime, and now the identity the secret authenticates is bound in the closure too. The shared runtime is also what makes the state features work across a whole surface rather than one call — a distributed throttle and shared sessions are a seam pointed at a shared store.

Because the seam is surface-agnostic, it can mint members of any surfacehttp, graphql, sse, stream, download — from the one shared runtime. And it is the object the framework integrations build once per app and bind a principal to per request.

See also

On this page