@tetsujs/cors lets a page on another origin call the API. It is one
beforeParse hook: it answers the browser’s preflight request and adds the
CORS headers to every other response.
A list is matched exactly and echoed back — echoing rather than
returning the list is what the header format requires. "*" allows
every origin, and is refused together with credentials, which the
specification does not permit.
An origin is written as a browser sends it — scheme, host and port,
nothing after: https://app.example.com. Anything else never matches,
so it is refused where it is written, naming the origin it means: a
trailing slash, capitals, a path, a default port. "null" — what a
sandboxed frame or a file: page sends — is taken as it is, and
refused with credentials: any site can send it.
On a request from an allowed origin, the hook puts its headers in ctx.out,
which the core applies to whatever response leaves, errors and 404s
included. A request from any other origin gets no CORS headers, and the
browser keeps the answer from the page.
Mount it on the application, not on a group. Group hooks do not run for
404, 405 and OPTIONS preflights (see Groups and
mounting), so CORS on a group would miss
the preflight it is for.
Mount it before every hook that can refuse, such as an authentication check
or a rate limit. A refusal from a hook placed before cors() goes out without
CORS headers, and the browser cannot read it. A preflight also carries no
credentials, so an authentication check placed first would refuse it.
Hooks that never refuse, such as requestId() and arrivalLog(), can go
before it. Preflights then get a request id and an arrival line too; placed
after it, they get neither.
allow cookies and credentials; refused with origin: "*" and with "null"
maxAge
86400
how long a browser may cache a preflight, in seconds
constbrowser=cors({
origin: string | readonly string[]
Which origins are allowed.
A list is matched exactly and echoed back — echoing rather than
returning the list is what the header format requires. "*" allows
every origin, and is refused together with credentials, which the
specification does not permit.
An origin is written as a browser sends it — scheme, host and port,
nothing after: https://app.example.com. Anything else never matches,
so it is refused where it is written, naming the origin it means: a
trailing slash, capitals, a path, a default port. "null" — what a
sandboxed frame or a file: page sends — is taken as it is, and
refused with credentials: any site can send it.
Response headers a browser may read. Empty by default.
exposeHeaders: ["x-request-id"],
});
Write each origin as a browser sends it: scheme, host and port, in lowercase,
with nothing after. Origins are compared exactly, so https://app.example.com/
or https://App.example.com would never match. cors() throws at startup
instead and names the origin you meant. Patterns are not supported: an origin
containing * is refused.
Custom schemes such as capacitor://localhost or chrome-extension://… work
as long as they are written in lowercase. "null", which sandboxed frames and
file: pages send, is accepted, but not together with credentials, since any
site can send it.
access-control-allow-origin: the request’s origin, or *;
access-control-allow-credentials: true, with credentials;
access-control-expose-headers, with exposeHeaders.
An OPTIONS request from an allowed origin is answered by the hook itself with
204, plus access-control-allow-methods, access-control-allow-headers and
access-control-max-age. It does not reach later hooks or a handler.
Unless origin is "*", every response carries vary: origin, including
those without CORS headers. Without it, a shared cache could serve one origin’s
answer to another. A Vary header the handler set is kept and merged.
The package also exports the types CorsOptions and CorsHook. Type a hook
with ReturnType<typeof cors> (which is CorsHook) rather than AnyHook,
which erases the slot the hook belongs to.