WIP - fix twilio functionality now that we use BFF
This commit is contained in:
@@ -31,46 +31,46 @@ export class VoiceService {
|
||||
/**
|
||||
* Get Twilio client for a tenant
|
||||
*/
|
||||
private async getTwilioClient(tenantIdOrDomain: string): Promise<{ client: Twilio.Twilio; config: TwilioConfig; tenantId: string }> {
|
||||
private async getTwilioClient(tenantId: string): Promise<{ client: Twilio.Twilio; config: TwilioConfig; tenantId: string }> {
|
||||
// Check cache first
|
||||
if (this.twilioClients.has(tenantIdOrDomain)) {
|
||||
if (this.twilioClients.has(tenantId)) {
|
||||
const centralPrisma = getCentralPrisma();
|
||||
|
||||
// Look up tenant by domain
|
||||
const domainRecord = await centralPrisma.domain.findUnique({
|
||||
where: { domain: tenantIdOrDomain },
|
||||
include: { tenant: { select: { id: true, integrationsConfig: true } } },
|
||||
// Look up tenant by ID
|
||||
const tenant = await centralPrisma.tenant.findUnique({
|
||||
where: { id: tenantId },
|
||||
select: { id: true, integrationsConfig: true },
|
||||
});
|
||||
|
||||
const config = this.getIntegrationConfig(domainRecord?.tenant?.integrationsConfig as any);
|
||||
const config = this.getIntegrationConfig(tenant?.integrationsConfig as any);
|
||||
return {
|
||||
client: this.twilioClients.get(tenantIdOrDomain),
|
||||
client: this.twilioClients.get(tenantId),
|
||||
config: config.twilio,
|
||||
tenantId: domainRecord.tenant.id
|
||||
tenantId: tenant.id
|
||||
};
|
||||
}
|
||||
|
||||
// Fetch tenant integrations config
|
||||
const centralPrisma = getCentralPrisma();
|
||||
|
||||
this.logger.log(`Looking up domain: ${tenantIdOrDomain}`);
|
||||
this.logger.log(`Looking up tenant: ${tenantId}`);
|
||||
|
||||
const domainRecord = await centralPrisma.domain.findUnique({
|
||||
where: { domain: tenantIdOrDomain },
|
||||
include: { tenant: { select: { id: true, integrationsConfig: true } } },
|
||||
const tenant = await centralPrisma.tenant.findUnique({
|
||||
where: { id: tenantId },
|
||||
select: { id: true, integrationsConfig: true },
|
||||
});
|
||||
|
||||
this.logger.log(`Domain record found: ${!!domainRecord}, Tenant: ${!!domainRecord?.tenant}, Config: ${!!domainRecord?.tenant?.integrationsConfig}`);
|
||||
this.logger.log(`Tenant found: ${!!tenant}, Config: ${!!tenant?.integrationsConfig}`);
|
||||
|
||||
if (!domainRecord?.tenant) {
|
||||
throw new Error(`Domain ${tenantIdOrDomain} not found`);
|
||||
if (!tenant) {
|
||||
throw new Error(`Tenant ${tenantId} not found`);
|
||||
}
|
||||
|
||||
if (!domainRecord.tenant.integrationsConfig) {
|
||||
if (!tenant.integrationsConfig) {
|
||||
throw new Error('Tenant integrations config not found. Please configure Twilio credentials in Settings > Integrations');
|
||||
}
|
||||
|
||||
const config = this.getIntegrationConfig(domainRecord.tenant.integrationsConfig as any);
|
||||
const config = this.getIntegrationConfig(tenant.integrationsConfig as any);
|
||||
|
||||
this.logger.log(`Config decrypted: ${!!config.twilio}, AccountSid: ${config.twilio?.accountSid?.substring(0, 10)}..., AuthToken: ${config.twilio?.authToken?.substring(0, 10)}..., Phone: ${config.twilio?.phoneNumber}`);
|
||||
|
||||
@@ -79,9 +79,9 @@ export class VoiceService {
|
||||
}
|
||||
|
||||
const client = Twilio.default(config.twilio.accountSid, config.twilio.authToken);
|
||||
this.twilioClients.set(tenantIdOrDomain, client);
|
||||
this.twilioClients.set(tenantId, client);
|
||||
|
||||
return { client, config: config.twilio, tenantId: domainRecord.tenant.id };
|
||||
return { client, config: config.twilio, tenantId: tenant.id };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,22 +105,64 @@ export class VoiceService {
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Find tenant by their configured Twilio phone number
|
||||
* Used for inbound call routing
|
||||
*/
|
||||
async findTenantByPhoneNumber(phoneNumber: string): Promise<{ tenantId: string; config: TwilioConfig } | null> {
|
||||
const centralPrisma = getCentralPrisma();
|
||||
|
||||
// Normalize phone number (remove spaces, ensure + prefix for comparison)
|
||||
const normalizedPhone = phoneNumber.replace(/\s+/g, '').replace(/^(\d)/, '+$1');
|
||||
|
||||
this.logger.log(`Looking up tenant by phone number: ${normalizedPhone}`);
|
||||
|
||||
// Get all tenants with integrations config
|
||||
const tenants = await centralPrisma.tenant.findMany({
|
||||
where: {
|
||||
integrationsConfig: { not: null },
|
||||
},
|
||||
select: { id: true, integrationsConfig: true },
|
||||
});
|
||||
|
||||
for (const tenant of tenants) {
|
||||
const config = this.getIntegrationConfig(tenant.integrationsConfig as any);
|
||||
if (config.twilio?.phoneNumber) {
|
||||
const tenantPhone = config.twilio.phoneNumber.replace(/\s+/g, '').replace(/^(\d)/, '+$1');
|
||||
if (tenantPhone === normalizedPhone) {
|
||||
this.logger.log(`Found tenant ${tenant.id} for phone number ${normalizedPhone}`);
|
||||
return { tenantId: tenant.id, config: config.twilio };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.warn(`No tenant found for phone number: ${normalizedPhone}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Twilio access token for browser Voice SDK
|
||||
*/
|
||||
async generateAccessToken(tenantDomain: string, userId: string): Promise<string> {
|
||||
const { config, tenantId } = await this.getTwilioClient(tenantDomain);
|
||||
async generateAccessToken(tenantId: string, userId: string): Promise<string> {
|
||||
const { config, tenantId: resolvedTenantId } = await this.getTwilioClient(tenantId);
|
||||
|
||||
if (!config.accountSid || !config.apiKey || !config.apiSecret) {
|
||||
throw new Error('Twilio API credentials not configured. Please add API Key and Secret in Settings > Integrations');
|
||||
}
|
||||
|
||||
// Include tenantId in the identity so we can extract it in TwiML webhooks
|
||||
// Format: tenantId:userId
|
||||
const identity = `${resolvedTenantId}:${userId}`;
|
||||
|
||||
this.logger.log(`Generating access token with identity: ${identity}`);
|
||||
this.logger.log(` Input tenantId: ${tenantId}, Resolved tenantId: ${resolvedTenantId}, userId: ${userId}`);
|
||||
|
||||
// Create an access token
|
||||
const token = new AccessToken(
|
||||
config.accountSid,
|
||||
config.apiKey,
|
||||
config.apiSecret,
|
||||
{ identity: userId, ttl: 3600 } // 1 hour expiry
|
||||
{ identity, ttl: 3600 } // 1 hour expiry
|
||||
);
|
||||
|
||||
// Create a Voice grant
|
||||
|
||||
Reference in New Issue
Block a user