diff --git a/api/router.ts b/api/router.ts index 458521f..2bd4cf8 100644 --- a/api/router.ts +++ b/api/router.ts @@ -1,4 +1,5 @@ import { randomBytes } from 'node:crypto'; +import { createRouter } from '@@/create-router'; import { createSidecarProxy } from '@@/sidecar/create-proxy'; import { mountPrefix } from '@@/plugins/manifest'; import { manifest } from '../manifest'; @@ -31,11 +32,20 @@ const PREFIX = `/api${mountPrefix({ appName: 'gitea', manifest })}`; const proxy = createSidecarProxy({ name: 'gitea', prefix: PREFIX }); /** - * Mint the frame cookie. Registered BEFORE the proxy's `/*`, because hono matches in registration order - * and the wildcard would otherwise swallow it and forward `/session` to the sidecar, which has no such - * route and would answer 404 — a 404 that looks exactly like the plugin being broken. + * OUR routes first, then the proxy's catch-all. + * + * `createSidecarProxy` registers `all('/*')` when it is CALLED, so anything added to `proxy.router` + * afterwards is dead — hono matches in registration order and the wildcard has already claimed + * everything. Both routes below were added that way at first, and the symptom was + * `POST /session -> 500`: forwarded to a sidecar that has no such route, reported as "internal error", + * and looking for all the world like the sidecar being broken. + * + * So this is a router of our own, with the proxy's mounted UNDER it at the end. */ -proxy.router.post('/session', (ctx) => { +const router_ = createRouter(); + +/** Mint the frame cookie for the iframe, which cannot carry a bearer token. */ +router_.post('/session', (ctx) => { const user = ctx.get('user') as { id: number } | undefined; if (!user) return ctx.json({ error: 'not authenticated' }, 401); ctx.header('set-cookie', mintFrameCookie(user.id, PREFIX)); @@ -53,7 +63,7 @@ proxy.router.post('/session', (ctx) => { * So this one path forwards the browser's request itself, headers and all. Everything else about the * plugin still goes through the shared proxy. */ -proxy.router.all('/_web/*', async (ctx) => { +router_.all('/_web/*', async (ctx) => { const userId = frameUser(ctx.req.header('cookie') ?? null); // Deliberately terse. Whoever reaches this without a cookie is a stray request, not a person — the // panel mints one before the frame loads. @@ -93,7 +103,10 @@ proxy.router.all('/_web/*', async (ctx) => { } }); -export const router = proxy.router; +// Last, so everything above wins. +router_.route('/', proxy.router); + +export const router = router_; /** Base URL of the sidecar's HTTP server, or null if it has not reported in yet. */ export const getGiteaServerUrl = proxy.getHttpUrl;