{
  "$schema": "https://hyperjs.ai/schema/registry-item.json",
  "name": "cors",
  "version": "0.1.0",
  "description": "Minimal, strict CORS middleware for Hyper.",
  "readme": "# @hyper/cors\n\nMinimal, strict CORS middleware for Hyper.\n\n## Install\n\nComponents are installed as source into your repo, not pulled from npm:\n\n```bash\nbunx hyper add cors\n```\n\nWires the alias `@hyper/cors` to `src/hyper/cors/` (configurable in `hyper.config.json`). See [hyperjs.ai](https://hyperjs.ai) for the full registry.\n\n## Usage\n\n```ts\nimport { Hyper } from \"@hyper/core\"\nimport { corsPlugin } from \"@hyper/cors\"\n\nexport default new Hyper()\n  .use(corsPlugin({ origin: [\"https://example.com\"] }))\n  .get(\"/\", () => ({ hello: \"world\" }))\n  .listen(3000)\n```\n\n## Docs\n\nSee the [main README](../../README.md) and [docs/](../../docs) for guides and integration recipes.\n\n## License\n\nMIT\n",
  "registryDeps": [
    "core"
  ],
  "peerDeps": {},
  "optionalPeerDeps": {},
  "files": [
    {
      "path": "cors/index.ts",
      "contents": "/**\n * @hyper/cors — strict, zero-config-wins CORS for Hyper.\n *\n * Secure by default:\n *   - origins MUST be a list or a callback; wildcard \"*\" is refused when\n *     credentials are on.\n *   - vary: Origin is always set.\n *   - Preflight answered via plugin pre-hook (short-circuits route match).\n *\n * Usage:\n *   app({ plugins: [corsPlugin({ origin: [\"https://app.example.com\"] })] })\n */\n\nimport type { HyperPlugin } from \"@hyper/core\"\n\nexport interface CorsConfig {\n  readonly origin: readonly string[] | ((origin: string) => boolean) | \"*\"\n  readonly methods?: readonly string[]\n  readonly headers?: readonly string[]\n  readonly credentials?: boolean\n  readonly exposeHeaders?: readonly string[]\n  readonly maxAge?: number\n  /**\n   * Opt out of the wildcard-origin hard error. Off by default.\n   *\n   * Passing `origin: \"*\"` without this flag is rejected at boot because\n   * wildcard CORS effectively disables the Same-Origin Policy for your\n   * API — any site on the internet can read it. If you really want that,\n   * set `allowAnyOrigin: true` to acknowledge the risk.\n   */\n  readonly allowAnyOrigin?: boolean\n}\n\nconst DEFAULT_METHODS = [\"GET\", \"HEAD\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\", \"OPTIONS\"] as const\nconst DEFAULT_HEADERS = [\"content-type\", \"authorization\", \"x-request-id\"] as const\n\nfunction assertValid(config: CorsConfig): void {\n  if (config.credentials && config.origin === \"*\") {\n    throw new Error(\n      \"cors: credentials=true is incompatible with origin='*'. \" +\n        \"Why: browsers refuse to send credentials to wildcard origins; this configuration never works. \" +\n        \"Fix: list the exact origins you trust in `origin: [...]`.\",\n    )\n  }\n  if (config.origin === \"*\" && !config.allowAnyOrigin) {\n    throw new Error(\n      \"cors: origin='*' is refused by default. \" +\n        \"Why: wildcard CORS lets every site on the internet read responses from your API. \" +\n        \"Fix: pass an explicit allow-list (`origin: ['https://app.example.com']`) or a predicate \" +\n        \"(`origin: (o) => o.endsWith('.example.com')`). If you really want public read access \" +\n        \"(public docs, OSS metrics, etc.), set `allowAnyOrigin: true` to acknowledge the risk.\",\n    )\n  }\n}\n\nfunction resolveOrigin(config: CorsConfig, origin: string): string | null {\n  if (config.origin === \"*\") return \"*\"\n  if (typeof config.origin === \"function\") return config.origin(origin) ? origin : null\n  return config.origin.includes(origin) ? origin : null\n}\n\nexport function corsPlugin(config: CorsConfig): HyperPlugin {\n  assertValid(config)\n  const allowMethods = (config.methods ?? DEFAULT_METHODS).join(\", \")\n  const allowHeaders = (config.headers ?? DEFAULT_HEADERS).join(\", \")\n  const exposeHeaders = config.exposeHeaders?.join(\", \")\n  const maxAge = (config.maxAge ?? 600).toString()\n  return {\n    name: \"@hyper/cors\",\n    request: {\n      preRoute({ req }) {\n        if (req.method !== \"OPTIONS\" || !req.headers.has(\"access-control-request-method\")) {\n          return\n        }\n        const origin = req.headers.get(\"origin\") ?? \"\"\n        const allowed = origin ? resolveOrigin(config, origin) : null\n        const headers = new Headers({ vary: \"Origin, Access-Control-Request-Headers\" })\n        if (allowed) {\n          headers.set(\"access-control-allow-origin\", allowed)\n          headers.set(\"access-control-allow-methods\", allowMethods)\n          headers.set(\"access-control-allow-headers\", allowHeaders)\n          headers.set(\"access-control-max-age\", maxAge)\n          if (config.credentials) headers.set(\"access-control-allow-credentials\", \"true\")\n        }\n        return new Response(null, { status: 204, headers })\n      },\n      after({ req, res }) {\n        const origin = req.headers.get(\"origin\")\n        if (!origin) return\n        const allowed = resolveOrigin(config, origin)\n        if (!allowed) return\n        res.headers.append(\"vary\", \"Origin\")\n        res.headers.set(\"access-control-allow-origin\", allowed)\n        if (config.credentials) res.headers.set(\"access-control-allow-credentials\", \"true\")\n        if (exposeHeaders) res.headers.set(\"access-control-expose-headers\", exposeHeaders)\n      },\n    },\n  }\n}\n",
      "sha256": "2e899bd6938273e082d8741be0ecad1d20dfca98962b594a54ccc777c7c29f8c"
    }
  ],
  "subpaths": {}
}