{"_id":"@dbl-works/cloudflare-router","_rev":"7-0de818de64c92f63954e78957563c90b","name":"@dbl-works/cloudflare-router","dist-tags":{"latest":"3.0.0"},"versions":{"0.2.0":{"name":"@dbl-works/cloudflare-router","version":"0.2.0","author":{"name":"dbl-works"},"license":"MIT","_id":"@dbl-works/cloudflare-router@0.2.0","maintainers":[{"name":"dbl-bot","email":"bot@dbl.works"},{"name":"lud11","email":"lud@reinmiedl.com"}],"homepage":"https://github.com/dbl-works/cloudflare-router#readme","bugs":{"url":"https://github.com/dbl-works/cloudflare-router/issues"},"dist":{"shasum":"899c03f6d817ebb79336bb26ebacd31358205e6d","tarball":"https://registry.npmjs.org/@dbl-works/cloudflare-router/-/cloudflare-router-0.2.0.tgz","fileCount":33,"integrity":"sha512-qCmp+u9W9R8CCephlDM1x1joD14xKcLtG5j8xGmGBxalnxZQlh3/KBX2ywP6MY9gW6Yqypg3RI+Gs7X3u4Py0w==","signatures":[{"sig":"MEUCICzEMy3+m3E3YA1rZB56yMZ6da/dOMSVeu8mrQUdEjZ6AiEArbtM7grpXHAkZxBLE+V/P/4Oie2a41TFcWQk61VLpU8=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":58324},"main":"dist/index.js","gitHead":"aaeb663b839e8ca6e8a4aa4f8b07a80db85cfcac","scripts":{"test":"yarn build && jest test/*.test.ts test/**/*.test.ts --coverage","build":"rm -rf dist && tsc","release":"release-it"},"_npmUser":{"name":"dbl-bot","email":"bot@dbl.works"},"release-it":{"git":{"requireCleanWorkingDir":false},"github":{"release":false}},"repository":{"url":"git+https://github.com/dbl-works/cloudflare-router.git","type":"git"},"_npmVersion":"10.2.1","description":"Cloudflare Router","directories":{},"_nodeVersion":"20.9.0","publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^27.5.1","ts-jest":"^27.0.7","ts-loader":"^9.2.6","release-it":"^16.2.1","typescript":"^4.4.4","@types/jest":"^27.0.2","jest-fetch-mock":"^3.0.3","@types/node-fetch":"^3.0.3","@cloudflare/workers-types":"^3.0.0","jest-environment-miniflare":"^2.14.1"},"_npmOperationalInternal":{"tmp":"tmp/cloudflare-router_0.2.0_1700915111029_0.8215211318775208","host":"s3://npm-registry-packages"}},"0.4.0":{"name":"@dbl-works/cloudflare-router","version":"0.4.0","author":{"name":"dbl-works"},"license":"MIT","_id":"@dbl-works/cloudflare-router@0.4.0","maintainers":[{"name":"dbl-bot","email":"bot@dbl.works"},{"name":"lud11","email":"lud@reinmiedl.com"}],"homepage":"https://github.com/dbl-works/cloudflare-router#readme","bugs":{"url":"https://github.com/dbl-works/cloudflare-router/issues"},"dist":{"shasum":"1d36677734d883bae59265fbf4d741d3d9a3dfe7","tarball":"https://registry.npmjs.org/@dbl-works/cloudflare-router/-/cloudflare-router-0.4.0.tgz","fileCount":35,"integrity":"sha512-0noo8n6RvMU99ELHyC/C1FzJmtiOwvF+FT+IDFyo3avk44pps/GYGnFQyU7uVC9ZeGZQxIe6rgiwO0TbPG6X0w==","signatures":[{"sig":"MEQCIGRKWgEJZTB1ZvGZoknFo2xIxHMj8dKSty5rDwyuHwhTAiBfFzY0BwIQn2gpI4G81sDWGS0IWpc0EOMdPXB31crrnw==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59819},"main":"dist/index.js","gitHead":"bd480bcefeeb87522de16cbbb0bfa057e05a7ba2","scripts":{"test":"yarn build && jest test/*.test.ts test/**/*.test.ts --coverage","build":"rm -rf dist && tsc","release":"release-it"},"_npmUser":{"name":"dbl-bot","email":"bot@dbl.works"},"release-it":{"git":{"requireCleanWorkingDir":false},"github":{"release":true}},"repository":{"url":"git+https://github.com/dbl-works/cloudflare-router.git","type":"git"},"_npmVersion":"8.5.0","description":"Cloudflare Router","directories":{},"_nodeVersion":"16.14.2","publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^27.5.1","ts-jest":"^27.0.7","ts-loader":"^9.2.6","release-it":"^16.2.1","typescript":"^4.4.4","@types/jest":"^27.0.2","jest-fetch-mock":"^3.0.3","@types/node-fetch":"^3.0.3","@cloudflare/workers-types":"^3.0.0","jest-environment-miniflare":"^2.14.1"},"_npmOperationalInternal":{"tmp":"tmp/cloudflare-router_0.4.0_1711449662328_0.6575382863549848","host":"s3://npm-registry-packages"}},"0.4.1":{"name":"@dbl-works/cloudflare-router","version":"0.4.1","author":{"name":"dbl-works"},"license":"MIT","_id":"@dbl-works/cloudflare-router@0.4.1","maintainers":[{"name":"lud11","email":"lud@reinmiedl.com"},{"name":"dbl-bot","email":"bot@dbl.works"}],"homepage":"https://github.com/dbl-works/cloudflare-router#readme","bugs":{"url":"https://github.com/dbl-works/cloudflare-router/issues"},"dist":{"shasum":"b02ab0cb315274708113c92589f267f75094d550","tarball":"https://registry.npmjs.org/@dbl-works/cloudflare-router/-/cloudflare-router-0.4.1.tgz","fileCount":32,"integrity":"sha512-cddXhRMrvcCXuCz5aNaz3E4ITf9L6XA9kPgbDRGl4zwLttLRi5t5EU3pqxKgnMRAF4tQnZHYMQNw1/CEJ9Ea5g==","signatures":[{"sig":"MEUCIGm4KGrLPZjZ1yvrKGmffbt0SvmVckj2Hq3gajXFZ4eoAiEAwtAnrcfdbpaMz7gvgttIY/Sefes1Ongb018Ch/R8XyU=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":59960},"main":"dist/index.js","gitHead":"9c544214a6e9abc89904497947d3766e378bb018","scripts":{"test":"yarn build && jest test/*.test.ts test/**/*.test.ts --coverage","build":"rm -rf dist && tsc","release":"release-it"},"_npmUser":{"name":"dbl-bot","email":"bot@dbl.works"},"release-it":{"git":{"requireCleanWorkingDir":false},"github":{"release":true}},"repository":{"url":"git+https://github.com/dbl-works/cloudflare-router.git","type":"git"},"_npmVersion":"10.9.2","description":"Cloudflare Router","directories":{},"_nodeVersion":"22.13.0","publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^27.5.1","ts-jest":"^27.0.7","ts-loader":"^9.2.6","release-it":"^16.2.1","typescript":"^5.7.3","@types/jest":"^27.0.2","jest-fetch-mock":"^3.0.3","@types/node-fetch":"^3.0.3","@cloudflare/workers-types":"^4.2.0","jest-environment-miniflare":"^2.14.1"},"_npmOperationalInternal":{"tmp":"tmp/cloudflare-router_0.4.1_1737037520568_0.9035953254419571","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"@dbl-works/cloudflare-router","version":"1.0.0","author":{"name":"dbl-works"},"license":"MIT","_id":"@dbl-works/cloudflare-router@1.0.0","maintainers":[{"name":"lud11","email":"lud@reinmiedl.com"},{"name":"dbl-bot","email":"bot@dbl.works"}],"homepage":"https://github.com/dbl-works/cloudflare-router#readme","bugs":{"url":"https://github.com/dbl-works/cloudflare-router/issues"},"dist":{"shasum":"eb07ee902c0883ed9cee27d4cbae5cd90c1388d5","tarball":"https://registry.npmjs.org/@dbl-works/cloudflare-router/-/cloudflare-router-1.0.0.tgz","fileCount":31,"integrity":"sha512-ym0sfX0HZ2ibJGEOiQLgO2wZHey+zGkLMvxjLOCySzhGUjxlTpEgf8K/IFiLNTug1VQUDQ4ir9LccVQU1uj54Q==","signatures":[{"sig":"MEYCIQC9nDRGw+jI3XMc8b2lNHkNkMLaF3m+adyfuwz6s/g1RAIhAKPLyaTJgTRaQ/fA1czBJLPbWjLFZq1Fs5rpqa/byx7i","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":25027},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=22"},"gitHead":"7d0e4e6f84d1816bbda64eb507dd3ec3cd975620","scripts":{"test":"vitest run","build":"rm -rf dist && tsc","release":"release-it"},"_npmUser":{"name":"dbl-bot","email":"bot@dbl.works"},"release-it":{"git":{"requireCleanWorkingDir":false},"github":{"release":true}},"repository":{"url":"git+https://github.com/dbl-works/cloudflare-router.git","type":"git"},"_npmVersion":"10.9.2","description":"Cloudflare Router","directories":{},"_nodeVersion":"22.16.0","publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.2","release-it":"^19.2.4","typescript":"^6.0.2","@types/node":"^25.5.2","@cloudflare/workers-types":"^4.20250109.0","@cloudflare/vitest-pool-workers":"^0.14.1"},"_npmOperationalInternal":{"tmp":"tmp/cloudflare-router_1.0.0_1775509179061_0.263783935246908","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@dbl-works/cloudflare-router","version":"1.1.0","author":{"name":"dbl-works"},"license":"MIT","_id":"@dbl-works/cloudflare-router@1.1.0","maintainers":[{"name":"lud11","email":"lud@reinmiedl.com"},{"name":"dbl-bot","email":"bot@dbl.works"}],"homepage":"https://github.com/dbl-works/cloudflare-router#readme","bugs":{"url":"https://github.com/dbl-works/cloudflare-router/issues"},"dist":{"shasum":"75962261d41d3a17690f8442ef0638ca8e07a156","tarball":"https://registry.npmjs.org/@dbl-works/cloudflare-router/-/cloudflare-router-1.1.0.tgz","fileCount":31,"integrity":"sha512-hGPFrBZjc6ZRYO1fVJ31TrnZPiYoFehzfl6CHkNEcAyE2s2c9so+KHdoy0YOoMS13EDSYRjtgt1WelYN1Q7qnQ==","signatures":[{"sig":"MEUCIG6XvT9LhTWEXzJItZl7Jh0IwSIFSQLktV6Z5hSFoGEqAiEAvefUxqHCBKcN0+IwidVVBUjskQYsCoBPYJ0JWLLEbFo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":25127},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=22"},"gitHead":"b2f8e3eb755fc7c4afa9071fd2e9fd09e5f5aefb","scripts":{"test":"vitest run","build":"rm -rf dist && tsc","release":"release-it"},"_npmUser":{"name":"lud11","email":"lud@reinmiedl.com"},"release-it":{"git":{"requireCleanWorkingDir":false},"github":{"release":true}},"repository":{"url":"git+https://github.com/dbl-works/cloudflare-router.git","type":"git"},"_npmVersion":"10.9.2","description":"Cloudflare Router","directories":{},"_nodeVersion":"22.16.0","publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.2","release-it":"^19.2.4","typescript":"^6.0.2","@types/node":"^25.5.2","@cloudflare/workers-types":"^4.20250109.0","@cloudflare/vitest-pool-workers":"^0.14.1"},"_npmOperationalInternal":{"tmp":"tmp/cloudflare-router_1.1.0_1777214216323_0.3233992042986986","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"name":"@dbl-works/cloudflare-router","version":"2.0.0","author":{"name":"dbl-works"},"license":"MIT","_id":"@dbl-works/cloudflare-router@2.0.0","maintainers":[{"name":"lud11","email":"lud@reinmiedl.com"},{"name":"dbl-bot","email":"bot@dbl.works"}],"homepage":"https://github.com/dbl-works/cloudflare-router#readme","bugs":{"url":"https://github.com/dbl-works/cloudflare-router/issues"},"dist":{"shasum":"228ee25fdc7fc5d4832cf3bb42ccf8378e58ecf7","tarball":"https://registry.npmjs.org/@dbl-works/cloudflare-router/-/cloudflare-router-2.0.0.tgz","fileCount":31,"integrity":"sha512-r57Tm1NoekG3YAO+w/uPELoeJSSNK6FHvwl1hNh5RB+gCrNF0deRrZYZT8hI7DEQ1+cQ8cgIZ02xB/PMlvNGAw==","signatures":[{"sig":"MEUCIQC8C1s/i9oDMs0JklImOCq5pgBvBxn2deCLnSgHX6SGAgIgUmcwElwyNK/BQJx2q7ww3+MQFxJ5zrtFDiNqGUwe8Ms=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":26884},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=22"},"gitHead":"d8ba37b7941d1f3ce1bdecc3136e8e940be297fe","scripts":{"lint":"eslint .","test":"vitest run","build":"rm -rf dist && tsc","release":"release-it"},"_npmUser":{"name":"lud11","email":"lud@reinmiedl.com"},"release-it":{"git":{"requireCleanWorkingDir":false},"github":{"release":true}},"repository":{"url":"git+https://github.com/dbl-works/cloudflare-router.git","type":"git"},"_npmVersion":"10.9.2","description":"Cloudflare Router","directories":{},"_nodeVersion":"22.16.0","publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.3.0","vitest":"^4.1.2","@eslint/js":"^10.0.1","release-it":"^19.2.4","typescript":"^6.0.2","@types/node":"^25.5.2","typescript-eslint":"^8.59.1","@cloudflare/workers-types":"^4.20250109.0","@cloudflare/vitest-pool-workers":"^0.14.1"},"_npmOperationalInternal":{"tmp":"tmp/cloudflare-router_2.0.0_1777840041103_0.19124249867062892","host":"s3://npm-registry-packages-npm-production"}},"3.0.0":{"name":"@dbl-works/cloudflare-router","author":{"name":"dbl-works"},"version":"3.0.0","license":"MIT","main":"dist/index.js","types":"dist/index.d.ts","type":"module","engines":{"node":">=22"},"description":"Cloudflare Router","homepage":"https://github.com/dbl-works/cloudflare-router#readme","bugs":{"url":"https://github.com/dbl-works/cloudflare-router/issues"},"repository":{"type":"git","url":"git+https://github.com/dbl-works/cloudflare-router.git"},"scripts":{"build":"rm -rf dist && tsc","lint":"eslint .","test":"vitest run","release":"release-it"},"release-it":{"git":{"requireCleanWorkingDir":false},"github":{"release":true}},"devDependencies":{"@cloudflare/vitest-pool-workers":"^0.14.1","@cloudflare/workers-types":"^4.20250109.0","@eslint/js":"^10.0.1","@types/node":"^25.5.2","eslint":"^10.3.0","fast-check":"^4.9.0","release-it":"^19.2.4","typescript":"^6.0.2","typescript-eslint":"^8.59.1","vitest":"^4.1.2"},"publishConfig":{"registry":"https://registry.npmjs.org","access":"public"},"gitHead":"53671bd508f93260703eb4b122aee9cb3845c49c","_id":"@dbl-works/cloudflare-router@3.0.0","_nodeVersion":"24.15.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-fhO2kvdu1IpVPZnD5ay0D7NW0G/B3Pnm0k76w5DfnJQl6mXMlNf48PoygCN1Lr7JW3a2fJ2PDDK3G4BolzkWJA==","shasum":"aa7f0fb578234c1d7f1264544431a52927290cf6","tarball":"https://registry.npmjs.org/@dbl-works/cloudflare-router/-/cloudflare-router-3.0.0.tgz","fileCount":51,"unpackedSize":86342,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDhaJ8AoS2LlJ8rBUWDAFtJVv5YToGU9q3deXNCp+T1hgIhALz8nhFnIrsOAj25TWGs2jPwWkEOCYC0DSUK/2vdG959"}]},"_npmUser":{"name":"lud11","email":"lud@reinmiedl.com"},"directories":{},"maintainers":[{"name":"lud11","email":"lud@reinmiedl.com"},{"name":"dbl-bot","email":"bot@dbl.works"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/cloudflare-router_3.0.0_1788721697318_0.028086093332060802"},"_hasShrinkwrap":false}},"time":{"created":"2023-11-25T12:25:10.917Z","modified":"2026-09-06T19:08:17.604Z","0.2.0":"2023-11-25T12:25:11.284Z","0.4.0":"2024-03-26T10:41:02.527Z","0.4.1":"2025-01-16T14:25:20.779Z","1.0.0":"2026-04-06T20:59:39.247Z","1.1.0":"2026-04-26T14:36:56.467Z","2.0.0":"2026-05-03T20:27:21.314Z","3.0.0":"2026-09-06T19:08:17.448Z"},"bugs":{"url":"https://github.com/dbl-works/cloudflare-router/issues"},"author":{"name":"dbl-works"},"license":"MIT","homepage":"https://github.com/dbl-works/cloudflare-router#readme","repository":{"type":"git","url":"git+https://github.com/dbl-works/cloudflare-router.git"},"description":"Cloudflare Router","maintainers":[{"name":"lud11","email":"lud@reinmiedl.com"},{"name":"dbl-bot","email":"bot@dbl.works"}],"readme":"# Cloudflare Router\n\nA Cloudflare Worker that maps hosts to origins, with edge caching and authentication per route. Built for single-page applications on S3, and usable as a plain HTTPS proxy.\n\n## Install\n\n```sh\nyarn add @dbl-works/cloudflare-router\n```\n\nUpgrading from 2.x? See [the migration guide](docs/migration-guide-v2-to-v3.md).\n\n## Usage\n\n```typescript\nimport { createRouter } from '@dbl-works/cloudflare-router'\n\nexport default createRouter({\n  // Defaults for every route. Each route may override them.\n  edgeCacheTtl: 86400,\n  auth: [{ type: 'basic', username: 'admin', password: 'letmein' }],\n\n  routes: {\n    // A string is an origin. The route takes every default.\n    'www.example.com': 's3://eu-central-1.my-bucket/landingpage',\n\n    // An object overrides defaults for one route.\n    'app.example.com': { origin: 's3://eu-central-1.my-bucket/app', edgeCacheTtl: 60 },\n    'public.example.com': { origin: 's3://eu-central-1.my-bucket/public', auth: [] },\n    'vpn.example.com': { origin: 's3://eu-central-1.my-bucket/internal', auth: [{ type: 'ip', allow: ['192.168.1.1'] }] },\n    'api.example.com': { origin: 'https://backend.example.com', edgeCacheTtl: 0, cors: true },\n  },\n})\n```\n\n### Route keys\n\n| Key                 | Matches                                          |\n| ------------------- | ------------------------------------------------ |\n| `app.example.com`   | Every request to that host                       |\n| `example.com/admin` | Requests to that host with a path under `/admin` |\n\nEvery key names a host. Matching is exact on the hostname and on path segment boundaries, so `/admin` matches `/admin/x` but not `/admin-panel`. The most specific key wins. A request that matches no key returns `404 Unknown host`.\n\n### Origins\n\n| Origin                         | Result                                      |\n| ------------------------------ | ------------------------------------------- |\n| `s3://eu-central-1.bucket/app` | The HTTPS URL of that S3 prefix             |\n| `https://origin.example/base`  | That URL, as a plain proxy                  |\n| `origin.example/base`          | The same, with `https://` added             |\n| `/new-path`                    | The same host with a new path prefix        |\n\nThe rest of the request path is appended to the origin. The request port never reaches the origin.\n\n### Route options\n\nEach option resolves the same way: the route value, then the top-level value, then the default.\n\n| Option         | Default                    | Meaning                                                                                                   |\n| -------------- | -------------------------- | --------------------------------------------------------------------------------------------------------- |\n| `auth`         | `[]`, public               | Rules that grant access. One matching rule is enough. `[]` on a route opts out of the top-level rules.    |\n| `edgeCacheTtl` | `0`, no cache              | Seconds to cache a `2xx` response at the edge. The cache key is the URL.                                  |\n| `spa`          | `true` for `s3://` origins | Serve `index.html` for every navigation. Assets keep their path and query string.                        |\n| `cors`         | `true` for `s3://` origins | Let a CORS preflight through without authentication. The origin answers it.                              |\n\n## Authentication\n\nTwo rule types exist:\n\n```typescript\n{ type: 'basic', username: 'admin', password: 'letmein' }\n{ type: 'ip', allow: ['192.168.1.1', '2001:db8::1'] }   // exact addresses, no CIDR\n```\n\n- A route with a `basic` rule answers a failed request with `401` and a Basic challenge. A route with `ip` rules alone answers `403`.\n- The client address comes from the `CF-Connecting-IP` header that Cloudflare sets.\n- On a host where any route uses Basic auth, the router removes the `Authorization: Basic` header before it contacts the origin. On other hosts the header is forwarded, so you can proxy to an origin with its own Basic auth.\n- A protected route may cache only an `s3://` origin. The cache key is the URL, so a cached response from an application origin would be served to every authorized user.\n- `OPTIONS` requests are authenticated like any other request. Set `cors: true` on a protected application origin that browsers on another host call, so the preflight passes.\n\n## Startup validation\n\n`createRouter` validates the whole configuration and throws on the first defect. The message names the key and the fix, so run `wrangler dev` after a change. It rejects unknown keys, malformed keys and origins, invalid auth rules, and routes that would make the worker fetch itself. The rules are listed in [the spec](docs/specs/one-list-of-routes.md#startup-validation).\n\n## Releases\n\n- [Make sure you're logged in to npm with an account that has access to the @dbl-works scope](https://docs.npmjs.com/cli/adduser.html)\n- Switch to a branch named `chore/release/X.X.X` and make sure the changelog is up to date.\n- In order to cut a release invoke `yarn release`. This will bump the version, update the changelog and push a new tag to the repo. The release will be automatically published to npm.\n","readmeFilename":"README.md"}