diff --git a/src/components/admin/MarkdownEditor.tsx b/src/components/admin/MarkdownEditor.tsx index 0ce632d2..07f2223d 100644 --- a/src/components/admin/MarkdownEditor.tsx +++ b/src/components/admin/MarkdownEditor.tsx @@ -30,6 +30,7 @@ import '@mdxeditor/editor/style.css'; import '@/styles/mdx-editor-theme.css'; import { useTheme } from '@/components/theme/ThemeProvider'; import { supabase } from '@/integrations/supabase/client'; +import { invokeWithTracking } from '@/lib/edgeFunctionTracking'; import { getCloudflareImageUrl } from '@/lib/cloudflareImageUtils'; import { useAutoSave } from '@/hooks/useAutoSave'; import { CheckCircle2, Loader2, AlertCircle } from 'lucide-react'; @@ -140,9 +141,11 @@ export function MarkdownEditor({ const formData = new FormData(); formData.append('file', file); - const { data, error } = await supabase.functions.invoke('upload-image', { - body: formData - }); + const { data, error } = await invokeWithTracking( + 'upload-image', + formData, + undefined + ); if (error) throw error; diff --git a/src/components/admin/TestDataGenerator.tsx b/src/components/admin/TestDataGenerator.tsx index 9a87c96e..d621d333 100644 --- a/src/components/admin/TestDataGenerator.tsx +++ b/src/components/admin/TestDataGenerator.tsx @@ -1,4 +1,5 @@ import { useState, useEffect } from 'react'; +import { invokeWithTracking } from '@/lib/edgeFunctionTracking'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Checkbox } from '@/components/ui/checkbox'; @@ -101,15 +102,17 @@ export function TestDataGenerator() { description: `Generating ${stage}...`, }); - const { data, error } = await supabase.functions.invoke('seed-test-data', { - body: { + const { data, error } = await invokeWithTracking( + 'seed-test-data', + { preset, fieldDensity, entityTypes: selectedEntityTypes, stage, ...options - } - }); + }, + (await supabase.auth.getUser()).data.user?.id + ); if (error) throw error; diff --git a/src/components/auth/MFARemovalDialog.tsx b/src/components/auth/MFARemovalDialog.tsx index 7151e115..670b096b 100644 --- a/src/components/auth/MFARemovalDialog.tsx +++ b/src/components/auth/MFARemovalDialog.tsx @@ -1,5 +1,6 @@ import { useState, useEffect } from 'react'; import { supabase } from '@/integrations/supabase/client'; +import { invokeWithTracking } from '@/lib/edgeFunctionTracking'; import { toast } from 'sonner'; import { getSessionAAL } from '@/types/supabase-session'; import { getErrorMessage } from '@/lib/errorHandler'; @@ -142,9 +143,11 @@ export function MFARemovalDialog({ open, onOpenChange, factorId, onSuccess }: MF setLoading(true); try { // Phase 3: Call edge function instead of direct unenroll - const { data, error } = await supabase.functions.invoke('mfa-unenroll', { - body: { factorId } - }); + const { data, error, requestId } = await invokeWithTracking( + 'mfa-unenroll', + { factorId }, + (await supabase.auth.getUser()).data.user?.id + ); if (error) throw error; if (data?.error) throw new Error(data.error); diff --git a/src/components/settings/AccountDeletionDialog.tsx b/src/components/settings/AccountDeletionDialog.tsx index fffea237..9951d2e2 100644 --- a/src/components/settings/AccountDeletionDialog.tsx +++ b/src/components/settings/AccountDeletionDialog.tsx @@ -1,4 +1,5 @@ import { useReducer } from 'react'; +import { invokeWithTracking } from '@/lib/edgeFunctionTracking'; import { AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter } from '@/components/ui/alert-dialog'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; @@ -57,9 +58,11 @@ export function AccountDeletionDialog({ open, onOpenChange, userEmail, onDeletio dispatch({ type: 'SET_LOADING', payload: true }); try { - const { data, error } = await supabase.functions.invoke('request-account-deletion', { - body: {}, - }); + const { data, error, requestId } = await invokeWithTracking( + 'request-account-deletion', + {}, + (await supabase.auth.getUser()).data.user?.id + ); if (error) throw error; @@ -88,9 +91,11 @@ export function AccountDeletionDialog({ open, onOpenChange, userEmail, onDeletio dispatch({ type: 'SET_LOADING', payload: true }); try { - const { error } = await supabase.functions.invoke('confirm-account-deletion', { - body: { confirmation_code: state.confirmationCode }, - }); + const { error, requestId } = await invokeWithTracking( + 'confirm-account-deletion', + { confirmation_code: state.confirmationCode }, + (await supabase.auth.getUser()).data.user?.id + ); if (error) throw error; @@ -110,9 +115,11 @@ export function AccountDeletionDialog({ open, onOpenChange, userEmail, onDeletio dispatch({ type: 'SET_LOADING', payload: true }); try { - const { error } = await supabase.functions.invoke('resend-deletion-code', { - body: {}, - }); + const { error, requestId } = await invokeWithTracking( + 'resend-deletion-code', + {}, + (await supabase.auth.getUser()).data.user?.id + ); if (error) throw error; diff --git a/src/components/settings/AccountProfileTab.tsx b/src/components/settings/AccountProfileTab.tsx index 71945475..a12fee0e 100644 --- a/src/components/settings/AccountProfileTab.tsx +++ b/src/components/settings/AccountProfileTab.tsx @@ -1,4 +1,5 @@ import { useState, useEffect } from 'react'; +import { invokeWithTracking } from '@/lib/edgeFunctionTracking'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { Button } from '@/components/ui/button'; @@ -172,12 +173,11 @@ export function AccountProfileTab() { } // Call the edge function with explicit authorization header - const { data, error } = await supabase.functions.invoke('cancel-email-change', { - method: 'POST', - headers: { - Authorization: `Bearer ${session.access_token}`, - }, - }); + const { data, error, requestId } = await invokeWithTracking( + 'cancel-email-change', + {}, + user.id + ); if (error) { console.error('Edge function error:', error); diff --git a/src/components/settings/DataExportTab.tsx b/src/components/settings/DataExportTab.tsx index ebbb66d5..fd8303fa 100644 --- a/src/components/settings/DataExportTab.tsx +++ b/src/components/settings/DataExportTab.tsx @@ -1,4 +1,5 @@ import { useState, useEffect } from 'react'; +import { invokeWithTracking } from '@/lib/edgeFunctionTracking'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Separator } from '@/components/ui/separator'; @@ -163,11 +164,10 @@ export function DataExportTab() { }); // Call edge function for secure export - const { data, error } = await supabase.functions.invoke( + const { data, error, requestId } = await invokeWithTracking( 'export-user-data', - { - body: validatedOptions - } + validatedOptions, + user.id ); if (error) { diff --git a/src/components/settings/DeletionStatusBanner.tsx b/src/components/settings/DeletionStatusBanner.tsx index 46898d19..adaf71b3 100644 --- a/src/components/settings/DeletionStatusBanner.tsx +++ b/src/components/settings/DeletionStatusBanner.tsx @@ -1,6 +1,7 @@ import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { Button } from '@/components/ui/button'; import { supabase } from '@/integrations/supabase/client'; +import { invokeWithTracking } from '@/lib/edgeFunctionTracking'; import { useToast } from '@/hooks/use-toast'; import { AlertTriangle, Loader2 } from 'lucide-react'; import { useState } from 'react'; @@ -26,9 +27,11 @@ export function DeletionStatusBanner({ scheduledDate, onCancelled }: DeletionSta const handleCancelDeletion = async () => { setLoading(true); try { - const { error } = await supabase.functions.invoke('cancel-account-deletion', { - body: { cancellation_reason: 'User cancelled from settings' }, - }); + const { error, requestId } = await invokeWithTracking( + 'cancel-account-deletion', + { cancellation_reason: 'User cancelled from settings' }, + (await supabase.auth.getUser()).data.user?.id + ); if (error) throw error; diff --git a/src/components/settings/PasswordUpdateDialog.tsx b/src/components/settings/PasswordUpdateDialog.tsx index 474ea871..6b8111e1 100644 --- a/src/components/settings/PasswordUpdateDialog.tsx +++ b/src/components/settings/PasswordUpdateDialog.tsx @@ -1,4 +1,5 @@ import { useState, useEffect } from 'react'; +import { invokeWithTracking } from '@/lib/edgeFunctionTracking'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { @@ -302,8 +303,9 @@ export function PasswordUpdateDialog({ open, onOpenChange, onSuccess }: Password // Step 4: Send security notification try { - await supabase.functions.invoke('trigger-notification', { - body: { + await invokeWithTracking( + 'trigger-notification', + { workflowId: 'security-alert', subscriberId: user.id, payload: { @@ -311,8 +313,9 @@ export function PasswordUpdateDialog({ open, onOpenChange, onSuccess }: Password timestamp: new Date().toISOString(), device: navigator.userAgent.split(' ')[0] } - } - }); + }, + user.id + ); } catch (notifError) { logger.error('Failed to send password change notification', { userId: user!.id, diff --git a/src/components/upload/PhotoUpload.tsx b/src/components/upload/PhotoUpload.tsx index c6d2a369..027fcc98 100644 --- a/src/components/upload/PhotoUpload.tsx +++ b/src/components/upload/PhotoUpload.tsx @@ -15,6 +15,8 @@ import { import { cn } from '@/lib/utils'; import { getErrorMessage } from '@/lib/errorHandler'; import { supabase } from '@/integrations/supabase/client'; +import { invokeWithTracking } from '@/lib/edgeFunctionTracking'; +import { useAuth } from '@/hooks/useAuth'; interface PhotoUploadProps { onUploadComplete?: (urls: string[], imageId?: string) => void; @@ -111,8 +113,9 @@ export function PhotoUpload({ const uploadFile = async (file: File, previewUrl: string): Promise => { try { - const { data: uploadData, error: uploadError } = await supabase.functions.invoke('upload-image', { - body: { + const { data: uploadData, error: uploadError, requestId } = await invokeWithTracking( + 'upload-image', + { metadata: { filename: file.name, size: file.size, @@ -120,8 +123,9 @@ export function PhotoUpload({ uploadedAt: new Date().toISOString() }, variant: isAvatar ? 'avatar' : 'public' - } - }); + }, + undefined + ); if (uploadError) { console.error('Upload URL error:', uploadError); @@ -239,10 +243,12 @@ export function PhotoUpload({ try { if (isAvatar && currentImageId) { try { - await supabase.functions.invoke('upload-image', { - method: 'DELETE', - body: { imageId: currentImageId } - }); + await invokeWithTracking( + 'upload-image', + { imageId: currentImageId }, + undefined, + 'DELETE' + ); } catch (deleteError) { console.warn('Failed to delete old avatar:', deleteError); } diff --git a/src/components/upload/UppyPhotoSubmissionUpload.tsx b/src/components/upload/UppyPhotoSubmissionUpload.tsx index cc6ee112..dac1f625 100644 --- a/src/components/upload/UppyPhotoSubmissionUpload.tsx +++ b/src/components/upload/UppyPhotoSubmissionUpload.tsx @@ -1,4 +1,5 @@ import React, { useState } from 'react'; +import { invokeWithTracking } from '@/lib/edgeFunctionTracking'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; @@ -96,9 +97,11 @@ export function UppyPhotoSubmissionUpload({ try { // Get upload URL from edge function - const { data: uploadData, error: uploadError } = await supabase.functions.invoke('upload-image', { - body: { metadata: { requireSignedURLs: false }, variant: 'public' } - }); + const { data: uploadData, error: uploadError } = await invokeWithTracking( + 'upload-image', + { metadata: { requireSignedURLs: false }, variant: 'public' }, + user?.id + ); if (uploadError) throw uploadError; diff --git a/src/components/upload/UppyPhotoUpload.tsx b/src/components/upload/UppyPhotoUpload.tsx index e57aead3..70d2ad7a 100644 --- a/src/components/upload/UppyPhotoUpload.tsx +++ b/src/components/upload/UppyPhotoUpload.tsx @@ -1,6 +1,7 @@ import React, { useRef, useState } from 'react'; import { supabase } from '@/integrations/supabase/client'; import { useToast } from '@/hooks/use-toast'; +import { invokeWithTracking } from '@/lib/edgeFunctionTracking'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Upload, X, Eye, Loader2, CheckCircle } from 'lucide-react'; @@ -100,9 +101,7 @@ export function UppyPhotoUpload({ setCurrentFileName(file.name); // Step 1: Get upload URL from Supabase edge function - const urlResponse = await supabase.functions.invoke('upload-image', { - body: { metadata, variant }, - }); + const urlResponse = await invokeWithTracking('upload-image', { metadata, variant }, undefined); if (urlResponse.error) { throw new Error(`Failed to get upload URL: ${urlResponse.error.message}`); diff --git a/src/hooks/useUnitPreferences.ts b/src/hooks/useUnitPreferences.ts index b3453206..8347c71f 100644 --- a/src/hooks/useUnitPreferences.ts +++ b/src/hooks/useUnitPreferences.ts @@ -1,4 +1,5 @@ import { useState, useEffect, useCallback } from 'react'; +import { invokeWithTracking } from '@/lib/edgeFunctionTracking'; import { useAuth } from '@/hooks/useAuth'; import { supabase } from '@/integrations/supabase/client'; import { logger } from '@/lib/logger'; @@ -82,7 +83,7 @@ export function useUnitPreferences() { const autoDetectPreferences = useCallback(async () => { try { - const response = await supabase.functions.invoke('detect-location'); + const response = await invokeWithTracking('detect-location', {}, user?.id); if (response.data && response.data.measurementSystem) { const newPreferences: UnitPreferences = { diff --git a/src/lib/emailValidation.ts b/src/lib/emailValidation.ts index 6f7630c3..5c47d5ef 100644 --- a/src/lib/emailValidation.ts +++ b/src/lib/emailValidation.ts @@ -1,4 +1,5 @@ import { supabase } from '@/integrations/supabase/client'; +import { invokeWithTracking } from '@/lib/edgeFunctionTracking'; import { logger } from '@/lib/logger'; import { getErrorMessage } from '@/lib/errorHandler'; @@ -14,9 +15,11 @@ interface EmailValidationResult { */ export async function validateEmailNotDisposable(email: string): Promise { try { - const { data, error } = await supabase.functions.invoke('validate-email-backend', { - body: { email } - }); + const { data, error } = await invokeWithTracking( + 'validate-email-backend', + { email }, + undefined + ); if (error) { logger.error('Email validation error from backend', { diff --git a/src/pages/AuthCallback.tsx b/src/pages/AuthCallback.tsx index 053993da..16b8c17a 100644 --- a/src/pages/AuthCallback.tsx +++ b/src/pages/AuthCallback.tsx @@ -1,4 +1,5 @@ import { useEffect, useState } from 'react'; +import { invokeWithTracking } from '@/lib/edgeFunctionTracking'; import { useNavigate } from 'react-router-dom'; import { supabase } from '@/integrations/supabase/client'; import { useToast } from '@/hooks/use-toast'; @@ -76,11 +77,11 @@ export default function AuthCallback() { try { console.log('[AuthCallback] Processing OAuth profile...'); - const { data, error } = await supabase.functions.invoke('process-oauth-profile', { - headers: { - Authorization: `Bearer ${session.access_token}`, - }, - }); + const { data, error, requestId } = await invokeWithTracking( + 'process-oauth-profile', + {}, + user.id + ); if (error) { console.error('[AuthCallback] Profile processing error:', error);