Overview
Every API response must include CORS headers so browsers allow the frontend to read it. Two parallel implementations exist — one for standalone edge functions, one for the sebuf gateway — but they share the same origin allowlist and logic.| File | Used by | Methods |
|---|---|---|
api/_cors.js | Standalone edge functions (api/*.js) | GET, OPTIONS (configurable) |
server/cors.ts | Sebuf gateway (api/[domain]/v1/[rpc].ts) | GET, POST, OPTIONS |
Allowed Origins
Both files use the same regex patterns:| Pattern | Matches |
|---|---|
(*.)?worldmonitor.app | Production + subdomains (tech., finance., etc.) |
worldmonitor-*-elie-*.vercel.app | Vercel preview deploys |
localhost:* / 127.0.0.1:* | Local development |
tauri.localhost:* / *.tauri.localhost:* | Desktop app (Tauri v2) |
tauri://localhost / asset://localhost | Desktop app (Tauri v2 asset protocol) |
Origin header (server-to-server, curl) are allowed through — the isDisallowedOrigin check only blocks when an origin is present and not on the allowlist.
Adding CORS to a New Edge Function
Every standalone edge function inapi/ must handle CORS manually. Follow this pattern:
- Every response must include
...corsin its headers — including errors, rate-limit 429s, and 500s. - Preflight (
OPTIONS) must return204with CORS headers and no body. getCorsHeaders(req, methods)— pass a custom methods string if the endpoint supports more thanGET, OPTIONS(e.g.,'POST, OPTIONS').
Sebuf Gateway (RPC Endpoints)
RPC endpoints defined in.proto files do not need manual CORS handling. The gateway (server/gateway.ts) calls getCorsHeaders() and isDisallowedOrigin() from server/cors.ts automatically for every request. CORS headers are injected into all responses including error boundaries.
Adding a New Allowed Origin
To allow a new origin:- Add a regex pattern to
ALLOWED_ORIGIN_PATTERNSin bothapi/_cors.jsandserver/cors.ts. - Update the test in
api/_cors.test.mjs. - If the origin is a new production subdomain, also add it to the Cloudflare R2 CORS rules (see MEMORY.md notes on R2 CORS in the repo root).
Allowed Headers
Both implementations allow these request headers:Content-TypeAuthorizationX-WorldMonitor-Key(API key for desktop/third-party access). See API Key Gating for key management details.
Access-Control-Allow-Headers in both files.
Railway Relay CORS
The Railway relay (scripts/ais-relay.cjs) has its own CORS handling with the ALLOW_VERCEL_PREVIEW_ORIGINS env var. See RELAY_PARAMETERS.md for details.