Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
ConversationRegion,
formatRegionalizedHostname,
SinchClientParameters,
SinchLogger,
SupportedConversationRegion,
UnifiedCredentials,
} from '@sinch/sdk-client';
Expand All @@ -16,10 +17,12 @@ export class ConversationDomainApi implements Api {
public readonly apiName: string;
public client?: ApiClient;
private sinchClientParameters: SinchClientParameters;
private logger: SinchLogger;

constructor(sinchClientParameters: SinchClientParameters, apiName: string) {
this.sinchClientParameters = sinchClientParameters;
this.apiName = apiName;
this.logger = new SinchLogger(sinchClientParameters.logger ?? console);
}

/**
Expand All @@ -31,7 +34,7 @@ export class ConversationDomainApi implements Api {
this.client = this.getSinchClient();
this.client.apiClientOptions.hostname = hostname;
} catch (error) {
console.error('Impossible to set a new hostname, the credentials need to be provided first.');
this.logger.error('Impossible to set a new hostname, the credentials need to be provided first.');
throw error;
}
}
Expand Down Expand Up @@ -61,7 +64,7 @@ export class ConversationDomainApi implements Api {
try {
this.getSinchClient();
} catch (error) {
console.error('Impossible to assign the new credentials to the Conversation API');
this.logger.error('Impossible to assign the new credentials to the Conversation API');
this.sinchClientParameters = parametersBackup;
throw error;
}
Expand All @@ -81,7 +84,7 @@ export class ConversationDomainApi implements Api {
if (!this.client) {
const region = this.sinchClientParameters.conversationRegion ?? ConversationRegion.UNITED_STATES;
if(!Object.values(SupportedConversationRegion).includes(region as SupportedConversationRegion)) {
console.warn(`The region "${region}" is not known as a supported region for the Conversation API`);
this.logger.warn(`The region "${region}" is not known as a supported region for the Conversation API`);
}
const apiClientOptions = buildOAuth2ApiClientOptions(this.sinchClientParameters, 'Conversation');
this.client = new ApiFetchClient(apiClientOptions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ describe('Conversation API', () => {
conversationApi = new ConversationDomainApi(params, 'dummy');
console.warn = jest.fn();
conversationApi.getSinchClient();
expect(console.warn).toHaveBeenCalledWith(
'The region "bzh" is not known as a supported region for the Conversation API');
expect(console.warn).toHaveBeenCalledWith('[Sinch SDK][Warn] '
+ 'The region "bzh" is not known as a supported region for the Conversation API');
expect(conversationApi.client?.apiClientOptions.hostname).toBe('https://bzh.conversation.api.sinch.com');
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,20 @@ import {
buildOAuth2ApiClientOptions,
ELASTIC_SIP_TRUNKING_HOSTNAME,
SinchClientParameters,
SinchLogger,
UnifiedCredentials,
} from '@sinch/sdk-client';

export class ElasticSipTrunkingDomainApi implements Api {
public readonly apiName: string;
public client?: ApiClient;
private sinchClientParameters: SinchClientParameters;
private logger: SinchLogger;

constructor(sinchClientParameters: SinchClientParameters, apiName: string) {
this.sinchClientParameters = sinchClientParameters;
this.apiName = apiName;
this.logger = new SinchLogger(sinchClientParameters.logger ?? console);
}

/**
Expand All @@ -41,7 +44,7 @@ export class ElasticSipTrunkingDomainApi implements Api {
try {
this.getSinchClient();
} catch (error) {
console.error('Impossible to assign the new credentials to the Elastic SIP Trunking API');
this.logger.error('Impossible to assign the new credentials to the Elastic SIP Trunking API');
this.sinchClientParameters = parametersBackup;
throw error;
}
Expand Down
3 changes: 1 addition & 2 deletions packages/fax/src/rest/v3/callbacks/callbacks-webhook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ export class FaxCallbackWebhooks implements CallbackProcessor<FaxWebhookEventPar
throw new Error(`Unknown Fax event: ${eventBody.event}`);
}
}
console.log(eventBody);
throw new Error('Unknown Fax event');
throw new Error(`Unknown Fax event: ${JSON.stringify(eventBody)}`);
}

private reviveFax(faxAsString: string): Fax {
Expand Down
7 changes: 5 additions & 2 deletions packages/fax/src/rest/v3/fax-domain-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
FaxRegion,
formatRegionalizedHostname,
SinchClientParameters,
SinchLogger,
SupportedFaxRegion,
UnifiedCredentials,
} from '@sinch/sdk-client';
Expand All @@ -15,10 +16,12 @@ export class FaxDomainApi implements Api {
public readonly apiName: string;
public client?: ApiClient;
private sinchClientParameters: SinchClientParameters;
private logger: SinchLogger;

constructor(sinchClientParameters: SinchClientParameters, apiName: string) {
this.sinchClientParameters = sinchClientParameters;
this.apiName = apiName;
this.logger = new SinchLogger(sinchClientParameters.logger ?? console);
}

/**
Expand Down Expand Up @@ -55,7 +58,7 @@ export class FaxDomainApi implements Api {
try {
this.getSinchClient();
} catch (error) {
console.error('Impossible to assign the new credentials to the Fax API');
this.logger.error('Impossible to assign the new credentials to the Fax API');
this.sinchClientParameters = parametersBackup;
throw error;
}
Expand All @@ -77,7 +80,7 @@ export class FaxDomainApi implements Api {
this.client = new ApiFetchClient(apiClientOptions);
const region = this.sinchClientParameters.faxRegion ?? FaxRegion.DEFAULT;
if(!Object.values(SupportedFaxRegion).includes(region as SupportedFaxRegion)) {
console.warn(`The region "${region}" is not known as a supported region for the Fax API`);
this.logger.warn(`The region "${region}" is not known as a supported region for the Fax API`);
}
this.client.apiClientOptions.hostname = this.sinchClientParameters.faxHostname ?? this.buildHostname(region);
}
Expand Down
4 changes: 2 additions & 2 deletions packages/fax/tests/rest/v3/fax-domain-api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ describe('Fax API', () => {
faxApi = new FaxDomainApi(params, 'dummy');
console.warn = jest.fn();
faxApi.getSinchClient();
expect(console.warn).toHaveBeenCalledWith(
'The region "bzh" is not known as a supported region for the Fax API');
expect(console.warn).toHaveBeenCalledWith('[Sinch SDK][Warn] '
+ 'The region "bzh" is not known as a supported region for the Fax API');
expect(faxApi.client?.apiClientOptions.hostname).toBe('https://bzh.fax.api.sinch.com');
});

Expand Down
5 changes: 4 additions & 1 deletion packages/numbers/src/rest/v1/numbers-domain-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,20 @@ import {
buildOAuth2ApiClientOptions,
NUMBERS_HOSTNAME,
SinchClientParameters,
SinchLogger,
UnifiedCredentials,
} from '@sinch/sdk-client';

export class NumbersDomainApi implements Api {
public readonly apiName: string;
public client?: ApiClient;
private sinchClientParameters: SinchClientParameters;
private logger: SinchLogger;

constructor(sinchClientParameters: SinchClientParameters, apiName: string) {
this.sinchClientParameters = sinchClientParameters;
this.apiName = apiName;
this.logger = new SinchLogger(sinchClientParameters.logger ?? console);
}

/**
Expand All @@ -41,7 +44,7 @@ export class NumbersDomainApi implements Api {
try {
this.getSinchClient();
} catch (error) {
console.error('Impossible to assign the new credentials to the Numbers API');
this.logger.error('Impossible to assign the new credentials to the Numbers API');
this.sinchClientParameters = parametersBackup;
throw error;
}
Expand Down
17 changes: 14 additions & 3 deletions packages/sdk-client/src/api/api-client-options-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,20 @@ import {
SigningRequest,
XTimestampRequest,
} from '../plugins';
import { SinchLogger } from '../logger';
import * as console from 'node:console';

export const buildOAuth2ApiClientOptions = (params: SinchClientParameters, apiName: string): ApiClientOptions => {
if (!params.projectId || !params.keyId || !params.keySecret) {
throw new Error(`Invalid configuration for the ${apiName} API: "projectId", "keyId" and "keySecret" values must be provided`);
}
const apiClientOptions: ApiClientOptions = {
projectId: params.projectId,
requestPlugins: [new Oauth2TokenRequest(params.keyId, params.keySecret, params.authHostname)],
requestPlugins: [
new Oauth2TokenRequest(params.keyId, params.keySecret, params.authHostname, params.logger),
],
useServicePlanId: false,
logger: params.logger,
};
addPlugins(apiClientOptions, params);
return apiClientOptions;
Expand All @@ -31,6 +36,7 @@ export const buildApplicationSignedApiClientOptions = (
new XTimestampRequest(),
new SigningRequest(params.applicationKey, params.applicationSecret),
],
logger: params.logger,
};
addPlugins(apiClientOptions, params);
return apiClientOptions;
Expand All @@ -44,15 +50,20 @@ export const buildFlexibleOAuth2OrApiTokenApiClientOptions = (params: SinchClien
projectId: params.servicePlanId,
requestPlugins: [new ApiTokenRequest(params.apiToken)],
useServicePlanId: true,
logger: params.logger,
};
if (params.projectId || params.keyId || params.keySecret) {
console.warn('As the servicePlanId and the apiToken are provided, all other credentials will be disregarded.');
new SinchLogger(params.logger ?? console).warn(
'As the servicePlanId and the apiToken are provided, all other credentials will be disregarded.');
}
} else if (params.projectId && params.keyId && params.keySecret) {
apiClientOptions = {
projectId: params.projectId,
requestPlugins: [new Oauth2TokenRequest(params.keyId, params.keySecret, params.authHostname)],
requestPlugins: [
new Oauth2TokenRequest(params.keyId, params.keySecret, params.authHostname, params.logger),
],
useServicePlanId: false,
logger: params.logger,
};
}
if (!apiClientOptions) {
Expand Down
3 changes: 2 additions & 1 deletion packages/sdk-client/src/api/api-client-options.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { RequestPlugin } from '../plugins/core/request-plugin';
import { ResponsePlugin } from '../plugins/core/response-plugin';
import { LoggerParameters } from '../domain';

interface BaseApiClientOptions {
/**
Expand Down Expand Up @@ -30,4 +31,4 @@ interface BaseApiClientOptions {
useServicePlanId?: boolean;
}

export interface ApiClientOptions extends Partial<BaseApiClientOptions> {}
export interface ApiClientOptions extends Partial<BaseApiClientOptions>, LoggerParameters {}
1 change: 1 addition & 0 deletions packages/sdk-client/src/api/api-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ export class ApiClient {
opts = await plugin.load().transform(opts);
}
}
opts.logger = this.apiClientOptions.logger;

return opts;
};
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk-client/src/api/api-errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export class GenericError extends Error {
const baseUrl = GenericError.formatUrl(errorContext.url);
const origin = GenericError.formatUrl(errorContext.origin);
super(
`[SDK] [apiName: ${errorContext.apiName || 'unknown'}]
`[apiName: ${errorContext.apiName || 'unknown'}]
[operationId: ${errorContext.operationId || 'unknown'}]
[baseUrl: ${baseUrl}] [origin: ${origin}] [errorType: SDK] ${message}`,
);
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk-client/src/client/api-fetch-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export class ApiFetchClient extends ApiClient {
...options,
requestPlugins: [new VersionRequest(), ...(options.requestPlugins || [])],
responsePlugins: [
new ExceptionResponse(),
new ExceptionResponse(undefined, options.logger),
...(options.responsePlugins || []),
],
});
Expand Down
9 changes: 8 additions & 1 deletion packages/sdk-client/src/domain/domain-interface.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { RequestPlugin } from '../plugins/core/request-plugin';
import { ResponsePlugin } from '../plugins/core/response-plugin';
import { Logger } from '../logger';

/**
* Global object that holds the API configuration.
Expand All @@ -13,7 +14,8 @@ export interface SinchClientParameters extends
Partial<ServicePlanIdCredentials>,
Partial<ApplicationCredentials>,
ApiHostname,
ApiPlugins {}
ApiPlugins,
LoggerParameters {}

export interface UnifiedCredentials {
/** The project ID associated with the API Client. You can find this on your [Dashboard](https://dashboard.sinch.com/account/access-keys). */
Expand Down Expand Up @@ -158,3 +160,8 @@ export type ConversationRegion = SupportedConversationRegion | string;
export const ConversationRegion = {
...SupportedConversationRegion,
};

export interface LoggerParameters {
/** Logger instance to be used by the SDK */
logger?: Logger;
}
1 change: 1 addition & 0 deletions packages/sdk-client/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './api';
export * from './client';
export * from './domain';
export * from './logger';
export * from './plugins';
export * from './utils';
1 change: 1 addition & 0 deletions packages/sdk-client/src/logger/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './logger';
27 changes: 27 additions & 0 deletions packages/sdk-client/src/logger/logger.ts

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️
May be adding some unit tests to ensure proper/format and log level.
Not sure we want to go to this direction for console logger and this PR, but other logging frameworks (e.g.: winston pointed by PR comment) are enabling to configure log level to not flood logs output/destination

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
export interface Logger {
debug(message: string, ...meta: any[]): void;
info(message: string, ...meta: any[]): void;
warn(message: string, ...meta: any[]): void;
error(message: string, ...meta: any[]): void;
}

export class SinchLogger implements Logger {
constructor(private baseLogger: Logger) {}

private format(level: string, message: string): string {
return `[Sinch SDK][${level}] ${message}`;
}

debug(message: string, ...meta: any[]): void {
this.baseLogger.debug(this.format('Debug', message), ...meta);
}
info(message: string, ...meta: any[]): void {
this.baseLogger.info(this.format('Info', message), ...meta);
}
warn(message: string, ...meta: any[]): void {
this.baseLogger.warn(this.format('Warn', message), ...meta);
}
error(message: string, ...meta: any[]): void {
this.baseLogger.error(this.format('Error', message), ...meta);
}
}
3 changes: 2 additions & 1 deletion packages/sdk-client/src/plugins/core/request-plugin.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Plugin, PluginRunner } from './plugin';
import { Headers, RequestInit } from 'node-fetch';
import FormData = require('form-data');
import { LoggerParameters } from '../../domain';

export type RequestBody = string | FormData;

Expand All @@ -14,7 +15,7 @@ export enum RequestPluginEnum {
X_TIMESTAMP_REQUEST = 'XTimestampRequest'
}

export interface RequestOptions extends RequestInit {
export interface RequestOptions extends RequestInit, LoggerParameters {
/** Query Parameters */
queryParams?: { [key: string]: string };
/** Force body to string */
Expand Down
Loading
Loading