Skip to content

Commit

Permalink
update express-texml-call-mask to Typescript (#28)
Browse files Browse the repository at this point in the history
* update express-texml-call-mask to Typescript

* update phone numbers table example

* use texml translator

* update package deps
  • Loading branch information
lucasassisrosa authored Oct 21, 2024
1 parent e28d961 commit af866e0
Show file tree
Hide file tree
Showing 17 changed files with 2,961 additions and 6,557 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/express-texml-call-mask.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: CI express-texml-call-mask

on:
push:
branches: [master]
paths:
- "express-texml-call-mask/**"
pull_request:
branches: [master]
paths:
- "express-texml-call-mask/**"

jobs:
type-check:
runs-on: ubuntu-latest
defaults:
run:
working-directory: express-texml-call-mask
strategy:
matrix:
node-version: [18.x, 20.x, 22.x]

steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run type-check
9 changes: 9 additions & 0 deletions express-texml-call-mask/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = {
parserOptions: {
ecmaVersion: 6,
},
rules: {
'new-cap': 'off',
'no-console': 'off',
},
};
1 change: 1 addition & 0 deletions express-texml-call-mask/.nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
20.17.0
2 changes: 2 additions & 0 deletions express-texml-call-mask/.tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
nodejs 20.17.0
npm 10.8.1
53 changes: 25 additions & 28 deletions express-texml-call-mask/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Sample application demonstrating Telnyx-Node Call Mask with TeXML

## Documentation & Tutorial

The full documentation and tutorial is available on [developers.telnyx.com](https://developers.telnyx.com/docs/v2/development/dev-env-setup?lang=node&utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link)
The full documentation and tutorial is available on [developers.telnyx.com](https://developers.telnyx.com/docs/development?lang=node&utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link#developer-setup)

## Diagram

Expand All @@ -20,30 +20,29 @@ The full documentation and tutorial is available on [developers.telnyx.com](http

You will need to set up:

* [Telnyx Account](https://telnyx.com/sign-up?utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link)
* [Telnyx Phone Number](https://portal.telnyx.com/#/app/numbers/my-numbers?utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link) enabled with:
* [Telnyx TeXML Application](https://developers.telnyx.com/docs/v2/call-control/texml-setup)
* [Telnyx Outbound Voice Profile](https://portal.telnyx.com/#/app/outbound-profiles?utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link)
* Ability to receive webhooks (with something like [ngrok](https://developers.telnyx.com/docs/v2/development/ngrok?utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link))
* [Node & NPM](https://developers.telnyx.com/docs/v2/development/dev-env-setup?lang=node&utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link) installed

- [Telnyx Account](https://telnyx.com/sign-up?utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link)
- [Telnyx Phone Number](https://portal.telnyx.com/#/app/numbers/my-numbers?utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link) enabled with:
- [Telnyx TeXML Application](https://developers.telnyx.com/docs/voice/programmable-voice/texml-setup)
- [Telnyx Outbound Voice Profile](https://portal.telnyx.com/#/app/outbound-profiles?utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link)
- Ability to receive webhooks (with something like [ngrok](https://developers.telnyx.com/docs/development?utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link#ngrok-setup))
- [Node & NPM](https://developers.telnyx.com/docs/development?lang=node&utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link#developer-setup) installed

## What you can do

* Call into your Telnyx Number
* Enter digits of the desired number to call
* Be forwarded to that number
- Call into your Telnyx Number
- Enter digits of the desired number to call
- Be forwarded to that number

## Usage

The following environmental variables need to be set

| Variable | Description |
|:------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------|
| `TELNYX_API_KEY` | Your [Telnyx API Key](https://portal.telnyx.com/#/app/api-keys?utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link) |
| `TELNYX_PUBLIC_KEY` | Your [Telnyx Public Key](https://portal.telnyx.com/#/app/account/public-key?utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link) |
| `PORT` | **Defaults to `8000`** The port the app will be served |
| `TELNYX_CONNECTION_ID` | The ID of the [**TeXML** call-control-connection](https://portal.telnyx.com/#/app/call-control/texml) to use for placing the calls |
| Variable | Description |
| :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `TELNYX_API_KEY` | Your [Telnyx API Key](https://portal.telnyx.com/#/app/api-keys?utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link) |
| `TELNYX_PUBLIC_KEY` | Your [Telnyx Public Key](https://portal.telnyx.com/#/app/account/public-key?utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link) |
| `PORT` | **Defaults to `8000`** The port the app will be served |
| `TELNYX_CONNECTION_ID` | The ID of the [**TeXML** call-control-connection](https://portal.telnyx.com/#/app/call-control/texml) to use for placing the calls |

### .env file

Expand All @@ -60,9 +59,9 @@ TELNYX_CONNECTION_ID=1494404757140276705

### Callback URLs For Telnyx Applications

| Callback Type | URL |
|:--------------------------------------|:----------------------------------------------------------------------|
| Inbound Call-Control Status Callback | `{ngrok-url}/dtmfDial/inbound` |
| Callback Type | URL |
| :----------------------------------- | :----------------------------- |
| Inbound Call-Control Status Callback | `{ngrok-url}/dtmfDial/inbound` |

### Install

Expand All @@ -82,7 +81,7 @@ Adding `app.use(express.urlencoded({ extended: true }));` to the application all

### Ngrok

This application is served on the port defined in the runtime environment (or in the `.env` file). Be sure to launch [ngrok](https://developers.telnyx.com/docs/v2/development/ngrok?utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link) for that port
This application is served on the port defined in the runtime environment (or in the `.env` file). Be sure to launch [ngrok](https://developers.telnyx.com/docs/development?utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link#ngrok-setup) for that port

```
./ngrok http 8000
Expand All @@ -105,27 +104,25 @@ Connections ttl opn rt1 rt5 p50 p90
0 0 0.00 0.00 0.00 0.00
```

At this point you can point your application to generated ngrok URL + path (Example: `http://{your-url}.ngrok.io/texml/answer`).
At this point you can point your application to generated ngrok URL + path (Example: `http://{your-url}.ngrok.io/texml/answer`).

### Setup & Run

#### Create a database

Edit the [`models/phoneNumberTable.json`](models/phoneNumberTable.json) file to fill in:

* Your Cell Phone Number(s)
* Your Telnyx Phone Number
- Your Cell Phone Number(s)
- Your Telnyx Phone Number

#### Start the Server

Start the server `node index.js`
Start the server `npm run start`

When you are able to run the server locally, the final step involves making your application accessible from the internet. So far, we've set up a local web server. This is typically not accessible from the public internet, making testing inbound requests to web applications difficult.

The best workaround is a tunneling service. They come with client software that runs on your computer and opens an outgoing permanent connection to a publicly available server in a data center. Then, they assign a public URL (typically on a random or custom subdomain) on that server to your account. The public server acts as a proxy that accepts incoming connections to your URL, forwards (tunnels) them through the already established connection and sends them to the local web server as if they originated from the same machine. The most popular tunneling tool is `ngrok`. Check out the [ngrok setup](https://developers.telnyx.com/docs/v2/development/ngrok) walkthrough to set it up on your computer and start receiving webhooks from inbound messages to your newly created application.

Once you've set up `ngrok` or another tunneling service you can add the public proxy URL to your Inbound Settings in the Mission Control Portal. To do this, click the edit symbol [] next to your [TeXML Applications](https://portal.telnyx.com/#/app/call-control/texml). In the "Inbound Settings" > "Webhook URL" field, paste the forwarding address from ngrok into the Webhook URL field. Add `texml/inbound` to the end of the URL to direct the request to the webhook endpoint in your server.
Once you've set up `ngrok` or another tunneling service you can add the public proxy URL to your Inbound Settings in the Mission Control Portal. To do this, click the edit symbol [] next to your [TeXML Applications](https://portal.telnyx.com/#/app/call-control/texml). In the "Inbound Settings" > "Webhook URL" field, paste the forwarding address from ngrok into the Webhook URL field. Add `texml/inbound` to the end of the URL to direct the request to the webhook endpoint in your server.

For now you'll leave “Failover URL” blank, but if you'd like to have Telnyx resend the webhook in the case where sending to the Webhook URL fails, you can specify an alternate address in this field.


83 changes: 0 additions & 83 deletions express-texml-call-mask/controllers/dtmfDialController.js

This file was deleted.

69 changes: 69 additions & 0 deletions express-texml-call-mask/controllers/dtmfDialController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import express from "express";
import Telnyx from "telnyx";
import * as db from "../models/db";
import * as texml from "../packages/texml";

const router = express.Router();

type TelnyxTexmlTranslatorGatherCallback = {
AccountSid: string;
CallSid: string;
CallSidLegacy: string;
Digits: string;
From: string;
To: string;
};

router
.route("/inbound")
.post<{}, unknown, Telnyx.events.CallEvent>(async (req, res) => {
const gatherSentence =
"Hello, please enter the phone number with country code you would like to dial followed by the pound sign";
const event = req.body;
console.log(event);

res.type("application/xml");
res.send(texml.gatherTeXML(gatherSentence, "#", 10, 15));
});

router
.route("/gather")
.post<{}, unknown, TelnyxTexmlTranslatorGatherCallback>(async (req, res) => {
const event = req.body;
console.log(event);
const phoneNumber = event.Digits;
const userRecord = db.lookupUserByPSTNPhoneNumber(event.From);

// Connect inbound caller to conf
// Create outbound dial to desired PSTN number
// when that call answers, add to conf
// save conf-id
// every {duration} play audio to conf-id

res.type("application/xml");
res.send(
texml.dialTeXML(
`${userRecord?.telnyxPhoneNumber}`,
"/dialFinished",
"POST",
"record-from-answer-dual",
"recordFinished",
`+${phoneNumber}`
)
);
});

router.route("/dialFinished").post(async (req, res) => {
const event = req.body;
console.log(event);
res.sendStatus(200);
});

router.route("/recordFinished").post(async (req, res) => {
const event = req.body;
console.log(event);
res.type("application/xml");
res.send(texml.hangupTeXML("Thank you for the call, hanging up"));
});

export default router;
18 changes: 0 additions & 18 deletions express-texml-call-mask/index.js

This file was deleted.

24 changes: 24 additions & 0 deletions express-texml-call-mask/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import "dotenv/config";
import http from "http";
import express from "express";
import dtmfDialController from "./controllers/dtmfDialController";

const app = express();
const httpServer = http.createServer(app);

app.use(express.json());

app.get("/", (_req, res) => {
res.send("Hello World 👋 🌎");
});

const dtmfDialPath = "/dtmfDial";
app.use(
dtmfDialPath,
express.urlencoded({ extended: true }),
dtmfDialController
);

const port = process.env.PORT || 3000;
httpServer.listen(port);
console.log(`Server listening on port: ${port}`);
5 changes: 0 additions & 5 deletions express-texml-call-mask/models/db.js

This file was deleted.

4 changes: 4 additions & 0 deletions express-texml-call-mask/models/db.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import phoneNumbersTable from "./phoneNumbersTable.json";

export const lookupUserByPSTNPhoneNumber = (phoneNumber: string) =>
phoneNumbersTable.filter((row) => row.pstnPhoneNumber === phoneNumber).at(0);
6 changes: 0 additions & 6 deletions express-texml-call-mask/models/phoneNumberTable.json

This file was deleted.

6 changes: 6 additions & 0 deletions express-texml-call-mask/models/phoneNumbersTable.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[
{
"pstnPhoneNumber": "+1...",
"telnyxPhoneNumber": "+1..."
}
]
Loading

0 comments on commit af866e0

Please sign in to comment.