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) |
- Username/password login configured entirely through environment variables
- HttpOnly,
SameSite=Strictbrowser 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
-
Import this repository into an EdgeOne Makers project, or install the CLI and run
edgeone makers deploy. -
In Storage → KV, create a namespace and bind it to the project with the variable name
LINKS_KV. -
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
-
Attach every hostname listed in
ALLOWED_SHORT_HOSTSto the same EdgeOne project. Blob storage namedshortly-authis created automatically on first use. -
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.
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:cloudflareThen 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_HOSTSThe 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/.
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 devAfter 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:cloudflareWrangler 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 buildAll 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": "..." } }.
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.