import db from "../db.server"; import type { LogEntry } from "./activity.server"; const SENSITIVE_KEYS = new Set(["api_secret", "app_secret", "apiSecret", "dreame-api-sign", "sign", "signature"]); export async function logActivityPush(entry: LogEntry): Promise { await db.activityPushLog.create({ data: { shop: entry.shop, orderId: entry.orderId || "unknown", customerId: entry.customerId, email: entry.email, activityId: entry.activityId || "unknown", eventType: entry.eventType, eventId: entry.eventId || "not-generated", status: entry.status, requestBody: sanitizeBody(entry.requestBody), responseBody: sanitizeBody(entry.responseBody), errorMessage: entry.errorMessage, }, }); if (Math.random() < 0.05) { await pruneLogs(); } } export async function pruneLogs(days = Number(process.env.LOG_RETENTION_DAYS || 7)): Promise { const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000); await db.activityPushLog.deleteMany({ where: { createdAt: { lt: cutoff, }, }, }); } export function sanitizeBody(body: string | undefined): string | undefined { if (!body) { return undefined; } try { return JSON.stringify(maskSensitive(JSON.parse(body))); } catch { return body.replace(/[a-f0-9]{32}/gi, "[redacted-md5]"); } } function maskSensitive(value: unknown): unknown { if (Array.isArray(value)) { return value.map(maskSensitive); } if (value && typeof value === "object") { return Object.fromEntries( Object.entries(value as Record).map(([key, child]) => [ key, SENSITIVE_KEYS.has(key) ? "[redacted]" : maskSensitive(child), ]), ); } return value; }