{"id":15412893,"url":"https://github.com/ascorbic/cdn-cache-control","last_synced_at":"2025-04-04T20:03:22.175Z","repository":{"id":243041011,"uuid":"811289639","full_name":"ascorbic/cdn-cache-control","owner":"ascorbic","description":"Easy cache header handling","archived":false,"fork":false,"pushed_at":"2024-12-08T23:03:16.000Z","size":84,"stargazers_count":98,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-21T18:09:47.340Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ascorbic.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-06T10:04:03.000Z","updated_at":"2025-03-01T06:01:10.000Z","dependencies_parsed_at":"2024-06-06T18:47:54.008Z","dependency_job_id":"b7160b13-6a3a-4338-a530-0075e89c936d","html_url":"https://github.com/ascorbic/cdn-cache-control","commit_stats":{"total_commits":13,"total_committers":3,"mean_commits":4.333333333333333,"dds":"0.46153846153846156","last_synced_commit":"bbd6d4511097108b101a048d4e07d93abe80b1f5"},"previous_names":["ascorbic/cachecontrol","ascorbic/cdn-cache-control"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ascorbic%2Fcdn-cache-control","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ascorbic%2Fcdn-cache-control/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ascorbic%2Fcdn-cache-control/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ascorbic%2Fcdn-cache-control/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ascorbic","download_url":"https://codeload.github.com/ascorbic/cdn-cache-control/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246085594,"owners_count":20721210,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-01T16:54:45.668Z","updated_at":"2025-03-28T19:05:18.181Z","avatar_url":"https://github.com/ascorbic.png","language":"TypeScript","readme":"\u003ch1 align=\"center\"\u003ecdn-cache-control\u003c/h1\u003e\n\u003cp align=\"center\"\u003e\n  \u003cimg alt=\"cdn-cache-control\" src=\"https://github.com/user-attachments/assets/62464d67-cbd5-48b5-a36d-800678ae22bb\" /\u003e\n\u003c/p\u003e\n\nEasy, opinionated CDN cache header handling.\n\nModern CDNs allow very fine-grained control over the cache. This is particularly useful for server-side rendering of web content, as it allows you to manually handle the invalidation of content, ensuring it stays fast and fresh. This package provides a subclass of the `Headers` class that makes it easier to set cache control headers for content served through a modern CDN. It provides a simple, chainable API with sensible defaults for common use cases. It works by setting the `Cache-Control` and `CDN-Cache-Control` headers to the appropriate values. If run on a supported platform it will use the more specific header for that CDN. e.g. on Netlify it will use the `Netlify-CDN-Cache-Control` header.\n\ne.g.\n\n```javascript\n// Expires in 1 minute, but use stale-while-revalidate to serve stale content after that\nconst headers = new CacheHeaders().ttl(ONE_MINUTE).swr();\n```\n\n## Installation\n\n```bash\nnpm install cdn-cache-control\n```\n\nIt is also available in [jsr](https://jsr.io) as `@ascorbic/cdn-cache-control`. If using Deno, you can import it directly without installing:\n\n```javascript\nimport { CacheHeaders } from \"jsr:@ascorbic/cdn-cache-control\";\n```\n\n## Usage\n\nThe module exports a single class, `CacheHeaders`, which is a subclass of the fetch [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers) class. It provides a chainable API for setting cache headers. By default it sets the `Cache-Control` and `CDN-Cache-Control` headers to sensible defaults for content that should be cached by the CDN and revalidated by the browser.\n\nIt can be instantiated with a `HeadersInit` value, which lets you base it on an existing `Headers` object, or an object or array with existing header values. In that case it will default to using existing `s-maxage` directives if present.\n\nYou can pass a `cdn` value as the second argument to set the CDN cache control header. In some cases this will enable targeted cache header names. e.g. for Netlify it will use the `Netlify-CDN-Cache-Control` header. Currently supported values are `netlify`, `vercel`, `cloudflare` and `akamai`. If you don't pass a value, or pass an unsupported one it will use the generic `CDN-Cache-Control` header. It will also attempt to detect the platform automatically on Vercel and Netlify.\n\n### Use cases\n\nIf you have content that you want to have the CDN cache until it is manually revalidated or purged with a new deploy, you can use the default values:\n\n```javascript\nimport { CacheHeaders } from \"cdn-cache-control\";\n\nconst headers = new CacheHeaders();\n```\n\nThis sets the `CDN-Cache-Control` header to `public,s-maxage=31536000,must-revalidate`, which tells the CDN to cache the content for a year. It sets `Cache-Control` to `public,max-age=0,must-revalidate`, which tells the browser to always check with the CDN for a fresh version. You should combine this with an `ETag` or `Last-Modified` header to allow the CDN to serve a `304 Not Modified` response when the content hasn't changed.\n\n#### stale-while-revalidate\n\nYou can enable `stale-while-revalidate` with the `swr` method, optionally passing a value for the time to serve stale content (defaults to one week):\n\n```javascript\nimport { CacheHeaders } from \"cdn-cache-control\";\n\nconst headers = new CacheHeaders().swr();\n```\n\nThis tells the CDN to serve stale content while revalidating the content in the background. Combine with the `ttl` method to set the time for which the content will be considered fresh (default is zero, meaning the CDN will always revalidate):\n\n```javascript\nimport { CacheHeaders, ONE_HOUR } from \"cdn-cache-control\";\n\nconst headers = new CacheHeaders().swr().ttl(ONE_HOUR);\n```\n\n#### Immutable content\n\nIf you are serving content that is guaranteed to never change then you can set it as immutable. You should only do this for responses with unique URLs, because there will be no way to invalidate it from the browser cache if it ever changes.\n\n```javascript\nimport { CacheHeaders } from \"cdn-cache-control\";\nconst headers = new CacheHeaders().immutable();\n```\n\nThis will set the CDN and browser caches to expire in 1 year, and add the immutable directive.\n\n#### Cache tags\n\nSome CDNs support the use of cache tags, which allow you to purge content from the cache in bulk. The `tag()` function makes it simple to add tags. You can call it with a string or array of strings.\n\n```javascript\nimport { CacheHeaders } from \"cdn-cache-control\";\nconst headers = new CacheHeaders().tag([\"blog\", \"blog:1\"]);\n```\n\nYou can then purge the tagged items from the cache using the CDN API. e.g. for Netlify the API is:\n\n```typescript\nimport { purgeCache } from \"@netlify/functions\";\n\nexport default async function handler(req: Request) =\u003e {\n  await purgeCache({\n    tags: [\"blog\", \"blog:1\", \"blog:2\"],\n  });\n  return new Response(\"Purged!\", { status: 202 })\n};\n\n```\n\n#### Using the generated headers\n\nThe headers object can be used anywhere that accepts a `fetch` `Headers` object. This includes most serverless hosts. It can also be used directly in many framework SSR functions. Some APIs need a plain object rather than a `Headers` object. For these you can use the `toObject()` method, which returns a plain object with the header names and values.\n\n```typescript\nimport { CacheHeaders } from \"cdn-cache-control\";\n\nexport default async function handler(request: Request): Promise\u003cResponse\u003e {\n  const headers = new CacheHeaders().swr();\n  // The `Response` constructor accepts the object directly\n  return new Response(\"Hello\", { headers });\n}\n```\n\nSome frameworks use a readonly `Response` object, so you need to use an existing `headers` object. In this case you can use the `copyTo` method to copy the headers to the response:\n\n```astro\n---\nimport { CacheHeaders, ONE_HOUR } from \"cdn-cache-control\";\n\nnew CacheHeaders().swr(ONE_HOUR).copyTo(Astro.response.headers);\n---\n\n```\n\n## API\n\n\u003c!-- TSDOC_START --\u003e\n\n## :wrench: Constants\n\n- [ONE_MINUTE](#gear-one_minute)\n- [ONE_HOUR](#gear-one_hour)\n- [ONE_DAY](#gear-one_day)\n- [ONE_WEEK](#gear-one_week)\n- [ONE_YEAR](#gear-one_year)\n\n### :gear: ONE_MINUTE\n\nNumber of seconds in one minute\n\n| Constant     | Type |\n| ------------ | ---- |\n| `ONE_MINUTE` | `60` |\n\n### :gear: ONE_HOUR\n\nNumber of seconds in one hour\n\n| Constant   | Type   |\n| ---------- | ------ |\n| `ONE_HOUR` | `3600` |\n\n### :gear: ONE_DAY\n\nNumber of seconds in one day\n\n| Constant  | Type    |\n| --------- | ------- |\n| `ONE_DAY` | `86400` |\n\n### :gear: ONE_WEEK\n\nNumber of seconds in one week\n\n| Constant   | Type     |\n| ---------- | -------- |\n| `ONE_WEEK` | `604800` |\n\n### :gear: ONE_YEAR\n\nNumber of seconds in one year\n\n| Constant   | Type       |\n| ---------- | ---------- |\n| `ONE_YEAR` | `31536000` |\n\n## :factory: CacheHeaders\n\n### Methods\n\n- [Installation](#installation)\n- [Usage](#usage)\n\t- [Use cases](#use-cases)\n\t\t- [stale-while-revalidate](#stale-while-revalidate)\n\t\t- [Immutable content](#immutable-content)\n\t\t- [Cache tags](#cache-tags)\n\t\t- [Using the generated headers](#using-the-generated-headers)\n- [API](#api)\n- [:wrench: Constants](#wrench-constants)\n\t- [:gear: ONE\\_MINUTE](#gear-one_minute)\n\t- [:gear: ONE\\_HOUR](#gear-one_hour)\n\t- [:gear: ONE\\_DAY](#gear-one_day)\n\t- [:gear: ONE\\_WEEK](#gear-one_week)\n\t- [:gear: ONE\\_YEAR](#gear-one_year)\n- [:factory: CacheHeaders](#factory-cacheheaders)\n\t- [Methods](#methods)\n\t\t- [:gear: tag](#gear-tag)\n\t\t- [:gear: swr](#gear-swr)\n\t\t- [:gear: immutable](#gear-immutable)\n\t\t- [:gear: ttl](#gear-ttl)\n\t\t- [:gear: toObject](#gear-toobject)\n\t\t- [:gear: copyTo](#gear-copyto)\n\t\t- [:gear: getCdnCacheControl](#gear-getcdncachecontrol)\n\t\t- [:gear: setCdnCacheControl](#gear-setcdncachecontrol)\n\t\t- [:gear: getCacheControl](#gear-getcachecontrol)\n\t\t- [:gear: setCacheControl](#gear-setcachecontrol)\n\t\t- [:gear: getCacheTags](#gear-getcachetags)\n\t\t- [:gear: setCacheTags](#gear-setcachetags)\n\n#### :gear: tag\n\nAdds a cache tag to the cache tags header. Cache tags are used to invalidate the cache for a URL.\n\n| Method | Type                                                   |\n| ------ | ------------------------------------------------------ |\n| `tag`  | `(tag: string or string[], ...tags: string[]) =\u003e this` |\n\nParameters:\n\n- `tag`: The cache tag to add. Can be a string or an array of strings.\n\n#### :gear: swr\n\nSets stale-while-revalidate directive for the CDN cache. By default the browser is sent a must-revalidate\ndirective to ensure that the browser always revalidates the cache with the server.\n\n| Method | Type                       |\n| ------ | -------------------------- |\n| `swr`  | `(value?: number) =\u003e this` |\n\nParameters:\n\n- `value`: The number of seconds to set the stale-while-revalidate directive to. Defaults to 1 week.\n\n#### :gear: immutable\n\nSets cache headers for content that should be cached for a long time and never revalidated.\nThe CDN cache will cache the content for the specified time, and the browser will cache the content\nindefinitely without revalidating. Do not use this unless the URL is fingerprinted or otherwise unique.\nOtherwise, the browser will cache the content indefinitely and never check for updates, including for new deploys.\n\n| Method      | Type                       |\n| ----------- | -------------------------- |\n| `immutable` | `(value?: number) =\u003e this` |\n\nParameters:\n\n- `value`: The number of seconds to set the CDN cache-control s-maxage directive to. Defaults to 1 year.\n\n#### :gear: ttl\n\nSets the s-maxage for items in the CDN cache. This is the maximum amount of time that the CDN will cache the content.\nIf used with swr, the content will revalidate in the background after the max age has passed. Otherwise, the content will be\nremoved from the cache after the max age has passed.\n\n| Method | Type                      |\n| ------ | ------------------------- |\n| `ttl`  | `(value: number) =\u003e this` |\n\n#### :gear: toObject\n\nReturns the headers as a plain object.\n\n| Method     | Type                           |\n| ---------- | ------------------------------ |\n| `toObject` | `() =\u003e Record\u003cstring, string\u003e` |\n\n#### :gear: copyTo\n\nCopy the headers from this instance to another Headers instance.\n\n| Method   | Type                                   |\n| -------- | -------------------------------------- |\n| `copyTo` | `\u003cT extends Headers\u003e(headers: T) =\u003e T` |\n\n#### :gear: getCdnCacheControl\n\nThe parsed cache-control header for the CDN cache.\n\n| Method               | Type                           |\n| -------------------- | ------------------------------ |\n| `getCdnCacheControl` | `() =\u003e Record\u003cstring, string\u003e` |\n\n#### :gear: setCdnCacheControl\n\n| Method               | Type                                           |\n| -------------------- | ---------------------------------------------- |\n| `setCdnCacheControl` | `(directives: Record\u003cstring, string\u003e) =\u003e void` |\n\n#### :gear: getCacheControl\n\nThe parsed cache-control header for the browser cache.\n\n| Method            | Type                           |\n| ----------------- | ------------------------------ |\n| `getCacheControl` | `() =\u003e Record\u003cstring, string\u003e` |\n\n#### :gear: setCacheControl\n\n| Method            | Type                                           |\n| ----------------- | ---------------------------------------------- |\n| `setCacheControl` | `(directives: Record\u003cstring, string\u003e) =\u003e void` |\n\n#### :gear: getCacheTags\n\nThe parsed content of the cache tags header.\n\n| Method         | Type             |\n| -------------- | ---------------- |\n| `getCacheTags` | `() =\u003e string[]` |\n\n#### :gear: setCacheTags\n\n| Method         | Type                       |\n| -------------- | -------------------------- |\n| `setCacheTags` | `(tags: string[]) =\u003e void` |\n\n\u003c!-- TSDOC_END --\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fascorbic%2Fcdn-cache-control","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fascorbic%2Fcdn-cache-control","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fascorbic%2Fcdn-cache-control/lists"}