-
-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathroute.ts
More file actions
131 lines (114 loc) · 4.16 KB
/
Copy pathroute.ts
File metadata and controls
131 lines (114 loc) · 4.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
export const fetchCache = 'force-no-store'
import { NextResponse } from 'next/server'
import { sanityWriteClient } from '@/lib/sanity-write-client'
import { generateOutreachEmail } from '@/lib/sponsor/gemini-outreach'
import { sendSponsorEmail } from '@/lib/sponsor/email-service'
import type { SponsorPoolEntry } from '@/lib/sponsor/gemini-outreach'
const MAX_PER_RUN = 5
const COOLDOWN_DAYS = 14
export async function POST(request: Request) {
// Auth: Bearer token check against CRON_SECRET
const cronSecret = process.env.CRON_SECRET;
if (!cronSecret) {
console.error('[SPONSOR] CRON_SECRET not configured');
return new Response('Server misconfigured', { status: 503 });
}
const authHeader = request.headers.get('authorization')
if (authHeader !== `Bearer ${cronSecret}`) {
console.error('[SPONSOR] Outreach cron: unauthorized request')
return new Response('Unauthorized', { status: 401 })
}
try {
console.log('[SPONSOR] Starting outbound sponsor outreach cron...')
// Calculate the cutoff date for cooldown
const cutoffDate = new Date()
cutoffDate.setDate(cutoffDate.getDate() - COOLDOWN_DAYS)
const cutoffISO = cutoffDate.toISOString()
// Query Sanity for eligible sponsor pool entries
const query = `*[
_type == "sponsorPool"
&& optedOut != true
&& (
!defined(lastContactedAt)
|| lastContactedAt < $cutoffDate
)
] | order(relevanceScore desc) [0...${MAX_PER_RUN - 1}] {
_id,
companyName,
contactName,
contactEmail,
website,
category,
relevanceScore,
optOutToken
}`
const sponsors: SponsorPoolEntry[] = await sanityWriteClient.fetch(query, {
cutoffDate: cutoffISO,
})
console.log(`[SPONSOR] Found ${sponsors.length} eligible sponsors for outreach`)
if (sponsors.length === 0) {
return NextResponse.json({
success: true,
message: 'No eligible sponsors for outreach',
processed: 0,
})
}
const results: Array<{ companyName: string; success: boolean; error?: string }> = []
for (const sponsor of sponsors) {
try {
// Generate personalized outreach email
const email = await generateOutreachEmail(sponsor)
// Send the email (stubbed)
const sendResult = await sendSponsorEmail(
sponsor.contactEmail,
email.subject,
email.body
)
if (sendResult.success) {
// Update lastContactedAt on the sponsor pool entry
await sanityWriteClient
.patch(sponsor._id)
.set({ lastContactedAt: new Date().toISOString() })
.commit()
// Create a sponsorLead with source='outbound'
await sanityWriteClient.create({
_type: 'sponsorLead',
companyName: sponsor.companyName,
contactName: sponsor.contactName,
contactEmail: sponsor.contactEmail,
source: 'outbound',
status: 'contacted',
threadId: crypto.randomUUID(),
lastEmailAt: new Date().toISOString(),
})
results.push({ companyName: sponsor.companyName, success: true })
console.log(`[SPONSOR] Outreach sent to: ${sponsor.companyName}`)
} else {
results.push({
companyName: sponsor.companyName,
success: false,
error: 'Email send failed',
})
}
} catch (error) {
const errorMsg = error instanceof Error ? error.message : String(error)
console.error(`[SPONSOR] Outreach failed for ${sponsor.companyName}:`, errorMsg)
results.push({ companyName: sponsor.companyName, success: false, error: errorMsg })
}
}
const successCount = results.filter((r) => r.success).length
console.log(`[SPONSOR] Outreach cron complete: ${successCount}/${results.length} successful`)
return NextResponse.json({
success: true,
processed: results.length,
successful: successCount,
results,
})
} catch (error) {
console.error('[SPONSOR] Outreach cron error:', error)
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
)
}
}