A server-side link shortening service powered by Linkat

AT Protocol Link Shortener#

A server-side link shortening service powered by your Linkat board. No database required - all links are fetched directly from AT Protocol!

✨ Features#

  • 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

🚀 Quick Start#

1. Clone and Install#

git clone git@github.com:ewanc26/atproto-shortlink # or git@tangled.sh:ewancroft.uk/atproto-shortlink
cd atproto-shortlink
npm install

2. Configure Your DID#

Create a .env file:

cp .env.example .env

Edit .env and add your AT Protocol DID:

# Find your DID at https://pdsls.dev/ by entering your handle
ATPROTO_DID=did:plc:your-did-here

How to find your DID:

  1. Visit PDSls
  2. Enter your AT Protocol handle (e.g., yourname.bsky.social)
  3. Copy the did:plc:... identifier

3. Set Up Your Linkat Board#

If you don't have a Linkat board yet:

  1. Visit https://linkat.blue
  2. Create a board with your links
  3. Add your links with titles and emojis

The shortener will automatically generate unique codes for each URL!

4. Test Your Configuration (Optional)#

Run the configuration test to verify everything is set up correctly:

npm run test:config

This will:

  • ✅ Check if .env exists and is configured
  • ✅ Validate your DID format
  • ✅ Test PDS connectivity
  • ✅ Verify your Linkat board is accessible
  • ✅ Show a preview of your first few links

5. Run the Server#

npm run dev

Visit http://localhost:5173 to see your service running!

📖 Usage#

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

🔧 API Endpoints#

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

Example API Response#

{
	"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"
		}
	]
}

📝 How Shortcodes Work#

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

🌐 Deployment#

Build for Production#

npm run build
npm run preview  # Test the production build locally

Deploy to Platforms#

This 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-node for standalone Node servers

For specific platforms, see SvelteKit adapters.

Environment Variables for Deployment#

Make sure to set ATPROTO_DID in your deployment platform's environment variables!

⚙️ Configuration#

Variable Required Description Example
ATPROTO_DID ✅ Yes Your AT Protocol DID did:plc:abc123xyz

🏗️ How It Works#

  1. You maintain your links in Linkat (stored in blue.linkat.board collection)
  2. Service fetches on-demand from your AT Protocol PDS via Slingshot resolution
  3. URLs are shortened using deterministic base62 hash encoding
  4. 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]

🔒 Security#

  • ✅ 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

🛠️ Development#

# Install dependencies
npm install

# Start dev server
npm run dev

# Type check
npm run check

# Format code
npm run format

# Check formatting
npm run lint

🎨 Styling with Tailwind CSS 4#

This 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

📦 Tech Stack#

  • Framework: SvelteKit 2
  • Styling: Tailwind CSS 4
  • Runtime: Server-side only (no client JavaScript required)
  • Data Source: AT Protocol (blue.linkat.board collection)
  • PDS Resolution: Slingshot by Microcosm
  • Redirects: HTTP 301 (permanent)
  • Shortcode Format: Base62 hash encoding

🔧 Troubleshooting#

Having issues? Check the Troubleshooting Guide for common problems and solutions.

Quick checks:

  1. Run npm run test:config to verify your setup
  2. Make sure Node.js 18+ is installed: node --version
  3. Check your DID at pdsls.dev
  4. Verify your Linkat board at linkat.blue

🤝 Contributing#

Contributions are welcome! Please feel free to submit a Pull Request.

📄 Licence#

AGPLv3 Licence - See LICENCE file for details


Made with ❤️ using AT Protocol and Linkat