feat(links): /api/kutt proxy (version + create + recent)
This commit is contained in:
@@ -34,6 +34,7 @@ import { router as littleblueRouter } from './routes/littleblue.js';
|
||||
import { router as aiUsageRouter } from './routes/ai_usage.js';
|
||||
import { router as infraRouter } from './routes/infra.js';
|
||||
import { router as clusterRouter } from './routes/cluster.js';
|
||||
import { router as kuttRouter } from './routes/kutt.js';
|
||||
|
||||
export function mountApi(app) {
|
||||
const api = Router();
|
||||
@@ -65,6 +66,7 @@ export function mountApi(app) {
|
||||
api.use('/conversations/:conversation_id/messages', messagesByConvRouter);
|
||||
api.use('/tags', tagsRouter);
|
||||
api.use('/links', linksRouter);
|
||||
api.use('/kutt', kuttRouter);
|
||||
api.use('/pending-changes', pendingChangesRouter);
|
||||
api.use('/audit', auditRouter);
|
||||
api.use('/search', searchRouter);
|
||||
|
||||
37
lib/api/routes/kutt.js
Normal file
37
lib/api/routes/kutt.js
Normal file
@@ -0,0 +1,37 @@
|
||||
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()));
|
||||
}));
|
||||
Reference in New Issue
Block a user