From ea72ab5aa9f0815a2c3b256379b11926b09a5fe2 Mon Sep 17 00:00:00 2001 From: Lakee Sivaraya Date: Fri, 16 Jan 2026 12:07:50 -0800 Subject: [PATCH] simplicifcaiton --- apps/sim/app/api/table/[tableId]/route.ts | 47 +--- .../api/table/[tableId]/rows/[rowId]/route.ts | 53 ++--- .../sim/app/api/table/[tableId]/rows/route.ts | 47 ++-- .../api/table/[tableId]/rows/upsert/route.ts | 46 ++-- apps/sim/app/api/table/utils.ts | 219 +++--------------- 5 files changed, 101 insertions(+), 311 deletions(-) diff --git a/apps/sim/app/api/table/[tableId]/route.ts b/apps/sim/app/api/table/[tableId]/route.ts index 02b66fe40..a39e0bc18 100644 --- a/apps/sim/app/api/table/[tableId]/route.ts +++ b/apps/sim/app/api/table/[tableId]/route.ts @@ -3,13 +3,8 @@ import { type NextRequest, NextResponse } from 'next/server' import { z } from 'zod' import { checkHybridAuth } from '@/lib/auth/hybrid' import { generateRequestId } from '@/lib/core/utils/request' -import { deleteTable, getTableById, type TableSchema } from '@/lib/table' -import { - checkTableAccess, - checkTableWriteAccess, - normalizeColumn, - verifyTableWorkspace, -} from '../utils' +import { deleteTable, type TableSchema } from '@/lib/table' +import { accessError, checkAccess, normalizeColumn, verifyTableWorkspace } from '../utils' const logger = createLogger('TableDetailAPI') @@ -38,33 +33,19 @@ export async function GET(request: NextRequest, { params }: TableRouteParams) { workspaceId: searchParams.get('workspaceId'), }) - const accessCheck = await checkTableAccess(tableId, authResult.userId) + const result = await checkAccess(tableId, authResult.userId, 'read') + if (!result.ok) return accessError(result, requestId, tableId) - if (!accessCheck.hasAccess) { - if ('notFound' in accessCheck && accessCheck.notFound) { - logger.warn(`[${requestId}] Table not found: ${tableId}`) - return NextResponse.json({ error: 'Table not found' }, { status: 404 }) - } - logger.warn( - `[${requestId}] User ${authResult.userId} attempted to access unauthorized table ${tableId}` - ) - return NextResponse.json({ error: 'Access denied' }, { status: 403 }) - } + const { table } = result const isValidWorkspace = await verifyTableWorkspace(tableId, validated.workspaceId) if (!isValidWorkspace) { logger.warn( - `[${requestId}] Workspace ID mismatch for table ${tableId}. Provided: ${validated.workspaceId}, Actual: ${accessCheck.table.workspaceId}` + `[${requestId}] Workspace ID mismatch for table ${tableId}. Provided: ${validated.workspaceId}, Actual: ${table.workspaceId}` ) return NextResponse.json({ error: 'Invalid workspace ID' }, { status: 400 }) } - const table = await getTableById(tableId) - - if (!table) { - return NextResponse.json({ error: 'Table not found' }, { status: 404 }) - } - logger.info(`[${requestId}] Retrieved table ${tableId} for user ${authResult.userId}`) const schemaData = table.schema as TableSchema @@ -122,23 +103,15 @@ export async function DELETE(request: NextRequest, { params }: TableRouteParams) workspaceId: searchParams.get('workspaceId'), }) - const accessCheck = await checkTableWriteAccess(tableId, authResult.userId) + const result = await checkAccess(tableId, authResult.userId, 'write') + if (!result.ok) return accessError(result, requestId, tableId) - if (!accessCheck.hasAccess) { - if ('notFound' in accessCheck && accessCheck.notFound) { - logger.warn(`[${requestId}] Table not found: ${tableId}`) - return NextResponse.json({ error: 'Table not found' }, { status: 404 }) - } - logger.warn( - `[${requestId}] User ${authResult.userId} attempted to delete unauthorized table ${tableId}` - ) - return NextResponse.json({ error: 'Access denied' }, { status: 403 }) - } + const { table } = result const isValidWorkspace = await verifyTableWorkspace(tableId, validated.workspaceId) if (!isValidWorkspace) { logger.warn( - `[${requestId}] Workspace ID mismatch for table ${tableId}. Provided: ${validated.workspaceId}, Actual: ${accessCheck.table.workspaceId}` + `[${requestId}] Workspace ID mismatch for table ${tableId}. Provided: ${validated.workspaceId}, Actual: ${table.workspaceId}` ) return NextResponse.json({ error: 'Invalid workspace ID' }, { status: 400 }) } diff --git a/apps/sim/app/api/table/[tableId]/rows/[rowId]/route.ts b/apps/sim/app/api/table/[tableId]/rows/[rowId]/route.ts index 0b4e81f8e..2ba9d663e 100644 --- a/apps/sim/app/api/table/[tableId]/rows/[rowId]/route.ts +++ b/apps/sim/app/api/table/[tableId]/rows/[rowId]/route.ts @@ -8,12 +8,7 @@ import { checkHybridAuth } from '@/lib/auth/hybrid' import { generateRequestId } from '@/lib/core/utils/request' import type { RowData, TableSchema } from '@/lib/table' import { validateRowData } from '@/lib/table' -import { - checkAccessOrRespond, - checkTableAccess, - getTableById, - verifyTableWorkspace, -} from '../../../utils' +import { accessError, checkAccess, verifyTableWorkspace } from '../../../utils' const logger = createLogger('TableRowAPI') @@ -50,24 +45,15 @@ export async function GET(request: NextRequest, { params }: RowRouteParams) { workspaceId: searchParams.get('workspaceId'), }) - const accessCheck = await checkTableAccess(tableId, authResult.userId) + const result = await checkAccess(tableId, authResult.userId, 'read') + if (!result.ok) return accessError(result, requestId, tableId) - if (!accessCheck.hasAccess) { - if ('notFound' in accessCheck && accessCheck.notFound) { - logger.warn(`[${requestId}] Table not found: ${tableId}`) - return NextResponse.json({ error: 'Table not found' }, { status: 404 }) - } - logger.warn( - `[${requestId}] User ${authResult.userId} attempted to access row from unauthorized table ${tableId}` - ) - return NextResponse.json({ error: 'Access denied' }, { status: 403 }) - } + const { table } = result - const actualWorkspaceId = validated.workspaceId const isValidWorkspace = await verifyTableWorkspace(tableId, validated.workspaceId) if (!isValidWorkspace) { logger.warn( - `[${requestId}] Workspace ID mismatch for table ${tableId}. Provided: ${validated.workspaceId}, Actual: ${accessCheck.table.workspaceId}` + `[${requestId}] Workspace ID mismatch for table ${tableId}. Provided: ${validated.workspaceId}, Actual: ${table.workspaceId}` ) return NextResponse.json({ error: 'Invalid workspace ID' }, { status: 400 }) } @@ -84,7 +70,7 @@ export async function GET(request: NextRequest, { params }: RowRouteParams) { and( eq(userTableRows.id, rowId), eq(userTableRows.tableId, tableId), - eq(userTableRows.workspaceId, actualWorkspaceId) + eq(userTableRows.workspaceId, validated.workspaceId) ) ) .limit(1) @@ -133,23 +119,19 @@ export async function PATCH(request: NextRequest, { params }: RowRouteParams) { const body: unknown = await request.json() const validated = UpdateRowSchema.parse(body) - const accessResult = await checkAccessOrRespond(tableId, authResult.userId, requestId, 'write') - if (accessResult instanceof NextResponse) return accessResult + const result = await checkAccess(tableId, authResult.userId, 'write') + if (!result.ok) return accessError(result, requestId, tableId) + + const { table } = result - const actualWorkspaceId = validated.workspaceId const isValidWorkspace = await verifyTableWorkspace(tableId, validated.workspaceId) if (!isValidWorkspace) { logger.warn( - `[${requestId}] Workspace ID mismatch for table ${tableId}. Provided: ${validated.workspaceId}, Actual: ${accessResult.table.workspaceId}` + `[${requestId}] Workspace ID mismatch for table ${tableId}. Provided: ${validated.workspaceId}, Actual: ${table.workspaceId}` ) return NextResponse.json({ error: 'Invalid workspace ID' }, { status: 400 }) } - const table = await getTableById(tableId) - if (!table) { - return NextResponse.json({ error: 'Table not found' }, { status: 404 }) - } - const rowData = validated.data as RowData const validation = await validateRowData({ @@ -172,7 +154,7 @@ export async function PATCH(request: NextRequest, { params }: RowRouteParams) { and( eq(userTableRows.id, rowId), eq(userTableRows.tableId, tableId), - eq(userTableRows.workspaceId, actualWorkspaceId) + eq(userTableRows.workspaceId, validated.workspaceId) ) ) .returning() @@ -222,14 +204,15 @@ export async function DELETE(request: NextRequest, { params }: RowRouteParams) { const body: unknown = await request.json() const validated = DeleteRowSchema.parse(body) - const accessResult = await checkAccessOrRespond(tableId, authResult.userId, requestId, 'write') - if (accessResult instanceof NextResponse) return accessResult + const result = await checkAccess(tableId, authResult.userId, 'write') + if (!result.ok) return accessError(result, requestId, tableId) + + const { table } = result - const actualWorkspaceId = validated.workspaceId const isValidWorkspace = await verifyTableWorkspace(tableId, validated.workspaceId) if (!isValidWorkspace) { logger.warn( - `[${requestId}] Workspace ID mismatch for table ${tableId}. Provided: ${validated.workspaceId}, Actual: ${accessResult.table.workspaceId}` + `[${requestId}] Workspace ID mismatch for table ${tableId}. Provided: ${validated.workspaceId}, Actual: ${table.workspaceId}` ) return NextResponse.json({ error: 'Invalid workspace ID' }, { status: 400 }) } @@ -240,7 +223,7 @@ export async function DELETE(request: NextRequest, { params }: RowRouteParams) { and( eq(userTableRows.id, rowId), eq(userTableRows.tableId, tableId), - eq(userTableRows.workspaceId, actualWorkspaceId) + eq(userTableRows.workspaceId, validated.workspaceId) ) ) .returning() diff --git a/apps/sim/app/api/table/[tableId]/rows/route.ts b/apps/sim/app/api/table/[tableId]/rows/route.ts index 85dca0763..6278e90ca 100644 --- a/apps/sim/app/api/table/[tableId]/rows/route.ts +++ b/apps/sim/app/api/table/[tableId]/rows/route.ts @@ -17,7 +17,7 @@ import { validateUniqueConstraints, } from '@/lib/table' import { buildFilterClause, buildSortClause } from '@/lib/table/query-builder' -import { checkAccessOrRespond, checkAccessWithFullTable, verifyTableWorkspace } from '../../utils' +import { accessError, checkAccess, verifyTableWorkspace } from '../../utils' const logger = createLogger('TableRowsAPI') @@ -88,10 +88,10 @@ async function handleBatchInsert( ): Promise { const validated = BatchInsertRowsSchema.parse(body) - const accessResult = await checkAccessWithFullTable(tableId, userId, requestId, 'write') - if (accessResult instanceof NextResponse) return accessResult + const accessResult = await checkAccess(tableId, userId, 'write') + if (!accessResult.ok) return accessError(accessResult, requestId, tableId) - const table = accessResult.table + const { table } = accessResult if (validated.workspaceId !== table.workspaceId) { logger.warn( @@ -178,15 +178,10 @@ export async function POST(request: NextRequest, { params }: TableRowsRouteParam const validated = InsertRowSchema.parse(body) - const accessResult = await checkAccessWithFullTable( - tableId, - authResult.userId, - requestId, - 'write' - ) - if (accessResult instanceof NextResponse) return accessResult + const accessResult = await checkAccess(tableId, authResult.userId, 'write') + if (!accessResult.ok) return accessError(accessResult, requestId, tableId) - const table = accessResult.table + const { table } = accessResult if (validated.workspaceId !== table.workspaceId) { logger.warn( @@ -295,13 +290,8 @@ export async function GET(request: NextRequest, { params }: TableRowsRouteParams offset, }) - const accessResult = await checkAccessWithFullTable( - tableId, - authResult.userId, - requestId, - 'read' - ) - if (accessResult instanceof NextResponse) return accessResult + const accessResult = await checkAccess(tableId, authResult.userId, 'read') + if (!accessResult.ok) return accessError(accessResult, requestId, tableId) const { table } = accessResult @@ -400,15 +390,10 @@ export async function PUT(request: NextRequest, { params }: TableRowsRouteParams const body: unknown = await request.json() const validated = UpdateRowsByFilterSchema.parse(body) - const accessResult = await checkAccessWithFullTable( - tableId, - authResult.userId, - requestId, - 'write' - ) - if (accessResult instanceof NextResponse) return accessResult + const accessResult = await checkAccess(tableId, authResult.userId, 'write') + if (!accessResult.ok) return accessError(accessResult, requestId, tableId) - const table = accessResult.table + const { table } = accessResult if (validated.workspaceId !== table.workspaceId) { logger.warn( @@ -583,13 +568,15 @@ export async function DELETE(request: NextRequest, { params }: TableRowsRoutePar const body: unknown = await request.json() const validated = DeleteRowsByFilterSchema.parse(body) - const accessResult = await checkAccessOrRespond(tableId, authResult.userId, requestId, 'write') - if (accessResult instanceof NextResponse) return accessResult + const accessResult = await checkAccess(tableId, authResult.userId, 'write') + if (!accessResult.ok) return accessError(accessResult, requestId, tableId) + + const { table } = accessResult const isValidWorkspace = await verifyTableWorkspace(tableId, validated.workspaceId) if (!isValidWorkspace) { logger.warn( - `[${requestId}] Workspace ID mismatch for table ${tableId}. Provided: ${validated.workspaceId}, Actual: ${accessResult.table.workspaceId}` + `[${requestId}] Workspace ID mismatch for table ${tableId}. Provided: ${validated.workspaceId}, Actual: ${table.workspaceId}` ) return NextResponse.json({ error: 'Invalid workspace ID' }, { status: 400 }) } diff --git a/apps/sim/app/api/table/[tableId]/rows/upsert/route.ts b/apps/sim/app/api/table/[tableId]/rows/upsert/route.ts index a42e45d00..fa4498190 100644 --- a/apps/sim/app/api/table/[tableId]/rows/upsert/route.ts +++ b/apps/sim/app/api/table/[tableId]/rows/upsert/route.ts @@ -8,7 +8,7 @@ import { checkHybridAuth } from '@/lib/auth/hybrid' import { generateRequestId } from '@/lib/core/utils/request' import type { RowData, TableSchema } from '@/lib/table' import { getUniqueColumns, validateRowData } from '@/lib/table' -import { checkAccessOrRespond, getTableById, verifyTableWorkspace } from '../../../utils' +import { accessError, checkAccess, verifyTableWorkspace } from '../../../utils' const logger = createLogger('TableUpsertAPI') @@ -35,23 +35,17 @@ export async function POST(request: NextRequest, { params }: UpsertRouteParams) const body: unknown = await request.json() const validated = UpsertRowSchema.parse(body) - const accessResult = await checkAccessOrRespond(tableId, authResult.userId, requestId, 'write') - if (accessResult instanceof NextResponse) return accessResult + const result = await checkAccess(tableId, authResult.userId, 'write') + if (!result.ok) return accessError(result, requestId, tableId) - const actualWorkspaceId = validated.workspaceId || accessResult.table.workspaceId - if (validated.workspaceId) { - const isValidWorkspace = await verifyTableWorkspace(tableId, validated.workspaceId) - if (!isValidWorkspace) { - logger.warn( - `[${requestId}] Workspace ID mismatch for table ${tableId}. Provided: ${validated.workspaceId}, Actual: ${accessResult.table.workspaceId}` - ) - return NextResponse.json({ error: 'Invalid workspace ID' }, { status: 400 }) - } - } + const { table } = result - const table = await getTableById(tableId) - if (!table) { - return NextResponse.json({ error: 'Table not found' }, { status: 404 }) + const isValidWorkspace = await verifyTableWorkspace(tableId, validated.workspaceId) + if (!isValidWorkspace) { + logger.warn( + `[${requestId}] Workspace ID mismatch for table ${tableId}. Provided: ${validated.workspaceId}, Actual: ${table.workspaceId}` + ) + return NextResponse.json({ error: 'Invalid workspace ID' }, { status: 400 }) } const schema = table.schema as TableSchema @@ -102,7 +96,7 @@ export async function POST(request: NextRequest, { params }: UpsertRouteParams) .where( and( eq(userTableRows.tableId, tableId), - eq(userTableRows.workspaceId, actualWorkspaceId), + eq(userTableRows.workspaceId, validated.workspaceId), ...validUniqueFilters ) ) @@ -110,7 +104,7 @@ export async function POST(request: NextRequest, { params }: UpsertRouteParams) const now = new Date() - const result = await db.transaction(async (trx) => { + const upsertResult = await db.transaction(async (trx) => { if (existingRow) { const [updatedRow] = await trx .update(userTableRows) @@ -132,7 +126,7 @@ export async function POST(request: NextRequest, { params }: UpsertRouteParams) .values({ id: `row_${crypto.randomUUID().replace(/-/g, '')}`, tableId, - workspaceId: actualWorkspaceId, + workspaceId: validated.workspaceId, data: validated.data, createdAt: now, updatedAt: now, @@ -147,20 +141,20 @@ export async function POST(request: NextRequest, { params }: UpsertRouteParams) }) logger.info( - `[${requestId}] Upserted (${result.operation}) row ${result.row.id} in table ${tableId}` + `[${requestId}] Upserted (${upsertResult.operation}) row ${upsertResult.row.id} in table ${tableId}` ) return NextResponse.json({ success: true, data: { row: { - id: result.row.id, - data: result.row.data, - createdAt: result.row.createdAt.toISOString(), - updatedAt: result.row.updatedAt.toISOString(), + id: upsertResult.row.id, + data: upsertResult.row.data, + createdAt: upsertResult.row.createdAt.toISOString(), + updatedAt: upsertResult.row.updatedAt.toISOString(), }, - operation: result.operation, - message: `Row ${result.operation === 'update' ? 'updated' : 'inserted'} successfully`, + operation: upsertResult.operation, + message: `Row ${upsertResult.operation === 'update' ? 'updated' : 'inserted'} successfully`, }, }) } catch (error) { diff --git a/apps/sim/app/api/table/utils.ts b/apps/sim/app/api/table/utils.ts index e5b5f3435..00fd3e2c8 100644 --- a/apps/sim/app/api/table/utils.ts +++ b/apps/sim/app/api/table/utils.ts @@ -1,196 +1,56 @@ -import { db } from '@sim/db' -import { userTableDefinitions, userTableRows } from '@sim/db/schema' import { createLogger } from '@sim/logger' -import { count, eq } from 'drizzle-orm' import { NextResponse } from 'next/server' import type { ColumnDefinition, TableDefinition } from '@/lib/table' +import { getTableById } from '@/lib/table' import { getUserEntityPermissions } from '@/lib/workspaces/permissions/utils' const logger = createLogger('TableUtils') -type PermissionLevel = 'read' | 'write' | 'admin' - -/** @deprecated Use TableDefinition from '@/lib/table' instead */ -export type TableData = TableDefinition - -export interface TableAccessResult { - hasAccess: true - table: Pick -} - -export interface TableAccessResultFull { - hasAccess: true - table: TableDefinition -} - -export interface TableAccessDenied { - hasAccess: false - notFound?: boolean - reason?: string -} +export type AccessResult = { ok: true; table: TableDefinition } | { ok: false; status: 404 | 403 } export interface ApiErrorResponse { error: string details?: unknown } -export async function checkTableAccess( - tableId: string, - userId: string -): Promise { - return checkTableAccessInternal(tableId, userId, 'read') -} - -export async function checkTableWriteAccess( - tableId: string, - userId: string -): Promise { - return checkTableAccessInternal(tableId, userId, 'write') -} - -export async function checkAccessOrRespond( +export async function checkAccess( tableId: string, userId: string, - requestId: string, - level: 'read' | 'write' | 'admin' = 'write' -): Promise { - const checkFn = level === 'read' ? checkTableAccess : checkTableWriteAccess - const accessCheck = await checkFn(tableId, userId) - - if (!accessCheck.hasAccess) { - if ('notFound' in accessCheck && accessCheck.notFound) { - logger.warn(`[${requestId}] Table not found: ${tableId}`) - return NextResponse.json({ error: 'Table not found' }, { status: 404 }) - } - logger.warn(`[${requestId}] User ${userId} denied ${level} access to table ${tableId}`) - return NextResponse.json({ error: 'Access denied' }, { status: 403 }) - } - - return accessCheck -} - -export async function checkAccessWithFullTable( - tableId: string, - userId: string, - requestId: string, - level: 'read' | 'write' | 'admin' = 'write' -): Promise { - const [tableData] = await db - .select() - .from(userTableDefinitions) - .where(eq(userTableDefinitions.id, tableId)) - .limit(1) - - if (!tableData) { - logger.warn(`[${requestId}] Table not found: ${tableId}`) - return NextResponse.json({ error: 'Table not found' }, { status: 404 }) - } - - const rowCount = await getTableRowCount(tableId) - const table = { ...tableData, rowCount } as unknown as TableDefinition - - if (table.createdBy === userId) { - return { hasAccess: true, table } - } - - const userPermission = await getUserEntityPermissions(userId, 'workspace', table.workspaceId) - - if (!hasPermissionLevel(userPermission, level)) { - logger.warn(`[${requestId}] User ${userId} denied ${level} access to table ${tableId}`) - return NextResponse.json({ error: 'Access denied' }, { status: 403 }) - } - - return { hasAccess: true, table } -} - -export async function getTableById(tableId: string): Promise { - const [table] = await db - .select() - .from(userTableDefinitions) - .where(eq(userTableDefinitions.id, tableId)) - .limit(1) + level: 'read' | 'write' | 'admin' = 'read' +): Promise { + const table = await getTableById(tableId) if (!table) { - return null + return { ok: false, status: 404 } } - const rowCount = await getTableRowCount(tableId) - return { ...table, rowCount } as unknown as TableDefinition + if (table.createdBy === userId) { + return { ok: true, table } + } + + const permission = await getUserEntityPermissions(userId, 'workspace', table.workspaceId) + const hasAccess = + permission !== null && + (level === 'read' || + (level === 'write' && (permission === 'write' || permission === 'admin')) || + (level === 'admin' && permission === 'admin')) + + return hasAccess ? { ok: true, table } : { ok: false, status: 403 } +} + +export function accessError( + result: { ok: false; status: 404 | 403 }, + requestId: string, + context?: string +): NextResponse { + const message = result.status === 404 ? 'Table not found' : 'Access denied' + logger.warn(`[${requestId}] ${message}${context ? `: ${context}` : ''}`) + return NextResponse.json({ error: message }, { status: result.status }) } export async function verifyTableWorkspace(tableId: string, workspaceId: string): Promise { - const table = await db - .select({ workspaceId: userTableDefinitions.workspaceId }) - .from(userTableDefinitions) - .where(eq(userTableDefinitions.id, tableId)) - .limit(1) - - if (table.length === 0) { - return false - } - - return table[0].workspaceId === workspaceId -} - -async function checkTableAccessInternal( - tableId: string, - userId: string, - requiredLevel: 'read' | 'write' | 'admin' -): Promise { - const table = await db - .select({ - id: userTableDefinitions.id, - createdBy: userTableDefinitions.createdBy, - workspaceId: userTableDefinitions.workspaceId, - }) - .from(userTableDefinitions) - .where(eq(userTableDefinitions.id, tableId)) - .limit(1) - - if (table.length === 0) { - return { hasAccess: false, notFound: true } - } - - const tableData = table[0] - - if (tableData.createdBy === userId) { - return { hasAccess: true, table: tableData } - } - - const userPermission = await getUserEntityPermissions(userId, 'workspace', tableData.workspaceId) - - if (hasPermissionLevel(userPermission, requiredLevel)) { - return { hasAccess: true, table: tableData } - } - - return { hasAccess: false } -} - -function hasPermissionLevel( - userPermission: 'read' | 'write' | 'admin' | null, - requiredLevel: PermissionLevel -): boolean { - if (userPermission === null) return false - - switch (requiredLevel) { - case 'read': - return true - case 'write': - return userPermission === 'write' || userPermission === 'admin' - case 'admin': - return userPermission === 'admin' - default: - return false - } -} - -async function getTableRowCount(tableId: string): Promise { - const [result] = await db - .select({ count: count() }) - .from(userTableRows) - .where(eq(userTableRows.tableId, tableId)) - - return Number(result?.count ?? 0) + const table = await getTableById(tableId) + return table?.workspaceId === workspaceId } export function errorResponse( @@ -205,30 +65,23 @@ export function errorResponse( return NextResponse.json(body, { status }) } -export function badRequestResponse( - message: string, - details?: unknown -): NextResponse { +export function badRequestResponse(message: string, details?: unknown) { return errorResponse(message, 400, details) } -export function unauthorizedResponse( - message = 'Authentication required' -): NextResponse { +export function unauthorizedResponse(message = 'Authentication required') { return errorResponse(message, 401) } -export function forbiddenResponse(message = 'Access denied'): NextResponse { +export function forbiddenResponse(message = 'Access denied') { return errorResponse(message, 403) } -export function notFoundResponse(message = 'Resource not found'): NextResponse { +export function notFoundResponse(message = 'Resource not found') { return errorResponse(message, 404) } -export function serverErrorResponse( - message = 'Internal server error' -): NextResponse { +export function serverErrorResponse(message = 'Internal server error') { return errorResponse(message, 500) }