Skip to content

Repository files navigation

Shortly

A private short-link dashboard that runs on EdgeOne Makers (formerly EdgeOne Pages) or Cloudflare Workers. The frontend is React + Vite, while the API and redirects run at the edge. The build uses Node.js 22.17.1 or newer, as required by the Vite/Rolldown toolchain.

Platform Link data Login, user, and API-key data
EdgeOne EdgeOne KV (LINKS_KV) EdgeOne Blob (shortly-auth)
Cloudflare Workers KV (LINKS_KV) D1 (AUTH_DB)

Features

  • Username/password login configured entirely through environment variables
  • HttpOnly, SameSite=Strict browser sessions
  • Generated or custom multi-segment short paths such as /ex/example
  • Root links on an attached custom domain such as https://go.example.com
  • Existing destinations return their original short URL instead of creating duplicates
  • Searchable link library
  • API keys are shown once, stored only as SHA-256 hashes, and can be revoked
  • JSON API for creating, getting, and querying links
  • Responsive React interface and edge-native redirects

Deploy to EdgeOne

  1. Import this repository into an EdgeOne Makers project, or install the CLI and run edgeone makers deploy.

  2. In Storage → KV, create a namespace and bind it to the project with the variable name LINKS_KV.

  3. In Project settings → Environment variables, add:

    ADMIN_USERNAME=your-username
    ADMIN_PASSWORD=use-a-long-random-password
    ALLOWED_SHORT_HOSTS=go.example.com,another.example.com
    SECURE_COOKIES=true
  4. Attach every hostname listed in ALLOWED_SHORT_HOSTS to the same EdgeOne project. Blob storage named shortly-auth is created automatically on first use.

  5. Deploy. The project configuration builds to dist, and the dashboard is served at /app/. Visiting the project root opens the dashboard unless that host root has been assigned as a short link.

The custom-host allowlist prevents the app from generating URLs for domains that you do not control. To create a root-domain short link, enter the full URL—such as https://go.example.com—in the custom short-link field. The current dashboard host keeps / reserved.

Deploy to Cloudflare Workers

The included wrangler.jsonc uses Cloudflare's automatic resource provisioning. The first deployment creates and binds Workers KV as LINKS_KV and D1 as AUTH_DB; no account-specific IDs need to be committed.

pnpm install
pnpm exec wrangler login
pnpm run deploy:cloudflare

Then configure the production credentials as encrypted Worker secrets:

pnpm exec wrangler secret put ADMIN_USERNAME
pnpm exec wrangler secret put ADMIN_PASSWORD
pnpm exec wrangler secret put ALLOWED_SHORT_HOSTS

The D1 table is created safely on first use. A matching migration is also included at cloudflare/migrations/0001_auth_objects.sql for deployments that manage D1 migrations separately. Add every hostname in ALLOWED_SHORT_HOSTS as a Cloudflare custom domain or route for this Worker. The dashboard is served from Workers Static Assets at /app/.

Local development

For EdgeOne, its local runtime runs the frontend, functions, KV binding, Blob, and environment variables together:

pnpm install
edgeone login
edgeone makers link
edgeone makers dev

After linking, set SECURE_COOKIES=false only when testing over local HTTP. Do not commit the generated .env file. pnpm dev starts Vite alone and is useful for UI work, but API routes require the EdgeOne runtime.

For Cloudflare, copy .dev.vars.example to .dev.vars, replace the sample credentials, then run:

pnpm run dev:cloudflare

Wrangler supplies local KV, D1, and static-asset bindings. The local .dev.vars and .wrangler state are ignored by Git.

Validation commands:

pnpm lint
pnpm test
pnpm build

API

All link endpoints accept either the login session cookie or an API key in Authorization: Bearer sk_live_…. API-key management itself requires a browser login.

Method Endpoint Purpose
GET /api/links?query=term&limit=30 List or query links
POST /api/links Create a link or return the existing match
GET /api/links/:id Get one link by id
GET /api/keys List API key metadata (session only)
POST /api/keys Create an API key (session only)
DELETE /api/keys/:id Revoke an API key (session only)

Create a generated link:

curl https://your-domain.example/api/links \
  -H "Authorization: Bearer $SHORTLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/a/long/article"}'

Create a custom path or custom-domain root:

{"url":"https://example.com/article","customAlias":"/ex/example"}
{"url":"https://example.com/article","customAlias":"https://go.example.com"}

Successful responses use { "ok": true, "data": ... }. Errors use { "ok": false, "error": { "code": "...", "message": "..." } }.

Storage layout

KV contains redirect records plus hashed destination, id, and listing indexes. EdgeOne Blob or Cloudflare D1 contains users/, sessions/, api-keys/records/, and hashed API-key lookup objects. Passwords are never copied from the environment into storage.

EdgeOne KV and Workers KV are eventually consistent across edge locations, so a brand-new link can take a short time to become visible from a different region. EdgeOne Blob authentication reads request strong consistency; D1 provides the equivalent durable auth-data role on Cloudflare.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages