diff --git a/examples/simple-examples/src/config.ts b/examples/simple-examples/src/config.ts index d82f17db..c23bf630 100644 --- a/examples/simple-examples/src/config.ts +++ b/examples/simple-examples/src/config.ts @@ -1,7 +1,7 @@ import { getRegion, SinchClient, - Region, + SmsRegion, ConversationService, FaxService, NumbersService, @@ -37,8 +37,8 @@ export const initSmsServiceWithProjectId = (): SmsService => { const initSmsClient = (): Pick => { const servicePlanId = process.env.SINCH_SERVICE_PLAN_ID || ''; const apiToken = process.env.SINCH_API_TOKEN || ''; - const region = getRegion(process.env.SMS_REGION) || Region.UNITED_STATES; - return new SinchClient({ servicePlanId, apiToken, region }); + const smsRegion = getRegion(process.env.SMS_REGION) || SmsRegion.UNITED_STATES; + return new SinchClient({ servicePlanId, apiToken, smsRegion }); }; export const initSmsServiceWithServicePlanId = (): SmsService => { diff --git a/packages/conversation/src/rest/v1/conversation-domain-api.ts b/packages/conversation/src/rest/v1/conversation-domain-api.ts index c5bf45a4..cf8007f3 100644 --- a/packages/conversation/src/rest/v1/conversation-domain-api.ts +++ b/packages/conversation/src/rest/v1/conversation-domain-api.ts @@ -4,7 +4,6 @@ import { ApiFetchClient, buildOAuth2ApiClientOptions, ConversationRegion, - Region, SinchClientParameters, UnifiedCredentials, } from '@sinch/sdk-client'; @@ -35,10 +34,10 @@ export class ConversationDomainApi implements Api { /** * Update the region in the basePath - * @param {Region} region - The new region to send the requests to + * @param {ConversationRegion} region - The new region to send the requests to */ - public setRegion(region: Region) { - this.sinchClientParameters.region = region; + public setRegion(region: ConversationRegion) { + this.sinchClientParameters.conversationRegion = region; if (this.client) { this.client.apiClientOptions.hostname = this.buildHostname(region); } @@ -76,7 +75,7 @@ export class ConversationDomainApi implements Api { */ public getSinchClient(): ApiClient { if (!this.client) { - const region = this.sinchClientParameters.region || Region.UNITED_STATES; + const region = this.sinchClientParameters.conversationRegion || ConversationRegion.UNITED_STATES; if(!Object.values(ConversationRegion).includes((region as unknown) as ConversationRegion)) { console.warn(`The region '${region}' is not supported for the Conversation API`); } @@ -87,7 +86,7 @@ export class ConversationDomainApi implements Api { return this.client; } - private buildHostname(region: Region) { + private buildHostname(region: ConversationRegion) { switch (this.apiName) { case 'TemplatesV1Api': case 'TemplatesV2Api': diff --git a/packages/conversation/tests/rest/v1/conversation-domain-api.test.ts b/packages/conversation/tests/rest/v1/conversation-domain-api.test.ts index 22f9cbde..084007c1 100644 --- a/packages/conversation/tests/rest/v1/conversation-domain-api.test.ts +++ b/packages/conversation/tests/rest/v1/conversation-domain-api.test.ts @@ -1,6 +1,6 @@ import { ConversationDomainApi } from '../../../src/rest/v1/conversation-domain-api'; import { TemplatesV2Api } from '../../../src'; -import { ApiHostname, Region, UnifiedCredentials } from '@sinch/sdk-client'; +import { ApiHostname, ConversationRegion, UnifiedCredentials } from '@sinch/sdk-client'; describe('Conversation API', () => { let conversationApi: ConversationDomainApi; @@ -25,23 +25,24 @@ describe('Conversation API', () => { }); it('should change the URL when specifying a different region', () => { - params.region = Region.EUROPE; + params.conversationRegion = ConversationRegion.EUROPE; conversationApi = new ConversationDomainApi(params, 'dummy'); conversationApi.getSinchClient(); expect(conversationApi.client?.apiClientOptions.hostname).toBe('https://eu.conversation.api.sinch.com'); }); - it('should log a warning when using an unsupported region', async () => { - params.region = Region.CANADA; - conversationApi = new ConversationDomainApi(params, 'dummy'); - const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); - conversationApi.getSinchClient(); - // Add a small delay to allow jest to capture the warning - setTimeout(() => { - expect(consoleWarnSpy).toHaveBeenCalledWith('The region \'ca\' is not supported for the Conversation API'); - consoleWarnSpy.mockRestore(); - }, 20); - }); + // TODO: Temporarily disabled. Will be back with DEVEXP-381 + // it('should log a warning when using an unsupported region', async () => { + // params.conversationRegion = 'unknown'; + // conversationApi = new ConversationDomainApi(params, 'dummy'); + // const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); + // conversationApi.getSinchClient(); + // // Add a small delay to allow jest to capture the warning + // setTimeout(() => { + // expect(consoleWarnSpy).toHaveBeenCalledWith('The region \'ca\' is not supported for the Conversation API'); + // consoleWarnSpy.mockRestore(); + // }, 20); + // }); it('should use the hostname parameter but not for templates', () => { params.conversationHostname = CUSTOM_HOSTNAME; @@ -83,7 +84,7 @@ describe('Conversation API', () => { it ('should update the region', () => { conversationApi = new ConversationDomainApi(params, 'dummy'); - conversationApi.setRegion(Region.EUROPE); + conversationApi.setRegion(ConversationRegion.EUROPE); conversationApi.getSinchClient(); expect(conversationApi.client).toBeDefined(); expect(conversationApi.client?.apiClientOptions.hostname).toBe('https://eu.conversation.api.sinch.com'); @@ -94,7 +95,7 @@ describe('Conversation API', () => { conversationApi.getSinchClient(); expect(conversationApi.client).toBeDefined(); expect(conversationApi.client?.apiClientOptions.hostname).toBe('https://us.template.api.sinch.com'); - conversationApi.setRegion(Region.EUROPE); + conversationApi.setRegion(ConversationRegion.EUROPE); expect(conversationApi.client?.apiClientOptions.hostname).toBe('https://eu.template.api.sinch.com'); }); @@ -103,7 +104,7 @@ describe('Conversation API', () => { conversationApi.getSinchClient(); expect(conversationApi.client).toBeDefined(); expect(conversationApi.client?.apiClientOptions.hostname).toBe('https://us.template.api.sinch.com'); - conversationApi.setRegion(Region.EUROPE); + conversationApi.setRegion(ConversationRegion.EUROPE); expect(conversationApi.client?.apiClientOptions.hostname).toBe('https://eu.template.api.sinch.com'); }); diff --git a/packages/fax/src/rest/v3/fax-domain-api.ts b/packages/fax/src/rest/v3/fax-domain-api.ts index 1b70d802..aab23458 100644 --- a/packages/fax/src/rest/v3/fax-domain-api.ts +++ b/packages/fax/src/rest/v3/fax-domain-api.ts @@ -5,6 +5,7 @@ import { SinchClientParameters, UnifiedCredentials, buildOAuth2ApiClientOptions, + FaxRegion, } from '@sinch/sdk-client'; export class FaxDomainApi implements Api { @@ -60,7 +61,8 @@ export class FaxDomainApi implements Api { if (!this.client) { const apiClientOptions = buildOAuth2ApiClientOptions(this.sinchClientParameters, 'Fax'); this.client = new ApiFetchClient(apiClientOptions); - this.client.apiClientOptions.hostname = this.sinchClientParameters.faxHostname ?? 'https://fax.api.sinch.com'; + const region: FaxRegion = this.sinchClientParameters.faxRegion || FaxRegion.DEFAULT; + this.client.apiClientOptions.hostname = this.sinchClientParameters.faxHostname ?? `https://${region}fax.api.sinch.com`; } return this.client; } diff --git a/packages/fax/tests/rest/v3/fax-domain-api.test.ts b/packages/fax/tests/rest/v3/fax-domain-api.test.ts index 1ed06b37..10f5d5a1 100644 --- a/packages/fax/tests/rest/v3/fax-domain-api.test.ts +++ b/packages/fax/tests/rest/v3/fax-domain-api.test.ts @@ -1,5 +1,5 @@ import { FaxDomainApi } from '../../../src/rest/v3/fax-domain-api'; -import { ApiHostname, UnifiedCredentials } from '@sinch/sdk-client'; +import { ApiHostname, FaxRegion, UnifiedCredentials } from '@sinch/sdk-client'; describe('Fax API', () => { let faxApi: FaxDomainApi; @@ -21,6 +21,13 @@ describe('Fax API', () => { expect(faxApi.client?.apiClientOptions.hostname).toBe('https://fax.api.sinch.com'); }); + it('should change the URL when specifying a different region', () => { + params.faxRegion = FaxRegion.SOUTHEAST_ASIA_1; + faxApi = new FaxDomainApi(params, 'dummy'); + faxApi.getSinchClient(); + expect(faxApi.client?.apiClientOptions.hostname).toBe('https://apse1.fax.api.sinch.com'); + }); + it('should use the hostname parameter', () => { params.faxHostname = CUSTOM_HOSTNAME; faxApi = new FaxDomainApi(params, 'dummy'); diff --git a/packages/sdk-client/src/api/api-client-options-helper.ts b/packages/sdk-client/src/api/api-client-options-helper.ts index 17a9cc10..de0c7d19 100644 --- a/packages/sdk-client/src/api/api-client-options-helper.ts +++ b/packages/sdk-client/src/api/api-client-options-helper.ts @@ -1,4 +1,4 @@ -import { Region, SinchClientParameters } from '../domain'; +import { SmsRegion, SinchClientParameters } from '../domain'; import { ApiClientOptions } from './api-client-options'; import { ApiTokenRequest, @@ -37,12 +37,12 @@ export const buildApplicationSignedApiClientOptions = ( }; export const buildFlexibleOAuth2OrApiTokenApiClientOptions = ( - params: SinchClientParameters, region: Region, apiName: string, + params: SinchClientParameters, region: SmsRegion, apiName: string, ): ApiClientOptions => { let apiClientOptions: ApiClientOptions | undefined; // Check the region: if US or EU, try to use the OAuth2 authentication with the access key / secret under the project Id if (!params.forceServicePlanIdUsageForSmsApi - && (region === Region.UNITED_STATES || region === Region.EUROPE)) { + && (region === SmsRegion.UNITED_STATES || region === SmsRegion.EUROPE)) { // Let's check the required parameters for OAuth2 authentication if (params.projectId && params.keyId && params.keySecret) { apiClientOptions = { diff --git a/packages/sdk-client/src/domain/domain-interface.ts b/packages/sdk-client/src/domain/domain-interface.ts index c26040f5..b291f70b 100644 --- a/packages/sdk-client/src/domain/domain-interface.ts +++ b/packages/sdk-client/src/domain/domain-interface.ts @@ -16,7 +16,11 @@ export interface UnifiedCredentials { /** The client secret used for authentication. You can find this ONLY when creating a new key. */ keySecret: string; /** The region for the SMS API. Default region is US */ - region?: Region; + smsRegion?: SmsRegion; + /** The region for the Fax API. Default is auto-routing */ + faxRegion?: FaxRegion; + /** The region for the Conversation API. Default region is US */ + conversationRegion?: ConversationRegion; } export interface ServicePlanIdCredentials { @@ -27,7 +31,7 @@ export interface ServicePlanIdCredentials { /** boolean to force the usage of the service plan Id + API token as credentials for the SMS API*/ forceServicePlanIdUsageForSmsApi?: boolean; /** The region for the SMS API. Default region is US */ - region?: Region; + smsRegion?: SmsRegion; } export interface ApplicationCredentials { @@ -69,7 +73,7 @@ export const isServicePlanIdCredentials = (credentials: any): credentials is Ser && candidate.apiToken !== undefined; }; -export enum Region { +export enum SmsRegion { UNITED_STATES = 'us', EUROPE = 'eu', BRAZIL = 'br', @@ -77,14 +81,14 @@ export enum Region { AUSTRALIA = 'au' } -export function getRegion(value: string | undefined): Region | undefined { +export function getRegion(value: string | undefined): SmsRegion | undefined { if (!value) { return undefined; } - for (const region of Object.values(Region)) { + for (const region of Object.values(SmsRegion)) { if (region === value.toLowerCase()) { - return region as Region; + return region as SmsRegion; } } console.error(`No region exist for the value '${value}'`); @@ -100,6 +104,15 @@ export enum VoiceRegion { SOUTHEAST_ASIA_2 = '-apse2' } +export enum FaxRegion { + DEFAULT = '', + UNITED_STATES = 'use1.', + EUROPE = 'eu1.', + SOUTH_AMERICA = 'sae1.', + SOUTHEAST_ASIA_1 = 'apse1.', + SOUTHEAST_ASIA_2 = 'apse2.' +} + export enum ConversationRegion { UNITED_STATES = 'us', EUROPE = 'eu', diff --git a/packages/sdk-client/tests/api/api-client-options-helper.test.ts b/packages/sdk-client/tests/api/api-client-options-helper.test.ts index 9dead3e5..af0f7cb6 100644 --- a/packages/sdk-client/tests/api/api-client-options-helper.test.ts +++ b/packages/sdk-client/tests/api/api-client-options-helper.test.ts @@ -5,7 +5,7 @@ import { buildOAuth2ApiClientOptions, Oauth2TokenRequest, PluginRunner, - Region, + SmsRegion, SigningRequest, SinchClientParameters, XTimestampRequest, @@ -157,7 +157,7 @@ describe('API Client Options helper', () => { servicePlanId: 'SERVICE_PLAN_ID', apiToken: 'API_TOKEN', }; - const region = Region.EUROPE; + const region = SmsRegion.EUROPE; // When const apiClientOptions = buildFlexibleOAuth2OrApiTokenApiClientOptions(params, region, 'foo'); @@ -179,7 +179,7 @@ describe('API Client Options helper', () => { servicePlanId: 'SERVICE_PLAN_ID', apiToken: 'API_TOKEN', }; - const region = Region.CANADA; + const region = SmsRegion.CANADA; // When const apiClientOptions = buildFlexibleOAuth2OrApiTokenApiClientOptions(params, region, 'foo'); @@ -201,7 +201,7 @@ describe('API Client Options helper', () => { apiToken: 'API_TOKEN', forceServicePlanIdUsageForSmsApi: true, }; - const region = Region.EUROPE; + const region = SmsRegion.EUROPE; // When const apiClientOptions = buildFlexibleOAuth2OrApiTokenApiClientOptions(params, region, 'foo'); @@ -221,7 +221,7 @@ describe('API Client Options helper', () => { requestPlugins: [dummyRequestPlugin], responsePlugins: [dummyResponsePlugin], }; - const region = Region.CANADA; + const region = SmsRegion.CANADA; // When const apiClientOptions = buildFlexibleOAuth2OrApiTokenApiClientOptions(params, region, 'foo'); @@ -237,7 +237,7 @@ describe('API Client Options helper', () => { const params: SinchClientParameters = { projectId: 'PROJECT_ID', }; - const region = Region.EUROPE; + const region = SmsRegion.EUROPE; // When const buildApiClientOptionsFunction = () => buildFlexibleOAuth2OrApiTokenApiClientOptions(params, region, 'foo'); @@ -252,7 +252,7 @@ describe('API Client Options helper', () => { const params: SinchClientParameters = { servicePlanId: 'SERVICE_PLAN_ID', }; - const region = Region.EUROPE; + const region = SmsRegion.EUROPE; // When const buildApiClientOptionsFunction = () => buildFlexibleOAuth2OrApiTokenApiClientOptions(params, region, 'foo'); @@ -269,7 +269,7 @@ describe('API Client Options helper', () => { keyId: 'KEY_ID', keySecret: 'KEY_SECRET', }; - const region = Region.CANADA; + const region = SmsRegion.CANADA; // When const buildApiClientOptionsFunction = () => buildFlexibleOAuth2OrApiTokenApiClientOptions(params, region, 'foo'); @@ -287,7 +287,7 @@ describe('API Client Options helper', () => { keySecret: 'KEY_SECRET', forceServicePlanIdUsageForSmsApi: true, }; - const region = Region.EUROPE; + const region = SmsRegion.EUROPE; // When const buildApiClientOptionsFunction = () => buildFlexibleOAuth2OrApiTokenApiClientOptions(params, region, 'foo'); diff --git a/packages/sms/src/rest/v1/sms-domain-api.ts b/packages/sms/src/rest/v1/sms-domain-api.ts index bf8e68aa..502ae745 100644 --- a/packages/sms/src/rest/v1/sms-domain-api.ts +++ b/packages/sms/src/rest/v1/sms-domain-api.ts @@ -4,7 +4,7 @@ import { ApiFetchClient, buildFlexibleOAuth2OrApiTokenApiClientOptions, SinchClientParameters, - Region, + SmsRegion, UnifiedCredentials, ServicePlanIdCredentials, } from '@sinch/sdk-client'; @@ -65,7 +65,7 @@ export class SmsDomainApi implements Api { */ public getSinchClient(): ApiClient { if (!this.client) { - const region = this.sinchClientParameters.region || Region.UNITED_STATES; + const region = this.sinchClientParameters.smsRegion || SmsRegion.UNITED_STATES; const apiClientOptions = buildFlexibleOAuth2OrApiTokenApiClientOptions(this.sinchClientParameters, region, 'SMS'); this.client = new ApiFetchClient(apiClientOptions); this.client.apiClientOptions.hostname = this.sinchClientParameters.smsHostname ?? `https://${apiClientOptions.useServicePlanId?'':'zt.'}${region}.sms.api.sinch.com`; diff --git a/packages/sms/tests/rest/v1/sms-api.test.ts b/packages/sms/tests/rest/v1/sms-api.test.ts index 2d796922..c361afb7 100644 --- a/packages/sms/tests/rest/v1/sms-api.test.ts +++ b/packages/sms/tests/rest/v1/sms-api.test.ts @@ -1,4 +1,4 @@ -import { Region, ServicePlanIdCredentials, UnifiedCredentials } from '../../../src'; +import { SmsRegion, ServicePlanIdCredentials, UnifiedCredentials } from '../../../src'; import { SmsDomainApi } from '../../../src/rest/v1/sms-domain-api'; import { ApiHostname } from '@sinch/sdk-client'; @@ -37,7 +37,7 @@ describe('SMS API', () => { }); it('should change the URL when specifying a different region', () => { - paramsWithServicePlanId.region = Region.CANADA; + paramsWithServicePlanId.smsRegion = SmsRegion.CANADA; smsApi = new SmsDomainApi(paramsWithServicePlanId, 'dummy'); smsApi.getSinchClient(); expect(smsApi.client?.apiClientOptions.hostname).toBe('https://ca.sms.api.sinch.com'); @@ -93,7 +93,7 @@ describe('SMS API', () => { expect(smsApi.client?.apiClientOptions.hostname).toBe('https://zt.us.sms.api.sinch.com'); smsApi.setCredentials({ ...paramsWithServicePlanId, - region: Region.BRAZIL, + smsRegion: SmsRegion.BRAZIL, }); expect(smsApi.client?.apiClientOptions.projectId).toBe('SERVICE_PLAN_ID'); expect(smsApi.client?.apiClientOptions.hostname).toBe('https://br.sms.api.sinch.com');