{"id":14006936,"url":"https://github.com/kotx/render","last_synced_at":"2026-01-12T14:49:50.079Z","repository":{"id":37831705,"uuid":"492356050","full_name":"kotx/render","owner":"kotx","description":"Cloudflare Worker to proxy and cache requests to R2","archived":false,"fork":false,"pushed_at":"2025-05-30T21:14:48.000Z","size":148,"stargazers_count":461,"open_issues_count":3,"forks_count":92,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-07-24T01:44:51.959Z","etag":null,"topics":["cloudflare-r2","cloudflare-workers"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kotx.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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,"zenodo":null},"funding":{"github":"kotx","liberapay":"kot"}},"created_at":"2022-05-15T00:50:59.000Z","updated_at":"2025-07-22T18:12:52.000Z","dependencies_parsed_at":"2023-02-15T19:01:22.892Z","dependency_job_id":"589fa362-9dcd-4be5-9a1a-6eb92483a535","html_url":"https://github.com/kotx/render","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/kotx/render","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kotx%2Frender","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kotx%2Frender/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kotx%2Frender/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kotx%2Frender/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kotx","download_url":"https://codeload.github.com/kotx/render/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kotx%2Frender/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28340410,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T12:22:26.515Z","status":"ssl_error","status_checked_at":"2026-01-12T12:22:10.856Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["cloudflare-r2","cloudflare-workers"],"created_at":"2024-08-10T10:01:43.270Z","updated_at":"2026-01-12T14:49:49.992Z","avatar_url":"https://github.com/kotx.png","language":"TypeScript","funding_links":["https://github.com/sponsors/kotx","https://liberapay.com/kot"],"categories":["TypeScript"],"sub_categories":[],"readme":"# Render\n\nProxies readonly requests to [Cloudflare R2](https://developers.cloudflare.com/r2) via [Cloudflare Workers](https://workers.dev).\n\nIf you want an uploader, try [Aster](https://github.com/kotx/aster)!\n\nIf you see a bug or something missing, please open an issue or pull request!\n\n## Features\n- File listings (with optional hidden files)!\n\n![screenshot of file listings in light mode](https://user-images.githubusercontent.com/33439542/193165135-1dd935f5-b68b-495a-97cc-9c69c3c0ce01.png)\n![screenshot of file listings in dark mode](https://user-images.githubusercontent.com/33439542/193165189-3cd4b79e-27ea-4397-bb80-f3ccf31185dc.png)\n\n\n- Handles `HEAD`, `GET`, and `OPTIONS` requests\n- Forwards caching headers (`etag`, `cache-control`, `expires`, `last-modified`)\n- Forwards content headers (`content-type`, `content-encoding`, `content-language`, `content-disposition`)\n- Caches served files using the [Cache API](https://developers.cloudflare.com/workers/runtime-apis/cache/)\n- Ranged requests (`range`, `if-range`, returns `content-range`)\n- Handles precondition headers (`if-modified-since`, `if-unmodified-since`, `if-match`, `if-none-match`)\n- Can serve an appended path if the requested url ends with / - Defaults to `index.html` in 0.5.0\n- Can serve custom 404 responses if a file is not found\n\n## Setup\n\n### Configuration\n\nCreate your R2 bucket(s) if you haven't already (replace `bucket_name` and `preview_bucket_name` appropriately):\n```sh\npnpm install\npnpm wrangler r2 bucket create bucket_name # required\npnpm wrangler r2 bucket create preview_bucket_name # optional\n```\nYou can also do this from the [Cloudflare dashboard](https://dash.cloudflare.com/?to=/:account/r2/buckets/new).\n\nEdit `wrangler.toml` to have the correct `bucket_name` and optionally, `preview_bucket_name`  (you can set it to `bucket_name`) if you're going to run this locally.\nYou can do this from a fork, if using the [GitHub Actions method](#method-2-github-actions).\n\nYou may edit `CACHE_CONTROL` to the default [`cache-control` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control) or remove it entirely to fall back to nothing. If you set `CACHE_CONTROL` to `\"no-store\"` then Cloudflare caching will not be used.\n\n### Deploying\n\nNote: Due to how custom domains for workers work, you MUST use a route to take advantage of caching. Cloudflare may fix this soon.\nAlso note that \\*.workers.dev domains do not cache responses. You MUST use a route to your own (sub)domain.\n\nIf you want to deploy render with multiple domains for one worker, check out [multi-render](https://github.com/Erisa/multi-render)! It uses render [as a package](#using-as-a-package) to serve multiple buckets to multiple domains with custom configurations.\n\n#### Method 1 (Local)\n```sh\npnpm wrangler publish # or `pnpm run deploy`\n```\n\n#### Method 2 (GitHub Actions)\n1. Fork this repository\n2. Set the secrets [`CF_API_TOKEN`](https://dash.cloudflare.com/profile/api-tokens) (with the `Edit Cloudflare Workers\t\n` template) and `CF_ACCOUNT_ID` in the repo settings\n3. Enable workflows in the Actions tab\n4. Update `wrangler.toml` as needed (this will trigger the workflow)\n5. (Optionally) set the worker route in the Cloudflare dashboard to use the Cache API\n\n## Using as a package\n\nYou may use this worker's functionality as a package by installing and importing [`render2`](https://www.npmjs.com/package/render2):\n```sh\nnpm install render2\n```\nUsage:\n```js\nimport render from \"render2\";\nrender.fetch(req, env, ctx);\n```\n\nYou can see an awesome example with [Erisa](https://github.com/Erisa)'s [multi-render](https://github.com/Erisa/multi-render)!\n\n## Development\n\nInstall deps:\n```sh\npnpm install\n```\n\nTo launch the development server:\n```sh\npnpm run dev\n```\n\n## Notable Related Projects\n\n- [auravoid](https://github.com/auravoid)'s [fork](https://github.com/auravoid/render) adds [Plausible](https://plausible.io) support.\n- [Erisa](https://github.com/Erisa)'s project [multi-render](https://github.com/erisa/multi-render) add support for domain-specific configurations.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkotx%2Frender","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkotx%2Frender","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkotx%2Frender/lists"}