Files
website/src/util/webhook.ts
2025-11-23 03:48:04 +01:00

77 lines
1.9 KiB
TypeScript

import { sleepSeconds } from './sleep.ts';
import { WEBHOOK_ENDPOINT } from 'astro:env/server';
import { logger } from '@util/log.ts';
export enum WebhookAction {
Signup = 'signup',
Report = 'report',
Strike = 'strike'
}
export type WebhookActionType<T extends WebhookAction> = {
[WebhookAction.Signup]: {
firstname: string;
lastname: string;
birthday: string;
telephone: string | null;
username: string;
edition: 'java' | 'bedrock';
uuid: string | null;
};
[WebhookAction.Report]: {
reporter: string | null;
reported: string | null;
reason: string;
};
[WebhookAction.Strike]: {
uuid: string;
};
}[T];
export async function sendWebhook<T extends WebhookAction>(action: T, data: WebhookActionType<T>) {
if (!WEBHOOK_ENDPOINT) return;
else if (!/^(https?:\/\/[^\s,]+)(?:,(https?:\/\/[^\s,]+))*$/.test(WEBHOOK_ENDPOINT)) {
logger.warn('webhook endpoint is invalid');
return;
}
const webhookFutures = [];
for (const webhook of WEBHOOK_ENDPOINT.split(',')) {
webhookFutures.push(
(async () => {
let retries = 0;
while (retries < 3) {
try {
const response = await fetch(webhook, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-webhook-action': action
},
body: JSON.stringify(data)
});
if (response.status === 200) break;
} catch (e) {
logger.warn(
{
retry: retries + 1,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
error: e.message
},
'error while sending webhook'
);
}
retries++;
await sleepSeconds(60);
}
})()
);
}
await Promise.all(webhookFutures);
}