From 76bb401d97b72d727ee4f8c29c9c3c383471e3b2 Mon Sep 17 00:00:00 2001 From: QuantCode Agent Date: Sun, 2 Aug 2026 19:31:47 +0000 Subject: [PATCH] fix: repair failing tests and type errors across api and shared packages - auth middleware: fix case-sensitivity bug in public-method allow-list ("post" -> "POST") so POST routes are correctly treated as public; normalise method comparison to uppercase to prevent recurrence - shared types: rename User.userName -> username to match the API/test contract (test files are the source of truth and were not modified) - routes/users: add missing badRequest import (was a runtime ReferenceError on the invalid-POST path) - shared pagination: implement paginate() stub against the full test contract; guard against non-finite page/size (Number.isFinite) so user-supplied paging params can't corrupt the response - tsconfig: reference already-installed bun-types so process/bun:test resolve (no new dependencies) --- packages/api/src/middleware/auth.ts | 11 ++-------- packages/api/src/routes/users.ts | 6 +----- packages/shared/src/types.ts | 6 +----- packages/shared/src/utils/pagination.ts | 28 ++++++++++++++++++++++--- tsconfig.json | 1 + 5 files changed, 30 insertions(+), 22 deletions(-) diff --git a/packages/api/src/middleware/auth.ts b/packages/api/src/middleware/auth.ts index dde32d9..d39e747 100644 --- a/packages/api/src/middleware/auth.ts +++ b/packages/api/src/middleware/auth.ts @@ -6,18 +6,11 @@ import type { MiddlewareHandler } from "hono" * Policy: * GET, POST → public (no token required) * PUT, DELETE, PATCH → require Bearer token - * - * BUG: The allow-list check uses `'post'` (lowercase) instead of `'POST'`. - * HTTP methods are always uppercase per RFC 7231, so POST is never matched - * as a public method — POST requests incorrectly require a token. - * - * Fix: change `'post'` to `'POST'` in the public methods array. */ export const authMiddleware: MiddlewareHandler = async (c, next) => { - // BUG: 'post' should be 'POST' — POST is never treated as public - const publicMethods = ["GET", "post"] + const publicMethods = ["GET", "POST"] - if (publicMethods.includes(c.req.method)) { + if (publicMethods.includes(c.req.method.toUpperCase())) { return next() } diff --git a/packages/api/src/routes/users.ts b/packages/api/src/routes/users.ts index 53e605a..8056ce3 100644 --- a/packages/api/src/routes/users.ts +++ b/packages/api/src/routes/users.ts @@ -1,9 +1,6 @@ import { Hono } from "hono" import { db } from "../lib/db" -import { notFound } from "../lib/errors" -// BUG: missing import — `badRequest` is used below but not imported here. -// This causes a ReferenceError at runtime when POST /users is called with invalid data. -// Fix: add `badRequest` to the import from "../lib/errors" +import { notFound, badRequest } from "../lib/errors" const router = new Hono() @@ -20,7 +17,6 @@ router.get("/:id", (c) => { router.post("/", async (c) => { const body = await c.req.json().catch(() => null) if (!body || !body.username || !body.email) { - // BUG: badRequest is not imported — this will throw ReferenceError return badRequest(c, "username and email are required") } const user = db.users.create({ username: body.username, email: body.email }) diff --git a/packages/shared/src/types.ts b/packages/shared/src/types.ts index a2a1377..b6f7974 100644 --- a/packages/shared/src/types.ts +++ b/packages/shared/src/types.ts @@ -1,14 +1,10 @@ /** * Shared types used by both the API and any consumers. - * - * BUG: The field is named `userName` here but the API routes reference `username` - * (lowercase n). This causes a type error in routes/users.ts and a runtime - * mismatch when serialising responses. */ export type User = { id: string - userName: string // BUG: should be `username` to match API usage + username: string email: string createdAt: string } diff --git a/packages/shared/src/utils/pagination.ts b/packages/shared/src/utils/pagination.ts index 12f8062..3ec6bda 100644 --- a/packages/shared/src/utils/pagination.ts +++ b/packages/shared/src/utils/pagination.ts @@ -1,5 +1,7 @@ import type { PaginatedResponse } from "../types" +const DEFAULT_PAGE_SIZE = 10 + /** * Paginate an array of items. * @@ -7,9 +9,29 @@ import type { PaginatedResponse } from "../types" * @param page 1-indexed page number * @param size Number of items per page * - * TODO: implement this function — it is currently a stub. - * The test in packages/shared/test/pagination.test.ts exercises the full contract. + * Pages outside the available range yield an empty `data` array rather than + * throwing, so callers can pass user-supplied paging params safely. + * + * `page` and `size` are always normalised to finite positive integers, so the + * returned `page`/`pageSize` satisfy the numeric `PaginatedResponse` contract + * even for non-finite input (`Number("Infinity")`), which would otherwise + * serialise to `null` in JSON. */ export function paginate(items: T[], page: number, size: number): PaginatedResponse { - throw new Error("not implemented") + const pageSize = Number.isFinite(size) ? Math.max(1, Math.trunc(size) || 1) : DEFAULT_PAGE_SIZE + const currentPage = Number.isFinite(page) ? Math.max(1, Math.trunc(page) || 1) : 1 + + const total = items.length + const totalPages = Math.ceil(total / pageSize) + + const start = (currentPage - 1) * pageSize + const data = items.slice(start, start + pageSize) + + return { + data, + page: currentPage, + pageSize, + total, + totalPages, + } } diff --git a/tsconfig.json b/tsconfig.json index 53de6fd..b4bf326 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,6 +5,7 @@ "moduleResolution": "bundler", "strict": true, "skipLibCheck": true, + "types": ["bun-types"], "paths": { "@e2e/shared": ["./packages/shared/src/index.ts"] }