Files
Momento/memento-note/app/api/cron/reminders/route.ts
Antigravity 718f4c6900
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 1m35s
perf: optimize MCP server (O(1) auth, compact JSON, trashedAt fix) + memento-note performance (lazy loading, server-side filtering, XSS fixes, dead code removal, security hardening)
MCP Server:
- Fix validateApiKey: O(1) direct lookup by shortId instead of loading all keys
- Add trashedAt:null filter to ALL note queries (trashed notes leaked in results)
- Compact JSON output (~40% smaller responses)
- Bounded session cache (Map with MAX_SESSIONS=500) to prevent memory leaks
- PostgreSQL connection pooling (connection_limit=10)
- Rewrite all 22 tool descriptions in clear English
- Fix /sse fallback to proper 307 redirect

memento-note Performance:
- loading=lazy on all note images
- Split notebooksRefreshKey from global refreshKey (note CRUD no longer re-fetches notebooks)
- Remove searchKey from trash count deps (no re-fetch on every keystroke)
- Server-side notebookId filter in getAllNotes() (biggest win)
- Skip collaborator fetch for non-shared notes (eliminates N+1 API calls)
- next/dynamic for MarkdownContent + 4 modals (code-split remark/rehype/KaTeX)
- Memoize DOMPurify sanitize with useMemo

Security:
- XSS: DOMPurify sanitize in note-card and note-history-modal
- Auth anti-enumeration: uniform errors in auth.ts
- CRON_SECRET mandatory on cron endpoints
- Rate limiting on login (5 attempts/min per email)
- Centralized API auth helpers (requireAuth/requireAdmin)
- randomize-labels changed GET→POST
- Removed debug endpoints (/api/debug/config, /api/debug/test-chat)

Cleanup:
- Removed dead code: .backup-keep, settings-backup, fix-*.js, debug-theme, fix-labels route
- Removed sensitive console.error in auth.ts
- Ollama fetchWithTimeout (30s/60s AbortController)
- i18n: full Arabic translation, Farsi missing keys
- Masonry drag-and-drop fix (localOrderMap, cross-section block)
- Sidebar notebook tooltip on truncation
2026-05-03 18:41:38 +00:00

74 lines
2.0 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
import prisma from '@/lib/prisma';
export const dynamic = 'force-dynamic'; // No caching
export async function POST(request: NextRequest) {
const cronSecret = process.env.CRON_SECRET
if (!cronSecret) {
console.error('[CronReminders] CRON_SECRET env var is required but not set')
return NextResponse.json({ error: 'Server misconfiguration' }, { status: 500 })
}
const authHeader = request.headers.get('authorization')
if (authHeader !== `Bearer ${cronSecret}`) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
try {
const now = new Date();
// 1. Find all due reminders that haven't been processed
const dueNotes = await prisma.note.findMany({
where: {
reminder: {
lte: now, // Less than or equal to now
},
isReminderDone: false,
isArchived: false, // Optional: exclude archived notes
trashedAt: null, // Exclude trashed notes
},
select: {
id: true,
title: true,
content: true,
reminder: true,
// Add other fields useful for notification
},
});
if (dueNotes.length === 0) {
return NextResponse.json({
success: true,
count: 0,
message: 'No due reminders found'
});
}
// 2. Mark them as done (Atomic operation logic would be better but simple batch update is fine here)
const noteIds = dueNotes.map((n: any) => n.id);
await prisma.note.updateMany({
where: {
id: { in: noteIds }
},
data: {
isReminderDone: true
}
});
// 3. Return the notes to N8N so it can send emails/messages
return NextResponse.json({
success: true,
count: dueNotes.length,
reminders: dueNotes
});
} catch (error) {
console.error('Error processing cron reminders:', error);
return NextResponse.json(
{ success: false, error: 'Internal Server Error' },
{ status: 500 }
);
}
}