ported from the standalone officer-atelier service: providers (adapter-shaped, openai the only adapter today), the generation queue, collections, and the database layer — kept on its own Postgres database rather than folded into officer_db, since both collections and provider_settings had rows on the machine this was extracted from. what changed rather than just moved: - images are served from an authenticated GET /files/:filename instead of an unauthenticated PUBLIC_URL-prefixed static route - the OpenAI-key bootstrap fallback reads the secret store (getSecret) before .env, per-adapter - provider_settings (the one-row-per-adapter shape providers replaced) did not come along — it has no callers left anywhere in the server code, only a migration script that also did not move ping/echo (smoke-test routes with no caller) did not move either; the sidecar's own /_health covers liveness. not yet wired into the platform: sidecar/index.ts exists but nothing mounts it, and web/ has not been written, so this is not yet a discoverable plugin.
25 lines
1.3 KiB
TypeScript
25 lines
1.3 KiB
TypeScript
import { createRouter } from '../create-router';
|
|
import { IMAGES_DIR } from '../env';
|
|
|
|
// `GET /files/:filename` — the generated image bytes.
|
|
//
|
|
// Was an unauthenticated top-level `/images/*` route with a durable `PUBLIC_URL`-prefixed link on the
|
|
// standalone service. Inside Officer it is mounted like every other route — the permission gate on the
|
|
// platform side already authenticated the request before the proxy forwarded it here, so this route
|
|
// itself needs no auth of its own; it only needs to refuse path traversal.
|
|
//
|
|
// Named `/files`, not `/images`, to avoid any ambiguity with the JSON API mounted at `/images` in
|
|
// hono.ts — `/images/:filename` here would sit one segment away from `/images/generations/:id`.
|
|
export const filesRouter = createRouter();
|
|
|
|
filesRouter.get('/:filename', async (ctx) => {
|
|
const name = ctx.req.param('filename');
|
|
// No traversal: the name is a filename, so anything with a separator is not one.
|
|
if (!name || name.includes('/') || name.includes('\\') || name.includes('..')) {
|
|
return ctx.text('Not found', 404);
|
|
}
|
|
const file = Bun.file(`${IMAGES_DIR}/${name}`);
|
|
if (!(await file.exists())) return ctx.text('Not found', 404);
|
|
return new Response(file, { headers: { 'cache-control': 'private, max-age=31536000, immutable' } });
|
|
});
|