{"id":50666740,"url":"https://github.com/seqre/atpr-to","last_synced_at":"2026-06-08T07:04:53.749Z","repository":{"id":352237316,"uuid":"1188954402","full_name":"seqre/atpr-to","owner":"seqre","description":null,"archived":false,"fork":false,"pushed_at":"2026-05-18T20:35:19.000Z","size":354,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-18T22:50:47.608Z","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":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/seqre.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,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-22T20:01:16.000Z","updated_at":"2026-05-18T20:33:28.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/seqre/atpr-to","commit_stats":null,"previous_names":["seqre/atpr-to"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/seqre/atpr-to","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seqre%2Fatpr-to","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seqre%2Fatpr-to/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seqre%2Fatpr-to/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seqre%2Fatpr-to/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/seqre","download_url":"https://codeload.github.com/seqre/atpr-to/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seqre%2Fatpr-to/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34051785,"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-08T02:00:07.615Z","response_time":111,"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":"2026-06-08T07:04:32.548Z","updated_at":"2026-06-08T07:04:53.743Z","avatar_url":"https://github.com/seqre.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# atpr.to\n\nAn AT Protocol URL shortener. Short URLs are stored as records in the user's own PDS and take the form:\n\n```\nhttps://atpr.to/@alice.bsky.social/abc123\n```\n\nAnyone with a Bluesky (or any atproto) account can create short links — no central database, your links live in your repo.\n\n---\n\n## How it works\n\n1. **Login** — OAuth via AT Protocol. Your session lives in a signed cookie.\n2. **Shorten** — `POST /shorten` writes a `to.atpr.link` record to your PDS via `com.atproto.repo.putRecord`. Only `http`/`https` URLs are accepted; an optional `expires_at` (ISO 8601) can be set.\n3. **Resolve** — `GET /@handle/code` looks up the record and redirects. Resolution tries [Slingshot](https://github.com/microcosm-blue/slingshot) first, falling back to direct PDS resolution if unavailable. Returns **410 Gone** if the link has an `expires_at` in the past.\n4. **UI** — `GET /` serves a login form; `GET /dashboard` shows your links with a shorten form and delete buttons.\n\n---\n\n## API\n\n| Method | Path | Description |\n|--------|------|-------------|\n| `GET` | `/` | Home page — login form (redirects to `/dashboard` if logged in) |\n| `GET` | `/dashboard` | Dashboard — link list, shorten form, logout (auth required) |\n| `GET` | `/.well-known/oauth-client-metadata.json` | OAuth client metadata |\n| `POST` | `/login` | Start OAuth flow |\n| `POST` | `/logout` | Clear session cookie and redirect to `/` |\n| `GET` | `/oauth/callback` | OAuth callback |\n| `GET` | `/links` | List authenticated user's short links as JSON (auth required) |\n| `POST` | `/shorten` | Create short URL — `{ url, code?, expires_at? }` (auth required) |\n| `DELETE` | `/shorten/{code}` | Delete short URL (auth required) |\n| `GET` | `/@{handle}/{code}` | Resolve and redirect (410 if expired) |\n| `GET` | `/@{handle}/{code}/info` | Preview page — destination, creation date, QR code |\n| `GET` | `/@{handle}/{code}/qr` | QR code as SVG |\n| `GET` | `/health` | Health check — pings Slingshot |\n\n---\n\n## Configuration\n\nLoading priority (last wins): compiled defaults → `Config.toml` → `ATPR__` environment variables.\n\n| Env var | Default | Description |\n|---------|---------|-------------|\n| `ATPR__BASE_URL` | `https://atpr.to` | Base URL for short links and OAuth metadata |\n| `ATPR__SLINGSHOT_URL` | `https://slingshot.microcosm.blue/` | Slingshot instance for fast resolution |\n| `ATPR__RATE_LIMIT__PER_SECOND` | `2` | Sustained request rate on mutation routes |\n| `ATPR__RATE_LIMIT__BURST_SIZE` | `10` | Burst allowance on mutation routes |\n\nNested keys use `__` as separator. A `Config.toml` in the working directory is loaded if present (see the committed example).\n\n---\n\n## Development\n\n**Prerequisites:** Rust stable, [cargo-lambda](https://www.cargo-lambda.info/), [cargo-nextest](https://nexte.st/)\n\n| Command | Description |\n|---------|-------------|\n| `just test` | Run tests |\n| `just fmt` | Format code |\n| `just fmt-check` | Check formatting |\n| `just lint` | Run Clippy |\n| `just local` | Run locally via Lambda runtime emulator |\n| `just build` | Build release binary for Lambda (arm64) |\n\n---\n\n## Deployment\n\n**Prerequisites:** AWS SAM CLI, `cargo-lambda`, ARM64 cross-compilation target.\n\n```sh\njust deploy        # guided (first time)\njust deploy-fast   # subsequent deploys\njust logs          # tail Lambda logs\n```\n\nThe SAM template deploys a single `provided.al2023` Lambda function on arm64, fronted by an HTTP API Gateway. Override `ATPR__BASE_URL` or `ATPR__SLINGSHOT_URL` via SAM parameter overrides or the Lambda console.\n\n---\n\n## Acknowledgements\n\nThanks to [**Jacquard**](https://github.com/fatfingers23/jacquard) for the AT Protocol OAuth and XRPC client library, and to [**Microcosm**](https://microcosm.blue) for running [Slingshot](https://github.com/microcosm-blue/slingshot), the AT Protocol relay that powers fast link resolution.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fseqre%2Fatpr-to","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fseqre%2Fatpr-to","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fseqre%2Fatpr-to/lists"}