/** * Device-Approval Email (Fallback wenn kein anderes Device online). * * Sendet eine Mail an die User-Email mit: * - 6-stelligem Code (zur Anzeige / visuellem Vergleich) * - Magic-Link (https://app.rebreak.org/approve-device?token=XYZ) der den * Approval direkt bestätigt — User muss nicht eingeloggt sein. * * Lyra-Voice: NICHT verwenden — strikt informational/sicherheitsneutral. */ import { Resend } from "resend"; export interface DeviceApprovalEmailOpts { recipientNickname: string; recipientEmail: string; code: string; emailToken: string; newDeviceLabel: string; // z.B. "iPhone 15 Pro (iOS)" expiresAt: Date; resendApiKey: string; appBaseUrl?: string; } export async function sendDeviceApprovalEmail( opts: DeviceApprovalEmailOpts, ): Promise { if (!opts.resendApiKey) { console.warn("[device-approval-email] resendApiKey not provided — skipping"); return; } const resend = new Resend(opts.resendApiKey); const baseUrl = opts.appBaseUrl ?? "https://app.rebreak.org"; const approveUrl = `${baseUrl}/approve-device?token=${encodeURIComponent(opts.emailToken)}`; const ttlMinutes = Math.max( 1, Math.round((opts.expiresAt.getTime() - Date.now()) / 60_000), ); const subject = `ReBreak: Neues Gerät bestätigen (Code ${opts.code})`; const html = ` ${subject}

ReBreak — Neues Gerät bestätigen

Hallo ${opts.recipientNickname},

Es wurde versucht, sich auf ${opts.newDeviceLabel} bei deinem ReBreak-Account anzumelden. Wenn du das warst, bestätige bitte unten.

Code zum Vergleich
${opts.code}
Gültig für ${ttlMinutes} Minuten

Vergleiche diesen Code mit dem, der auf deinem neuen Gerät angezeigt wird. Wenn die Codes übereinstimmen, klicke auf den Button.

Gerät bestätigen
Wenn das nicht du warst: Ignoriere diese Mail. Ohne Bestätigung bekommt das Gerät keinen Zugang. Der Versuch läuft in ${ttlMinutes} Minuten ab.
`.trim(); try { await resend.emails.send({ from: "ReBreak ", to: opts.recipientEmail, subject, html, }); } catch (err: any) { console.error("[device-approval-email] Failed to send:", err?.message ?? err); } }