Utilities

Low-level helpers from @hornjs/fest for custom integration, advanced middleware composition, and framework authoring.

Before You Reach For These

Most applications only need:

  • Server
  • route tables
  • middleware
  • createContextKey()

The helpers on this page are mainly useful if you are:

  • composing handlers programmatically
  • integrating fest into another host runtime
  • building higher-level abstractions on top of fest
  • coordinating request-scoped async work manually

Import

import {
  createServerRequest,
  createWaitUntil,
  raceRequestAbort,
  runMiddleware,
  toServerHandlerObject,
  wrapFetch,
  type HTTPMethod,
  type MaybePromise,
} from "@hornjs/fest";

createServerRequest()

Turn an existing Request into a ServerRequest.

This is the low-level helper behind server.createRequest(). In normal application code, prefer server.createRequest(request) when you already have a Server instance.

createServerRequest() is most useful when you need to derive a new request while preserving invocation state from an existing ServerRequest.

import { createServerRequest, type ServerRequest } from "@hornjs/fest";

function replaceHeaders(request: ServerRequest, headers: HeadersInit) {
  return createServerRequest(new Request(request, { headers }), {
    context: request.context,
    runtime: request.runtime,
    waitUntil: request.waitUntil,
    originalRequest: request._request ?? request,
    params: request.params,
  });
}

The resulting ServerRequest keeps the expected fest fields such as:

  • context
  • runtime
  • waitUntil
  • _request
  • params
  • clone()

raceRequestAbort()

Tie async work to a request's abort signal.

If the request aborts before the promise settles, the returned promise rejects with the abort reason.

import { raceRequestAbort } from "@hornjs/fest";

async function readUser(request: Request) {
  return raceRequestAbort(fetch("https://example.com/api/user"), request);
}

This is useful when you are writing helpers that should stop surfacing results for requests the client has already abandoned.

createWaitUntil()

Create a small registry for background tasks.

This mirrors service-worker-style waitUntil() behavior: register promises as work that should still be awaited later.

import { createWaitUntil } from "@hornjs/fest";

const waiter = createWaitUntil();

waiter.waitUntil(sendAnalytics());
waiter.waitUntil(writeAuditLog());

await waiter.wait();

Rejected promises are logged and removed so a later wait() call can still finish cleanly.

Handler Composition

toServerHandlerObject()

Normalize a bare handler or handler object into the object form used by fest.

const handlerObject = toServerHandlerObject((request) => {
  return new Response(`Hello ${new URL(request.url).pathname}`);
});

await handlerObject.handleRequest(request);

This is useful when your own abstraction wants to accept either:

  • a bare ServerHandler
  • or a { handleRequest, middleware } object

runMiddleware()

Execute a middleware chain against a terminal handler.

const response = await runMiddleware(
  middleware,
  request,
  async (request) => new Response(new URL(request.url).pathname),
);

runMiddleware() is a low-level primitive. Callers are expected to pass a valid ServerRequest, not a raw Request.

If the terminal handler is a handler object with its own middleware, that inner middleware runs after the outer middleware array completes.

wrapFetch()

Compose a Server instance into the final fetch-style request kernel.

Server uses this internally after plugins and runtime adapter setup. You usually do not need it unless you are testing or building a custom abstraction around Server.

const kernel = wrapFetch(server);
const response = await kernel(server.createRequest(new Request("http://localhost/")));

Type Helpers

MaybePromise<T>

Use MaybePromise<T> for APIs that may return either a sync value or a promise.

type Loader<T> = () => MaybePromise<T>;

HTTPMethod

HTTPMethod is the string union used by route-table method maps:

  • GET
  • POST
  • PUT
  • DELETE
  • PATCH
  • HEAD
  • OPTIONS
Read more in Invocation Context.
Read more in Middleware.