npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

next-yate

v0.2.1

Published

Next-Yate is Nodejs External module for YATE (Yet Another Telephony Engine)

Downloads

4

Readme

Next-Yate

Next-Yate is Nodejs interface library to the Yate external module (Yet Another Telephony Engine).

Features

  • Simple to use.
  • Channel half-stuff abstraction. (Now creation of IVR or dialplan is as easy as a piece of cake).
  • Auto-restore connections and message handlers on network collisions.
  • Cache of all requests in offline mode.
  • Auto-acknowledge of the incoming messages by acknowledge_timeout. (This can be critical under high load, as it prevents Yate from crashing).
  • Independence of other Nodejs modules.

(* Compatibility with javascript.yate has been moved to Next-Yate-Compat)

View API

External module protocol

Overiew

  • Yate class provides connection to Yate's external module.
  • YateMessage class is object Yate's external module can interact with.
  • YateChannel class is an abstraction over incoming call leg messages flow.

Quick start

Before starting

(If you still don't know what Yate is https://docs.yate.ro/wiki/Main_Page)

Make sure the Yate's module extmodule.yate is successfully loaded (https://docs.yate.ro/wiki/External_Module)

yate.conf:

[modules]
extmodule.yate=true

extmodule.conf:

; For network connection
[listener sample]
type=tcp
addr=127.0.0.1
port=5040
role=global
;
; Local stdin/stdout connected scripts
[scripts]
myscript.sh=            ; Custom shell wrapper around Nodejs script
node.sh=my_script.js    ; Run my_script.js with example wrapper: examples/node.sh

Install

npm install next-yate

Network connected script

example_core_api.js:

// Core API
const { Yate, YateMessage } = require("next-yate");
let yate = new Yate({ host: "127.0.0.1" });

yate.init(() => console.log("Connected")); // Initialize connection before use
yate.output("Hello World!");

Local connected script

When launching your script, be sure that Nodejs will find the necessary libraries.

extmodule.conf:

[scripts]
node.sh=my_scrypt.js

Example of shell wrapper around Nodejs

node.sh:

#!/bin/sh

SCRIPTS=/path_to/share/scripts
export NODE_PATH=$SCRIPTS
NODE=`which node`

$NODE $SCRIPTS/$1

Direct script execution (Channel mode)

regexroute.conf:

^NNN=extmodule/nodata/node.sh example.js

example.js

const { Yate } = require("next-yate");
const yate = new Yate();
const Channel = yate.toChannel();
Channel.init(main, {autoring: true});

async function main(message) {
    await Channel.callTo("wave/play/./share/sounds/welcome.au");
    await Channel.answered();
    Channel.callJust("conf/333", {"lonely": true});
}

Featured IVR example (using YateChannel)

IVR Description:

  • Answer on the service number = 1234567890

    |

  • Welcome menu (entry point)

  1. Setup the DTMF handler:

    1 = Jump to the Callerid menu

    2 = Jump to the Echotest menu

    3 = Transfer to support

    0 = Repeat Welcome menu prompt

  2. Play the menu prompt

  3. Pause 5 seconds

  4. Repeat the prompt up to 3 times or end the call

    |

  • Callerid Menu
  1. Setup the DTMF handler:

    1 = Repeat Callerid

    0 = Return to the Welcome menu

  2. Play the caller id by numbers

  3. Replay slower

  4. Wait 10 seconds and redirect to Welcome

    |

  • Echotest Menu
  1. Setup the DTMF handler:

    1 = Repeat Echotest

    0 = Return to the Welcome menu

  2. Play the Echo prompt

  3. Give the signal to start recording

  4. Record a sample lasting 3 seconds

  5. Give the signal of the end of the recording

  6. Play the recorded sample

  7. Wait 10 seconds and redirect to Welcome

Code:

const {Yate, YateChannel} = require("next-yate");
const yate = new Yate({host: "127.0.0.1"});
yate.init(); // Connect to Yate
yate.install(onRoute, "call.route", 100, "called", "1234567890"); // Install the service number 1234567890

function onRoute(message) {
    message.retValue("dumb/");
    message.autoanswer = true;
    let chan = new YateChannel(message);
    chan.caller = message.caller; // Remember the callerid
    chan.counter = 0; // Welcome prompt counter
    chan.init(() => welcome(chan)).catch(console.log));
    return true;
}

