JUNOHUB-test/src/app/api/integrations/gmail/watch/route.ts
root 71a75892a5 Add Juno Engine templates and Bedrock email flow
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 19:44:51 +05:00

159 lines
5.3 KiB
TypeScript

import { NextResponse } from "next/server"
import { auth } from "@/auth"
import { prisma } from "@/lib/prisma"
import { logger } from "@/lib/logger"
import { getGmailAccessToken } from "@/lib/gmail"
/**
* POST /api/integrations/gmail/watch
* Set up Gmail push notifications (watch) for a user's mailbox
*
* This creates a watch request that tells Gmail to send push notifications
* to the webhook endpoint when new emails arrive.
*
* Note: Gmail watch requests expire after 7 days and need to be renewed.
*/
export async function POST(req: Request) {
try {
const session = await auth()
if (!session?.user?.id) {
return NextResponse.json({ message: "Unauthorized" }, { status: 401 })
}
// Get Gmail access token
const accessToken = await getGmailAccessToken(session.user.id)
if (!accessToken) {
return NextResponse.json(
{ message: "Gmail not connected. Please connect your Gmail account first." },
{ status: 400 }
)
}
// Get webhook URL
const baseUrl =
process.env.AUTH_URL ||
process.env.NEXTAUTH_URL ||
process.env.NEXT_PUBLIC_APP_URL ||
"http://localhost:3000"
const webhookUrl = `${baseUrl}/api/webhooks/gmail`
// Get user's email from integration
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const integration = await (prisma as any).gmailIntegration.findUnique({
where: { userId: session.user.id },
select: { email: true }
})
if (!integration?.email) {
return NextResponse.json(
{ message: "Gmail email not found" },
{ status: 400 }
)
}
// Create watch request
// Gmail will send push notifications to the webhook URL
const watchResponse = await fetch(
"https://gmail.googleapis.com/gmail/v1/users/me/watch",
{
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
topicName: process.env.GMAIL_PUBSUB_TOPIC || "projects/your-project/topics/gmail-notifications",
labelIds: ["INBOX"], // Watch for emails in inbox
})
}
)
if (!watchResponse.ok) {
const errorData = await watchResponse.json().catch(() => ({}))
logger.error("Failed to set up Gmail watch", { error: errorData })
// If topic doesn't exist, provide helpful error message
if (watchResponse.status === 400) {
return NextResponse.json(
{
message: "Gmail Pub/Sub topic not configured. Please set up Google Cloud Pub/Sub first.",
error: errorData
},
{ status: 400 }
)
}
return NextResponse.json(
{ message: "Failed to set up Gmail watch", error: errorData },
{ status: watchResponse.status }
)
}
const watchData = await watchResponse.json()
const expiration = watchData.expiration ? new Date(parseInt(watchData.expiration)).toISOString() : null
logger.info("Gmail watch set up successfully", {
userId: session.user.id,
email: integration.email,
expiration
})
return NextResponse.json({
success: true,
message: "Gmail push notifications enabled",
expiration,
webhookUrl
})
} catch (error) {
logger.error("Error setting up Gmail watch", error)
return NextResponse.json(
{ message: "Failed to set up Gmail watch" },
{ status: 500 }
)
}
}
/**
* GET /api/integrations/gmail/watch
* Check watch status
*/
export async function GET() {
try {
const session = await auth()
if (!session?.user?.id) {
return NextResponse.json({ message: "Unauthorized" }, { status: 401 })
}
const accessToken = await getGmailAccessToken(session.user.id)
if (!accessToken) {
return NextResponse.json(
{ message: "Gmail not connected" },
{ status: 400 }
)
}
// Stop any existing watch (optional - just to check status)
const stopResponse = await fetch(
"https://gmail.googleapis.com/gmail/v1/users/me/stop",
{
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json"
}
}
)
return NextResponse.json({
watchActive: !stopResponse.ok, // If stop fails, watch might be active
message: stopResponse.ok ? "Watch stopped" : "Watch may be active"
})
} catch (error) {
logger.error("Error checking Gmail watch status", error)
return NextResponse.json(
{ message: "Failed to check watch status" },
{ status: 500 }
)
}
}