Return better error messages
This commit is contained in:
@@ -85,9 +85,44 @@ export function createWebhookSmsRouter(deps: WebhookSmsRouterDeps): Router {
|
||||
return;
|
||||
}
|
||||
|
||||
const status = (req.body as Record<string, unknown>)?.status;
|
||||
const messageUuid = (req.body as Record<string, unknown>)?.message_uuid;
|
||||
logger.info({ event: 'sms.status_update', messageUuid, status }, 'Message status update');
|
||||
const data = (req.body ?? {}) as Record<string, unknown>;
|
||||
const status = data.status;
|
||||
const messageUuid = data.message_uuid;
|
||||
|
||||
// Vonage Messages API status callbacks include fields like:
|
||||
// message_uuid, to, from, channel, timestamp, status (plus optional fields like workflow).
|
||||
// For rejected statuses, additional reason/code fields may also be present depending on channel/route.
|
||||
const to = typeof data.to === 'string' ? data.to : undefined;
|
||||
const from = typeof data.from === 'string' ? data.from : undefined;
|
||||
const channel = typeof data.channel === 'string' ? data.channel : undefined;
|
||||
const timestamp = typeof data.timestamp === 'string' ? data.timestamp : undefined;
|
||||
|
||||
const rejectionCode =
|
||||
(typeof data.error_code === 'string' || typeof data.error_code === 'number' ? data.error_code : undefined) ??
|
||||
(typeof data.err_code === 'string' || typeof data.err_code === 'number' ? data.err_code : undefined) ??
|
||||
(typeof data.code === 'string' || typeof data.code === 'number' ? data.code : undefined);
|
||||
const rejectionReason =
|
||||
(typeof data.error_title === 'string' ? data.error_title : undefined) ??
|
||||
(typeof data.error === 'string' ? data.error : undefined) ??
|
||||
(typeof data.reason === 'string' ? data.reason : undefined) ??
|
||||
(typeof data.detail === 'string' ? data.detail : undefined) ??
|
||||
(typeof data.description === 'string' ? data.description : undefined);
|
||||
|
||||
logger.info(
|
||||
{
|
||||
event: 'sms.status_update',
|
||||
messageUuid,
|
||||
status,
|
||||
channel,
|
||||
timestamp,
|
||||
to: to ? maskPhone(to) : undefined,
|
||||
from: from ? maskPhone(from) : undefined,
|
||||
rejectionCode,
|
||||
rejectionReason,
|
||||
payload: sanitizeVonageStatusPayload(data),
|
||||
},
|
||||
'Message status update'
|
||||
);
|
||||
|
||||
res.status(200).json({ status: 'received' });
|
||||
});
|
||||
@@ -95,6 +130,19 @@ export function createWebhookSmsRouter(deps: WebhookSmsRouterDeps): Router {
|
||||
return router;
|
||||
}
|
||||
|
||||
function sanitizeVonageStatusPayload(data: Record<string, unknown>): Record<string, unknown> {
|
||||
// Avoid leaking full phone numbers or message contents into logs.
|
||||
const out: Record<string, unknown> = { ...data };
|
||||
if (typeof out.to === 'string') out.to = maskPhone(out.to);
|
||||
if (typeof out.from === 'string') out.from = maskPhone(out.from);
|
||||
|
||||
// Best-effort removal of any accidental content fields if present.
|
||||
for (const key of ['text', 'message', 'content', 'image', 'video', 'file', 'audio']) {
|
||||
if (key in out) delete out[key];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
async function handleInbound(body: unknown, deps: WebhookSmsRouterDeps) {
|
||||
const parsed = parseVonageInboundMessage(body);
|
||||
if (!parsed) {
|
||||
|
||||
Reference in New Issue
Block a user