152 lines
3.8 KiB
TypeScript
152 lines
3.8 KiB
TypeScript
|
|
/**
|
||
|
|
* WhatsApp Provider Abstraction Layer
|
||
|
|
*
|
||
|
|
* Supports multiple WhatsApp providers with a common interface:
|
||
|
|
* - Meta WhatsApp Business Cloud API
|
||
|
|
* - Twilio WhatsApp
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { prisma } from '@/lib/prisma'
|
||
|
|
import { MetaWhatsAppProvider } from './meta-provider'
|
||
|
|
import { TwilioWhatsAppProvider } from './twilio-provider'
|
||
|
|
|
||
|
|
export interface WhatsAppResult {
|
||
|
|
success: boolean
|
||
|
|
messageId?: string
|
||
|
|
error?: string
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface WhatsAppProvider {
|
||
|
|
sendText(to: string, body: string): Promise<WhatsAppResult>
|
||
|
|
sendTemplate(
|
||
|
|
to: string,
|
||
|
|
template: string,
|
||
|
|
params: Record<string, string>
|
||
|
|
): Promise<WhatsAppResult>
|
||
|
|
testConnection(): Promise<{ success: boolean; error?: string }>
|
||
|
|
}
|
||
|
|
|
||
|
|
export type WhatsAppProviderType = 'META' | 'TWILIO'
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get the configured WhatsApp provider
|
||
|
|
* Returns null if WhatsApp is not enabled or not configured
|
||
|
|
*/
|
||
|
|
export async function getWhatsAppProvider(): Promise<WhatsAppProvider | null> {
|
||
|
|
try {
|
||
|
|
// Check if WhatsApp is enabled
|
||
|
|
const enabledSetting = await prisma.systemSettings.findUnique({
|
||
|
|
where: { key: 'whatsapp_enabled' },
|
||
|
|
})
|
||
|
|
|
||
|
|
if (enabledSetting?.value !== 'true') {
|
||
|
|
return null
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get provider type
|
||
|
|
const providerSetting = await prisma.systemSettings.findUnique({
|
||
|
|
where: { key: 'whatsapp_provider' },
|
||
|
|
})
|
||
|
|
|
||
|
|
const providerType = (providerSetting?.value || 'META') as WhatsAppProviderType
|
||
|
|
|
||
|
|
if (providerType === 'META') {
|
||
|
|
return await createMetaProvider()
|
||
|
|
} else if (providerType === 'TWILIO') {
|
||
|
|
return await createTwilioProvider()
|
||
|
|
}
|
||
|
|
|
||
|
|
return null
|
||
|
|
} catch (error) {
|
||
|
|
console.error('Failed to get WhatsApp provider:', error)
|
||
|
|
return null
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Create Meta WhatsApp provider from settings
|
||
|
|
*/
|
||
|
|
async function createMetaProvider(): Promise<WhatsAppProvider | null> {
|
||
|
|
const [phoneNumberIdSetting, accessTokenSetting] = await Promise.all([
|
||
|
|
prisma.systemSettings.findUnique({
|
||
|
|
where: { key: 'whatsapp_meta_phone_number_id' },
|
||
|
|
}),
|
||
|
|
prisma.systemSettings.findUnique({
|
||
|
|
where: { key: 'whatsapp_meta_access_token' },
|
||
|
|
}),
|
||
|
|
])
|
||
|
|
|
||
|
|
if (!phoneNumberIdSetting?.value || !accessTokenSetting?.value) {
|
||
|
|
console.warn('Meta WhatsApp not fully configured')
|
||
|
|
return null
|
||
|
|
}
|
||
|
|
|
||
|
|
return new MetaWhatsAppProvider(
|
||
|
|
phoneNumberIdSetting.value,
|
||
|
|
accessTokenSetting.value
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Create Twilio WhatsApp provider from settings
|
||
|
|
*/
|
||
|
|
async function createTwilioProvider(): Promise<WhatsAppProvider | null> {
|
||
|
|
const [accountSidSetting, authTokenSetting, phoneNumberSetting] = await Promise.all([
|
||
|
|
prisma.systemSettings.findUnique({
|
||
|
|
where: { key: 'whatsapp_twilio_account_sid' },
|
||
|
|
}),
|
||
|
|
prisma.systemSettings.findUnique({
|
||
|
|
where: { key: 'whatsapp_twilio_auth_token' },
|
||
|
|
}),
|
||
|
|
prisma.systemSettings.findUnique({
|
||
|
|
where: { key: 'whatsapp_twilio_phone_number' },
|
||
|
|
}),
|
||
|
|
])
|
||
|
|
|
||
|
|
if (
|
||
|
|
!accountSidSetting?.value ||
|
||
|
|
!authTokenSetting?.value ||
|
||
|
|
!phoneNumberSetting?.value
|
||
|
|
) {
|
||
|
|
console.warn('Twilio WhatsApp not fully configured')
|
||
|
|
return null
|
||
|
|
}
|
||
|
|
|
||
|
|
return new TwilioWhatsAppProvider(
|
||
|
|
accountSidSetting.value,
|
||
|
|
authTokenSetting.value,
|
||
|
|
phoneNumberSetting.value
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Check if WhatsApp is configured and available
|
||
|
|
*/
|
||
|
|
export async function isWhatsAppEnabled(): Promise<boolean> {
|
||
|
|
const provider = await getWhatsAppProvider()
|
||
|
|
return provider !== null
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get the current provider type
|
||
|
|
*/
|
||
|
|
export async function getWhatsAppProviderType(): Promise<WhatsAppProviderType | null> {
|
||
|
|
try {
|
||
|
|
const enabledSetting = await prisma.systemSettings.findUnique({
|
||
|
|
where: { key: 'whatsapp_enabled' },
|
||
|
|
})
|
||
|
|
|
||
|
|
if (enabledSetting?.value !== 'true') {
|
||
|
|
return null
|
||
|
|
}
|
||
|
|
|
||
|
|
const providerSetting = await prisma.systemSettings.findUnique({
|
||
|
|
where: { key: 'whatsapp_provider' },
|
||
|
|
})
|
||
|
|
|
||
|
|
return (providerSetting?.value || 'META') as WhatsAppProviderType
|
||
|
|
} catch {
|
||
|
|
return null
|
||
|
|
}
|
||
|
|
}
|