import { serve } from 'https://deno.land/std@0.190.0/http/server.ts'; import { createEdgeFunction, type EdgeFunctionContext } from '../_shared/edgeFunctionWrapper.ts'; import { corsHeaders } from '../_shared/cors.ts'; import { addSpanEvent } from '../_shared/logger.ts'; const handler = async (req: Request, { supabase, user, span, requestId }: EdgeFunctionContext) => { addSpanEvent(span, 'resending_deletion_code', { userId: user.id }); // Find pending deletion request const { data: deletionRequest, error: requestError } = await supabase .from('account_deletion_requests') .select('*') .eq('user_id', user.id) .eq('status', 'pending') .maybeSingle(); if (requestError || !deletionRequest) { throw new Error('No pending deletion request found'); } // Check rate limiting (max 3 resends per hour - ~20 minutes between resends) const lastSent = new Date(deletionRequest.confirmation_code_sent_at); const now = new Date(); const hoursSinceLastSend = (now.getTime() - lastSent.getTime()) / (1000 * 60 * 60); if (hoursSinceLastSend < 0.33) { addSpanEvent(span, 'resend_rate_limited', { hoursSinceLastSend, minRequired: 0.33 }); throw new Error('Please wait at least 20 minutes between resend requests'); } // Generate new confirmation code const { data: codeData, error: codeError } = await supabase .rpc('generate_deletion_confirmation_code'); if (codeError) { throw codeError; } const confirmationCode = codeData as string; // Update deletion request with new code const { error: updateError } = await supabase .from('account_deletion_requests') .update({ confirmation_code: confirmationCode, confirmation_code_sent_at: now.toISOString(), }) .eq('id', deletionRequest.id); if (updateError) { throw updateError; } const scheduledDate = new Date(deletionRequest.scheduled_deletion_at); addSpanEvent(span, 'new_code_generated', { scheduledDeletionDate: scheduledDate.toISOString() }); // Send email with new code const forwardEmailKey = Deno.env.get('FORWARDEMAIL_API_KEY'); const fromEmail = Deno.env.get('FROM_EMAIL_ADDRESS') || 'noreply@thrillwiki.com'; if (forwardEmailKey) { try { await fetch('https://api.forwardemail.net/v1/emails', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Basic ${btoa(forwardEmailKey + ':')}`, }, body: JSON.stringify({ from: fromEmail, to: user.email, subject: 'Account Deletion - New Confirmation Code', html: `

New Confirmation Code

You requested a new confirmation code for your account deletion.

Your account will be permanently deleted on ${scheduledDate.toLocaleDateString()}.

CONFIRMATION CODE: ${confirmationCode}

To confirm deletion after the waiting period, you'll need to enter this 6-digit code.

Need to cancel? Log in and visit your account settings to reactivate your account.

`, }), }); addSpanEvent(span, 'email_sent', { email: user.email }); } catch (emailError) { addSpanEvent(span, 'email_send_failed', { error: emailError instanceof Error ? emailError.message : String(emailError) }); } } addSpanEvent(span, 'resend_completed', { userId: user.id }); return { success: true, message: 'New confirmation code sent successfully', }; }; serve(createEdgeFunction({ name: 'resend-deletion-code', requireAuth: true, corsHeaders, enableTracing: true, logRequests: true, rateLimitTier: 'moderate', // 10 requests per minute }, handler));