diff --git a/plugins/webhook-event-forwarder/README.md b/plugins/webhook-event-forwarder/README.md index 88fff8dd..b517030d 100644 --- a/plugins/webhook-event-forwarder/README.md +++ b/plugins/webhook-event-forwarder/README.md @@ -23,6 +23,7 @@ The `callback` parameter takes a function that will be called with the webhook r The `options` parameter takes an object with the following properties: - `debug` - `boolean` - (optional) - Whether to log debug messages. +- `timeout` - `number` - (optional) - Timeout in milliseconds for the webhook request. Defaults to 5000ms (5 seconds). ## Usage @@ -47,3 +48,14 @@ listener.use(webhookEventForwarder("https://webhook.site/...", (data, event) => console.log(data, event); })); ``` + +#### With timeout configuration + +```ts listener.js +listener.use(webhookEventForwarder("https://webhook.site/...", (data, event) => { + console.log(data, event); +}, { + timeout: 10000, // 10 seconds + debug: true +})); +``` diff --git a/plugins/webhook-event-forwarder/src/forward-webhook.e2e.spec.ts b/plugins/webhook-event-forwarder/src/forward-webhook.e2e.spec.ts index da65ee44..e8938730 100644 --- a/plugins/webhook-event-forwarder/src/forward-webhook.e2e.spec.ts +++ b/plugins/webhook-event-forwarder/src/forward-webhook.e2e.spec.ts @@ -119,6 +119,7 @@ describe('forward-webhook() e2e', () => { it('should error', async () => { mockWebhookFetch.mockResolvedValue({ status: 500, + statusText: 'Internal Server Error', ok: false, headers: { get: vi.fn().mockReturnValue('application/json'), @@ -140,7 +141,7 @@ describe('forward-webhook() e2e', () => { expect.objectContaining({ topic: 'commit:created', data: { - data: 'Error: Error forwarding webhook', + data: 'Error: Error forwarding webhook: 500 Internal Server Error', error: true, message: 'Error received, please try again', }, diff --git a/plugins/webhook-event-forwarder/src/forward.webhook.ts b/plugins/webhook-event-forwarder/src/forward.webhook.ts index f842d326..dedecb95 100644 --- a/plugins/webhook-event-forwarder/src/forward.webhook.ts +++ b/plugins/webhook-event-forwarder/src/forward.webhook.ts @@ -9,10 +9,15 @@ export function webhookEventForward( ) => Promise | unknown, options?: { debug?: boolean + timeout?: number } ) { return async (listener: FlatfileListener) => { return listener.on('**', async (event) => { + const controller = new AbortController() + const timeoutMs = options?.timeout ?? 5000 // Default 5 seconds + const timeoutId = setTimeout(() => controller.abort(), timeoutMs) + try { const response = await fetch(url, { method: 'POST', @@ -20,9 +25,14 @@ export function webhookEventForward( 'Content-Type': 'application/json', }, body: JSON.stringify(event), + signal: controller.signal, }) - if (!response.ok) throw new Error('Error forwarding webhook') + if (!response.ok) { + throw new Error( + `Error forwarding webhook: ${response.status} ${response.statusText}` + ) + } const contentType = response.headers.get('content-type') const isJson = contentType?.includes('application/json') @@ -30,8 +40,13 @@ export function webhookEventForward( callback ? await callback(data, event) : null } catch (err) { + const errorMessage = + err.name === 'AbortError' + ? `Webhook request timed out after ${timeoutMs}ms` + : err.toString() + if (options?.debug) { - console.error(err.toString()) + console.error(`[webhook-event-forwarder] ${errorMessage}`) } callback @@ -39,11 +54,13 @@ export function webhookEventForward( { error: true, message: 'Error received, please try again', - data: err.toString(), + data: errorMessage, }, event ) : null + } finally { + clearTimeout(timeoutId) } }) }