Masar / src /services /activityLog.ts
Hussien Haider
H
5084012
Raw
History Blame Contribute Delete
1.56 kB
import { supabase } from '../config/supabase';
export type LogAction =
// User actions
| 'USER_SIGNED_UP'
| 'USER_SIGNED_IN'
| 'PROFILE_UPDATED'
| 'AVATAR_UPLOADED'
| 'CHALLENGE_SUBMITTED'
| 'CHALLENGE_COMPLETED'
| 'DUEL_CREATED'
| 'DUEL_SUBMIT'
| 'EXAM_SUBMITTED'
| 'EXAM_PASSED'
| 'BADGE_EARNED'
| 'TEAM_CREATED'
| 'TEAM_JOINED'
| 'TEAM_LEFT'
| 'TEAM_INVITE_SENT'
| 'TEAM_INVITE_ACCEPTED'
| 'TEAM_INVITE_REJECTED'
| 'TEAM_DELETED'
| 'TEAM_IMAGE_UPLOADED'
| 'NEWS_CREATED'
| 'NEWS_UPDATED'
| 'NEWS_DELETED'
| 'PASSWORD_CHANGED'
// Admin actions
| 'USER_BANNED'
| 'USER_UNBANNED'
| 'USER_DELETED'
| 'USER_ROLE_CHANGED'
| 'COURSE_RELEASE_TOGGLED'
// Security events
| 'INVALID_TOKEN'
| 'BANNED_ACCESS_ATTEMPT'
| 'PRIVILEGE_ESCALATION'
| 'RATE_LIMIT_HIT'
| 'ROUTE_PROBING'
| 'SUSPICIOUS_INPUT'
| 'UNAUTHENTICATED_ACCESS'
| 'TOKEN_REUSE_ATTEMPT';
interface LogEntry {
user_id?: string;
action: LogAction;
details?: string;
ip?: string;
user_agent?: string;
}
export async function logActivity(entry: LogEntry): Promise<void> {
try {
const details = [
entry.details,
entry.ip ? `IP:${entry.ip}` : null,
entry.user_agent ? `UA:${entry.user_agent}` : null,
].filter(Boolean).join(' | ');
await supabase
.from('activity_logs')
.insert({
user_id: entry.user_id || null,
action: entry.action,
details: details || null,
});
} catch {
// Silent fail — logging should never break the main flow
}
}