(config) => readonly [...parts], outermost first. Return
the tuple as const so its length and order are visible to the types.
Optionalinternal?: InternalKeys that are plumbing rather than public API. They are
absent from the composite's declared contributions and stripped from ctx at
its boundary, so a downstream layer sees neither the type nor the value. Each
must be a key some part actually contributes.
They are scoped to the composite, not deleted from the stack: a key an
upstream layer contributed under the same name is restored on the way out, so
marking a key internal can never make someone else's vanish. Restoring has to
happen at runtime, because internal keys are absent from Contributes and so
invisible to both NoConflict and ValidateEntries — the downstream
type keeps the upstream's value, and this is what makes the runtime agree.
import { defineComposite } from '@supabase/middleware'
// `withGate` contributes the whole auth result at `ctx.auth`; the projections
// republish the individual keys the public contract promises. `auth` itself is
// an implementation detail, so it is marked internal.
export const withAuth = defineComposite({
build: (config: { mode: 'user' | 'none' }) =>
[withGate(config), withMode(), withClaims()] as const,
internal: ['auth'],
})
// Nested, or flat — one declaration serves both.
export default {
fetch: pipeline([withAuth({ mode: 'user' }), withPostgres()], async (req, ctx) => {
ctx.authMode // from withMode
ctx.jwtClaims // from withClaims
ctx.postgres // reads ctx.jwtClaims as its own `In`
return Response.json({ ok: true })
}),
}
Bundles a series of middleware into a single middleware.
buildreceives the composite's config and returns the parts, outermost first — the same orderpipelinetakes. The composite's contributions are derived from the parts', so it publishes exactly the union of what they contribute. There is no argument for declaring a key, so a composite cannot over-declare — andinternalmay only name a key some part actually contributes. Prerequisites are derived the same way — a part'sInthat an earlier part contributes is discharged internally, and anything outstanding becomes the composite's ownIn.At runtime the parts fold exactly as
pipelinefolds them, each merging its own single key. A part that short-circuits therefore does so from inside the fold, where an enclosing middleware's response seam observes its response.