Build log · Software & apps

Link Compressor

Software & appsdone4 versionsCloudflare WorkerKVURL shortenerQR codesVanilla JS

reflection not written yet · every fact below is generated from this project’s own spec and files

What it is

A URL shortener that lives on my own domain: paste a long link, get a tiny isaac1804.com/s/xxxxx back. It compresses the link itself first — stripping utm_*/fbclid/igshid/si tracking junk (and telling you what it removed, while leaving signed download URLs alone) — then stores it in Cloudflare KV with click counting, custom names, duplicate detection and QR codes. Bulk mode takes one link per line and shows the exact saving per link (was 214 chars → 33 chars, 85% smaller). Anyone can compress any link (rate limited per IP so it cannot become a spam redirector) and that is all they can do; the 🔒 admin password at the top unlocks everything else — who created each link and who clicked it (IP, city, ISP, device), deleting, custom names, the full list and unlimited links.

Version history

Straight from the project’s own card data — what each version added.

V1

Worker + KV shortener routed onto isaac1804.com: 5-char codes from an alphabet with no 0/O/1/l/i, 302 redirects with click counting, same-URL reuse, admin token for custom names, deletes and stats. Tool page: bulk paste, tracking-parameter stripping with a per-link saving readout, inline QR codes, searchable/exportable history.

V1.1

Compressing opened to everyone — any link, no token, because it has to work for whoever I send the tool to. Abuse guard is now a 200-links-per-hour-per-IP limit; the token only gates custom names, deleting and the full list.

V1.2

Tracking: every link records who created it and every click records who opened it (IP, city/country, ISP, device, referer) — readable only with the password, in a per-link log plus a combined activity feed.

V1.3

Fully admin controlled: a 🔒 Admin box at the top of the page takes the password and unlocks the logs, deleting, custom names and unlimited links — visitors can only make and follow links. Fixed Delete, which was shown to everyone and only printed an error when locked; it now appears only when unlocked, and any 401 re-asks for the password.

Files on the site

By the numbers

Measured from the real working folder ~/Documents/projects/apps/isaac-links/ — not a claim, a count.

48
files
1,545
lines of code
6
file types used
2026-09-27
oldest file
2026-10-24
last touched

Mostly: Python ×4 · Shell ×3 · JSON ×2 · JavaScript ×1 · Markdown ×1 · TOML ×1

What broke, and what I’d change

Not written yet. This is the part only I can write — what actually went wrong, and what I’d do differently. It lives in builds/reflections/link-compressor.md (see _TEMPLATE.md); as soon as that file has words in it, this section fills in on the next build.

Everything else on this page — the spec, the version history, the file counts — is generated from the project’s own build notes and files, so nothing here is guesswork.

Build spec

The project’s own build notes, rendered. Open the raw .md ↗

Show the spec

Link Compressor — isaac1804.com/s/

Category: Software & Apps · Status: Done

A self-hosted URL shortener on my own domain: paste a long link, get a tiny https://isaac1804.com/s/xxxxx back that keeps working and tells me who opened it. (The browser-only a1d2.org Link Compressor only rewrites links; this one actually hosts them.)

Stack / Tools: Cloudflare Worker + Workers KV + Routes · vanilla HTML/CSS/JS single page on Pages · wrangler · Playwright (headless e2e) · QR generated in-page (no CDN)

Build path:

  • V1 — Worker + KV shortener routed onto isaac1804.com: 5-char codes from an alphabet with no 0 O 1 l i (survives being read aloud), 302 redirects, click counting, same-URL reuse, admin token for custom names + deletes.
  • V1.1 — compressing opened to everyone (it has to work for whoever I send it to); abuse guard became 200 links/IP/hour + http(s)-only targets.
  • V1.2 — tracking: every link records who created it, every click records who opened it (IP, city/country, ISP, device, referer) — per-link log + combined activity feed, password-only.
  • V1.3 — fully admin controlled: 🔒 password box at the top unlocks everything; visitors can only make and follow links. Delete fixed (it was rendered for everyone and only printed an error when locked).

Location: live https://isaac1804.com/tools/link-compressor/ · repo ~/Documents/projects/apps/isaac-links/ (deploy.sh) · page source ~/Desktop/homepage-deploy/tools/link-compressor/

Notes

  • Compresses the link itself first: strips utm_*/fbclid/gclid/igshid/si/spm/mc_cid… and reports what it removed; signed-URL params (X-Amz-Signature, token, expires) are left alone so download links never break.
  • Two credentials accepted, checked constant-time, sent as the X-Link-Token header only (query strings are refused so a secret can never leak into browser history, edge logs or Referer): the admin password (LINKS_PASSWORD Worker secret — current value in apps/isaac-links/ADMIN-CREDENTIALS-2026-10.txt, mode 600, never published) and the long random LINKS_TOKEN (~/.isaac-links-token). 5 wrong tries per IP ⇒ 15-minute lockout.
  • Access model — visitor: create + follow, nothing else (401 on list/log/activity/delete, custom names 403). Password: logs, delete, custom names, global list, bulk, QR, no hourly cap (rate limit is skipped when authenticated).
  • Pitfall — Cloudflare route patterns are matched including the query string: /api/activity does not match /api/activity?limit=5 (the request falls through to Pages' 404). Every pattern ends in *.
  • Pitfall — a button that can only fail reads as broken. Render admin-only buttons only when unlocked; locked shows one 🔒 button that focuses the password field, and any 401 mid-session re-locks + re-asks.
  • Verified live by test-e2e.py (46 checks) and test-delete-admin.py (lock/wrong-password/unlock/delete) — headless Playwright against the real site.