80 lines
2.9 KiB
JavaScript
80 lines
2.9 KiB
JavaScript
const https = require('https');
|
|
const http = require('http');
|
|
|
|
module.exports = {
|
|
type: 'webhook',
|
|
category: 'messaging',
|
|
name: 'Universal REST Webhook',
|
|
description: 'Send a generic HTTP POST request with a custom JSON payload. Variables {{to}} and {{message}} will be replaced.',
|
|
|
|
configSchema: [
|
|
{ key: 'url', label: 'Webhook URL', type: 'url', required: true, placeholder: 'https://api.example.com/send' },
|
|
{ key: 'method', label: 'HTTP Method', type: 'text', required: true, placeholder: 'POST' },
|
|
{ key: 'headers', label: 'Custom Headers (JSON)', type: 'text', required: false, placeholder: '{"Authorization": "Bearer ...", "Content-Type": "application/json"}' },
|
|
{ key: 'payloadTemplate', label: 'Payload Template', type: 'text', required: true, placeholder: '{"recipient": "{{to}}", "text": "{{message}}"}' },
|
|
{ key: 'apiSecret', label: 'API Secret / Auth Token', type: 'password', required: false, secret: true }
|
|
],
|
|
|
|
validate: async (config) => {
|
|
if (!config.url) return { ok: false, error: 'URL is required' };
|
|
if (!config.payloadTemplate) return { ok: false, error: 'Payload template is required' };
|
|
try {
|
|
if (config.headers) JSON.parse(config.headers);
|
|
} catch (e) {
|
|
return { ok: false, error: 'Headers must be valid JSON' };
|
|
}
|
|
return { ok: true };
|
|
},
|
|
|
|
sendMessage: async (config, payload) => {
|
|
const { to, message } = payload;
|
|
let payloadStr = config.payloadTemplate || '{}';
|
|
|
|
// Replace template variables safely
|
|
payloadStr = payloadStr.replace(/\{\{to\}\}/g, to).replace(/\{\{message\}\}/g, message);
|
|
|
|
// If there is an API secret, replace {{secret}} in the headers or url
|
|
let headersObj = {};
|
|
if (config.headers) {
|
|
try {
|
|
const parsed = JSON.parse(config.headers);
|
|
for (const [k, v] of Object.entries(parsed)) {
|
|
headersObj[k] = config.apiSecret ? String(v).replace(/\{\{secret\}\}/g, config.apiSecret) : v;
|
|
}
|
|
} catch(e) {}
|
|
}
|
|
|
|
if (!headersObj['Content-Type']) {
|
|
headersObj['Content-Type'] = 'application/json';
|
|
}
|
|
|
|
const urlObj = new URL(config.url);
|
|
const options = {
|
|
hostname: urlObj.hostname,
|
|
port: urlObj.port || (urlObj.protocol === 'https:' ? 443 : 80),
|
|
path: urlObj.pathname + urlObj.search,
|
|
method: config.method || 'POST',
|
|
headers: headersObj
|
|
};
|
|
|
|
const client = urlObj.protocol === 'https:' ? https : http;
|
|
|
|
return new Promise((resolve, reject) => {
|
|
const req = client.request(options, (res) => {
|
|
let body = '';
|
|
res.on('data', chunk => body += chunk);
|
|
res.on('end', () => {
|
|
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
resolve({ status: res.statusCode, body });
|
|
} else {
|
|
reject(new Error(`Webhook failed: ${res.statusCode} ${body}`));
|
|
}
|
|
});
|
|
});
|
|
req.on('error', reject);
|
|
req.write(payloadStr);
|
|
req.end();
|
|
});
|
|
}
|
|
};
|