Files
menulio/apps/api/src/index.ts
T
AyrisAI 1a3e46f16c fix(api): raise Fastify body size limit for AI menu photo uploads
Default 1 MiB limit rejected base64-encoded camera photos before the
request handler ever ran ("Request body is too large"), unrelated to
the OpenAI model. Also adds the public domains RLS policy needed for
custom-domain resolution on the public menu page (already applied
manually via SQL Editor, committing for history).
2026-08-20 05:13:03 +03:00

56 lines
1.9 KiB
TypeScript

import cors from "@fastify/cors";
import Fastify from "fastify";
import { env } from "./env.js";
import { aiImportsRoutes } from "./routes/ai-imports.js";
import { analyticsRoutes } from "./routes/analytics.js";
import { domainsRoutes } from "./routes/domains.js";
import { menuCategoriesRoutes } from "./routes/menu-categories.js";
import { menuItemsRoutes } from "./routes/menu-items.js";
import { menusRoutes } from "./routes/menus.js";
import { meRoutes } from "./routes/me.js";
import { qrRoutes } from "./routes/qr.js";
import { restaurantsRoutes } from "./routes/restaurants.js";
import { subscriptionRoutes } from "./routes/subscription.js";
// Default Fastify bodyLimit is 1 MiB — a base64-encoded menu photo from a
// phone camera routinely exceeds that, so AI import uploads need real headroom.
const app = Fastify({ logger: true, bodyLimit: 20 * 1024 * 1024 });
await app.register(cors);
// Clients (mobile fetch/axios in particular) commonly send
// `Content-Type: application/json` on bodyless POSTs — treat an empty body
// as `{}` instead of the default 400.
app.addContentTypeParser("application/json", { parseAs: "string" }, (_req, body, done) => {
if (!body) {
done(null, {});
return;
}
try {
done(null, JSON.parse(body as string));
} catch (err) {
done(err as Error, undefined);
}
});
app.get("/", async () => ({ name: "menul.io API", status: "ok", version: "0.0.1" }));
app.get("/health", async () => ({ status: "ok" }));
await app.register(meRoutes);
await app.register(restaurantsRoutes);
await app.register(menusRoutes);
await app.register(menuCategoriesRoutes);
await app.register(menuItemsRoutes);
await app.register(qrRoutes);
await app.register(aiImportsRoutes);
await app.register(domainsRoutes);
await app.register(analyticsRoutes);
await app.register(subscriptionRoutes);
app
.listen({ port: env.PORT, host: "0.0.0.0" })
.catch((err) => {
app.log.error(err);
process.exit(1);
});