import { Router } from 'express'; import { z } from 'zod'; import { asyncWrap } from '../errors.js'; import { requireOwner } from '../cap.js'; import { validate } from '../validate.js'; import { compareVersions, fetchLatestKuttRelease, createLink, recentLinks } from '../../links/kutt.js'; export const router = Router(); const cfg = () => ({ base: process.env.KUTT_API_URL, key: process.env.KUTT_API_KEY }); // GET /kutt/version — running (pinned env) vs latest GitHub release (cached 6h). let cache = { at: 0, val: null }; router.get('/version', requireOwner, asyncWrap(async (_req, res) => { const running = process.env.KUTT_VERSION || 'unknown'; if (Date.now() - cache.at > 6 * 3600e3 || !cache.val) { try { cache = { at: Date.now(), val: await fetchLatestKuttRelease({}) }; } catch { return res.json({ running, latest: null, updateAvailable: false, error: 'version check unavailable' }); } } res.json({ ...compareVersions(running, cache.val.latest), url: cache.val.url }); })); const linkBody = z.object({ target: z.string().url(), customurl: z.string().max(64).optional(), description: z.string().max(200).optional() }); // POST /kutt — create via Kutt (owner). Key stays server-side. router.post('/', requireOwner, validate({ body: linkBody }), asyncWrap(async (req, res) => { if (!process.env.KUTT_API_KEY) return res.status(502).json({ error: { code: 'kutt_unconfigured' } }); res.status(201).json(await createLink(req.body, cfg())); })); // GET /kutt/recent — last few links (owner). router.get('/recent', requireOwner, asyncWrap(async (_req, res) => { res.json(await recentLinks(cfg())); }));