import { createClient } from "https://esm.sh/@supabase/supabase-js@2.57.4"; import { corsHeadersWithTracing as corsHeaders } from '../_shared/cors.ts'; import { edgeLogger } from "../_shared/logger.ts"; import { createEdgeFunction } from '../_shared/edgeFunctionWrapper.ts'; interface AnnouncementPayload { title: string; message: string; severity: 'info' | 'warning' | 'critical'; actionUrl?: string; } export default createEdgeFunction( { name: 'notify-system-announcement', requireAuth: true, corsHeaders: corsHeaders }, async (req, context) => { const supabaseUrl = Deno.env.get('SUPABASE_URL')!; const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!; const supabase = createClient(supabaseUrl, supabaseServiceKey); context.span.setAttribute('action', 'notify_system_announcement'); // Check user role const { data: roles, error: roleError } = await supabase .from('user_roles') .select('role') .eq('user_id', context.userId) .in('role', ['admin', 'superuser']); if (roleError || !roles || roles.length === 0) { throw new Error('Unauthorized: Admin or superuser role required'); } // Get user profile for logging const { data: profile } = await supabase .from('profiles') .select('username, display_name') .eq('user_id', context.userId) .single(); const payload: AnnouncementPayload = await req.json(); // Validate required fields if (!payload.title || !payload.message || !payload.severity) { throw new Error('Missing required fields: title, message, or severity'); } if (!['info', 'warning', 'critical'].includes(payload.severity)) { throw new Error('Invalid severity level. Must be: info, warning, or critical'); } edgeLogger.info('Processing system announcement', { action: 'notify_system_announcement', title: payload.title, severity: payload.severity, publishedBy: profile?.username || 'unknown', requestId: context.requestId }); // Fetch the workflow ID for system announcements const { data: template, error: templateError } = await supabase .from('notification_templates') .select('workflow_id') .eq('workflow_id', 'system-announcement') .eq('is_active', true) .maybeSingle(); if (templateError) { edgeLogger.error('Error fetching workflow', { action: 'notify_system_announcement', requestId: context.requestId, error: templateError }); throw new Error(`Failed to fetch workflow: ${templateError.message}`); } if (!template) { edgeLogger.warn('No active system-announcement workflow found', { action: 'notify_system_announcement', requestId: context.requestId }); throw new Error('No active system-announcement workflow configured'); } const announcementId = crypto.randomUUID(); const publishedAt = new Date().toISOString(); const publishedBy = profile?.display_name || profile?.username || 'System Admin'; // Build notification payload for all users const notificationPayload = { baseUrl: 'https://www.thrillwiki.com', announcementId, title: payload.title, message: payload.message, severity: payload.severity, actionUrl: payload.actionUrl || '', publishedAt, publishedBy, }; edgeLogger.info('Triggering announcement to all users via "users" topic', { action: 'notify_system_announcement', requestId: context.requestId }); // Invoke the trigger-notification function with users topic const { data: result, error: notifyError } = await supabase.functions.invoke( 'trigger-notification', { body: { workflowId: template.workflow_id, topicKey: 'users', payload: notificationPayload, }, } ); if (notifyError) { edgeLogger.error('Error triggering notification', { action: 'notify_system_announcement', requestId: context.requestId, error: notifyError }); throw notifyError; } edgeLogger.info('System announcement triggered successfully', { action: 'notify_system_announcement', requestId: context.requestId, result }); return new Response( JSON.stringify({ success: true, transactionId: result?.transactionId, announcementId, payload: notificationPayload, }), { headers: { 'Content-Type': 'application/json', }, status: 200, } ); } );