CORS

Cross-Origin Resource Sharing configuration. Handles preflight OPTIONS requests and sets CORS headers on responses.

The cors() function returns an object with two pieces:

  • preflight(route) registers a catch-all OPTIONS /** route that responds to preflight requests with the appropriate CORS headers.
  • headers(request, response) adds CORS headers to a response. Call it in onResponse.
import { setup, route, cors } from "@hectoday/http";

const corsConfig = cors({ origin: "*" });

const app = setup({
  onResponse: ({ request, response }) => {
    return corsConfig.headers(request, response);
  },
  routes: [
    corsConfig.preflight(route),
    /* ... */
  ],
});

cors() options

cors({
  origin: "*", // or string[]
  methods: ["GET", "POST", "PUT", "DELETE"], // Allowed methods
  allowHeaders: ["Content-Type", "Authorization"], // Allowed request headers
  exposeHeaders: ["X-Request-Id"], // Headers the browser can read
  credentials: true, // Allow cookies/auth headers
  maxAge: 86400, // Preflight cache duration (seconds)
});

origin

Type: string | string[]

Which origins are allowed to make requests.

// Allow all origins
cors({ origin: "*" });

// Allow one origin
cors({ origin: "https://myapp.com" });

// Allow multiple origins
cors({ origin: ["https://myapp.com", "https://admin.myapp.com"] });

methods

Type: string[] — Default: ["GET", "HEAD", "PUT", "PATCH", "POST", "DELETE"]

HTTP methods allowed in cross-origin requests.

allowHeaders

Type: string[] — Default: []

Request headers the client is allowed to send. If not specified, the handler echoes back whatever the browser requests in Access-Control-Request-Headers.

exposeHeaders

Type: string[] — Default: []

Response headers the browser is allowed to read. By default, browsers can only read a small set of “simple” headers. Add custom headers here.

cors({ origin: "*", exposeHeaders: ["X-Request-Id", "X-Response-Time"] });

credentials

Type: boolean — Default: false

Whether to allow credentials (cookies, Authorization header) in cross-origin requests. When true, origin cannot be "*". The handler will echo back the requesting origin instead and set Access-Control-Allow-Credentials: true.

maxAge

Type: number — Default: none

How long (in seconds) the browser caches the preflight response. A preflight is an OPTIONS request the browser sends before the actual request. Caching it avoids an extra round trip.

How it works

Preflight requests

corsConfig.preflight(route) registers a catch-all OPTIONS /** route. When the browser sends a preflight request, this route responds with a 204 No Content and the appropriate CORS headers (Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headers, etc.). The request never reaches your other routes.

Actual requests

corsConfig.headers(request, response) reads the Origin header from the request, checks it against the allowed origins, and returns a new response with the CORS headers attached. Call it at the end of onResponse and return its result.

Example: API with frontend

import { setup, route, cors } from "@hectoday/http";

const corsConfig = cors({
  origin: ["https://myapp.com", "http://localhost:5173"],
  credentials: true,
  exposeHeaders: ["X-Request-Id"],
});

const app = setup({
  onResponse: ({ request, response }) => {
    return corsConfig.headers(request, response);
  },
  routes: [
    corsConfig.preflight(route),
    /* ... */
  ],
});

This allows requests from the production frontend (myapp.com) and the local dev server (localhost:5173), with cookies and auth headers permitted.