139 lines
4.7 KiB
TypeScript
139 lines
4.7 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server"
|
|
import { prisma } from "@/lib/prisma"
|
|
import { logger } from "@/lib/logger"
|
|
import { processIncomingEmail } from "@/lib/gmail/emailProcessor"
|
|
|
|
/**
|
|
* POST /api/webhooks/gmail
|
|
* Gmail Push Notification Webhook
|
|
*
|
|
* This endpoint receives push notifications from Gmail when new emails arrive.
|
|
* It processes the email and generates an AI-powered reply using the knowledge base.
|
|
*
|
|
* Setup:
|
|
* 1. Register this webhook URL in Google Cloud Console
|
|
* 2. Set up Gmail watch for each user's mailbox
|
|
* 3. When emails arrive, Gmail sends a notification here
|
|
*/
|
|
export async function POST(req: NextRequest) {
|
|
try {
|
|
// Gmail sends a verification token on initial setup
|
|
const verificationToken = req.headers.get("x-goog-challenge")
|
|
if (verificationToken) {
|
|
logger.info("Gmail webhook verification request received")
|
|
// Return the verification token to confirm webhook ownership
|
|
return new NextResponse(verificationToken, { status: 200 })
|
|
}
|
|
|
|
// Parse the notification payload
|
|
const body = await req.json().catch(() => ({}))
|
|
const messageData = body.message?.data
|
|
|
|
if (!messageData) {
|
|
logger.warn("Gmail webhook received without message data")
|
|
return NextResponse.json({ message: "No message data" }, { status: 200 })
|
|
}
|
|
|
|
// Decode base64url encoded message data
|
|
const decodedData = Buffer.from(messageData, "base64")
|
|
.toString("utf-8")
|
|
|
|
const notification = JSON.parse(decodedData)
|
|
const emailAddress = notification.emailAddress
|
|
const historyId = notification.historyId
|
|
|
|
logger.info("Gmail webhook notification received", {
|
|
emailAddress,
|
|
historyId,
|
|
notification
|
|
})
|
|
|
|
// Find the user by Gmail email address
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const integration = await (prisma as any).gmailIntegration.findFirst({
|
|
where: {
|
|
email: emailAddress
|
|
},
|
|
include: {
|
|
user: {
|
|
include: {
|
|
stores: {
|
|
where: { isActive: true },
|
|
take: 1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
})
|
|
|
|
if (!integration) {
|
|
logger.warn("Gmail integration not found for email", { emailAddress })
|
|
return NextResponse.json(
|
|
{ message: "Integration not found" },
|
|
{ status: 200 } // Return 200 to prevent retries
|
|
)
|
|
}
|
|
|
|
// 🛡️ SECURITY: Only allow VENDORS to use automated replies
|
|
// Suppliers should not send automated responses via JUNO
|
|
if (integration.user.role !== "VENDOR") {
|
|
logger.info("Skipping Gmail processing for non-vendor role", {
|
|
emailAddress,
|
|
role: integration.user.role
|
|
})
|
|
return NextResponse.json({
|
|
success: true,
|
|
message: "Skipping processing for non-vendor account"
|
|
})
|
|
}
|
|
|
|
const userId = integration.userId
|
|
const storeId = integration.user.stores[0]?.id || null
|
|
|
|
// Process the incoming email
|
|
// This will fetch the email, analyze it, and send an AI-powered or fallback reply
|
|
const result = await processIncomingEmail(userId, storeId, historyId)
|
|
|
|
logger.info("Gmail webhook processing result", {
|
|
userId,
|
|
storeId,
|
|
historyId,
|
|
success: result.success,
|
|
error: result.error,
|
|
flagged: result.flagged,
|
|
replied: result.replied,
|
|
})
|
|
|
|
return NextResponse.json({
|
|
success: result.success,
|
|
error: result.error,
|
|
flagged: result.flagged ?? false,
|
|
replied: result.replied ?? false,
|
|
message: result.flagged
|
|
? "Email flagged — no auto-reply sent"
|
|
: result.success
|
|
? "Email processed successfully"
|
|
: "Email processing completed with errors (see logs)",
|
|
})
|
|
} catch (error) {
|
|
logger.error("Gmail webhook error", error)
|
|
// Return 200 to prevent Gmail from retrying
|
|
// Log errors internally for debugging
|
|
return NextResponse.json(
|
|
{ message: "Webhook processed with errors" },
|
|
{ status: 200 }
|
|
)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* GET /api/webhooks/gmail
|
|
* Health check endpoint
|
|
*/
|
|
export async function GET() {
|
|
return NextResponse.json({
|
|
status: "ok",
|
|
message: "Gmail webhook endpoint is active"
|
|
})
|
|
}
|