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.
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 4ce232ee856d7de1ba5f2b6d
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.
functions/api.ts
// Bio's public HTTP API: no account. Anyone can make a page; the owner key that comes back is what
// lets you change it and read its stats later. Every route answers JSON; GET / describes the routes.
// Writes go through the same policy rules as the web app.
import { SITE_URL } from "./lib/config";
import { applyInput, checkHandle, fromDoc, newPage, pageUrl, editUrl, randomKey, toDoc, type Page, type PageDoc } from "./lib/bio";
import { qrMatrix, qrSvg } from "./lib/qr";
const NOW = { operation: "time", value: "now" };
const PLUS_ONE = { operation: "increment", value: 1 };
const HANDLE_RE = /^[a-z0-9][a-z0-9-]{1,28}[a-z0-9]$/;
const FIELDS = ["name", "bio", "avatar", "links", "socials", "theme", "buttonStyle", "showCredit"];
const cors = {
"access-control-allow-origin": "*",
"access-control-allow-methods": "GET, POST, PATCH, OPTIONS",
"access-control-allow-headers": "content-type, x-owner-key",
};
const json = (body: unknown, status = 200) =>
new Response(JSON.stringify(body, null, 2), { status, headers: { "content-type": "application/json; charset=utf-8", ...cors } });
const fail = (status: number, error: string) => json({ error }, status);
class HttpError extends Error { constructor(public status: number, message: string) { super(message); } }
async function body(req: Request): Promise<Record<string, unknown>> {
try {
const parsed = await req.json();
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
} catch { /* fall through */ }
throw new HttpError(400, "Send a JSON object body.");
}
async function load(ctx: any, handle: string): Promise<PageDoc> {
if (!HANDLE_RE.test(handle)) throw new HttpError(404, "There is no page at this address.");
let doc = await ctx.bounded.get(`pages/${handle}`);
// Now and then a read comes back with none of the page's fields. The rules give every page a name,
// so read once more rather than draw a blank page or let a PATCH wipe the links.
if (doc && !doc.name) doc = await ctx.bounded.get(`pages/${handle}`);
if (!doc) throw new HttpError(404, "There is no page at this address.");
if (!doc.name) throw new HttpError(503, "The page did not load. Try again in a moment.");
return doc;
}
/** Every API caller shares one identity, so owner actions always check the key first. */
async function ownerKey(ctx: any, req: Request, handle: string): Promise<string> {
const key = req.headers.get("x-owner-key")?.trim() || "";
if (!key) throw new HttpError(401, "Send the page's owner key in the x-owner-key header.");
const stored = await ctx.bounded.get(`pagekeys/${handle}`);
if (!stored || stored.key !== key) throw new HttpError(403, "That owner key does not match this page.");
return key;
}
async function listAll(ctx: any, path: string): Promise<any[]> {
const rows: any[] = [];
let cursor: string | undefined;
for (let page = 0; page < 20; page++) {
const res = await ctx.bounded.get(path, { limit: 500, ...(cursor ? { cursor } : {}) });
for (const r of res?.data || []) rows.push({ ...r, id: r.id ?? String(r._id ?? r.pathId ?? "").split("/").pop() });
cursor = res?.nextCursor;
if (!cursor) break;
}
return rows;
}
function describe(handle: string, page: Page, doc: { views?: number; createdAt?: number }) {
return {
handle,
url: pageUrl(handle),
...page,
views: doc.views ?? 0,
createdAt: new Date((doc.createdAt ?? Math.floor(Date.now() / 1000)) * 1000).toISOString(),
};
}
const routes = {
name: "Bio by OpenApps",
about: "Free link in bio pages: a photo, a name, a short bio, your links and social icons at one address. No account and no key to make a page; the owner key you get back lets you change it and see its views and clicks.",
docs: `${SITE_URL}/llms.txt`,
openapi: `${SITE_URL}/openapi.json`,
routes: [
"POST /pages {handle, name, bio?, avatar?, links?: [{title, url, hidden?} or {title, header: true}], socials?, theme?, buttonStyle?, showCredit?} -> the page, its private edit link and the owner key",
"GET /pages/:handle -> the public page as JSON",
"PATCH /pages/:handle with header x-owner-key {any of the fields above} -> the updated page",
"GET /pages/:handle/stats with header x-owner-key -> views and clicks per link",
"GET /pages/:handle/qr.svg -> a QR code of the page address, as an SVG image",
"GET /view/:handle -> the public page as JSON, counting one view (what the page itself does)",
"GET /go/:handle/:linkId -> {url}: where a link goes (counts one click)",
],
};
export default async function api(req: Request, ctx: any) {
if (req.method === "OPTIONS") return new Response(null, { status: 204, headers: cors });
const url = new URL(req.url);
const parts = url.pathname.split("/").filter(Boolean);
// Accept both /pages/... and /api/pages/... so a copied path works either way.
if (parts[0] === "api") parts.shift();
try {
if (!parts.length && req.method === "GET") return json(routes);
const me = ctx.user.id;
if (parts[0] === "go" && parts.length === 3 && req.method === "GET") {
const page = fromDoc(await load(ctx, parts[1]));
const link = page.links.find((l) => l.id === parts[2] && !l.header && !l.hidden);
if (!link) return fail(404, "This link is no longer on the page.");
try { await ctx.bounded.set(`pages/${parts[1]}/clicks/${link.id}`, { count: PLUS_ONE }); } catch { /* a missed count never blocks the visit */ }
return json({ url: link.url });
}
if (parts[0] === "view" && parts.length === 2 && req.method === "GET") {
// Count while reading, so the visitor never waits for one after the other. The rules refuse the
// count when there is no page, so a wrong address creates nothing. A missed count never blocks the visit.
const counted = HANDLE_RE.test(parts[1]) ? ctx.bounded.set(`pages/${parts[1]}`, { views: PLUS_ONE }).catch(() => {}) : null;
const [doc] = await Promise.all([load(ctx, parts[1]), counted]);
return json(describe(parts[1], fromDoc(doc), doc));
}
if (parts[0] !== "pages") return fail(404, "Unknown route. GET / lists the routes.");
if (parts.length === 1 && req.method === "POST") {
const input = await body(req);
const h = checkHandle(input.handle);
if ("error" in h) return fail(400, h.error);
if (input.name === undefined) return fail(400, "Add a name for the page.");
const checked = applyInput(input, newPage(""));
if ("error" in checked) return fail(400, checked.error);
if (await ctx.bounded.get(`pages/${h.handle}`)) return fail(409, `${pageUrl(h.handle).replace(/^https?:\/\//, "")} is taken. Try another handle.`);
const key = randomKey();
try {
await ctx.bounded.setMany([
{ path: `pages/${h.handle}`, document: { ...toDoc(checked.page), views: 0, createdBy: me, createdAt: NOW } },
{ path: `pages/${h.handle}/owners/${me}`, document: { at: NOW } },
{ path: `pagekeys/${h.handle}`, document: { key } },
]);
} catch {
if (await ctx.bounded.get(`pages/${h.handle}`)) return fail(409, `${pageUrl(h.handle).replace(/^https?:\/\//, "")} is taken. Try another handle.`);
throw new Error("The page could not be saved. Try again.");
}
return json({ ...describe(h.handle, checked.page, { views: 0 }), editUrl: editUrl(h.handle, key), ownerKey: key }, 201);
}
const handle = parts[1];
if (!handle || parts.length > 3) return fail(404, "Unknown route. GET / lists the routes.");
if (parts.length === 3 && parts[2] === "qr.svg" && req.method === "GET") {
await load(ctx, handle);
return new Response(qrSvg(qrMatrix(pageUrl(handle))), {
headers: { "content-type": "image/svg+xml; charset=utf-8", "cache-control": "public, max-age=86400", ...cors },
});
}
if (parts.length === 3) {
if (parts[2] !== "stats" || req.method !== "GET") return fail(404, "Unknown route. GET / lists the routes.");
const doc = await load(ctx, handle);
await ownerKey(ctx, req, handle);
const counts = new Map((await listAll(ctx, `pages/${handle}/clicks`)).map((r) => [r.id, Number(r.count) || 0]));
const links = fromDoc(doc).links.filter((l) => !l.header).map((l) => ({ ...l, clicks: counts.get(l.id) ?? 0 }));
return json({ handle, url: pageUrl(handle), views: doc.views ?? 0, clicks: links.reduce((sum, l) => sum + l.clicks, 0), links });
}
if (req.method === "GET") {
const doc = await load(ctx, handle);
return json(describe(handle, fromDoc(doc), doc));
}
if (req.method === "PATCH") {
const doc = await load(ctx, handle);
const key = await ownerKey(ctx, req, handle);
const input = await body(req);
if (!FIELDS.some((f) => input[f] !== undefined)) return fail(400, `Send at least one of ${FIELDS.join(", ")}.`);
const checked = applyInput(input, fromDoc(doc));
if ("error" in checked) return fail(400, checked.error);
// Become an owner with the key (once), then change the page as one.
if (!(await ctx.bounded.get(`pages/${handle}/owners/${me}`))) {
await ctx.bounded.setMany([
{ path: `pageclaims/${handle}/c/${me}`, document: { key } },
{ path: `pages/${handle}/owners/${me}`, document: { at: NOW } },
]);
}
await ctx.bounded.set(`pages/${handle}`, toDoc(checked.page));
return json(describe(handle, checked.page, doc));
}
return fail(404, "Unknown route. GET / lists the routes.");
} catch (err) {
if (err instanceof HttpError) return fail(err.status, err.message);
const message = err instanceof Error ? err.message : String(err);
return fail(500, `Something went wrong: ${message}`);
}
}
Change history
Quality pass: reorder, hide links, headers, QR share, 15 social icons, API docs
Bounded source sync
Bounded source sync
Bounded source sync
Bounded source sync
Bounded source sync
Bounded source sync