happy-server/sources/modules/github.ts
2025-08-26 20:39:55 -07:00

84 lines
3.2 KiB
TypeScript

import { App } from "octokit";
import { Webhooks } from "@octokit/webhooks";
import type { EmitterWebhookEvent } from "@octokit/webhooks";
import { log } from "@/utils/log";
let app: App | null = null;
let webhooks: Webhooks | null = null;
export async function initGithub() {
if (
process.env.GITHUB_APP_ID &&
process.env.GITHUB_PRIVATE_KEY &&
process.env.GITHUB_CLIENT_ID &&
process.env.GITHUB_CLIENT_SECRET &&
process.env.GITHUB_REDIRECT_URI &&
process.env.GITHUB_WEBHOOK_SECRET
) {
app = new App({
appId: process.env.GITHUB_APP_ID,
privateKey: process.env.GITHUB_PRIVATE_KEY,
webhooks: {
secret: process.env.GITHUB_WEBHOOK_SECRET
}
});
// Initialize standalone webhooks handler for type-safe event processing
webhooks = new Webhooks({
secret: process.env.GITHUB_WEBHOOK_SECRET
});
// Register type-safe event handlers
registerWebhookHandlers();
}
}
function registerWebhookHandlers() {
if (!webhooks) return;
// Type-safe handlers for specific events
webhooks.on("push", async ({ id, name, payload }: EmitterWebhookEvent<"push">) => {
log({ module: 'github-webhook', event: 'push' },
`Push to ${payload.repository.full_name} by ${payload.pusher.name}`);
});
webhooks.on("pull_request", async ({ id, name, payload }: EmitterWebhookEvent<"pull_request">) => {
log({ module: 'github-webhook', event: 'pull_request' },
`PR ${payload.action} on ${payload.repository.full_name}: #${payload.pull_request.number} - ${payload.pull_request.title}`);
});
webhooks.on("issues", async ({ id, name, payload }: EmitterWebhookEvent<"issues">) => {
log({ module: 'github-webhook', event: 'issues' },
`Issue ${payload.action} on ${payload.repository.full_name}: #${payload.issue.number} - ${payload.issue.title}`);
});
webhooks.on(["star.created", "star.deleted"], async ({ id, name, payload }: EmitterWebhookEvent<"star.created" | "star.deleted">) => {
const action = payload.action === 'created' ? 'starred' : 'unstarred';
log({ module: 'github-webhook', event: 'star' },
`Repository ${action}: ${payload.repository.full_name} by ${payload.sender.login}`);
});
webhooks.on("repository", async ({ id, name, payload }: EmitterWebhookEvent<"repository">) => {
log({ module: 'github-webhook', event: 'repository' },
`Repository ${payload.action}: ${payload.repository.full_name}`);
});
// Catch-all for unhandled events
webhooks.onAny(async ({ id, name, payload }: EmitterWebhookEvent) => {
log({ module: 'github-webhook', event: name as string },
`Received webhook event: ${name}`, { id });
});
webhooks.onError((error: any) => {
log({ module: 'github-webhook', level: 'error' },
`Webhook handler error: ${error.event?.name}`, error);
});
}
export function getWebhooks(): Webhooks | null {
return webhooks;
}
export function getApp(): App | null {
return app;
}