feat(26-02): discovery HTTP routes, server registration, and route tests

- Create src/server/routes/discovery.ts with GET /setups, /items, /categories handlers
- Register discoveryRoutes in src/server/index.ts with browseTier rate limiting
- Add auth skip for /api/discovery/* GET requests in auth middleware
- Create tests/routes/discovery.test.ts with 10 tests covering all endpoints and pagination
This commit is contained in:
2026-04-10 14:57:35 +02:00
parent a00b90d97a
commit 0323e0cd33
3 changed files with 287 additions and 0 deletions

View File

@@ -13,6 +13,7 @@ import { requireAuth } from "./middleware/auth.ts";
import { createRateLimit } from "./middleware/rateLimit.ts";
import { authRoutes } from "./routes/auth.ts";
import { categoryRoutes } from "./routes/categories.ts";
import { discoveryRoutes } from "./routes/discovery.ts";
import { globalItemRoutes } from "./routes/global-items.ts";
import { imageRoutes } from "./routes/images.ts";
import { itemRoutes } from "./routes/items.ts";
@@ -123,6 +124,10 @@ const browseTier = createRateLimit(120, 60_000);
const detailTier = createRateLimit(60, 60_000);
// Browse endpoints — higher limit for list/search
app.use("/api/discovery/*", async (c, next) => {
if (c.req.method === "GET") return browseTier(c, next);
return next();
});
app.use("/api/global-items", async (c, next) => {
if (c.req.method === "GET" && !c.req.path.match(/^\/api\/global-items\/\d+$/))
return browseTier(c, next);
@@ -162,6 +167,9 @@ app.use("/api/*", async (c, next) => {
// Skip public tags endpoint (GET /api/tags)
if (c.req.path.startsWith("/api/tags") && c.req.method === "GET")
return next();
// Skip public discovery endpoints (GET /api/discovery/*)
if (c.req.path.startsWith("/api/discovery") && c.req.method === "GET")
return next();
// Skip public global-items endpoint (GET /api/global-items)
if (c.req.path.startsWith("/api/global-items") && c.req.method === "GET")
return next();
@@ -179,6 +187,7 @@ app.route("/api/settings", settingsRoutes);
app.route("/api/threads", threadRoutes);
app.route("/api/users", profileRoutes);
app.route("/api/setups", setupRoutes);
app.route("/api/discovery", discoveryRoutes);
app.route("/api/global-items", globalItemRoutes);
app.route("/api/tags", tagRoutes);