Point0by 1gr14
  • Меню
    • GitHub
    • Блог
  • Introduction
    • Overview
    • Getting Started
    • Full Overview
    • Benchmarks
    • Points
  • Points
    • Page
    • Layout
    • Component
    • Provider
    • Mountable
    • Query
    • Infinite Query
    • Mutation
    • Action
    • Root
    • Base
    • Plugin
  • Methods
    • Validation
    • Loader
    • Context
    • Middleware
    • Loading & error
    • .with
    • Mapper
    • Transformer
    • Stage Methods
  • Core
    • Navigation
    • SSR
    • RSC
    • Request
    • Response
    • Error handling
    • Env
    • Head
    • MDX
    • Assets
    • File upload
    • OpenAPI
    • Query client
    • Events
    • Infer
  • Engine
    • Engine Config
    • Engine Runtime
    • CLI
    • Dev
    • Build
    • Compiler
    • Generator
    • Project MCP
    • Docs MCP
    • Importer
    • Public dir
    • Testing
    • Deploy
    • Bun or Vite
  • Extra
    • SsrStore
    • CookieStore
    • Basic Auth
    • CORS
    • Cache-Control
    • Compress
  • Examples
    • Basic
    • Vite
    • Better Auth
    • Capacitor
    • Expo
  • 1gr14
    • Главная
    • Start0
    • Поддержать
    • Обучение
    • Группа
    • Блог
    • Автор
  • Сообщество
    • Discord
    • Telegram
  • Опенсорс
    • Point0
    • Route0
    • Error0
    • Flat
  • Аккаунт
    • Войти
    • Регистрация
Point0by 1gr14
Создаю опенсорс во славу Господа Иисуса Христа ☦️
С любовью ко всем разработчикам на свете ❤️
Условия использованияПолитика конфиденциальностиСергей Дмитриев 2026 😎

CORS

  • Раздел: Extra

On this page

  1. Mounting it
  2. Locking down the origin: origin
  3. Preflight: preflight
  4. Methods and headers
  5. Credentials and caching
  6. Reference
  7. cors(options)
  8. Behavior at a glance

@point0/cors is a CORS middleware. cors(options) returns a Point0 middleware function: mount it on your root and every response gets the Access-Control-* headers, and every preflight OPTIONS request gets a 204 — so a client on a different origin (a native/mobile app, or a front-end served from another domain) can call your API.

import { Point0 } from '@point0/core'
import { cors } from '@point0/cors'

// examples/expo/src/lib/root.tsx — let the native app reach the API
export const root = Point0.lets
  .root()
  .middleware(cors()) // ← every response carries CORS headers; OPTIONS → 204
  // ...
  .root()

That bare cors() is the most permissive default: it reflects whatever Origin the request carried, allows credentials, mirrors the request method, and echoes the requested headers back. The shipped expo example uses it because the Expo app and the API server live on different origins.

cors() is cut from the client bundle — its body and the imports it uses are removed, so it never ships to the browser. .middleware(...) arguments are server-only, and the compiler prunes the then-unused @point0/cors import with them.

Mounting it

cors(...) is a plain Point0 middleware, so it goes wherever .middleware goes. On the root it covers the whole API, which is the usual placement:

Point0.lets
  .root()
  .middleware(cors({ origin: 'https://app.example.com' }))
  .root()

.middleware also takes a route, so you can scope CORS to a subtree:

.middleware('/api/*', cors())

Locking down the origin: origin

origin decides which request origins are allowed. It defaults to true.

cors({ origin: true }) //                          allow any origin (default)
cors({ origin: false }) //                         allow none
cors({ origin: 'https://app.example.com' }) //     one origin
cors({ origin: ['https://app.example.com', 'https://admin.example.com'] }) // a list
cors({ origin: /\.example\.com$/ }) //             a RegExp tested against the origin
cors({ origin: (ctx) => isAllowed(ctx) }) //       a predicate

