import { Injectable, Logger } from '@nestjs/common'; import axios, { AxiosResponse } from 'axios'; import { IntegrationStrategy, IntegrationResult, } from '../integration.strategy'; interface Msg91SmsConfig { authKey: string; senderId: string; route?: string; // Route like '4' for transactional, '1' for promotional baseUrl?: string; dltTemplateId?: string; entityId?: string; } interface Msg91SmsApiResponse { type: string; message?: string; request_id?: string; error?: { code: string; message: string; }; } @Injectable() export class Msg91SmsStrategy implements IntegrationStrategy { private readonly logger = new Logger(Msg91SmsStrategy.name); private readonly defaultBaseUrl = 'https://api.msg91.com/api/v5'; async sendMessage( to: string, message: string, config: any, ): Promise { try { if (!this.validateConfig(config)) { throw new Error('Invalid MSG91 SMS configuration'); } const msg91Config = config as Msg91SmsConfig; const baseUrl = msg91Config.baseUrl || this.defaultBaseUrl; const url = `${baseUrl}/flow`; const payload = { sender: msg91Config.senderId, route: msg91Config.route || '4', // Default to transactional country: '91', // Default to India sms: [ { message: message, to: [this.formatPhoneNumber(to)], }, ], }; // Add DLT Template ID if provided if (msg91Config.dltTemplateId) { payload['DLT_TE_ID'] = msg91Config.dltTemplateId; } // Add Entity ID if provided if (msg91Config.entityId) { payload['DLT_PE_ID'] = msg91Config.entityId; } const response: AxiosResponse = await axios.post( url, payload, { headers: { authkey: msg91Config.authKey, 'Content-Type': 'application/json', }, timeout: 30000, }, ); if ( response.data?.type === 'success' || response.status === 200 ) { const messageId = response.data?.request_id || new Date().getTime().toString(); this.logger.log( `MSG91 SMS sent successfully to ${to}, messageId: ${messageId}`, ); return { success: true, messageId: messageId, provider: 'msg91', service: 'SMS', timestamp: new Date(), }; } else { throw new Error( response.data?.error?.message || response.data?.message || 'Failed to send SMS via MSG91', ); } } catch (error) { this.logger.error( `Failed to send MSG91 SMS to ${to}`, error.response?.data || error.message, ); return { success: false, provider: 'msg91', service: 'SMS', error: this.extractErrorMessage(error), timestamp: new Date(), }; } } private formatPhoneNumber(phoneNumber: string): string { // Remove any non-digit characters except + let formatted = phoneNumber.replace(/[^\d+]/g, ''); // Remove + if present formatted = formatted.replace(/\+/g, ''); // Remove country code if it's 91 (India) as MSG91 handles it separately if (formatted.startsWith('91')) { formatted = formatted.substring(2); } return formatted; } private extractErrorMessage(error: any): string { if (error.response?.data?.error?.message) { return error.response.data.error.message; } if (error.response?.data?.message) { return error.response.data.message; } if (error.message) { return error.message; } return 'Unknown MSG91 SMS API error'; } validateConfig(config: any): boolean { if (!config || typeof config !== 'object') { return false; } // Required fields if (!config.authKey || !config.senderId) { return false; } return true; } }