// Welcome menu item
async function welcome(chan) {
    if (!chan.ready) return;
    chan.counter++;

    // Setup DTMF handler
    chan.watch(dtmf => {
        switch(dtmf.text) {
            case "1":
                chan.reset(); // Drop the active chain of prompts
                callerid(chan); // Jump to CallerId menu item
                break;
            case "2":
                chan.reset();
                echo(chan); // Jump to Echo menu item
                break;
            case "3":
                chan.reset();
                chan.callJust("sip/sip:[email protected]"); // Transfer the call to support
                break;
            case "0":
                chan.reset();
                welcome(chan); // Jump to Welcome menu item
                break;
        }
    }, "chan.dtmf");

    // Play the chain of prompts
    try {
        await chan.callTo("wave/play/./share/sounds/words/hello.wav");
        await chan.callTo("wave/play/./share/sounds/words/you-have-reached-a-test-number.wav");
        await chan.callTo("wave/play/./share/sounds/words/press-1.wav");
        await chan.callTo("wave/play/./share/sounds/words/to-hear-callerid.wav");
        await chan.callTo("wave/play/./share/sounds/words/press-2.wav");
        await chan.callTo("wave/play/./share/sounds/words/to-echotest.wav");
        await chan.callTo("wave/play/./share/sounds/words/press-3.wav");
        await chan.callTo("wave/play/./share/sounds/words/to-talk-with-operator.wav");
        await chan.callTo("wave/play/./share/sounds/words/press-0.wav");
        await chan.callTo("wave/play/./share/sounds/words/to-hear-menu-again.wav");
        // Wait 5 sec and repeat the prompt
        await new Promise(res => {setTimeout(res, 5000)});
        // Repeat the prompt or hangup
        if (chan.counter < 2) {
            welcome(chan);
        } else {
            chan.hangup();
        }
    } catch(err) {
        console.log(err);
        return;
    }
}

// CallerId menu item
async function callerid(chan) {
    if (!chan.ready) return;

    // Change DTMF handler: 
    chan.watch(dtmf => {
        if (dtmf.text === "1") {
            chan.reset();
            callerid(chan);
        } else if (dtmf.text === "0") {
            chan.reset();
            welcome(chan);
        }
    }, "chan.dtmf");

    // Play the sequence
    try {
        // Say the callerid by numbers
        await chan.callTo("wave/play/./share/sounds/words/your-callerid-is.wav");
        for (let i = 0; i < chan.caller.length; i++) {
            await chan.callTo("wave/play/./share/sounds/digits/" + chan.caller.charAt(i) + ".wav");
        }
        await chan.callTo("wave/record/-", {timeout: 2000});
        // Repeat the callerid slowly
        await chan.callTo("wave/play/./share/sounds/words/your-callerid-is.wav");
        for (let i = 0; i < chan.caller.length; i++) {
            await chan.callTo("wave/play/./share/sounds/digits/" + chan.caller.charAt(i) + ".wav");
            await chan.callTo("wave/record/-", {timeout: 500}); // here is pause 0.5 sec between words
        }
        // Wait 2 seconds
        await chan.callTo("wave/record/-", {timeout: 2000});
        // Play menu prompt
        await chan.callTo("wave/play/./share/sounds/words/press-1.wav");
        await chan.callTo("wave/play/./share/sounds/words/to-hear-callerid.wav");
        await chan.callTo("wave/play/./share/sounds/words/again.wav");
        // Wait 10 seconds
        await chan.callTo("wave/record/-", {timeout: 10000});
        // If nothing happened back to Welcome
        welcome(chan);
    } catch(err) {
        console.log(err);
        return;
    }
}

// Echo menu item
async function echo(chan) {
    if (!chan.ready) return;

    chan.watch(dtmf => {
        if (dtmf.text === "1") {
            chan.reset();
            echo(chan);
        } else if (dtmf.text === "0") {
            chan.reset();
            welcome(chan);
        }
    }, "chan.dtmf");

    // Rec and play the Echo
    try {
        let rec = "/tmp/rec-" + Date.now() + ".au";
        // Play prompt
        await chan.callTo("wave/play/./share/sounds/echotest.au");
        // tink
        await chan.callTo("tone/dtmf/0");
        // Rec the voice 3 seconds
        await chan.callTo("wave/record/" + rec, {timeout: 3000});
        // tink
        await chan.callTo("tone/dtmf/0");
        // Play recorded voice
        await chan.callTo("wave/play/" + rec);
        // tink
        await chan.callTo("tone/dtmf/0");
        // Wait 10 sec
        await chan.callTo("wave/record/-", {timeout: 10000});
        // Go to welcome
        welcome(chan);
    } catch(err) {
        console.log(err);
        return;
    }
}

More examples

examples

API

View API