2024-06-05 13:20:26 -07:00
import { supabase_service } from "../supabase" ;
import { withAuth } from "../../lib/withAuth" ;
import { Resend } from "resend" ;
import { NotificationType } from "../../types" ;
2024-07-25 09:48:06 -03:00
import { Logger } from "../../../src/lib/logger" ;
2024-10-15 17:28:28 -03:00
import { sendSlackWebhook } from "../alerts/slack" ;
import { getNotificationString } from "./notification_string" ;
import { AuthCreditUsageChunk } from "../../controllers/v1/types" ;
2024-06-05 13:20:26 -07:00
const emailTemplates : Record <
NotificationType ,
{ subject : string ; html : string }
> = {
[ NotificationType . APPROACHING_LIMIT ] : {
subject : "You've used 80% of your credit limit - Firecrawl" ,
html : "Hey there,<br/><p>You are approaching your credit limit for this billing period. Your usage right now is around 80% of your total credit limit. Consider upgrading your plan to avoid hitting the limit. Check out our <a href='https://firecrawl.dev/pricing'>pricing page</a> for more info.</p><br/>Thanks,<br/>Firecrawl Team<br/>" ,
} ,
[ NotificationType . LIMIT_REACHED ] : {
2024-06-06 11:23:10 -07:00
subject :
"Credit Limit Reached! Take action now to resume usage - Firecrawl" ,
2024-06-05 13:20:26 -07:00
html : "Hey there,<br/><p>You have reached your credit limit for this billing period. To resume usage, please upgrade your plan. Check out our <a href='https://firecrawl.dev/pricing'>pricing page</a> for more info.</p><br/>Thanks,<br/>Firecrawl Team<br/>" ,
} ,
[ NotificationType . RATE_LIMIT_REACHED ] : {
subject : "Rate Limit Reached - Firecrawl" ,
2024-06-06 10:41:54 -07:00
html : "Hey there,<br/><p>You've hit one of the Firecrawl endpoint's rate limit! Take a breather and try again in a few moments. If you need higher rate limits, consider upgrading your plan. Check out our <a href='https://firecrawl.dev/pricing'>pricing page</a> for more info.</p><p>If you have any questions, feel free to reach out to us at <a href='mailto:hello@firecrawl.com'>hello@firecrawl.com</a></p><br/>Thanks,<br/>Firecrawl Team<br/><br/>Ps. this email is only sent once every 7 days if you reach a rate limit." ,
2024-06-05 13:20:26 -07:00
} ,
} ;
export async function sendNotification (
team_id : string ,
notificationType : NotificationType ,
startDateString : string ,
2024-10-15 17:28:28 -03:00
endDateString : string ,
chunk : AuthCreditUsageChunk
2024-06-05 13:20:26 -07:00
) {
return withAuth ( sendNotificationInternal ) (
team_id ,
notificationType ,
startDateString ,
2024-10-15 17:28:28 -03:00
endDateString ,
chunk
2024-06-05 13:20:26 -07:00
) ;
}
async function sendEmailNotification (
email : string ,
2024-10-15 17:28:28 -03:00
notificationType : NotificationType ,
2024-06-05 13:20:26 -07:00
) {
2024-06-06 11:23:10 -07:00
const resend = new Resend ( process . env . RESEND_API_KEY ) ;
2024-06-05 13:53:31 -07:00
2024-06-05 13:20:26 -07:00
try {
const { data , error } = await resend . emails . send ( {
from : "Firecrawl <firecrawl@getmendableai.com>" ,
to : [ email ] ,
reply_to : "hello@firecrawl.com" ,
subject : emailTemplates [ notificationType ] . subject ,
html : emailTemplates [ notificationType ] . html ,
} ) ;
if ( error ) {
2024-07-25 09:48:06 -03:00
Logger . debug ( ` Error sending email: ${ error } ` ) ;
2024-06-05 13:20:26 -07:00
return { success : false } ;
}
} catch ( error ) {
2024-07-25 09:48:06 -03:00
Logger . debug ( ` Error sending email (2): ${ error } ` ) ;
2024-06-05 13:20:26 -07:00
return { success : false } ;
}
}
export async function sendNotificationInternal (
team_id : string ,
notificationType : NotificationType ,
startDateString : string ,
2024-10-15 17:28:28 -03:00
endDateString : string ,
chunk : AuthCreditUsageChunk
2024-06-05 13:20:26 -07:00
) : Promise < { success : boolean } > {
2024-06-06 11:23:10 -07:00
if ( team_id === "preview" ) {
return { success : true } ;
}
2024-07-25 20:43:50 -04:00
const fifteenDaysAgo = new Date ( ) ;
fifteenDaysAgo . setDate ( fifteenDaysAgo . getDate ( ) - 15 ) ;
2024-06-05 13:20:26 -07:00
const { data , error } = await supabase_service
. from ( "user_notifications" )
. select ( "*" )
. eq ( "team_id" , team_id )
. eq ( "notification_type" , notificationType )
2024-07-25 20:43:50 -04:00
. gte ( "sent_date" , fifteenDaysAgo . toISOString ( ) ) ;
2024-06-05 13:20:26 -07:00
if ( error ) {
2024-07-25 09:48:06 -03:00
Logger . debug ( ` Error fetching notifications: ${ error } ` ) ;
2024-06-05 13:20:26 -07:00
return { success : false } ;
}
if ( data . length !== 0 ) {
2024-07-25 20:43:50 -04:00
// Logger.debug(`Notification already sent for team_id: ${team_id} and notificationType: ${notificationType} in the last 15 days`);
return { success : false } ;
}
const { data : recentData , error : recentError } = await supabase_service
. from ( "user_notifications" )
. select ( "*" )
. eq ( "team_id" , team_id )
. eq ( "notification_type" , notificationType )
. gte ( "sent_date" , startDateString )
. lte ( "sent_date" , endDateString ) ;
if ( recentError ) {
Logger . debug ( ` Error fetching recent notifications: ${ recentError } ` ) ;
return { success : false } ;
}
if ( recentData . length !== 0 ) {
// Logger.debug(`Notification already sent for team_id: ${team_id} and notificationType: ${notificationType} within the specified date range`);
2024-06-05 13:20:26 -07:00
return { success : false } ;
} else {
2024-07-25 20:43:50 -04:00
console . log ( ` Sending notification for team_id: ${ team_id } and notificationType: ${ notificationType } ` ) ;
2024-06-05 13:20:26 -07:00
// get the emails from the user with the team_id
const { data : emails , error : emailsError } = await supabase_service
. from ( "users" )
. select ( "email" )
. eq ( "team_id" , team_id ) ;
if ( emailsError ) {
2024-07-25 09:48:06 -03:00
Logger . debug ( ` Error fetching emails: ${ emailsError } ` ) ;
2024-06-05 13:20:26 -07:00
return { success : false } ;
}
for ( const email of emails ) {
await sendEmailNotification ( email . email , notificationType ) ;
}
const { error : insertError } = await supabase_service
. from ( "user_notifications" )
. insert ( [
{
team_id : team_id ,
notification_type : notificationType ,
sent_date : new Date ( ) . toISOString ( ) ,
} ,
] ) ;
2024-10-15 17:28:28 -03:00
if ( process . env . SLACK_ADMIN_WEBHOOK_URL && emails . length > 0 ) {
sendSlackWebhook (
` ${ getNotificationString ( notificationType ) } : Team ${ team_id } , with email ${ emails [ 0 ] . email } . Number of credits used: ${ chunk . adjusted_credits_used } | Number of credits in the plan: ${ chunk . price_credits } ` ,
false ,
process . env . SLACK_ADMIN_WEBHOOK_URL
) . catch ( ( error ) = > {
Logger . debug ( ` Error sending slack notification: ${ error } ` ) ;
} ) ;
}
2024-06-05 13:20:26 -07:00
if ( insertError ) {
2024-07-25 09:48:06 -03:00
Logger . debug ( ` Error inserting notification record: ${ insertError } ` ) ;
2024-06-05 13:20:26 -07:00
return { success : false } ;
}
return { success : true } ;
}
}