## Bug Fixes ### Note Card Actions - Fix broken size change functionality (missing state declaration) - Implement React 19 useOptimistic for instant UI feedback - Add startTransition for non-blocking updates - Ensure smooth animations without page refresh - All note actions now work: pin, archive, color, size, checklist ### Markdown LaTeX Rendering - Add remark-math and rehype-katex plugins - Support inline equations with dollar sign syntax - Support block equations with double dollar sign syntax - Import KaTeX CSS for proper styling - Equations now render correctly instead of showing raw LaTeX ## Technical Details - Replace undefined currentNote references with optimistic state - Add optimistic updates before server actions for instant feedback - Use router.refresh() in transitions for smart cache invalidation - Install remark-math, rehype-katex, and katex packages ## Testing - Build passes successfully with no TypeScript errors - Dev server hot-reloads changes correctly
101 lines
2.4 KiB
TypeScript
101 lines
2.4 KiB
TypeScript
import { NextResponse } from 'next/server'
|
|
import prisma from '@/lib/prisma'
|
|
import { auth } from '@/auth'
|
|
import { validateEmbedding } from '@/lib/utils'
|
|
|
|
/**
|
|
* Admin endpoint to validate all embeddings in the database
|
|
* Returns a list of notes with invalid embeddings
|
|
*/
|
|
export async function GET() {
|
|
try {
|
|
const session = await auth()
|
|
if (!session?.user?.id) {
|
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
|
}
|
|
|
|
// Check if user is admin
|
|
const user = await prisma.user.findUnique({
|
|
where: { id: session.user.id },
|
|
select: { role: true }
|
|
})
|
|
|
|
if (!user || user.role !== 'ADMIN') {
|
|
return NextResponse.json({ error: 'Forbidden - Admin only' }, { status: 403 })
|
|
}
|
|
|
|
// Fetch all notes with embeddings
|
|
const allNotes = await prisma.note.findMany({
|
|
select: {
|
|
id: true,
|
|
title: true,
|
|
embedding: true
|
|
}
|
|
})
|
|
|
|
const invalidNotes: Array<{
|
|
id: string
|
|
title: string
|
|
issues: string[]
|
|
}> = []
|
|
|
|
let validCount = 0
|
|
let missingCount = 0
|
|
let invalidCount = 0
|
|
|
|
for (const note of allNotes) {
|
|
// Check if embedding is missing
|
|
if (!note.embedding) {
|
|
missingCount++
|
|
invalidNotes.push({
|
|
id: note.id,
|
|
title: note.title || 'Untitled',
|
|
issues: ['Missing embedding']
|
|
})
|
|
continue
|
|
}
|
|
|
|
// Parse and validate embedding
|
|
try {
|
|
const embedding = JSON.parse(note.embedding)
|
|
const validation = validateEmbedding(embedding)
|
|
|
|
if (!validation.valid) {
|
|
invalidCount++
|
|
invalidNotes.push({
|
|
id: note.id,
|
|
title: note.title || 'Untitled',
|
|
issues: validation.issues
|
|
})
|
|
} else {
|
|
validCount++
|
|
}
|
|
} catch (error) {
|
|
invalidCount++
|
|
invalidNotes.push({
|
|
id: note.id,
|
|
title: note.title || 'Untitled',
|
|
issues: [`Failed to parse embedding: ${error}`]
|
|
})
|
|
}
|
|
}
|
|
|
|
return NextResponse.json({
|
|
success: true,
|
|
summary: {
|
|
total: allNotes.length,
|
|
valid: validCount,
|
|
missing: missingCount,
|
|
invalid: invalidCount
|
|
},
|
|
invalidNotes
|
|
})
|
|
} catch (error) {
|
|
console.error('[EMBEDDING_VALIDATION] Error:', error)
|
|
return NextResponse.json(
|
|
{ success: false, error: String(error) },
|
|
{ status: 500 }
|
|
)
|
|
}
|
|
}
|