diff --git a/api/report-error.ts b/api/report-error.js similarity index 65% rename from api/report-error.ts rename to api/report-error.js index 8abfd4c..19c4f8d 100644 --- a/api/report-error.ts +++ b/api/report-error.js @@ -1,62 +1,62 @@ -import type { VercelRequest, VercelResponse } from '@vercel/node'; +const axios = require('axios'); // In-memory rate limiting for error reporting -const rateLimitMap = new Map() -const RATE_LIMIT_WINDOW_MS = 60 * 1000 // 1 minute -const RATE_LIMIT_MAX_REQUESTS = 10 +const rateLimitMap = new Map(); +const RATE_LIMIT_WINDOW_MS = 60 * 1000; // 1 minute +const RATE_LIMIT_MAX_REQUESTS = 10; -function isRateLimited(ip: string): boolean { - const now = Date.now() - const record = rateLimitMap.get(ip) +function isRateLimited(ip) { + const now = Date.now(); + const record = rateLimitMap.get(ip); if (!record || now > record.resetTime) { - rateLimitMap.set(ip, { count: 1, resetTime: now + RATE_LIMIT_WINDOW_MS }) - return false + rateLimitMap.set(ip, { count: 1, resetTime: now + RATE_LIMIT_WINDOW_MS }); + return false; } if (record.count >= RATE_LIMIT_MAX_REQUESTS) { - return true + return true; } - record.count++ - return false + record.count++; + return false; } // Vercel serverless handler -export default async function handler(req: VercelRequest, res: VercelResponse) { +module.exports = async function handler(req, res) { // CORS headers - res.setHeader('Access-Control-Allow-Origin', '*') - res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS') - res.setHeader('Access-Control-Allow-Headers', 'Content-Type') + res.setHeader('Access-Control-Allow-Origin', '*'); + res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS'); + res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); // Handle preflight if (req.method === 'OPTIONS') { - return res.status(200).end() + return res.status(200).end(); } // Only POST allowed if (req.method !== 'POST') { - return res.status(405).json({ error: 'Method not allowed' }) + return res.status(405).json({ error: 'Method not allowed' }); } try { // Rate limiting - const ip = (req.headers['x-forwarded-for'] as string)?.split(',')[0]?.trim() || 'unknown' + const ip = req.headers['x-forwarded-for']?.split(',')[0]?.trim() || 'unknown'; if (isRateLimited(ip)) { - return res.status(429).json({ error: 'Rate limit exceeded' }) + return res.status(429).json({ error: 'Rate limit exceeded' }); } // Check Discord webhook URL - const webhookUrl = process.env.DISCORD_ERROR_WEBHOOK_URL + const webhookUrl = process.env.DISCORD_ERROR_WEBHOOK_URL; if (!webhookUrl) { - console.error('[ErrorReporting] DISCORD_ERROR_WEBHOOK_URL not configured') - return res.status(503).json({ error: 'Error reporting service unavailable' }) + console.error('[ErrorReporting] DISCORD_ERROR_WEBHOOK_URL not configured'); + return res.status(503).json({ error: 'Error reporting service unavailable' }); } // Validate payload - const payload = req.body + const payload = req.body; if (!payload?.error) { - return res.status(400).json({ error: 'Invalid payload: missing error field' }) + return res.status(400).json({ error: 'Invalid payload: missing error field' }); } // Build Discord embed @@ -71,33 +71,32 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { ], timestamp: new Date().toISOString(), footer: { text: 'Community Error Reporting' } - } + }; if (payload.stack) { - const stackLines = String(payload.stack).split('\n').slice(0, 15).join('\n') - embed.fields.push({ - name: 'Stack Trace', - value: `\`\`\`\n${stackLines.slice(0, 1000)}\n\`\`\``, - inline: false - }) + const stackLines = String(payload.stack).split('\n').slice(0, 15).join('\n'); + embed.fields.push({ + name: 'Stack Trace', + value: `\`\`\`\n${stackLines.slice(0, 1000)}\n\`\`\``, + inline: false + }); } // Send to Discord - const axios = (await import('axios')).default await axios.post(webhookUrl, { username: 'Microsoft Rewards Bot', avatar_url: 'https://raw.githubusercontent.com/LightZirconite/Microsoft-Rewards-Bot/refs/heads/main/assets/logo.png', embeds: [embed] - }, { timeout: 10000 }) + }, { timeout: 10000 }); - console.log('[ErrorReporting] Report sent successfully') - return res.json({ success: true, message: 'Error report received' }) + console.log('[ErrorReporting] Report sent successfully'); + return res.json({ success: true, message: 'Error report received' }); } catch (error) { - console.error('[ErrorReporting] Failed:', error) - return res.status(500).json({ + console.error('[ErrorReporting] Failed:', error); + return res.status(500).json({ error: 'Failed to send error report', - message: error instanceof Error ? error.message : 'Unknown error' - }) + message: error.message || 'Unknown error' + }); } -} +};