Skip to content

COXKPER/Shortr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 

Repository files navigation

⚡ Shortr — URL Shortener for Telamon

A production-ready URL shortener and link analytics backend built entirely in Lua on the Telamon HTTP framework.


Features

Feature Detail
Shorten URLs Auto-generated 6-char codes or custom vanity codes
Click tracking Every redirect records a click + timestamp
Tags Attach arbitrary tags to links; filter the list by tag
Auth API-key guard on all write/admin endpoints
HTML dashboard / renders live stats in a polished dark-theme page
Pure file-based storage One JSON file; no database required
Structured JSON API All endpoints return consistent JSON envelopes

Architecture

/etc/telamon/
├── config.toml           # Telamon config
├── telamon.service       # systemd unit
├── data/
│   └── db.json           # link store (auto-created)
└── scripts/
    ├── index.lua         # GET /            — dashboard
    ├── health.lua        # GET /health      — health check
    ├── r/index.lua       # GET /r?c=CODE    — redirect + click tracking
    ├── lib/
    │   ├── store.lua     # JSON persistence helpers
    │   ├── auth.lua      # API key validation
    │   └── utils.lua     # code gen, URL building, time_ago
    └── api/
        ├── shorten/index.lua  # POST /api/shorten
        ├── links/index.lua    # GET  /api/links
        ├── link/index.lua     # GET  /api/link?c=CODE
        ├── stats/index.lua    # GET  /api/stats
        └── delete/index.lua   # DELETE /api/delete?c=CODE

Endpoints

Public (no auth required)

Method Path Description
GET / HTML dashboard with live stats
GET /health JSON health check
GET /api/stats Global stats + top-10 + tag leaderboard
GET /r?c=CODE Redirect to original URL (records click)

Protected (X-API-Key header required)

Method Path Description
POST /api/shorten Create a short link
GET /api/links List all links (?tag=X, ?sort=clicks|created|code)
GET /api/link?c=CODE Detail for one link
DELETE /api/delete?c=CODE Permanently delete a link

Installation

Prerequisites

  • Telamon binary installed at /usr/local/bin/telamon
  • lua.unsandboxed = true in config.toml (required for io and os)
  • systemd-based Linux server (or run manually for dev)

Quick install

chmod +x install.sh
sudo ./install.sh

Manual install

# 1. Build Telamon (from the Telamon source directory)
go build -o /usr/local/bin/telamon .

# 2. Create directories and copy files
sudo mkdir -p /etc/telamon/{scripts,static,data}
sudo cp config.toml /etc/telamon/
sudo cp -r scripts/* /etc/telamon/scripts/

# 3. Install systemd unit
sudo cp telamon.service /etc/systemd/system/
sudo systemctl daemon-reload

# 4. Set your API key
sudo sed -i 's/changeme-admin-key/YOUR_SECRET_KEY/' \
    /etc/systemd/system/telamon.service
sudo systemctl daemon-reload

# 5. Enable and start
sudo systemctl enable --now telamon
sudo systemctl status telamon

Configuration

API Key

Set via the TELAMON_API_KEY environment variable:

# /etc/systemd/system/telamon.service
[Service]
Environment=TELAMON_API_KEY=my-super-secret-key

After changing:

sudo systemctl daemon-reload && sudo systemctl restart telamon

For local dev without systemd:

export TELAMON_API_KEY=my-super-secret-key
telamon --config config.toml

Usage Examples

export HOST="http://localhost"
export KEY="my-super-secret-key"

# ── Create links ───────────────────────────────────────────────────────────

# Auto-generated code
curl -s -X POST $HOST/api/shorten \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $KEY" \
  -d '{"url":"https://example.com","title":"Example Site","tags":["demo"]}'

# Custom vanity code
curl -s -X POST $HOST/api/shorten \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $KEY" \
  -d '{"url":"https://anthropic.com","code":"claude","title":"Anthropic"}'

# ── Use links ──────────────────────────────────────────────────────────────

# Follow redirect (records a click)
curl -L "$HOST/r?c=claude"

# ── Analytics ─────────────────────────────────────────────────────────────

# Public stats
curl -s $HOST/api/stats | python3 -m json.tool

# List all (sorted by clicks, default)
curl -s -H "X-API-Key: $KEY" $HOST/api/links

# Filter by tag
curl -s -H "X-API-Key: $KEY" "$HOST/api/links?tag=demo"

# Sort by creation date
curl -s -H "X-API-Key: $KEY" "$HOST/api/links?sort=created"

# Single link detail
curl -s -H "X-API-Key: $KEY" "$HOST/api/link?c=claude"

# ── Delete ─────────────────────────────────────────────────────────────────

curl -s -X DELETE -H "X-API-Key: $KEY" "$HOST/api/delete?c=claude"

Response Schema

POST /api/shorten → 201

{
  "ok": true,
  "code": "aBc4dE",
  "short_url": "http://your-host/r?c=aBc4dE",
  "url": "https://example.com",
  "title": "Example Site",
  "tags": ["demo"],
  "clicks": 0,
  "created_at": 1719532800
}

GET /api/stats → 200

{
  "ok": true,
  "total_links": 42,
  "total_clicks": 1337,
  "top_links": [
    { "code": "claude", "title": "Anthropic", "clicks": 420, "created_at": 1719532800 }
  ],
  "top_tags": [
    { "tag": "demo", "count": 5 }
  ],
  "server": { "version": "1.0.0", "timestamp": 1719619200 }
}

Error envelope

{
  "error": "Bad Request",
  "message": "URL must start with http:// or https://"
}

Storage

Links are stored in /etc/telamon/data/db.json. The directory is auto-created on first write.

Schema:

{
  "links": {
    "aBc4dE": {
      "code": "aBc4dE",
      "url": "https://example.com",
      "title": "Example Site",
      "tags": ["demo"],
      "clicks": 7,
      "created_at": 1719532800,
      "last_clicked": 1719619200
    }
  },
  "meta": {
    "total_clicks": 7,
    "total_links": 1,
    "created_at": 1719532800
  }
}

Backup: Simply copy /etc/telamon/data/db.json.
Concurrency note: Telamon creates a new Lua VM per request; there is no built-in locking. For high write concurrency, add a mutex in Go or run behind a queue.


Lua Module Conventions

All scripts follow the Telamon notation rules:

-- Colon notation for request/response (methods with implicit self)
response:json({ ok = true })
request:getParam("c")

-- Dot notation for stateless utilities
json.encode(data)
telamon.log("message")

Shared modules are loaded by adjusting package.path at the top of each script:

package.path = "/etc/telamon/scripts/?.lua;" .. package.path
local store = require("lib.store")

License

MIT

About

based in Telamon

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages