diff --git a/server/src/sms/parse.ts b/server/src/sms/parse.ts index cfd70df..8e90dee 100644 --- a/server/src/sms/parse.ts +++ b/server/src/sms/parse.ts @@ -26,12 +26,35 @@ export function parseVonageInboundMessage(body: unknown): ParsedInboundSms | nul try { const data = body as Record; - const from = (data.from as string) || ''; - const to = (data.to as string) || ''; - const text = (data.text as string) || ''; + // Vonage may send either a flat shape (from/to/text) or a nested one: + // { + // from: { type: 'sms', number: '1999...' }, + // to: { type: 'sms', number: '1999...' }, + // message: { content: { type: 'text', text: '...' } } + // } + const from = + (typeof data.from === 'string' ? data.from : '') || + (data.from && typeof data.from === 'object' + ? (((data.from as Record).number as string) || '') + : ''); + const to = + (typeof data.to === 'string' ? data.to : '') || + (data.to && typeof data.to === 'object' + ? (((data.to as Record).number as string) || '') + : ''); + + const nestedText = + data.message && typeof data.message === 'object' + ? (((data.message as Record).content as Record | undefined)?.text as string) || '' + : ''; + const text = (data.text as string) || nestedText || ''; const messageId = (data.message_uuid as string) || ''; - const messageType = (data.message_type as string) || ''; - const channel = (data.channel as string) || 'sms'; + const nestedMessageType = + data.message && typeof data.message === 'object' + ? (((data.message as Record).content as Record | undefined)?.type as string) || '' + : ''; + const messageType = (data.message_type as string) || nestedMessageType || ''; + const channel = (data.channel as string) || ((data.to as Record | undefined)?.type as string) || 'sms'; // Collect media URLs from MMS messages const mediaUrls: string[] = []; @@ -47,6 +70,12 @@ export function parseVonageInboundMessage(body: unknown): ParsedInboundSms | nul const fileUrl = (data.file as Record)?.url as string; if (fileUrl) mediaUrls.push(fileUrl); } + // Nested media shapes (best-effort) + const nestedMediaUrl = + data.message && typeof data.message === 'object' + ? (((data.message as Record).content as Record | undefined)?.url as string) || '' + : ''; + if (nestedMediaUrl) mediaUrls.push(nestedMediaUrl); const hasMedia = mediaUrls.length > 0 || channel === 'mms';