A server-side link shortening service powered by your Linkat board. No database required - all links are fetched directly from AT Protocol!
- Zero Configuration Database: Uses your existing Linkat board as the data source
- β‘ Hash-Based Shortcodes: Automatic 6-character codes generated from URLs (e.g.,
/a3k9zx) - π Server-Side Only: Pure API-based, no client UI needed
- π― Smart Redirects: Instant HTTP 301 redirects to your target URLs
- π Automatic PDS Discovery: Resolves your PDS endpoint via Slingshot
- β‘ Built-in Cache: 5-minute cache for optimal performance
- π¨ Tailwind CSS 4: Modern styling with the latest Tailwind version
git clone [email protected]:ewanc26/atproto-shortlink # or [email protected]:ewancroft.uk/atproto-shortlink
cd atproto-shortlink
npm installCreate a .env file:
cp .env.example .envEdit .env and add your AT Protocol DID:
# Find your DID at https://pdsls.dev/ by entering your handle
ATPROTO_DID=did:plc:your-did-hereHow to find your DID:
- Visit PDSls
- Enter your AT Protocol handle (e.g.,
yourname.bsky.social) - Copy the
did:plc:...identifier
If you don't have a Linkat board yet:
- Visit https://linkat.blue
- Create a board with your links
- Add your links with titles and emojis
The shortener will automatically generate unique codes for each URL!
Run the configuration test to verify everything is set up correctly:
npm run test:configThis will:
- β
Check if
.envexists and is configured - β Validate your DID format
- β Test PDS connectivity
- β Verify your Linkat board is accessible
- β Show a preview of your first few links
npm run devVisit http://localhost:5173 to see your service running!
Once running, your short links work like this:
# Redirect to your configured URLs
http://localhost:5173/a3k9zx β Redirects to your GitHub
http://localhost:5173/b7m2wp β Redirects to your blog
http://localhost:5173/c4n8qz β Redirects to your portfolio
# View service info
http://localhost:5173/ β Shows API information and available links
# Get JSON list of links
http://localhost:5173/api/links β Returns all short links as JSON| Endpoint | Method | Description | Response |
|---|---|---|---|
/ |
GET | Service status and link listing | HTML |
/:shortcode |
GET | Redirect to full URL | 301 Redirect |
/api/links |
GET | List all available short links | JSON |
{
"success": true,
"count": 3,
"links": [
{
"shortcode": "a3k9zx",
"url": "https://github.com/yourname",
"title": "My GitHub Profile",
"emoji": "π»",
"shortUrl": "/a3k9zx"
},
{
"shortcode": "b7m2wp",
"url": "https://yourblog.com",
"title": "Personal Blog",
"emoji": "π",
"shortUrl": "/b7m2wp"
}
]
}Shortcodes are automatically generated as 6-character base62 hashes from your URLs. Each URL will always produce the same shortcode, ensuring consistency.
- Base62 encoding: Uses 0-9, a-z, A-Z (62 characters)
- Collision-resistant: 62^6 = ~56 billion possible combinations
- Deterministic: Same URL = same shortcode every time
- URL-safe: No special characters needed
npm run build
npm run preview # Test the production build locallyThis project uses @sveltejs/adapter-auto which works with:
- Vercel: Push to GitHub and connect your repo
- Netlify: Push to GitHub and connect your repo
- Cloudflare Pages: Push to GitHub and connect your repo
- Node.js: Use
adapter-nodefor standalone Node servers
For specific platforms, see SvelteKit adapters.
Make sure to set ATPROTO_DID in your deployment platform's environment variables!
| Variable | Required | Description | Example |
|---|---|---|---|
ATPROTO_DID |
β Yes | Your AT Protocol DID | did:plc:abc123xyz |
- You maintain your links in Linkat (stored in
blue.linkat.boardcollection) - Service fetches on-demand from your AT Protocol PDS via Slingshot resolution
- URLs are shortened using deterministic base62 hash encoding
- Accessing a short link (e.g.,
/a3k9zx) triggers an instant 301 redirect
graph LR
A[User visits /a3k9zx] --> B[Service fetches Linkat data]
B --> C[Looks up shortcode in links]
C --> D[301 Redirect to target URL]
- β All Linkat data is public by design
- β No authentication required
- β Read-only access to AT Protocol data
- β No data storage (fetches on-demand with cache)
- β 5-minute cache to prevent abuse
# Install dependencies
npm install
# Start dev server
npm run dev
# Type check
npm run check
# Format code
npm run format
# Check formatting
npm run lintThis project uses Tailwind CSS 4 with the new Vite plugin.
Key features:
- β
Native CSS imports with
@import 'tailwindcss' - β Faster builds with the Vite plugin
- β Automatic dark mode support
- β No config file needed for basic usage
- Framework: SvelteKit 2
- Styling: Tailwind CSS 4
- Runtime: Server-side only (no client JavaScript required)
- Data Source: AT Protocol (
blue.linkat.boardcollection) - PDS Resolution: Slingshot by Microcosm
- Redirects: HTTP 301 (permanent)
- Shortcode Format: Base62 hash encoding
Having issues? Check the Troubleshooting Guide for common problems and solutions.
Quick checks:
- Run
npm run test:configto verify your setup - Make sure Node.js 18+ is installed:
node --version - Check your DID at pdsls.dev
- Verify your Linkat board at linkat.blue
Contributions are welcome! Please feel free to submit a Pull Request.
AGPLv3 Licence - See LICENCE file for details
- Linkat - The link board service
- AT Protocol - The underlying protocol
- SvelteKit - The web framework
- Tailwind CSS - CSS framework
- PDSls - Find your DID
- Slingshot - Identity resolver
Made with β€οΈ using AT Protocol and Linkat