links-free.openapps.xyz

Source

This app’s code and revision history are public. Download a copy or explore the files below.

Public
The app’s code and revision history are public.
Owned app · rev 9e2af813edac
Run it yourself
Take the whole tree and run it on your own machine. The download needs no account. Cloning needs a sign-in.
Download .zip
bounded clone 3151231032497ed786b88a0a
A copy you download is not bounded. The guarantees this app runs under - declared egress, proven invariants, writes that fail closed - live in the runtime serving this page, not in the files. What you get is auditable source you can read and run, with no runtime guarantees attached.
← All files
AGENTS.md
# Links

Links makes free short links and QR codes that never expire, and is a free alternative to Bitly, TinyURL, Rebrandly and paid QR code generators. It is an OpenApp in the OpenApps free apps store (https://free-apps.openapps.xyz/), owned by the OpenApps team.

## What it promises

- Free, with no limit on links, QR codes or clicks, no ads and no paid tier. Never add a cap, an upsell, tracking or a page in front of the redirect.
- Links never expire. Only the owner can turn a link off.
- No sign-up. Every visitor is a guest account created in the browser.
- The owner can change where a link goes at any time; the short link and its QR code never change.
- Clicks are counted per day and never per person: no address, location, device or referrer is stored.
- Nobody can list links or read a destination without opening the link. Random endings are 7 characters from an alphabet without look-alikes.
- AI assistants can do everything a person can through the public API (`functions/api.ts`), documented in `public/llms.txt` and `public/openapi.json`. Keep both true whenever the API changes, and keep `public/index.md` true to the landing page.

## How it is built

- `index.html` is the static landing page that search engines and AI crawlers read. Keep its copy, comparison (sourced, with the month it was checked), FAQ and JSON-LD in sync with what the app does. The inline script at the very top of `<head>` is the redirect: on `/<code>` it calls `GET /go/<code>` and runs `location.replace`, showing "Opening..." meanwhile, and a "does not exist" or "turned off" screen when the API says so. Its reserved list must match `RESERVED` in `functions/lib/links.ts`, and its API base must carry the real app id.
- `src/` is the React app. `/` mounts the shortener into the hero and "Your links" below it; `/e/<code>#k=<key>` hides the landing and shows the edit page (loaded on demand). `/?url=...&code=...` opens the shortener filled in. `/#links=<code>.<key>,...` adds links to this browser (the "Copy link for another device" button makes it). The data client (`@bounded-sh/client`) loads on first use through `sdk()` in `src/lib/bounded.ts`, so short links and first visits never download it.
- "Your links" lives in this browser's localStorage (`links:mine`, code and owner key). It can be searched, exported as CSV and moved to another device; removing a link there only forgets it in this browser.
- `functions/lib/links.ts` validates destinations and endings for both the app and the API (http and https only, up to 2,000 characters, never a Links address; endings 3 to 32 of `A-Z a-z 0-9 - _`, reserved words refused) and names UTC days as `yyyymmdd`.
- `functions/lib/qr.ts` is the QR encoder (byte mode, level M), shared so the app and the API's `/qr/<code>.svg` draw the same code. It matches the `qrcode` npm package module for module.
- `functions/lib/config.ts` holds the app id, the short link host (`SITE_URL`) and the API base.
- `policy.json` holds the data rules. `links/<code>` is readable only by its owners and by the public `api` function, which may only add one to `clicks`. `links/<code>/days/<yyyymmdd>` counts opens per UTC day; only the api function writes it, one at a time, and owners read it. Owners are the creator, or anyone who presents the owner key (`linkkeys/<code>`, readable only by the API) through `linkclaims`. The edit link carries the key in its `#k=` fragment, which never reaches a server.
- `policy-tests/links.json` checks those rules; run `bounded tests run` after any policy change.

## Working on it

Changes ship through previews and releases as your runtime instructions describe; Links is an OpenApp, so nobody deploys it directly. `npm run build` typechecks and builds to `dist/`. The function bundles `functions/lib` when it is deployed, so a change to `config.ts`, `links.ts` or `qr.ts` needs the function released as well as the site. A policy change that the function depends on goes out before the function.

Check a change by making a link with a random and a custom ending, opening the short link in a fresh browser (it should land on the destination, and the total and today's bar should go up), changing the destination from the edit link on another browser, downloading the QR code as PNG and SVG, moving your links to a second browser, downloading the CSV, and calling the API with curl.

## Voice

Plain words, short sentences, no jargon, no em dashes. Say what happens, not how clever it is.

Change history

Quality pass: clicks per day, CSV export, links on other devices
9e2af813ed · 5 hours ago
Bounded source sync
29eee7dafa · 1 day ago
Bounded source sync
c5e634046a · 1 day ago
Bounded source sync
12abf93e7e · 1 day ago
Bounded source sync
d0d6a654b1 · 1 day ago
Bounded source sync
e03049f905 · 1 day ago
Bounded source sync
eb5c793bfa · 1 day ago
Bounded source sync
5dd8ec26e1 · 1 day ago