voice-transcription/webhook.delivery.test.ts
Rama main · réplica de lectura del repositorio original.
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { createHmac } from 'node:crypto';
import type { PluginNetCapability, PluginNetRequestInit, PluginNetResponse } from '../types/openwa';
import { WebhookDelivery, TranscriptionPayload } from './webhook.delivery.ts';
function res(partial: { ok?: boolean; status?: number }): PluginNetResponse {
return {
ok: partial.ok ?? true,
status: partial.status ?? 200,
statusText: '',
headers: {},
body: '',
};
}
function fakeNet(response: PluginNetResponse) {
const calls: Array<{ url: string; init: PluginNetRequestInit }> = [];
const net: PluginNetCapability = {
fetch: async (url: string, init?: PluginNetRequestInit) => {
calls.push({ url, init: init ?? {} });
return response;
},
};
return { net, calls };
}
const payload: TranscriptionPayload = {
event: 'message.transcription',
sessionId: 's1',
messageId: 'm1',
chatId: 'c1@s.whatsapp.net',
status: 'completed',
source: 'speech-to-text',
untrusted: true,
transcription: { text: 'hola mundo', language: 'es', provider: 'faster-whisper', model: 'small' },
};
test('POSTs the payload as JSON to the configured url', async () => {
const { net, calls } = fakeNet(res({}));
await new WebhookDelivery({ url: 'http://hook.local/in', timeoutMs: 5000, net }).deliver(payload);
assert.equal(calls[0].url, 'http://hook.local/in');
assert.equal(calls[0].init.method, 'POST');
assert.equal(calls[0].init.headers!['content-type'], 'application/json');
assert.deepEqual(JSON.parse(calls[0].init.body as string), payload);
});
test('signs the body with HMAC-SHA256 in X-OpenWA-Signature when a secret is configured', async () => {
const { net, calls } = fakeNet(res({}));
await new WebhookDelivery({ url: 'http://hook.local/in', secret: 'shh', timeoutMs: 5000, net }).deliver(payload);
const sentBody = calls[0].init.body as string;
const expected = `sha256=${createHmac('sha256', 'shh').update(sentBody).digest('hex')}`;
assert.equal(calls[0].init.headers!['X-OpenWA-Signature'], expected);
assert.equal(calls[0].init.headers!['authorization'], undefined); // bearer replaced by the signature
});
test('omits the signature header when no secret is configured', async () => {
const { net, calls } = fakeNet(res({}));
await new WebhookDelivery({ url: 'http://hook.local/in', timeoutMs: 5000, net }).deliver(payload);
assert.equal(calls[0].init.headers!['X-OpenWA-Signature'], undefined);
});
test('throws on a non-ok status so the caller can log the miss', async () => {
const { net } = fakeNet(res({ ok: false, status: 502 }));
await assert.rejects(
new WebhookDelivery({ url: 'http://hook.local/in', timeoutMs: 5000, net }).deliver(payload),
/502/,
);
});