improvement(routes): type all untyped routes (#1848)

* improvement(routes): type all untyped routes

* fix routes, remove unused workspace members route

* fix obfuscation of errors behind zod errors

* remove extraneous comments
This commit is contained in:
Waleed
2025-11-07 15:24:30 -08:00
committed by GitHub
parent c4278266ef
commit bb7016a99f
48 changed files with 1043 additions and 558 deletions

View File

@@ -2,11 +2,32 @@ import { db } from '@sim/db'
import { memory } from '@sim/db/schema'
import { and, eq } from 'drizzle-orm'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { createLogger } from '@/lib/logs/console/logger'
import { generateRequestId } from '@/lib/utils'
const logger = createLogger('MemoryByIdAPI')
const memoryQuerySchema = z.object({
workflowId: z.string().uuid('Invalid workflow ID format'),
})
const agentMemoryDataSchema = z.object({
role: z.enum(['user', 'assistant', 'system'], {
errorMap: () => ({ message: 'Role must be user, assistant, or system' }),
}),
content: z.string().min(1, 'Content is required'),
})
const genericMemoryDataSchema = z.record(z.unknown())
const memoryPutBodySchema = z.object({
data: z.union([agentMemoryDataSchema, genericMemoryDataSchema], {
errorMap: () => ({ message: 'Invalid memory data structure' }),
}),
workflowId: z.string().uuid('Invalid workflow ID format'),
})
export const dynamic = 'force-dynamic'
export const runtime = 'nodejs'
@@ -24,29 +45,36 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
const url = new URL(request.url)
const workflowId = url.searchParams.get('workflowId')
if (!workflowId) {
logger.warn(`[${requestId}] Missing required parameter: workflowId`)
const validation = memoryQuerySchema.safeParse({ workflowId })
if (!validation.success) {
const errorMessage = validation.error.errors
.map((err) => `${err.path.join('.')}: ${err.message}`)
.join(', ')
logger.warn(`[${requestId}] Validation error: ${errorMessage}`)
return NextResponse.json(
{
success: false,
error: {
message: 'workflowId parameter is required',
message: errorMessage,
},
},
{ status: 400 }
)
}
const { workflowId: validatedWorkflowId } = validation.data
// Query the database for the memory
const memories = await db
.select()
.from(memory)
.where(and(eq(memory.key, id), eq(memory.workflowId, workflowId)))
.where(and(eq(memory.key, id), eq(memory.workflowId, validatedWorkflowId)))
.orderBy(memory.createdAt)
.limit(1)
if (memories.length === 0) {
logger.warn(`[${requestId}] Memory not found: ${id} for workflow: ${workflowId}`)
logger.warn(`[${requestId}] Memory not found: ${id} for workflow: ${validatedWorkflowId}`)
return NextResponse.json(
{
success: false,
@@ -58,7 +86,9 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
)
}
logger.info(`[${requestId}] Memory retrieved successfully: ${id} for workflow: ${workflowId}`)
logger.info(
`[${requestId}] Memory retrieved successfully: ${id} for workflow: ${validatedWorkflowId}`
)
return NextResponse.json(
{
success: true,
@@ -96,28 +126,35 @@ export async function DELETE(
const url = new URL(request.url)
const workflowId = url.searchParams.get('workflowId')
if (!workflowId) {
logger.warn(`[${requestId}] Missing required parameter: workflowId`)
const validation = memoryQuerySchema.safeParse({ workflowId })
if (!validation.success) {
const errorMessage = validation.error.errors
.map((err) => `${err.path.join('.')}: ${err.message}`)
.join(', ')
logger.warn(`[${requestId}] Validation error: ${errorMessage}`)
return NextResponse.json(
{
success: false,
error: {
message: 'workflowId parameter is required',
message: errorMessage,
},
},
{ status: 400 }
)
}
const { workflowId: validatedWorkflowId } = validation.data
// Verify memory exists before attempting to delete
const existingMemory = await db
.select({ id: memory.id })
.from(memory)
.where(and(eq(memory.key, id), eq(memory.workflowId, workflowId)))
.where(and(eq(memory.key, id), eq(memory.workflowId, validatedWorkflowId)))
.limit(1)
if (existingMemory.length === 0) {
logger.warn(`[${requestId}] Memory not found: ${id} for workflow: ${workflowId}`)
logger.warn(`[${requestId}] Memory not found: ${id} for workflow: ${validatedWorkflowId}`)
return NextResponse.json(
{
success: false,
@@ -130,9 +167,13 @@ export async function DELETE(
}
// Hard delete the memory
await db.delete(memory).where(and(eq(memory.key, id), eq(memory.workflowId, workflowId)))
await db
.delete(memory)
.where(and(eq(memory.key, id), eq(memory.workflowId, validatedWorkflowId)))
logger.info(`[${requestId}] Memory deleted successfully: ${id} for workflow: ${workflowId}`)
logger.info(
`[${requestId}] Memory deleted successfully: ${id} for workflow: ${validatedWorkflowId}`
)
return NextResponse.json(
{
success: true,
@@ -163,30 +204,37 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{
try {
logger.info(`[${requestId}] Processing memory update request for ID: ${id}`)
// Parse request body
const body = await request.json()
const { data, workflowId } = body
let validatedData
let validatedWorkflowId
try {
const body = await request.json()
const validation = memoryPutBodySchema.safeParse(body)
if (!data) {
logger.warn(`[${requestId}] Missing required field: data`)
return NextResponse.json(
{
success: false,
error: {
message: 'Memory data is required',
if (!validation.success) {
const errorMessage = validation.error.errors
.map((err) => `${err.path.join('.')}: ${err.message}`)
.join(', ')
logger.warn(`[${requestId}] Validation error: ${errorMessage}`)
return NextResponse.json(
{
success: false,
error: {
message: `Invalid request body: ${errorMessage}`,
},
},
},
{ status: 400 }
)
}
{ status: 400 }
)
}
if (!workflowId) {
logger.warn(`[${requestId}] Missing required field: workflowId`)
validatedData = validation.data.data
validatedWorkflowId = validation.data.workflowId
} catch (error: any) {
logger.warn(`[${requestId}] Failed to parse request body: ${error.message}`)
return NextResponse.json(
{
success: false,
error: {
message: 'workflowId is required',
message: 'Invalid JSON in request body',
},
},
{ status: 400 }
@@ -197,11 +245,11 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{
const existingMemories = await db
.select()
.from(memory)
.where(and(eq(memory.key, id), eq(memory.workflowId, workflowId)))
.where(and(eq(memory.key, id), eq(memory.workflowId, validatedWorkflowId)))
.limit(1)
if (existingMemories.length === 0) {
logger.warn(`[${requestId}] Memory not found: ${id} for workflow: ${workflowId}`)
logger.warn(`[${requestId}] Memory not found: ${id} for workflow: ${validatedWorkflowId}`)
return NextResponse.json(
{
success: false,
@@ -215,28 +263,19 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{
const existingMemory = existingMemories[0]
// Validate memory data based on the existing memory type
// Additional validation for agent memory type
if (existingMemory.type === 'agent') {
if (!data.role || !data.content) {
logger.warn(`[${requestId}] Missing agent memory fields`)
const agentValidation = agentMemoryDataSchema.safeParse(validatedData)
if (!agentValidation.success) {
const errorMessage = agentValidation.error.errors
.map((err) => `${err.path.join('.')}: ${err.message}`)
.join(', ')
logger.warn(`[${requestId}] Agent memory validation error: ${errorMessage}`)
return NextResponse.json(
{
success: false,
error: {
message: 'Agent memory requires role and content',
},
},
{ status: 400 }
)
}
if (!['user', 'assistant', 'system'].includes(data.role)) {
logger.warn(`[${requestId}] Invalid agent role: ${data.role}`)
return NextResponse.json(
{
success: false,
error: {
message: 'Agent role must be user, assistant, or system',
message: `Invalid agent memory data: ${errorMessage}`,
},
},
{ status: 400 }
@@ -245,16 +284,20 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{
}
// Update the memory with new data
await db.delete(memory).where(and(eq(memory.key, id), eq(memory.workflowId, workflowId)))
await db
.delete(memory)
.where(and(eq(memory.key, id), eq(memory.workflowId, validatedWorkflowId)))
// Fetch the updated memory
const updatedMemories = await db
.select()
.from(memory)
.where(and(eq(memory.key, id), eq(memory.workflowId, workflowId)))
.where(and(eq(memory.key, id), eq(memory.workflowId, validatedWorkflowId)))
.limit(1)
logger.info(`[${requestId}] Memory updated successfully: ${id} for workflow: ${workflowId}`)
logger.info(
`[${requestId}] Memory updated successfully: ${id} for workflow: ${validatedWorkflowId}`
)
return NextResponse.json(
{
success: true,