@supabase/middleware - v0.6.0
    Preparing search index...

    Function defineComposite

    • Bundles a series of middleware into a single middleware.

      build receives the composite's config and returns the parts, outermost first — the same order pipeline takes. 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 — and internal may only name a key some part actually contributes. Prerequisites are derived the same way — a part's In that an earlier part contributes is discharged internally, and anything outstanding becomes the composite's own In.

      At runtime the parts fold exactly as pipeline folds 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.

      Type Parameters

      • Config
      • const Entries extends readonly AnyEntry[]
      • const Internal extends readonly (keyof Contributions<Entries, Record<never, never>> & string)[] = []

      Parameters

      • spec: { build: (config: Config) => Entries; internal?: Internal }
        • build: (config: Config) => Entries

          (config) => readonly [...parts], outermost first. Return the tuple as const so its length and order are visible to the types.

        • Optionalinternal?: Internal

          Keys 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.

      Returns Composite<
          Omit<Contributions<Entries, Record<never, never>>, Internal[number]>,
          Config,
          Prerequisites<Entries, Record<never, never>, Record<never, never>>,
      >

      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 })
      }),
      }