From 9efb9004b4d7e47663e9a18d0f2f3f12b1a16dfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Sans=C3=B3n?= <57395395+csansoon@users.noreply.github.com> Date: Wed, 19 Nov 2025 17:13:17 +0100 Subject: [PATCH] Added an optional generic type to API routes to enforce the return type --- .../[projectId]/runs/completed/route.ts | 10 +++++++--- apps/web/src/middlewares/adminHandler.ts | 3 ++- apps/web/src/middlewares/authHandler.ts | 3 ++- apps/web/src/middlewares/errorHandler.ts | 3 ++- apps/web/src/middlewares/types.ts | 18 ++++++++++++++++++ apps/web/src/services/routes/api.ts | 12 ------------ apps/web/src/stores/runs/completedRuns.ts | 9 ++++++++- 7 files changed, 39 insertions(+), 19 deletions(-) create mode 100644 apps/web/src/middlewares/types.ts diff --git a/apps/web/src/app/api/projects/[projectId]/runs/completed/route.ts b/apps/web/src/app/api/projects/[projectId]/runs/completed/route.ts index dced6aa176..ae76e5aa84 100644 --- a/apps/web/src/app/api/projects/[projectId]/runs/completed/route.ts +++ b/apps/web/src/app/api/projects/[projectId]/runs/completed/route.ts @@ -1,12 +1,16 @@ import { authHandler } from '$/middlewares/authHandler' import { errorHandler } from '$/middlewares/errorHandler' -import { RunSourceGroup, SpanType } from '@latitude-data/constants' +import { + CompletedRun, + RunSourceGroup, + SpanType, +} from '@latitude-data/constants' import { listCompletedRuns } from '@latitude-data/core/services/runs/completed/listCompleted' import { Workspace } from '@latitude-data/core/schema/models/types/Workspace' import { NextRequest, NextResponse } from 'next/server' -export const GET = errorHandler( +export const GET = errorHandler( authHandler( async ( request: NextRequest, @@ -43,7 +47,7 @@ export const GET = errorHandler( next: runs.next ? JSON.stringify(runs.next) : null, } - return NextResponse.json(response, { status: 200 }) + return NextResponse.json(response.items, { status: 200 }) }, ), ) diff --git a/apps/web/src/middlewares/adminHandler.ts b/apps/web/src/middlewares/adminHandler.ts index 1107d1fab1..fa61acae06 100644 --- a/apps/web/src/middlewares/adminHandler.ts +++ b/apps/web/src/middlewares/adminHandler.ts @@ -1,8 +1,9 @@ import { getCurrentUserOrRedirect } from '$/services/auth/getCurrentUser' import { notFound } from 'next/navigation' import { NextRequest } from 'next/server' +import { RouteHandler } from './types' -export function adminHandler(handler: any) { +export function adminHandler(handler: RouteHandler) { return async ( req: NextRequest, { params, ...rest }: { params?: Promise> } = {}, diff --git a/apps/web/src/middlewares/authHandler.ts b/apps/web/src/middlewares/authHandler.ts index c54df0a18a..c8e6dfe062 100644 --- a/apps/web/src/middlewares/authHandler.ts +++ b/apps/web/src/middlewares/authHandler.ts @@ -1,7 +1,8 @@ import { getDataFromSession } from '$/data-access' import { NextRequest, NextResponse } from 'next/server' +import { RouteHandler } from './types' -export function authHandler(handler: any) { +export function authHandler(handler: RouteHandler) { return async ( req: NextRequest, { diff --git a/apps/web/src/middlewares/errorHandler.ts b/apps/web/src/middlewares/errorHandler.ts index 59f8b39051..01992040ff 100644 --- a/apps/web/src/middlewares/errorHandler.ts +++ b/apps/web/src/middlewares/errorHandler.ts @@ -3,6 +3,7 @@ import { env } from '@latitude-data/env' import { captureException } from '$/helpers/captureException' import { NextRequest, NextResponse } from 'next/server' import debug from '@latitude-data/core/lib/debug' +import { RouteHandler } from './types' interface AbortError extends DOMException { name: 'AbortError' @@ -18,7 +19,7 @@ export function isAbortError(error: unknown): error is AbortError { ) } -export function errorHandler(handler: any) { +export function errorHandler(handler: RouteHandler) { const isDev = env.NODE_ENV === 'development' return async (req: NextRequest, res: any) => { try { diff --git a/apps/web/src/middlewares/types.ts b/apps/web/src/middlewares/types.ts new file mode 100644 index 0000000000..a738eef91d --- /dev/null +++ b/apps/web/src/middlewares/types.ts @@ -0,0 +1,18 @@ +import { NextRequest, NextResponse } from 'next/server' + +type ApiMessageResponse = { + message: string +} + +type ApiErrorResponse = { + error: string +} + +export type RouteHandler = ( + req: NextRequest, + res: any, +) => Promise< + | NextResponse + | NextResponse + | NextResponse +> diff --git a/apps/web/src/services/routes/api.ts b/apps/web/src/services/routes/api.ts index 04d45170eb..3b401de95e 100644 --- a/apps/web/src/services/routes/api.ts +++ b/apps/web/src/services/routes/api.ts @@ -399,18 +399,6 @@ export const API_ROUTES = { completed: { root: `${projectRoot}/runs/completed`, count: `${projectRoot}/runs/completed/count`, - detail: ({ - limit, - sourceGroup, - }: { - limit?: number - sourceGroup?: RunSourceGroup - } = {}) => { - const params = new URLSearchParams() - if (limit) params.set('limit', limit.toString()) - if (sourceGroup) params.set('sourceGroup', sourceGroup) - return `${projectRoot}/runs/completed?${params.toString()}` - }, }, detail: (uuid: string) => ({ root: `${projectRoot}/runs/${uuid}`, diff --git a/apps/web/src/stores/runs/completedRuns.ts b/apps/web/src/stores/runs/completedRuns.ts index ccb38417bf..0f4fd76386 100644 --- a/apps/web/src/stores/runs/completedRuns.ts +++ b/apps/web/src/stores/runs/completedRuns.ts @@ -15,6 +15,7 @@ import { import { useCallback, useMemo } from 'react' import useSWR, { SWRConfiguration } from 'swr' +import { compactObject } from '@latitude-data/core/lib/compactObject' export function useCompletedRuns( { @@ -32,7 +33,13 @@ export function useCompletedRuns( opts?: SWRConfiguration, ) { const fetcher = useFetcher( - ROUTES.api.projects.detail(project.id).runs.completed.detail(search), + ROUTES.api.projects.detail(project.id).runs.completed.root, + { + searchParams: compactObject({ + limit: search?.limit ? search.limit.toString() : undefined, + sourceGroup: search?.sourceGroup, + }) as Record, + }, ) const {