/** * Check Transaction Status Edge Function * * Allows clients to poll the status of a moderation transaction * using its idempotency key. * * Part of Sacred Pipeline Phase 3: Enhanced Error Handling */ import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4'; import { corsHeaders } from '../_shared/cors.ts'; import { edgeLogger } from '../_shared/logger.ts'; import { createEdgeFunction } from '../_shared/edgeFunctionWrapper.ts'; import { validateString } from '../_shared/typeValidation.ts'; interface StatusRequest { idempotencyKey: string; } interface StatusResponse { status: 'pending' | 'processing' | 'completed' | 'failed' | 'expired' | 'not_found'; createdAt?: string; updatedAt?: string; expiresAt?: string; attempts?: number; lastError?: string; completedAt?: string; action?: string; submissionId?: string; } export default createEdgeFunction( { name: 'check-transaction-status', requireAuth: true, corsHeaders: corsHeaders }, async (req, context) => { const supabase = createClient( Deno.env.get('SUPABASE_URL')!, Deno.env.get('SUPABASE_ANON_KEY')!, { global: { headers: { Authorization: req.headers.get('Authorization')! } } } ); // Parse request const { idempotencyKey }: StatusRequest = await req.json(); validateString(idempotencyKey, 'idempotencyKey', { userId: context.userId, requestId: context.requestId }); context.span.setAttribute('action', 'check_transaction_status'); context.span.setAttribute('idempotency_key', idempotencyKey); edgeLogger.info('Checking transaction status', { requestId: context.requestId, userId: context.userId, idempotencyKey, }); // Query idempotency_keys table const { data: keyRecord, error: queryError } = await supabase .from('idempotency_keys') .select('*') .eq('key', idempotencyKey) .single(); if (queryError || !keyRecord) { edgeLogger.info('Idempotency key not found', { requestId: context.requestId, idempotencyKey, error: queryError, }); return new Response( JSON.stringify({ status: 'not_found', error: 'Transaction not found. It may have expired or never existed.' } as StatusResponse), { status: 404, headers: { 'Content-Type': 'application/json' } } ); } // Verify user owns this key if (keyRecord.user_id !== context.userId) { edgeLogger.warn('User does not own idempotency key', { requestId: context.requestId, userId: context.userId, keyUserId: keyRecord.user_id, }); return new Response( JSON.stringify({ error: 'Unauthorized', status: 'not_found' }), { status: 403, headers: { 'Content-Type': 'application/json' } } ); } // Build response const response: StatusResponse = { status: keyRecord.status, createdAt: keyRecord.created_at, updatedAt: keyRecord.updated_at, expiresAt: keyRecord.expires_at, attempts: keyRecord.attempts, action: keyRecord.action, submissionId: keyRecord.submission_id, }; // Include error if failed if (keyRecord.status === 'failed' && keyRecord.last_error) { response.lastError = keyRecord.last_error; } // Include completed timestamp if completed if (keyRecord.status === 'completed' && keyRecord.completed_at) { response.completedAt = keyRecord.completed_at; } edgeLogger.info('Transaction status retrieved', { requestId: context.requestId, status: response.status, }); return new Response( JSON.stringify(response), { status: 200, headers: { 'Content-Type': 'application/json' } } ); } );