Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/Elastic SIP Trunking #73

Merged
merged 5 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
21 changes: 12 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ import {

const sinch = new SinchClient(sinchClientParameters);
const conversationService = sinch.conversation;
const elasticSipTrunkingService = sinch.elasticSipTrunking;
const faxService = sinch.fax;
const numbersService = sinch.numbers;
const smsService = sinch.sms;
Expand Down Expand Up @@ -135,14 +136,15 @@ console.log(`The SMS has been sent successfully. Here is the batch id: ${respons

Here is the list of the Sinch products and their level of support by the Node.js SDK:

| API Category | API Name | Status |
|------------------------|------------------|:------:|
| Messaging | SMS API | ✅ |
| | Conversation API | ✅ |
| | Fax API | ✅ |
| Voice and Video | Voice API | ✅ |
| Numbers & Connectivity | Numbers API | ✅ |
| Verification | Verification API | ✅ |
| API Category | API Name | Status |
|------------------------|---------------------------------|:------:|
| Messaging | SMS API | ✅ |
| | Conversation API | ✅ |
| | Fax API | ✅ |
| Voice and Video | Voice API | ✅ |
| | Elastic SIP Trunking API (beta) | ✅ |
| Numbers & Connectivity | Numbers API | ✅ |
| Verification | Verification API | ✅ |

### Packages

Expand All @@ -153,7 +155,8 @@ The Sinch Node.js SDK is packaged in the following way:
- [`@sinch/voice`](./packages/voice): package that contains the Voice services: Callouts, Calls, Conferences, Applications management and Webhooks callbacks.
- [`@sinch/numbers`](./packages/numbers): package that contains the Numbers services: Available number, Active number, Available regions, Callbacks management and Webhooks callbacks.
- [`@sinch/verification`](./packages/verification): package that contains the Verification services: Verification start and report, Verification status and Webhooks callbacks.
- [`@sinch/fax`](./packages/fax): package that contains the Fax services: Services, Faxes and Faxes-on-emails
- [`@sinch/fax`](./packages/fax): package that contains the Fax services: Services, Faxes and Faxes-on-emails.
- [`@sinch/elastic-sip-trunking`](./packages/elastic-sip-trunking): package that contains the Elastic SIP Trunking services: SIP Trunks, Access Control List, SIP Endpoints, Country Permissions, Phones Numbers and Calls.
- [`@sinch/sdk-client`](./packages/sdk-client): package included by all the other ones that contains the API client classes and helpers.

## Examples
Expand Down
5 changes: 5 additions & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ const config: Config.InitialOptions = {
testMatch: ['<rootDir>/packages/conversation/tests/**/*.test.ts'],
coveragePathIgnorePatterns: ['node_modules', 'tests'],
},
{
displayName: 'Elastic SIP Trunking',
testMatch: ['<rootDir>/packages/elastic-sip-trunking/tests/**/*.test.ts'],
coveragePathIgnorePatterns: ['node_modules', 'tests'],
},
{
displayName: 'Fax',
testMatch: ['<rootDir>/packages/fax/tests/**/*.test.ts'],
Expand Down
8 changes: 8 additions & 0 deletions packages/elastic-sip-trunking/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Version 1.1.0
- Initial version. Support for:
- SIP Trunks
- Access Control List
- SIP Endpoints
- Country Permissions
- Phone Numbers
- Calls
121 changes: 121 additions & 0 deletions packages/elastic-sip-trunking/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Sinch Elastic SIP Trunking SDK for Node.js

This package contains the Sinch Elastic SIP Trunking SDK for Node.js for use with [Sinch APIs](https://developers.sinch.com/). To use it, you will need a Sinch account. Please [sign up](https://dashboard.sinch.com/signup) or [log in](https://dashboard.sinch.com/login) if you already have one.

## Installation

We recommend to use this SDK as part of the `@sinch/sdk-core` package as it will take care about the authentication plugins to use.

However, it's still possible to use this SDK standalone is you need to access the Elastic SIP Trunking API only.

### With NPM

```bash
npm install @sinch/elastic-sip-trunking
```

### With Yarn

```bash
yarn add @sinch/elastic-sip-trunking
```

## Usage

### Credentials

The `Elastic SIP Trunking` API uses the Sinch unified authentication with OAuth2. You will need to provide the following credentials:
- projectId: can be found in the [Account Dashboard](https://dashboard.sinch.com/settings/access-keys)
- keyId:: can be found in your Access key list in the [Account Dashboard](https://dashboard.sinch.com/settings/access-keys)
- keySecret: can be found **ONLY** when generating a new access key: keep it safe!

### As part of the Sinch SDK
JPPortier marked this conversation as resolved.
Show resolved Hide resolved

If you are using this SDK as part of the Sinch SDK (`@sinch/sdk-core`) you can access it as the `elasticSipTrunking` property of the client that you would have instantiated.

```typescript
import {
ElasticSipTrunkingService,
ElasticSipTrunking,
SinchClient,
UnifiedCredentials,
} from '@sinch/sdk-core';

const credentials: UnifiedCredentials = {
projectId: 'PROJECT_ID',
keyId: 'KEY_ID',
keySecret: 'KEY_SECRET',
};

// Access the 'elasticSipTrunking' service registered on the Sinch Client
const sinch = new SinchClient(credentials);
const elasticSipTrunkingService: ElasticSipTrunkingService = sinch.elasticSipTrunking;

// Build the request data
const requestData: ElasticSipTrunking.CreateSipTrunkRequestData = {
createSipTrunkRequestBody: {
name: 'Acme Trunk',
hostName: 'acme-domain-1',
}
};

// Use the 'elasticSipTrunking' service registered on the Sinch Client
const result = await sinch.elasticSipTrunking.sipTrunks.create(requestData);
```

### Standalone

The SDK can be used standalone if you need to use only the Elastic SIP Trunking APIs.

```typescript
import {
UnifiedCredentials,
} from '@sinch/sdk-client';
import {
ElasticSipTrunkingService,
ElasticSipTrunking,
} from '@sinch/elastic-sip-trunking';

const credentials: UnifiedCredentials = {
projectId: 'PROJECT_ID',
keyId: 'KEY_ID',
keySecret: 'KEY_SECRET',
};

// Declare the 'elasticSipTrunking' service in a standalone way
const elasticSipTrunkingService = new ElasticSipTrunkingService(options);

// Build the request data
const requestData: ElasticSipTrunking.CreateSipTrunkRequestData = {
createSipTrunkRequestBody: {
name: 'Acme Trunk',
hostName: 'acme-domain-1',
}
};

// Use the standalone declaration of the 'elasticSipTrunking' service
const result = await elasticSipTrunkingService.sipTrunks.create(requestData);
```

## Promises

All the methods that interact with the Sinch APIs use Promises. You can use `await` in an `async` method to wait for the response or you can resolve them yourself with `then()` / `catch()`.

```typescript
// Method 1: Wait for the Promise to complete
let result: ElasticSipTrunking.SipTrunk;
try {
result = await elasticSipTrunkingService.sipTrunks.create(requestData);
console.log(`SIP trunk successfully created at '${response.createTime.toISOString()}' with the id '${response.id}'`);
} catch (error: any) {
console.error(`ERROR ${error.statusCode}: Impossible to create a SIP Trunk with the hostname '${requestData.hostName}'`);
}

// Method 2: Resolve the promise
elasticSipTrunkingService.sipTrunks.create(requestData)
.then(response => console.log(`SIP trunk successfully created at '${response.createTime.toISOString()}' with the id '${response.id}'`))
.catch(error => console.error(`ERROR ${error.statusCode}: Impossible to create a SIP Trunk with the hostname '${requestData.hostName}'`));
```

## Contact
Developer Experience team: [[email protected]](mailto:[email protected])
36 changes: 36 additions & 0 deletions packages/elastic-sip-trunking/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "@sinch/elastic-sip-trunking",
"version": "1.1.0",
"description": "Sinch Elastic SIP Trunking API",
"homepage": "",
"repository": {
"type": "git"
},
"license": "Apache-2.0",
"author": "Sinch",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.js",
"require": "./dist/index.js"
}
},
"directories": {
"src": "dist",
"test": "tests"
},
"files": ["/dist"],
"scripts": {
"build": "yarn run clean && yarn run compile",
"clean": "rimraf dist tsconfig.tsbuildinfo tsconfig.build.tsbuildinfo",
"compile": "tsc -p tsconfig.build.json && tsc -p tsconfig.tests.json && rimraf dist/tests tsconfig.build.tsbuildinfo"
},
"dependencies": {
"@sinch/sdk-client": "^1.0.0"
},
"devDependencies": {},
"publishConfig": {
"directory": "dist"
}
}
2 changes: 2 additions & 0 deletions packages/elastic-sip-trunking/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './rest';
export * from '@sinch/sdk-client';
1 change: 1 addition & 0 deletions packages/elastic-sip-trunking/src/rest/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './v1';
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import {
Api,
ApiClient,
ApiFetchClient,
buildOAuth2ApiClientOptions,
SinchClientParameters,
UnifiedCredentials,
} from '@sinch/sdk-client';

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

constructor(sinchClientParameters: SinchClientParameters, apiName: string) {
this.sinchClientParameters = sinchClientParameters;
this.apiName = apiName;
}

/**
* Update the default hostname for the API
* @param {string} hostname - The new hostname to use for the APIs.
*/
public setHostname(hostname: string) {
this.client = this.getSinchClient();
this.client.apiClientOptions.hostname = hostname;
}

/**
* Updates the credentials used to authenticate API requests
* @param {UnifiedCredentials} credentials
*/
public setCredentials(credentials: UnifiedCredentials) {
const parametersBackup = { ...this.sinchClientParameters };
this.sinchClientParameters = {
...parametersBackup,
...credentials,
};
this.resetApiClient();
try {
this.getSinchClient();
} catch (error) {
console.error('Impossible to assign the new credentials to the Elastic SIP Trunking API');
this.sinchClientParameters = parametersBackup;
throw error;
}
}

private resetApiClient() {
this.client = undefined;
}

/**
* Checks the configuration parameters are ok and initialize the API client. Once initialized, the same instance will
* be returned for the subsequent API calls (singleton pattern)
* @return {ApiClient} the API Client or throws an error in case the configuration parameters are not ok
* @private
*/
public getSinchClient(): ApiClient {
if (!this.client) {
const apiClientOptions = buildOAuth2ApiClientOptions(this.sinchClientParameters, 'Elastic SIP Trunking');
this.client = new ApiFetchClient(apiClientOptions);
this.client.apiClientOptions.hostname = this.sinchClientParameters.elasticSipTrunkingHostname ?? 'https://elastic-trunking.api.sinch.com';
}
return this.client;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { SinchClientParameters } from '@sinch/sdk-client';

export class ElasticSipTrunkingService {

// eslint-disable-next-line @typescript-eslint/no-unused-vars
constructor(_params: SinchClientParameters) {

}

/**
* Update the default basePath for each API
*
* @param {string} _basePath - The new base path to use for all the APIs.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public setBasePath(_basePath: string) {

}
}
1 change: 1 addition & 0 deletions packages/elastic-sip-trunking/src/rest/v1/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './elastic-sip-trunking-service';
17 changes: 17 additions & 0 deletions packages/elastic-sip-trunking/tsconfig.build.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"extends": "../../tsconfig.json",

"compilerOptions": {
"rootDir": "src",
"outDir": "dist"
},

"include": ["src/**/*.ts"],
"exclude": ["node_modules", "dist"],

"references": [{ "path": "../sdk-client" }],

"ts-node": {
"esm": true
}
}
11 changes: 11 additions & 0 deletions packages/elastic-sip-trunking/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "../../tsconfig.json",
"references": [
{
"path": "tsconfig.build.json"
},
{
"path": "tsconfig.tests.json"
}
]
}
17 changes: 17 additions & 0 deletions packages/elastic-sip-trunking/tsconfig.tests.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"extends": "../../tsconfig.json",

"compilerOptions": {
"rootDir": ".",
"outDir": "dist/tests"
},

"include": ["src/**/*.ts", "tests/**/*.ts"],
"exclude": ["node_modules", "dist"],

"references": [{ "path": "../sdk-client" }],

"ts-node": {
"esm": true
}
}
5 changes: 5 additions & 0 deletions packages/sdk-client/src/api/api-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ import FormData = require('form-data');

export enum PaginationEnum {

Choose a reason for hiding this comment

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

May be having such list + naming + comment + dedicated field names variation processing is highlighting a design to be improved: is it possible to have something like

  • a common interface definition/abstraction (avoiding dedicated payload names)
  • each domain is implementing it own real data to data abstraction service

And, because at domain level, it won't "hurt" to have domain logic moved from generic client to dedicated domain

NONE,
/** Used by the Numbers API */
TOKEN,
/** used by the SMS API */
PAGE,
/** used by the Elastic SIP Trunking API */
PAGE2,
/** used by the Fax API */
PAGE3
}
export interface ApiListPromise<T> extends Promise<PageResult<T>>, AsyncIterableIterator<T> {
Expand Down
Loading
Loading