A server-side link shortening service powered by Linkat
1# AT Protocol Link Shortener 2 3A **server-side** link shortening service powered by your [Linkat](https://linkat.blue) board. No database required - all links are fetched directly from AT Protocol! 4 5## ✨ Features 6 7- **Zero Configuration Database**: Uses your existing Linkat board as the data source 8-**Hash-Based Shortcodes**: Automatic 6-character codes generated from URLs (e.g., `/a3k9zx`) 9- 🚀 **Server-Side Only**: Pure API-based, no client UI needed 10- 🎯 **Smart Redirects**: Instant HTTP 301 redirects to your target URLs 11- 🔍 **Automatic PDS Discovery**: Resolves your PDS endpoint via Slingshot 12-**Built-in Cache**: 5-minute cache for optimal performance 13- 🎨 **Tailwind CSS 4**: Modern styling with the latest Tailwind version 14 15## 🚀 Quick Start 16 17### 1. Clone and Install 18 19```bash 20git clone git@github.com:ewanc26/atproto-shortlink # or git@tangled.sh:ewancroft.uk/atproto-shortlink 21cd atproto-shortlink 22npm install 23``` 24 25### 2. Configure Your DID 26 27Create a `.env` file: 28 29```bash 30cp .env.example .env 31``` 32 33Edit `.env` and add your AT Protocol DID: 34 35```ini 36# Find your DID at https://pdsls.dev/ by entering your handle 37ATPROTO_DID=did:plc:your-did-here 38``` 39 40**How to find your DID:** 41 421. Visit [PDSls](https://pdsls.dev/) 432. Enter your AT Protocol handle (e.g., `yourname.bsky.social`) 443. Copy the `did:plc:...` identifier 45 46### 3. Set Up Your Linkat Board 47 48If you don't have a Linkat board yet: 49 501. Visit [https://linkat.blue](https://linkat.blue) 512. Create a board with your links 523. Add your links with titles and emojis 53 54The shortener will automatically generate unique codes for each URL! 55 56### 4. Test Your Configuration (Optional) 57 58Run the configuration test to verify everything is set up correctly: 59 60```bash 61npm run test:config 62``` 63 64This will: 65 66- ✅ Check if `.env` exists and is configured 67- ✅ Validate your DID format 68- ✅ Test PDS connectivity 69- ✅ Verify your Linkat board is accessible 70- ✅ Show a preview of your first few links 71 72### 5. Run the Server 73 74```bash 75npm run dev 76``` 77 78Visit `http://localhost:5173` to see your service running! 79 80## 📖 Usage 81 82Once running, your short links work like this: 83 84```bash 85# Redirect to your configured URLs 86http://localhost:5173/a3k9zx → Redirects to your GitHub 87http://localhost:5173/b7m2wp → Redirects to your blog 88http://localhost:5173/c4n8qz → Redirects to your portfolio 89 90# View service info 91http://localhost:5173/ → Shows API information and available links 92 93# Get JSON list of links 94http://localhost:5173/api/links → Returns all short links as JSON 95``` 96 97## 🔧 API Endpoints 98 99| Endpoint | Method | Description | Response | 100| ------------- | ------ | ------------------------------- | ------------ | 101| `/` | GET | Service status and link listing | HTML | 102| `/:shortcode` | GET | Redirect to full URL | 301 Redirect | 103| `/api/links` | GET | List all available short links | JSON | 104 105### Example API Response 106 107```json 108{ 109 "success": true, 110 "count": 3, 111 "links": [ 112 { 113 "shortcode": "a3k9zx", 114 "url": "https://github.com/yourname", 115 "title": "My GitHub Profile", 116 "emoji": "💻", 117 "shortUrl": "/a3k9zx" 118 }, 119 { 120 "shortcode": "b7m2wp", 121 "url": "https://yourblog.com", 122 "title": "Personal Blog", 123 "emoji": "📝", 124 "shortUrl": "/b7m2wp" 125 } 126 ] 127} 128``` 129 130## 📝 How Shortcodes Work 131 132Shortcodes are automatically generated as 6-character base62 hashes from your URLs. Each URL will always produce the same shortcode, ensuring consistency. 133 134- **Base62 encoding**: Uses 0-9, a-z, A-Z (62 characters) 135- **Collision-resistant**: 62^6 = ~56 billion possible combinations 136- **Deterministic**: Same URL = same shortcode every time 137- **URL-safe**: No special characters needed 138 139## 🌐 Deployment 140 141### Build for Production 142 143```bash 144npm run build 145npm run preview # Test the production build locally 146``` 147 148### Deploy to Platforms 149 150This project uses `@sveltejs/adapter-auto` which works with: 151 152- **Vercel**: Push to GitHub and connect your repo 153- **Netlify**: Push to GitHub and connect your repo 154- **Cloudflare Pages**: Push to GitHub and connect your repo 155- **Node.js**: Use `adapter-node` for standalone Node servers 156 157For specific platforms, see [SvelteKit adapters](https://kit.svelte.dev/docs/adapters). 158 159### Environment Variables for Deployment 160 161Make sure to set `ATPROTO_DID` in your deployment platform's environment variables! 162 163## ⚙️ Configuration 164 165| Variable | Required | Description | Example | 166| ------------- | -------- | -------------------- | ------------------- | 167| `ATPROTO_DID` | ✅ Yes | Your AT Protocol DID | `did:plc:abc123xyz` | 168 169## 🏗️ How It Works 170 1711. **You maintain your links** in [Linkat](https://linkat.blue) (stored in `blue.linkat.board` collection) 1722. **Service fetches on-demand** from your AT Protocol PDS via Slingshot resolution 1733. **URLs are shortened** using deterministic base62 hash encoding 1744. **Accessing a short link** (e.g., `/a3k9zx`) triggers an instant 301 redirect 175 176```mermaid 177graph LR 178 A[User visits /a3k9zx] --> B[Service fetches Linkat data] 179 B --> C[Looks up shortcode in links] 180 C --> D[301 Redirect to target URL] 181``` 182 183## 🔒 Security 184 185- ✅ All Linkat data is public by design 186- ✅ No authentication required 187- ✅ Read-only access to AT Protocol data 188- ✅ No data storage (fetches on-demand with cache) 189- ✅ 5-minute cache to prevent abuse 190 191## 🛠️ Development 192 193```bash 194# Install dependencies 195npm install 196 197# Start dev server 198npm run dev 199 200# Type check 201npm run check 202 203# Format code 204npm run format 205 206# Check formatting 207npm run lint 208``` 209 210## 🎨 Styling with Tailwind CSS 4 211 212This project uses **Tailwind CSS 4** with the new Vite plugin. 213 214Key features: 215 216- ✅ Native CSS imports with `@import 'tailwindcss'` 217- ✅ Faster builds with the Vite plugin 218- ✅ Automatic dark mode support 219- ✅ No config file needed for basic usage 220 221## 📦 Tech Stack 222 223- **Framework**: [SvelteKit 2](https://kit.svelte.dev/) 224- **Styling**: [Tailwind CSS 4](https://tailwindcss.com/) 225- **Runtime**: Server-side only (no client JavaScript required) 226- **Data Source**: AT Protocol (`blue.linkat.board` collection) 227- **PDS Resolution**: [Slingshot](https://slingshot.microcosm.blue) by Microcosm 228- **Redirects**: HTTP 301 (permanent) 229- **Shortcode Format**: Base62 hash encoding 230 231## 🔧 Troubleshooting 232 233Having issues? Check the [Troubleshooting Guide](./TROUBLESHOOTING.md) for common problems and solutions. 234 235Quick checks: 236 2371. Run `npm run test:config` to verify your setup 2382. Make sure Node.js 18+ is installed: `node --version` 2393. Check your DID at [pdsls.dev](https://pdsls.dev/) 2404. Verify your Linkat board at [linkat.blue](https://linkat.blue) 241 242## 🤝 Contributing 243 244Contributions are welcome! Please feel free to submit a Pull Request. 245 246## 📄 Licence 247 248AGPLv3 Licence - See [LICENCE](./LICENCE) file for details 249 250## Links 251 252- [Linkat](https://linkat.blue) - The link board service 253- [AT Protocol](https://atproto.com) - The underlying protocol 254- [SvelteKit](https://kit.svelte.dev) - The web framework 255- [Tailwind CSS](https://tailwindcss.com) - CSS framework 256- [PDSls](https://pdsls.dev/) - Find your DID 257- [Slingshot](https://slingshot.microcosm.blue) - Identity resolver 258 259--- 260 261Made with ❤️ using AT Protocol and Linkat