{"id":51286788,"url":"https://github.com/minagishl/twitter-url-rewrite-proxy","last_synced_at":"2026-06-30T06:30:31.364Z","repository":{"id":354392829,"uuid":"1223340153","full_name":"minagishl/twitter-url-rewrite-proxy","owner":"minagishl","description":"A simple proxy that rewrites Twitter (X) URLs to alternative domains like fixupx.com or fxtwitter.com.","archived":false,"fork":false,"pushed_at":"2026-04-28T10:22:48.000Z","size":15,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-28T12:26:40.871Z","etag":null,"topics":["docker","proxy","rewrite","twitter","url"],"latest_commit_sha":null,"homepage":"","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/minagishl.png","metadata":{"files":{"readme":"README.md","changelog":null,"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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"custom":"https://minagishl.com/amazon-wishlist"}},"created_at":"2026-04-28T08:23:36.000Z","updated_at":"2026-04-28T10:30:24.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/minagishl/twitter-url-rewrite-proxy","commit_stats":null,"previous_names":["minagishl/twitter-url-rewrite-proxy"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/minagishl/twitter-url-rewrite-proxy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/minagishl%2Ftwitter-url-rewrite-proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/minagishl%2Ftwitter-url-rewrite-proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/minagishl%2Ftwitter-url-rewrite-proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/minagishl%2Ftwitter-url-rewrite-proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/minagishl","download_url":"https://codeload.github.com/minagishl/twitter-url-rewrite-proxy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/minagishl%2Ftwitter-url-rewrite-proxy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34955984,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-30T02:00:05.919Z","response_time":92,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["docker","proxy","rewrite","twitter","url"],"created_at":"2026-06-30T06:30:30.560Z","updated_at":"2026-06-30T06:30:31.347Z","avatar_url":"https://github.com/minagishl.png","language":"TypeScript","funding_links":["https://minagishl.com/amazon-wishlist"],"categories":[],"sub_categories":[],"readme":"# Twitter URL Rewrite Proxy\n\nA Bun + TypeScript + Elysia service that fetches an upstream URL, rewrites matching hostnames in the response, and returns the transformed content.\n\n## Features\n\n- Built-in rewrite rules managed in TypeScript.\n- Additional rewrite rules loaded from environment variables.\n- A single `/rewrite` API for fetch-and-rewrite behavior.\n- Request parsing that changes by request `Content-Type`.\n- Response transformation that changes by upstream response `Content-Type`.\n- OpenAPI documentation served by Elysia.\n\n## Requirements\n\n- Bun 1.3 or later\n\n## Installation\n\n```bash\nbun install\n```\n\n## Rule Configuration\n\nBuilt-in rules are defined in `src/config/rules.ts` through the exported `builtInRules` array:\n\n```ts\nexport const builtInRules = [\n  { from: \"x.com\", to: \"fixupx.com\" },\n  { from: \"twitter.com\", to: \"fxtwitter.com\" },\n];\n```\n\nEnvironment variables can add more rules at startup:\n\n- `REWRITE_RULES_JSON`: JSON string using the shape `{ \"rules\": [{ \"from\": \"...\", \"to\": \"...\" }] }`\n- `REWRITE_RULES`: comma-separated `from:to` pairs\n- `PORT`: server port, defaults to `3000`\n\nExample:\n\n```bash\nexport REWRITE_RULES_JSON='{\"rules\":[{\"from\":\"vxtwitter.com\",\"to\":\"fixvx.com\"}]}'\nexport REWRITE_RULES='mobile.twitter.com:fxtwitter.com,fixvx.com:fixupx.com'\n```\n\nThe service normalizes hosts to lowercase, validates them, and deduplicates rules by the `from` hostname. If the same `from` host is defined multiple times, the last normalized entry wins.\n\n## Running the Server\n\nDevelopment mode:\n\n```bash\nbun run dev\n```\n\nSingle run:\n\n```bash\nbun run start\n```\n\n## Docker\n\nBuild and run with Docker Compose:\n\n```bash\ndocker compose up --build\n```\n\nThe service is exposed on `http://localhost:3000` by default.\n\nYou can pass rule-related environment variables through your shell or `.env` file:\n\n- `REWRITE_RULES_JSON`\n- `REWRITE_RULES`\n- `PORT`\n\nStop the container:\n\n```bash\ndocker compose down\n```\n\n## Docker Image Publishing (GitHub Actions)\n\nThis repository includes a workflow at `.github/workflows/publish-docker-image.yml` that builds and pushes multi-arch images to GitHub Container Registry (GHCR).\n\nTrigger conditions:\n\n- push to `main`\n- version tags like `v1.0.0`\n- manual run from GitHub Actions (`workflow_dispatch`)\n\nPublished image name:\n\n```text\nghcr.io/\u003cowner\u003e/\u003crepo\u003e\n```\n\nRequired repository settings:\n\n- GitHub Actions must be enabled.\n- Workflow permissions must allow `packages: write` (already set in the workflow).\n\n## API Documentation\n\nOpenAPI UI:\n\n```text\nhttp://localhost:3000/openapi\n```\n\nRaw OpenAPI JSON:\n\n```text\nhttp://localhost:3000/openapi/json\n```\n\nThis project uses [`@elysia/openapi`](https://elysiajs.com/plugins/openapi.html).\n\n## API\n\n### `GET /rewrite`\n\nFetch an upstream URL from the `url` query parameter, rewrite matching absolute URLs in the upstream response body, and return the transformed response.\n\n```bash\ncurl 'http://localhost:3000/rewrite?url=https%3A%2F%2Fexample.com'\n```\n\nTo also rewrite selected response headers such as `Location`, set `rewriteHeaders=true`:\n\n```bash\ncurl 'http://localhost:3000/rewrite?url=https%3A%2F%2Fexample.com\u0026rewriteHeaders=true'\n```\n\n### `POST /rewrite`\n\n`POST /rewrite` performs the same fetch-and-rewrite operation, but reads the upstream URL from the request based on the request `Content-Type`:\n\n- `application/json`: expects `{ \"url\": \"https://example.com\" }`\n- `text/plain`: expects the raw URL as the request body\n- `application/x-www-form-urlencoded`: expects a `url` field\n- query string fallback: `?url=...`\n\nUnsupported request media types return `415 Unsupported Media Type`.\n\nJSON request example:\n\n```bash\ncurl -X POST http://localhost:3000/rewrite \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"url\":\"https://example.com\"}'\n```\n\nPlain text request example:\n\n```bash\ncurl -X POST http://localhost:3000/rewrite \\\n  -H 'Content-Type: text/plain' \\\n  --data 'https://example.com'\n```\n\nForm request example:\n\n```bash\ncurl -X POST http://localhost:3000/rewrite \\\n  -H 'Content-Type: application/x-www-form-urlencoded' \\\n  --data 'url=https%3A%2F%2Fexample.com'\n```\n\nMalformed JSON, a missing `url`, or a non-absolute URL return `400` with a JSON error payload:\n\n```json\n{\n  \"error\": \"A non-empty url value is required.\"\n}\n```\n\n## Response Content-Type Handling\n\nThe service rewrites upstream response bodies for:\n\n- `text/plain`\n- `text/html`\n- `application/json`\n- `application/x-www-form-urlencoded`\n- text-like formats such as `application/*+json`, XML, and JavaScript\n\nBinary or unsupported upstream content types are returned unchanged.\n\nFor JSON responses, the service parses the payload, rewrites URL-like strings recursively, and serializes the result back to JSON.\n\n## Notes\n\n- Rewriting focuses on absolute `http://` and `https://` URLs.\n- Host replacement is an exact hostname match.\n- Response header rewriting is opt-in through `rewriteHeaders=true`.\n- Environment variable changes are applied when the server starts.\n- `POST /rewrite` accepts only `application/json`, `text/plain`, and `application/x-www-form-urlencoded` bodies unless the `url` is provided in the query string.\n\n## Type Checking\n\n```bash\nbun run check\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fminagishl%2Ftwitter-url-rewrite-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fminagishl%2Ftwitter-url-rewrite-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fminagishl%2Ftwitter-url-rewrite-proxy/lists"}