import type { ActionFunction } from '@remix-run/node'
import { json } from '@remix-run/node'
import crypto from 'crypto'
// The `loader` function handle the GET request to the route
// In this case, we are returning a 400 status, cause we only want to handle POST requests only
// See more about Remix route's loader here: https://remix.run/docs/en/route/loader
export let loader = () => {
return json ({ message: 'Bad request!' }, { status: 400 })
}
// The `action` function handle non-GET requests to the route
// See more about Remix route's action here: https://remix.run/docs/en/route/action
export let action : ActionFunction = async ({ request }) => {
// Return a 405 status if the request method is not POST
if ( request . method !== 'POST' ) {
return json ({ message: 'Method not allowed' }, 405 )
}
// Verify the webhook signature
let signature = request . headers . get ( 'X-Hub-Signature-256' )
let rawBody = await request . text ()
let webhookSecret = process . env . GITHUB_APP_WEBHOOK_SECRET
let hmac = crypto . createHmac ( 'sha256' , webhookSecret )
hmac . update ( rawBody )
let generatedSignature = `sha256=${ hmac . digest ( 'hex' ) }`
if ( signature !== generatedSignature ) {
return json ({ message: 'Webhook must originate from GitHub!' }, 400 )
}
let event = request . headers . get ( 'X-GitHub-Event' )
console . log ( `✅ Github webhook verified!. Event: "${ event }"` )
try {
let payload = JSON . parse ( rawBody )
if ( event === 'your_subscribed_event' ) {
let { action , sender , ... rest } = payload
// Do something with the payload from Github
// `action` is the action that triggered the event
// `sender` is the user that triggered the event
}
return json ({ message: 'Webhook processed successfully!' , event }, 200 )
} catch ( err ) {
console . log ( `❌ Error processing webhook event: ${ err ?. toString () }` )
// Return a 200 status to Github to avoid retries
// even if the webhook payload is not processed successfully in your app
return json ({ message: 'Webhook processed!' , event }, 200 )
}
}