Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Gradleless/nah.pet

Open more actions menu

Repository files navigation

🐾 Nah.pet – Open Source URL Shortener

License: MIT SvelteKit TypeScript

Translation status Translation status

Nah.pet"Rewriting paths with bad energy"
Open-source URL shortener with custom domains and analytics.

📚 OpenAPI Documentation


✨ Features

  • ✂️ URL Shortening with custom slugs
  • 🔐 Password protection for sensitive links
  • Automatic link expiration
  • 📊 Detailed analytics (clicks, geolocation, browsers)
  • 🌐 Custom domains with complete isolation
  • 👥 Admin system with manual approval
  • 🔑 REST API with API key authentication
  • 🌍 Multilingual interface

🌍 Translation Status

Translation status Translation status

Translation status

Managed with Paraglide JS and Weblate for type-safety.


🌐 Custom Domains

Why cat.yourDomain.tld?

The cat. prefix bypasses CORS restrictions from Cloudflare and other CDNs by using a dedicated subdomain.

DNS Setup

  1. Domain verification:

    • DNS: TXT record with token
    • File: /.well-known/nah-pet-verification.txt
  2. CNAME configuration:

    Type: CNAME
    Name: cat.example.com
    Value: cat.nah.pet
    TTL: 300
    
  3. Redirection:

    https://cat.example.com/abc123 → CNAME → cat.nah.pet → nah.pet
    

Each custom domain is fully isolated—no access to system routes (/admin, /login, etc.).


🚀 Installation

🐳 Docker Compose

git clone https://github.com/anhostfr/nah.pet
cd link-shortener

cp .env.example .env
# Edit variables
# DATABASE_URL=postgresql://user:password@postgres:5432/nahpet
# PUBLIC_MAIN_DOMAIN=your-domain.com
# ADMIN_EMAIL=admin@example.com
# OAUTH_CLIENT_ID=your_oauth_id (optional)
# OAUTH_CLIENT_SECRET=your_oauth_secret (optional)
# PUBLIC_DOC=false (set to 'true' for public API docs)
# PUBLIC_ALLOW_REGISTRATION=true (set to 'false' to disable registration)

docker-compose up -d

Access:

  • Web interface: http://localhost:3000
  • API: http://localhost:3000/doc

🛠️ Manual Installation

bun install
createdb nahpet
cp .env.example .env  # Edit variables
bunx prisma migrate deploy
bun run dev

🔌 REST API

Built with sveltekit-api from JacobLinCool, OpenAPI 3.0 specification.

Main Endpoints

  • GET /api/v1/links – List links
  • POST /api/v1/links – Create a link
  • GET/PUT/DELETE /api/v1/links/{id} – Manage a link
  • GET /api/v1/stats – Global statistics
  • GET /api/v1/stats/{slug} – Link statistics
  • POST /api/v1/links/bulk – Bulk operations
  • GET /api/v1/stats/export – Export data

SDK Generation

npm install @openapitools/openapi-generator-cli -g

curl -o openapi.json https://your-domain.com/api/v1/openapi.json

openapi-generator-cli generate \
  -i openapi.json \
  -g typescript-axios \
  -o ./sdk-typescript

Authentication

curl -H "Authorization: Bearer YOUR_API_KEY" \
     "https://your-domain.com/api/v1/links"

🏗️ Tech Stack

  • Frontend/Backend: SvelteKit 5 + TypeScript
  • Runtime: Bun 1.x
  • Database: PostgreSQL + Prisma ORM
  • Authentication: Lucia Auth + OAuth2
  • Styling: TailwindCSS 4 + Shadcn/ui
  • i18n: Paraglide JS
  • API: Sveltekit-api (OpenAPI)
  • Deployment: Docker + Docker Compose

Project Structure

src/
├── routes/          # Pages and API
├── lib/
│   ├── components/  # Svelte components
│   ├── server/      # Server logic
│   └── paraglide/   # Translations
└── api/v1/           # API definitions

🛠️ Development

bun run dev        # Development
bun run build      # Production
bun run check      # TypeScript check
bun run format     # Prettier formatting

bunx prisma studio
bunx prisma generate
bunx prisma migrate dev

Environment Variables

DATABASE_URL=postgresql://postgres:password@localhost:5432/nahpet
PUBLIC_MAIN_DOMAIN=localhost:5173
ADMIN_EMAIL=admin@example.com
OAUTH_CLIENT_ID=your_oauth_client_id (optional)
OAUTH_CLIENT_SECRET=your_oauth_client_secret (optional)

# Access control (optional)
PUBLIC_DOC=false                      # Set to 'true' to make API docs public
PUBLIC_ALLOW_REGISTRATION=true        # Set to 'false' to disable registration

Screenshots

Dashboard Screenshot
Dashboard
Analytics Screenshot
Analytics
Analytics Slug Screenshot
Analytics (Slug)

🤝 Contributing

Translations

cp messages/en.json messages/es.json  # Add Spanish
# Add "es" in project.inlang/settings.json

Code

  1. Fork the repository
  2. Create a branch feature/my-feature
  3. Develop with bun run dev
  4. Check with bun run check + bun run format
  5. Open a Pull Request

📄 License

MIT – see LICENSE


🙏 Acknowledgements


"It's a no from us, dawg." – but it's a yes for open source!

Packages

 
 
 

Contributors

Morty Proxy This is a proxified and sanitized view of the page, visit original site.