import Fastify from "fastify" import type { GatewayConfig } from "./config.js" import { proxyToUpstream } from "./proxy.js" export function createGatewayServer(config: GatewayConfig) { const app = Fastify({ logger: true, }) app.get("/health", async () => ({ service: "image-platform-gateway", status: "ok", })) app.get<{ Params: ImageParams; Querystring: ImageQuery }>( "/images/:assetId/:version/:preset", async (request, reply) => { const version = parseVersionParam(request.params.version) if (version === null) { return reply.code(400).send({ message: "image version must use v{number} format", statusCode: 400, }) } const width = parseOptionalInteger(request.query.w) const quality = parseOptionalInteger(request.query.q) const format = request.query.f ?? "auto" return reply.code(501).header("cache-control", "no-store").send({ assetId: request.params.assetId, format, message: "image gateway read-through pipeline is not implemented yet", preset: request.params.preset, quality, status: "not_implemented", version, width, }) }, ) app.all("/api/*", async (request, reply) => proxyToUpstream(request, reply, config.backendUpstream)) app.all("/docs", async (request, reply) => proxyToUpstream(request, reply, config.backendUpstream)) app.all("/docs/*", async (request, reply) => proxyToUpstream(request, reply, config.backendUpstream)) app.all("/docs-json", async (request, reply) => proxyToUpstream(request, reply, config.backendUpstream)) app.setNotFoundHandler(async (_request, reply) => { return reply.code(404).send({ message: "route not found", statusCode: 404, }) }) return app } type ImageQuery = { f?: string q?: string w?: string } type ImageParams = { assetId: string preset: string version: string } function parseVersionParam(value: string) { if (!value.startsWith("v")) { return null } const parsed = Number.parseInt(value.slice(1), 10) return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : null } function parseOptionalInteger(value: string | undefined) { if (!value) { return null } const parsed = Number.parseInt(value, 10) return Number.isFinite(parsed) ? parsed : null }