How each form resolves:

  • true — reflects the request's Origin header back. With no Origin header it falls back to *.
  • false — never sets Access-Control-Allow-Origin; no cross-origin client is allowed.
  • string — compared against the request origin. A bare host like 'example.com' matches http://example.com and https://example.com (the protocol is ignored). Include a protocol — 'https://example.com' — and the protocol must match too. The match is exact on the host, not a substring: 'example.com' does not match notexample.com.
  • RegExp — .test(requestOrigin); the full origin string (with protocol) is tested.
  • function — receives the middleware context and returns boolean (may be async). Return true to allow the request's origin.
  • array — any mix of the above; the first entry that allows the origin wins.

When a request origin is allowed, that exact origin is echoed back in Access-Control-Allow-Origin (not a literal *), which is what browsers require once credentials are in play.

Preflight: preflight

A cross-origin request that isn't "simple" makes the browser send an OPTIONS preflight first. By default (preflight: true) cors() answers it with a bare 204 carrying the CORS headers — the real request then follows. Set preflight: false to let OPTIONS fall through to your own handler untouched (no CORS headers added):

cors({ preflight: false }) // OPTIONS is passed through to next(), no CORS headers

Methods and headers

cors({
  methods: ['GET', 'POST'], //              Access-Control-Allow-Methods
  allowedHeaders: ['Content-Type', 'Authorization'], // Access-Control-Allow-Headers
  exposeHeaders: ['X-Total-Count'], //      Access-Control-Expose-Headers
})

Each of methods, allowedHeaders, and exposeHeaders takes a string, a string array (joined with , ), or a boolean. They default to true, which means "reflect what the request asked for":

  • methods: true — mirrors the incoming request's method (or the Access-Control-Request-Method on a preflight). '*' and a single method like 'GET' are also accepted; false omits the header.
  • allowedHeaders: true — echoes the Access-Control-Request-Headers the preflight asked for (falling back to the keys present on the request).
  • exposeHeaders: true — exposes the keys present on the request.

Credentials and caching

cors({
  credentials: true, // Access-Control-Allow-Credentials: true (default)
  maxAge: 600, //       Access-Control-Max-Age in seconds
})
  • credentials defaults to true, which sends Access-Control-Allow-Credentials: true. Set it to false to drop the header. With credentials on, an allowed origin is always echoed back literally — the spec forbids * together with credentials, and cors() honors that.
  • maxAge is the preflight cache lifetime in seconds, written to Access-Control-Max-Age. It defaults to 5. A maxAge of 0 omits the header entirely.

Reference

cors(options)

Every option is optional; cors() with no argument is the permissive default.

OptionTypeDefaultWhat
originboolean | string | RegExp | fn | array of thosetruewhich origins are allowed (true reflects the request origin)
methodsboolean | '*' | method | method[]trueAccess-Control-Allow-Methods (true mirrors the request)
allowedHeaderstrue | string | string[]trueAccess-Control-Allow-Headers (true reflects the request)
exposeHeaderstrue | string | string[]trueAccess-Control-Expose-Headers (true reflects the request)
credentialsbooleantruesend Access-Control-Allow-Credentials: true
maxAgenumber5Access-Control-Max-Age in seconds (0 omits the header)
preflightbooleantrueanswer OPTIONS preflight with 204 (else pass through)

Behavior at a glance

AspectBehavior
Sidecut from the client bundle — the .middleware(...) argument and its imports are removed, so it never ships to the browser
Default originreflects the request Origin; * only when there's no Origin header
Credentials + originan allowed origin is echoed literally, never * (spec requirement)
String origin matchhost-only by default; add a protocol to require a protocol match
Preflight OPTIONSanswered with 204 when preflight: true; passed through otherwise
Varyset to Origin for a reflected origin, * for a wildcard

If you also expose OpenAPI docs from a separate origin, the same cors() on the root covers those routes too.

НазадBasic AuthДалееCache-Control

Enjoying Point0?

Give it a star on GitHub, ask questions, and follow what's new

Star Point0

A star on GitHub helps more developers find Point0
Star on GitHub

Start0

Point0 integrated into the Start0 SaaS boilerplate — the best way to use it
Explore Start0

YouTube

Tutorials, walkthroughs, and updates
YouTube

Discord

Questions and chat in English
Join Discord

Telegram

News channel and chat in Russian
ChannelChat

Twitter

Posts and updates
Twitter