image cache on cloudflare r2
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

HTML 54.9%
TypeScript 33.9%
JavaScript 11.1%
Other 0.1%
3 1 0

Clone this repository

https://tangled.org/dunkirk.sh/l4 https://tangled.org/did:plc:krxbvxvis5skq7jj6eot23ul/l4
git@knot.dunkirk.sh:dunkirk.sh/l4 git@knot.dunkirk.sh:did:plc:krxbvxvis5skq7jj6eot23ul/l4

For self-hosted knots, clone URLs may differ based on your setup.

Download tar.gz
README.md

The L4 cache#

This is my own image cdn built on cloudflare r2 mainly so I can have fast optimized images on my blog.

Docs#

bun install
wrangler r2 bucket create l4-images
wrangler kv namespace create L4

Update wrangler.toml with the KV namespace ID and set HOST to your domain as well as INDIKO_URL to your Indiko instance

Production#

wrangler secret put INDIKO_CLIENT_ID
wrangler secret put INDIKO_CLIENT_SECRET
bun run deploy

Development#

bun run dev

Create .dev.vars for local development:

INDIKO_CLIENT_ID=your_client_id
INDIKO_CLIENT_SECRET=your_client_secret

CLI Usage#

Install CLI#

cd cli
bun install
bun run build
npm link

Configure#

l4 config --api-key <your-api-key> --url https://l4.yourdomain.com

Upload Image#

l4 upload image.jpg
l4 upload image.jpg --key custom-name.jpg

List Images#

l4 list
l4 list --limit 50

Delete Image#

l4 delete image-key.jpg

Get Image URL#

l4 url image.jpg
l4 url image.jpg --width 800 --format webp --quality 85

Image Transformations#

Images are served via /i/:key with optional query parameters:

  • w - Width (pixels)
  • h - Height (pixels)
  • f - Format (auto, webp, avif, jpeg)
  • q - Quality (1-100, default 85)
  • fit - Fit mode (scale-down, contain, cover, crop, pad)

Examples#

/i/photo.jpg?w=800&f=webp
/i/photo.jpg?w=400&h=400&fit=cover&q=90
/i/photo.jpg?f=auto

API Endpoints#

Authentication#

  • GET /login - Login page
  • GET /api/login - Initiate OAuth
  • GET /api/callback - OAuth callback
  • POST /api/logout - Logout
  • GET /api/me - Get current user

Images#

  • POST /api/upload - Upload image (multipart/form-data)
  • GET /api/images - List images
  • DELETE /api/images/:key - Delete image
  • GET /i/:key - Serve image (public)

API Keys#

  • GET /api/keys - List API keys
  • POST /api/keys - Create API key
  • DELETE /api/keys/:id - Delete API key

Architecture#

┌─────────────┐
│   Browser   │
└──────┬──────┘
       │
       ├─── HTML/JS (Indiko OAuth)
       │
       ├─── Upload/Manage Images
       │
       v
┌─────────────────┐
│ Cloudflare      │
│ Workers         │
│                 │
│ - Auth          │
│ - Transform     │
│ - Cache         │
└────────┬────────┘
         │
         ├─── Session/Metadata
         v
    ┌────────┐
    │   KV   │
    └────────┘
         │
         ├─── Original Images
         v
    ┌────────┐
    │   R2   │
    └────────┘

© 2025-present Kieran Klukas