Files
ECC/docker/context-profiles/complex-eval/reference/webhook-relay/src/app.js
T

74 lines
2.4 KiB
JavaScript

'use strict';
const http = require('node:http');
const crypto = require('node:crypto');
const MAX_ATTEMPTS = 5;
const BASE_DELAY_MS = 100;
function createRelay() {
const deliveries = new Map();
async function attempt(record) {
record.attempts += 1;
try {
const response = await fetch(record.url, {
method: 'POST', headers: { 'content-type': 'application/json' },
body: JSON.stringify(record.payload), signal: AbortSignal.timeout(5000) });
if (response.status >= 200 && response.status < 300) {
record.status = 'delivered';
record.lastError = null;
return;
}
record.lastError = `HTTP ${response.status}`;
} catch (error) {
record.lastError = error && error.message ? error.message : 'delivery failed';
}
if (record.attempts >= MAX_ATTEMPTS) {
record.status = 'dead';
return;
}
const delay = BASE_DELAY_MS * 2 ** (record.attempts - 1);
setTimeout(() => { void attempt(record); }, delay);
}
const server = http.createServer((req, res) => {
if (req.method === 'POST' && req.url === '/deliveries') {
let body = '';
req.on('data', chunk => { body += chunk; });
req.on('end', () => {
let parsed;
try { parsed = JSON.parse(body); } catch {
res.writeHead(400, { 'content-type': 'application/json' });
res.end(JSON.stringify({ error: 'invalid JSON body' }));
return;
}
const id = crypto.randomUUID();
const record = { id, url: parsed.url, payload: parsed.payload,
status: 'pending', attempts: 0, lastError: null };
deliveries.set(id, record);
void attempt(record);
res.writeHead(202, { 'content-type': 'application/json' });
res.end(JSON.stringify({ id }));
});
return;
}
const match = /^\/deliveries\/([0-9a-f-]+)$/.exec(req.url || '');
if (req.method === 'GET' && match) {
const record = deliveries.get(match[1]);
if (!record) {
res.writeHead(404, { 'content-type': 'application/json' });
res.end(JSON.stringify({ error: 'not found' }));
return;
}
res.writeHead(200, { 'content-type': 'application/json' });
res.end(JSON.stringify(record));
return;
}
res.writeHead(404, { 'content-type': 'application/json' });
res.end(JSON.stringify({ error: 'not found' }));
});
return server;
}
module.exports = { createRelay };