{"id":30413085,"url":"https://github.com/longcipher/cfly","last_synced_at":"2025-08-22T02:33:52.412Z","repository":{"id":310607736,"uuid":"1035744695","full_name":"longcipher/cfly","owner":"longcipher","description":"A blazing-fast, serverless URL shortener built on Cloudflare Workers.","archived":false,"fork":false,"pushed_at":"2025-08-19T05:47:00.000Z","size":14,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-08-19T07:21:05.968Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/longcipher.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}},"created_at":"2025-08-11T03:03:25.000Z","updated_at":"2025-08-19T05:47:03.000Z","dependencies_parsed_at":"2025-08-19T07:21:09.574Z","dependency_job_id":"0cbb3ccd-61d8-4201-93fc-72dd5ba67c49","html_url":"https://github.com/longcipher/cfly","commit_stats":null,"previous_names":["longcipher/cfly"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/longcipher/cfly","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/longcipher%2Fcfly","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/longcipher%2Fcfly/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/longcipher%2Fcfly/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/longcipher%2Fcfly/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/longcipher","download_url":"https://codeload.github.com/longcipher/cfly/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/longcipher%2Fcfly/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271576174,"owners_count":24783679,"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","status":"online","status_checked_at":"2025-08-22T02:00:08.480Z","response_time":65,"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":[],"created_at":"2025-08-22T02:33:50.115Z","updated_at":"2025-08-22T02:33:52.399Z","avatar_url":"https://github.com/longcipher.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Cfly - URL Shortener Service\n\nA high-performance URL shortening service built with Cloudflare Workers and Rust.\n\n## ✨ Features\n\n- 🚀 **High Performance**: Built on Cloudflare Workers global edge network\n- 🦀 **Rust Powered**: Written in Rust and WebAssembly for exceptional performance\n- 🔗 **Easy to Use**: Supports custom short links and automatic generation\n- 🌍 **Global Deployment**: Automatically deployed across 200+ cities worldwide\n- 📊 **Real-time Logging**: Built-in request logging and error handling\n- 🔧 **Easy Configuration**: Simple configuration through environment variables\n- 🎯 **Git Integration**: Fallback to Git commit URLs when KV storage lookup fails\n\n## 🛠️ Tech Stack\n\n- **Runtime**: Cloudflare Workers\n- **Language**: Rust + WebAssembly\n- **Storage**: Cloudflare KV Store\n- **Framework**: worker-rs\n- **Build Tool**: worker-build + wrangler\n\n## 📚 API Documentation\n\n### Redirect Endpoints\n\n#### Root Path Redirect\n```\nGET /\n```\nAutomatically redirects to the configured homepage address.\n\n**Response**:\n- `301 Moved Permanently` - Redirects to the address configured in the HOME environment variable\n\n#### Short Link Redirect\n```\nGET /:shortCode\n```\nRedirects to the target URL based on the short link code. If no short link is found in KV storage, the service will attempt to fetch and redirect based on Git commit information.\n\n**Parameters**:\n- `shortCode` - Short link code\n\n**Response**:\n- `301 Moved Permanently` - Redirects to target URL (from KV storage or Git commit)\n- `404 Not Found` - Short link does not exist and Git fallback failed\n- `400 Bad Request` - Invalid request\n\n**Git Integration Fallback**:\nWhen a short link is not found in KV storage, the service will:\n1. Construct a Git patch URL: `{GIT_REPO}/commit/{path}.patch`\n2. Fetch the patch file from the Git repository\n3. Extract the commit subject from the patch\n4. Redirect to the extracted URL or the repository itself\n\n**Example**:\n```bash\n# Access short link\ncurl -I https://your-domain.workers.dev/abc123\n\n# Response (from KV storage)\nHTTP/2 301\nlocation: https://example.com\n\n# Response (from Git fallback)\nHTTP/2 301\nlocation: https://github.com/user/repo/commit/abc123\n```\n\n## 🚀 Quick Start\n\n### Prerequisites\n\n- ✅ Rust installed (`curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh`)\n- ✅ Node.js installed\n- ✅ Cloudflare account\n\n### 5-Minute Deployment\n\n1. **Clone project**\n   ```bash\n   git clone https://github.com/longcipher/cfly.git\n   cd cfly/cfly\n   ```\n\n2. **Install dependencies**\n   ```bash\n   npm install -g wrangler\n   rustup target add wasm32-unknown-unknown\n   ```\n\n3. **Login to Cloudflare**\n   ```bash\n   wrangler login\n   ```\n\n4. **Create KV storage**\n   ```bash\n   npx wrangler kv namespace create cfly\n   npx wrangler kv namespace create cfly --preview\n   ```\n\n5. **Configure wrangler.toml**\n   Update `wrangler.toml` with your KV namespace IDs and settings:\n   ```toml\n   name = \"your-worker-name\"\n   \n   [[kv_namespaces]]\n   binding = \"cfly\"\n   preview_id = \"your-preview-kv-id\"\n   id = \"your-production-kv-id\"\n   \n   [vars]\n   HOME = \"https://your-homepage.com\"\n   GIT_REPO = \"https://github.com/your-user/your-repo\"  # Optional for Git fallback\n   ```\n\n6. **Deploy**\n   ```bash\n   npx wrangler build\n   npx wrangler deploy\n   ```\n\n### Git Integration (Optional)\n\nWhen a short link is not found in KV storage, Cfly can fallback to Git commit URLs:\n\n- Set `GIT_REPO` environment variable in `wrangler.toml`\n- Access `/commit-hash` will fetch `{GIT_REPO}/commit/commit-hash.patch`\n- Redirects to the extracted commit URL or repository\n\n**Example**: `https://your-domain.workers.dev/abc123` → fetches commit patch → redirects to commit URL\n\n### 3. Login to Cloudflare\n\n```bash\nwrangler login\n```\n\n### 4. Configure Project\n\n#### Create KV Namespace\n\n```bash\n# Create production KV namespace\nnpx wrangler kv namespace create cfly\n\n# Create preview KV namespace  \nnpx wrangler kv namespace create cfly --preview\n```\n\nAfter executing the commands, copy the KV namespace configuration output to `wrangler.toml`.\n\n#### Update wrangler.toml Configuration\n\nEdit `wrangler.toml` and update the following configuration:\n\n```toml\nname = \"your-worker-name\"  # Change to your Worker name\nmain = \"build/worker/shim.mjs\"\ncompatibility_date = \"2025-08-19\"\n\n[build]\ncommand = \"cargo install -q worker-build \u0026\u0026 worker-build --release\"\n\n[[kv_namespaces]]\nbinding = \"cfly\"\npreview_id = \"your-preview-kv-namespace-id\"    # Replace with actual preview environment ID\nid = \"your-production-kv-namespace-id\"         # Replace with actual production environment ID\n\n[vars]\nHOME = \"https://your-homepage.com\"             # Change to your homepage address\n\n[observability]\nenabled = true\n```\n\n### 5. Local Development\n\n```bash\n# Use just (recommended)\njust dev\n\n# Or use wrangler directly\nnpx wrangler dev\n```\n\nThe service will start at `http://localhost:8787`.\n\n### 6. Add Short Link Data\n\nBefore local development or deployment, add some short link data:\n\n```bash\n# Add single short link\nnpx wrangler kv key put --binding=cfly --preview false \"github\" \"https://github.com/longcipher/cfly\"\nnpx wrangler kv key put --binding=cfly --preview false \"blog\" \"https://blog.example.com\"\n\n# Or batch add (create urls.json file)\necho '[\n  {\"key\": \"github\", \"value\": \"https://github.com/longcipher/cfly\"},\n  {\"key\": \"blog\", \"value\": \"https://blog.example.com\"},\n  {\"key\": \"docs\", \"value\": \"https://docs.example.com\"}\n]' \u003e urls.json\n\nnpx wrangler kv bulk put --binding=cfly urls.json\nnpx wrangler kv bulk put --binding=cfly --preview false urls.json\n```\n\n### 7. Deploy to Production\n\n```bash\n# Use just (recommended)\njust deploy\n\n# Or use wrangler directly\nnpx wrangler deploy\n```\n\n## ⚙️ Cloudflare Configuration Steps\n\n### 1. Create KV Namespace\n\nCreate KV namespace in Cloudflare Dashboard:\n\n1. Login to [Cloudflare Dashboard](https://dash.cloudflare.com/)\n2. Select your account\n3. Go to **Workers \u0026 Pages** \u003e **KV**\n4. Click **Create a namespace**\n5. Enter namespace name (e.g., `cfly`)\n6. Record the generated Namespace ID\n\nOr create using CLI:\n\n```bash\n# Create production namespace\nnpx wrangler kv namespace create cfly\n\n# Create preview namespace\nnpx wrangler kv namespace create cfly --preview\n```\n\n### 2. Configure KV Namespace\n\nUpdate KV configuration in `wrangler.toml`:\n\n```toml\n[[kv_namespaces]]\nbinding = \"cfly\"                        # Binding name used in code\npreview_id = \"your-preview-kv-id\"       # Development environment KV ID\nid = \"your-production-kv-id\"            # Production environment KV ID\n```\n\n### 3. Set Environment Variables\n\nConfigure environment variables in `wrangler.toml`:\n\n```toml\n[vars]\nHOME = \"https://your-homepage.com\"  # Root path redirect address\nGIT_REPO = \"https://github.com/your-user/your-repo\"  # Git repository for fallback redirect (optional)\n```\n\nOr set in Cloudflare Dashboard:\n\n1. Go to **Workers \u0026 Pages**\n2. Select your Worker\n3. Go to **Settings** \u003e **Variables**\n4. Add environment variables\n\n### 4. Manage Short Link Data\n\n#### Add Short Links Using CLI\n\n```bash\n# Add single short link\nnpx wrangler kv key put --binding=cfly --preview false \"abc123\" \"https://example.com\"\n\n# View all short links (production)\nnpx wrangler kv key list --binding=cfly --preview false\n\n# View all short links (preview)\nnpx wrangler kv key list --binding=cfly --preview\n\n# Get specific short link (production)\nnpx wrangler kv key get --binding=cfly --preview false \"abc123\"\n\n# Delete short link (production)\nnpx wrangler kv key delete --binding=cfly --preview false \"abc123\"\n```\n\n#### Batch Import Short Links\n\nCreate a JSON file `urls.json`:\n\n```json\n[\n  {\"key\": \"github\", \"value\": \"https://github.com/longcipher/cfly\"},\n  {\"key\": \"blog\", \"value\": \"https://blog.example.com\"},\n  {\"key\": \"docs\", \"value\": \"https://docs.example.com\"},\n  {\"key\": \"twitter\", \"value\": \"https://twitter.com/yourhandle\"}\n]\n```\n\nImport data:\n\n```bash\nnpx wrangler kv bulk put --binding=cfly urls.json\n```\n\n#### Manage Using Dashboard\n\n1. Go to **Workers \u0026 Pages** \u003e **KV**\n2. Select your namespace\n3. Click **Add entry**\n4. Enter key-value pair:\n   - Key: Short link code (e.g., `abc123`)\n   - Value: Target URL (e.g., `https://example.com`)\n\n### 5. Custom Domain (Optional)\n\nConfigure custom domain:\n\n1. In Cloudflare Dashboard, go to **Workers \u0026 Pages**\n2. Select your Worker\n3. Go to **Settings** \u003e **Triggers**\n4. Click **Add Custom Domain**\n5. Enter your domain (e.g., `s.example.com`)\n6. Complete DNS verification\n\n## 📝 Development Commands\n\nThe project uses [just](https://github.com/casey/just) as a task runner:\n\n```bash\n# Build project\njust build\n\n# Start development server\njust dev\n\n# Deploy to production\njust deploy\n```\n\nYou can also use wrangler commands directly:\n\n```bash\n# Local development\nnpx wrangler dev\n\n# Build project\nnpx wrangler build\n\n# Deploy\nnpx wrangler deploy\n\n# View logs\nnpx wrangler tail\n\n# KV operations\n# Production KV operations (explicitly target production with --preview false)\nnpx wrangler kv key list --binding=cfly --preview false\nnpx wrangler kv key get --binding=cfly --preview false \"key-name\"\nnpx wrangler kv key put --binding=cfly --preview false \"key-name\" \"value\"\nnpx wrangler kv key delete --binding=cfly --preview false \"key-name\"\n\n# Preview KV operations\nnpx wrangler kv key list --binding=cfly --preview\nnpx wrangler kv key get --binding=cfly --preview \"key-name\"\nnpx wrangler kv key put --binding=cfly --preview \"key-name\" \"value\"\nnpx wrangler kv key delete --binding=cfly --preview \"key-name\"\n```\n\n## 🔧 Configuration Guide\n\n### wrangler.toml Configuration Details\n\n```toml\n# Worker basic information\nname = \"cfly\"                           # Worker name, must be globally unique\nmain = \"build/worker/shim.mjs\"          # Entry file path\ncompatibility_date = \"2025-08-19\"      # Compatibility date\n\n# Build configuration\n[build]\ncommand = \"cargo install -q worker-build \u0026\u0026 worker-build --release\"\n\n# KV storage binding\n[[kv_namespaces]]\nbinding = \"cfly\"                        # Binding name used in code\npreview_id = \"preview-namespace-id\"     # Development environment KV ID\nid = \"production-namespace-id\"          # Production environment KV ID\n\n# Environment variables\n[vars]\nHOME = \"https://your-homepage.com\"      # Root path redirect address\n\n# Monitoring configuration\n[observability]\nenabled = true                          # Enable logging and monitoring\n```\n\n### Cargo.toml Configuration Details\n\nKey dependencies and optimization configuration:\n\n```toml\n[dependencies]\nworker = { version = \"0.6.1\", features = ['http', 'axum'] }\nworker-macros = { version = \"0.6.1\", features = ['http'] }\n\n# Important: Disable wasm-opt to avoid compatibility issues\n[package.metadata.wasm-pack.profile.release]\nwasm-opt = false\n\n# Release configuration optimization\n[profile.release]\nlto = true                              # Link-time optimization\nstrip = true                            # Remove debug information\nopt-level = \"s\"                         # Optimize for code size\ncodegen-units = 1                       # Reduce code generation units\n```\n\n## 📊 Monitoring and Logging\n\n### View Real-time Logs\n\n```bash\n# View all logs\nnpx wrangler tail\n\n# Formatted output\nnpx wrangler tail --format=pretty\n\n# Only error logs\nnpx wrangler tail --format=json | jq 'select(.level == \"error\")'\n\n# Filter by time\nnpx wrangler tail --since=\"2025-08-19T10:00:00Z\"\n```\n\n### Cloudflare Analytics\n\nIn Cloudflare Dashboard you can view:\n\n- Request count and frequency statistics\n- Error rate and response time analysis\n- Traffic source and geographic distribution\n- CPU usage and memory consumption\n\n## 🚨 Troubleshooting\n\n### Common Issues and Solutions\n\n1. **wasm-bindgen version error**\n   ```\n   error: expected bool value, got 168\n   ```\n   **Solution**: Ensure `wasm-opt = false` is set in `Cargo.toml`\n\n2. **KV binding error**\n   ```\n   KvError::InvalidKvStore: cfly\n   ```\n   **Solution**: Check that the KV binding name in `wrangler.toml` matches `ctx.kv(\"cfly\")` in the code\n\n3. **Build failure**\n   ```\n   Missing entry-point to Worker script\n   ```\n   **Solution**: Ensure `worker-build` has been run and `build/worker/shim.mjs` file is generated\n\n4. **Deployment permission error**\n   ```\n   Authentication error\n   ```\n   **Solution**: Run `wrangler login` to re-authenticate with Cloudflare\n\n5. **KV namespace not found**\n   ```\n   Namespace not found\n   ```\n   **Solution**: Ensure KV namespace is created and ID is correctly configured in `wrangler.toml`\n\n### Debugging Tips\n\n1. **Enable verbose logging**:\n   ```bash\n   RUST_LOG=debug npx wrangler dev\n   ```\n\n2. **Check KV data**:\n   ```bash\n   npx wrangler kv key list --binding=cfly --preview\n   npx wrangler kv key get --binding=cfly \"test-key\" --preview\n   ```\n\n3. **Local debugging mode**:\n   ```bash\n   npx wrangler dev --local --port 8080\n   ```\n\n4. **Check Worker status**:\n   ```bash\n   npx wrangler whoami\n   npx wrangler list\n   ```\n\n5. **Validate configuration**:\n   ```bash\n   npx wrangler dev --dry-run\n   ```\n\n## 🚀 Advanced Features\n\n### Custom Error Pages\n\nYou can modify error responses in `src/lib.rs`:\n\n```rust\n// Custom 404 page\nResponse::from_html(r#\"\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\u003chead\u003e\u003ctitle\u003eShort Link Not Found\u003c/title\u003e\u003c/head\u003e\n\u003cbody\u003e\u003ch1\u003eSorry, this short link does not exist\u003c/h1\u003e\u003c/body\u003e\n\u003c/html\u003e\n\"#)?.with_status(404)\n```\n\n### Add Statistics Feature\n\nYou can record access statistics in KV:\n\n```rust\n// Increment access count\nlet count_key = format!(\"stats:{}\", name);\nlet current_count: u64 = ctx.kv(\"cfly\")?\n    .get(\u0026count_key)\n    .text()\n    .await?\n    .unwrap_or_default()\n    .parse()\n    .unwrap_or(0);\n\nctx.kv(\"cfly\")?\n    .put(\u0026count_key, (current_count + 1).to_string())?\n    .execute()\n    .await?;\n```\n\n### Support Expiration Time\n\nSet TTL when adding short links:\n\n```bash\n# Set to expire after 1 hour\nnpx wrangler kv key put --binding=cfly \"temp123\" \"https://example.com\" --ttl 3600\n```\n\n## 🤝 Contributing\n\n1. Fork the project\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add some amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n### Development Standards\n\n- Use `cargo fmt` to format code\n- Use `cargo clippy` to check code quality\n- Ensure all tests pass with `cargo test`\n- Update relevant documentation\n\n## 🙏 Acknowledgments\n\n- [Cloudflare Workers](https://workers.cloudflare.com/) - Edge computing platform\n- [worker-rs](https://github.com/cloudflare/workers-rs) - Rust Workers framework\n- [wrangler](https://github.com/cloudflare/workers-sdk) - Workers development tools\n- [just](https://github.com/casey/just) - Command runner\n- [hink](https://github.com/ccbikai/hink) - Use github commit for short link\n\n## 📄 License\n\nThis project is licensed under the Apache-2.0 License - see the [LICENSE](LICENSE) file for details.\n\n---\n\nIf this project helps you, please give it a ⭐️!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flongcipher%2Fcfly","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flongcipher%2Fcfly","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flongcipher%2Fcfly/lists"}