Compare commits

...

21 Commits

Author SHA1 Message Date
akirilyuk
2336948cc4 allow new settings for gather verb 2022-02-26 11:55:46 +01:00
akirilyuk
caa7b3a03a change log level to debug 2022-02-14 17:11:47 +01:00
akirilyuk
63c0c97024 add husky pre push hook 2022-02-14 14:23:26 +01:00
akirilyuk
b126719ba7 add husky pre push hook 2022-02-14 14:22:04 +01:00
akirilyuk
d79c733aa2 fix linting 2022-02-14 14:16:44 +01:00
akirilyuk
15f85c9730 add say and gather task features 2022-02-14 14:08:56 +01:00
Dave Horton
c1130adf03 merge 2022-02-12 10:12:45 -05:00
Dave Horton
f982f6c7d8 update to latest realtimedb-helpers 2022-02-12 10:10:03 -05:00
Snyk bot
f20190b0fc fix: upgrade aws-sdk from 2.1061.0 to 2.1062.0 (#69)
Snyk has created this PR to upgrade aws-sdk from 2.1061.0 to 2.1062.0.

See this package in npm:
https://www.npmjs.com/package/aws-sdk

See this project in Snyk:
https://app.snyk.io/org/davehorton/project/cec90d0e-0ded-433e-a42e-fe78b28ae489?utm_source=github&utm_medium=referral&page=upgrade-pr
2022-02-12 09:23:13 -05:00
Snyk bot
74e85e1b16 fix: upgrade aws-sdk from 2.1060.0 to 2.1061.0 (#68)
Snyk has created this PR to upgrade aws-sdk from 2.1060.0 to 2.1061.0.

See this package in npm:
https://www.npmjs.com/package/aws-sdk

See this project in Snyk:
https://app.snyk.io/org/davehorton/project/cec90d0e-0ded-433e-a42e-fe78b28ae489?utm_source=github&utm_medium=referral&page=upgrade-pr
2022-02-11 07:48:02 -05:00
Dave Horton
63e9cb985e allow target-level headers on outdials (#29) 2022-02-10 14:34:21 -05:00
Dave Horton
2e88ab1f55 bugfix: race condition on hangup sometimes resulted in outbound call attempt even though caller had hung up 2022-02-10 12:15:25 -05:00
Dave Horton
7f75a35515 bugfix: race condition on hangup could cause us to send dup webhook 2022-02-10 11:16:57 -05:00
Dave Horton
941727e93f add fs_public_ip to webhook payload (only when running in ec2 autoscale group) 2022-02-10 09:51:48 -05:00
Dave Horton
d8bfa33a00 include fs_sip_address and api_base_url in webhook paylods 2022-02-10 09:19:33 -05:00
Dave Horton
30ed5b6a02 add support for vad to gather and transcribe (#67) 2022-02-10 08:45:16 -05:00
Dave Horton
bac1b7f2c6 bump version 2022-02-09 15:42:27 -05:00
Dave Horton
48deb3ae89 update to latest @jambonz/realtimedb-helpers with support for redis username / password auth 2022-02-09 15:21:55 -05:00
Dave Horton
de83f735ea memory leak fixes 2022-02-08 20:33:16 -05:00
Dave Horton
cfe9397502 lint 2022-02-03 07:36:01 -05:00
Dave Horton
dda3335060 update deps, add helmet middleware 2022-02-03 07:31:30 -05:00
15 changed files with 375 additions and 162 deletions

3
.husky/pre-push Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run jslint

3
app.js
View File

@@ -31,6 +31,7 @@ const {
// HTTP
const express = require('express');
const helmet = require('helmet');
const app = express();
Object.assign(app.locals, {
logger,
@@ -73,6 +74,8 @@ srf.invite((req, res) => {
});
// HTTP
app.use(helmet());
app.use(helmet.hidePoweredBy());
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use('/', httpRoutes);

View File

@@ -1,7 +1,6 @@
const {CallDirection, CallStatus} = require('../utils/constants');
const parseUri = require('drachtio-srf').parseUri;
const { v4: uuidv4 } = require('uuid');
/**
* @classdesc Represents the common information for all calls
* that is provided in call status webhooks
@@ -9,6 +8,7 @@ const { v4: uuidv4 } = require('uuid');
class CallInfo {
constructor(opts) {
let from ;
let srf;
this.direction = opts.direction;
if (opts.req) {
const u = opts.req.getParsedHeader('from');
@@ -19,6 +19,7 @@ class CallInfo {
if (this.direction === CallDirection.Inbound) {
// inbound call
const {app, req} = opts;
srf = req.srf;
this.callSid = req.locals.callSid,
this.accountSid = app.account_sid,
this.applicationSid = app.application_sid;
@@ -33,6 +34,7 @@ class CallInfo {
else if (opts.parentCallInfo) {
// outbound call that is a child of an existing call
const {req, parentCallInfo, to, callSid} = opts;
srf = req.srf;
this.callSid = callSid || uuidv4();
this.parentCallSid = parentCallInfo.callSid;
this.accountSid = parentCallInfo.accountSid;
@@ -47,6 +49,7 @@ class CallInfo {
else if (this.direction === CallDirection.None) {
// outbound SMS
const {messageSid, accountSid, applicationSid, res} = opts;
srf = res.srf;
this.messageSid = messageSid;
this.accountSid = accountSid;
this.applicationSid = applicationSid;
@@ -55,6 +58,7 @@ class CallInfo {
else {
// outbound call triggered by REST
const {req, callSid, accountSid, applicationSid, to, tag} = opts;
srf = req.srf;
this.callSid = callSid;
this.accountSid = accountSid;
this.applicationSid = applicationSid;
@@ -65,6 +69,11 @@ class CallInfo {
this.to = to;
if (tag) this._customerData = tag;
}
this.localSipAddress = srf.locals.localSipAddress;
if (srf.locals.publicIp) {
this.publicIp = srf.locals.publicIp;
}
}
/**
@@ -100,7 +109,8 @@ class CallInfo {
callStatus: this.callStatus,
callerId: this.callerId,
accountSid: this.accountSid,
applicationSid: this.applicationSid
applicationSid: this.applicationSid,
fsSipAddress: this.localSipAddress
};
['parentCallSid', 'originatingSipIp', 'originatingSipTrunkName'].forEach((prop) => {
if (this[prop]) obj[prop] = this[prop];
@@ -110,6 +120,13 @@ class CallInfo {
if (this._customerData) {
Object.assign(obj, {customerData: this._customerData});
}
if (process.env.JAMBONES_API_BASE_URL) {
Object.assign(obj, {apiBaseUrl: process.env.JAMBONES_API_BASE_URL});
}
if (this.publicIp) {
Object.assign(obj, {fsPublicIp: this.publicIp});
}
return obj;
}

View File

@@ -48,6 +48,7 @@ class CallSession extends Emitter {
this.taskIdx = 0;
this.stackIdx = 0;
this.callGone = false;
this.notifiedComplete = false;
this.tmpFiles = new Set();
@@ -988,6 +989,12 @@ class CallSession extends Emitter {
_notifyCallStatusChange({callStatus, sipStatus, duration}) {
if (this.callMoved) return;
/* race condition: we hang up at the same time as the caller */
if (callStatus === CallStatus.Completed) {
if (this.notifiedComplete) return;
this.notifiedComplete = true;
}
assert((typeof duration === 'number' && callStatus === CallStatus.Completed) ||
(!duration && callStatus !== CallStatus.Completed),
'duration MUST be supplied when call completed AND ONLY when call completed');

View File

@@ -453,7 +453,7 @@ class Conference extends Task {
this._playSession = null;
break;
}
} while (!this.killed && !this.conf_hold_status === 'hold');
} while (!this.killed && this.conf_hold_status !== 'hold');
}
/**

View File

@@ -147,7 +147,7 @@ class TaskDial extends Task {
this.epOther.play(this.dialMusic).catch((err) => {});
}
}
await this._attemptCalls(cs);
if (!this.killed) await this._attemptCalls(cs);
await this.awaitTaskDone();
this.logger.debug({callSid: this.cs.callSid}, 'Dial:exec task is done, sending actionHook if any');
await this.performAction(this.results, this.killReason !== KillReason.Replaced);
@@ -179,6 +179,7 @@ class TaskDial extends Task {
this._killOutdials();
if (this.sd) {
this.sd.kill();
this.sd.removeAllListeners();
this.sd = null;
}
if (this.callSid) sessionTracker.remove(this.callSid);
@@ -366,6 +367,9 @@ class TaskDial extends Task {
opts.headers['X-Requested-Carrier-Sid'] = voip_carrier_sid;
}
}
if (this.killed) return;
const sd = placeCall({
logger: this.logger,
application: cs.application,
@@ -381,7 +385,9 @@ class TaskDial extends Task {
sd
.on('callCreateFail', () => {
clearTimeout(this.timerRing);
this.dials.delete(sd.callSid);
sd.removeAllListeners();
if (this.dials.size === 0 && !this.sd) {
this.logger.debug('Dial:_attemptCalls - all calls failed after call create err, ending task');
this.kill(cs);
@@ -423,6 +429,7 @@ class TaskDial extends Task {
})
.on('accept', async() => {
this.logger.debug(`Dial:_attemptCalls - we have a winner: ${sd.callSid}`);
clearTimeout(this.timerRing);
try {
await this._connectSingleDial(cs, sd);
} catch (err) {
@@ -431,7 +438,9 @@ class TaskDial extends Task {
})
.on('decline', () => {
this.logger.debug(`Dial:_attemptCalls - declined: ${sd.callSid}`);
clearTimeout(this.timerRing);
this.dials.delete(sd.callSid);
sd.removeAllListeners();
if (this.dials.size === 0 && !this.sd) {
this.logger.debug('Dial:_attemptCalls - all calls failed after decline, ending task');
this.kill(cs);

View File

@@ -10,19 +10,25 @@ const {
const makeTask = require('./make_task');
const assert = require('assert');
const GATHER_STABILITY_THRESHOLD = Number(process.env.JAMBONZ_GATHER_STABILITY_THRESHOLD || 0.7);
class TaskGather extends Task {
constructor(logger, opts, parentTask) {
super(logger, opts);
this.preconditions = TaskPreconditions.Endpoint;
[
'finishOnKey', 'hints', 'input', 'numDigits',
'partialResultHook',
'finishOnKey', 'hints', 'input', 'numDigits', 'minDigits', 'maxDigits',
'interDigitTimeout', 'submitDigit', 'partialResultHook', 'bargein', 'dtmfBargein',
'retries', 'retryPromptTts', 'retryPromptUrl',
'speechTimeout', 'timeout', 'say', 'play'
].forEach((k) => this[k] = this.data[k]);
this.listenDuringPrompt = this.data.listenDuringPrompt === false ? false : true;
this.minBargeinWordCount = this.data.minBargeinWordCount || 1;
this.timeout = (this.timeout || 5) * 1000;
this.interim = this.partialResultCallback;
this.logger.debug({opts}, 'created gather task');
this.timeout = (this.timeout || 15) * 1000;
this.interim = this.partialResultCallback || this.bargein;
if (this.data.recognizer) {
const recognizer = this.data.recognizer;
this.vendor = recognizer.vendor;
@@ -48,6 +54,12 @@ class TaskGather extends Task {
if (this.say) this.sayTask = makeTask(this.logger, {say: this.say}, this);
if (this.play) this.playTask = makeTask(this.logger, {play: this.play}, this);
if (this.sayTask || this.playTask) {
// this is specially for barge in where we want to make a bargebale promt
// to a user without listening after the say task has finished
this.listenAfterSpeech = typeof this.data.listenAfterSpeech === 'boolean' ? this.data.listenAfterSpeech : true;
}
this.parentTask = parentTask;
}
@@ -80,33 +92,63 @@ class TaskGather extends Task {
throw new Error(`no speech-to-text service credentials for ${this.vendor} have been configured`);
}
const startListening = (cs, ep) => {
this._startTimer();
if (this.input.includes('speech') && !this.listenDuringPrompt) {
this._initSpeech(cs, ep)
.then(() => {
this._startTranscribing(ep);
return updateSpeechCredentialLastUsed(this.sttCredentials.speech_credential_sid);
})
.catch(() => {});
}
};
try {
if (this.sayTask) {
this.sayTask.exec(cs, ep); // kicked off, _not_ waiting for it to complete
this.sayTask.on('playDone', (err) => {
if (!this.killed) this._startTimer();
this.logger.debug('Gather: kicking off say task');
this.sayTask.exec(cs, ep);
this.sayTask.on('playDone', async(err) => {
if (err) return this.logger.error({err}, 'Gather:exec Error playing tts');
this.logger.debug('Gather: say task completed');
if (!this.killed) {
if (this.listenAfterSpeech === true) {
startListening(cs, ep);
} else {
this.notifyTaskDone();
}
}
});
}
else if (this.playTask) {
this.playTask.exec(cs, ep); // kicked off, _not_ waiting for it to complete
this.playTask.on('playDone', (err) => {
if (!this.killed) this._startTimer();
});
this.playTask.on('playDone', async(err) => {
if (err) return this.logger.error({err}, 'Gather:exec Error playing url');
if (!this.killed) {
if (this.listenAfterSpeech === true) {
startListening(cs, ep);
} else {
this.notifyTaskDone();
}
}
}
);
}
else this._startTimer();
else startListening(cs, ep);
if (this.input.includes('speech')) {
if (this.input.includes('speech') && this.listenDuringPrompt) {
await this._initSpeech(cs, ep);
this._startTranscribing(ep);
updateSpeechCredentialLastUsed(this.sttCredentials.speech_credential_sid)
.catch(() => {/*already logged error */});
}
if (this.input.includes('digits')) {
if (this.input.includes('digits') || this.dtmfBargein) {
ep.on('dtmf', this._onDtmf.bind(this, cs, ep));
}
await this.awaitTaskDone();
this.logger.debug('Gather:exec task has completed');
} catch (err) {
this.logger.error(err, 'TaskGather:exec error');
}
@@ -118,6 +160,7 @@ class TaskGather extends Task {
}
kill(cs) {
this.logger.debug('Gather:kill');
super.kill(cs);
this._killAudio(cs);
this.ep.removeAllListeners('dtmf');
@@ -126,12 +169,28 @@ class TaskGather extends Task {
_onDtmf(cs, ep, evt) {
this.logger.debug(evt, 'TaskGather:_onDtmf');
if (evt.dtmf === this.finishOnKey) this._resolve('dtmf-terminator-key');
clearTimeout(this.interDigitTimer);
let resolved = false;
if (this.dtmfBargein) this._killAudio(cs);
if (evt.dtmf === this.finishOnKey) {
resolved = true;
this._resolve('dtmf-terminator-key');
}
else {
this.digitBuffer += evt.dtmf;
if (this.digitBuffer.length === this.numDigits) this._resolve('dtmf-num-digits');
const len = this.digitBuffer.length;
if (len === this.numDigits || len === this.maxDigits) {
resolved = true;
this._resolve('dtmf-num-digits');
}
}
if (!resolved && this.interDigitTimeout > 0 && this.digitBuffer.length >= this.minDigits) {
/* start interDigitTimer */
const ms = this.interDigitTimeout * 1000;
this.logger.debug(`starting interdigit timer of ${ms}`);
this.interDigitTimer = setTimeout(() => this._resolve('dtmf-interdigit-timeout'), ms);
}
this._killAudio(cs);
}
async _initSpeech(cs, ep) {
@@ -197,7 +256,7 @@ class TaskGather extends Task {
ep.startTranscription({
vendor: this.vendor,
locale: this.language,
interim: this.partialResultCallback ? true : false,
interim: this.interim,
}).catch((err) => {
const {writeAlerts, AlertType} = this.cs.srf.locals;
this.logger.error(err, 'TaskGather:_startTranscribing error');
@@ -237,25 +296,56 @@ class TaskGather extends Task {
}
_onTranscription(cs, ep, evt) {
this.logger.debug(evt, 'TaskGather:_onTranscription');
if ('aws' === this.vendor && Array.isArray(evt) && evt.length > 0) evt = evt[0];
if ('microsoft' === this.vendor) {
const nbest = evt.NBest;
const newEvent = {
is_final: evt.RecognitionStatus === 'Success',
alternatives: [
{
confidence: nbest[0].Confidence,
transcript: nbest[0].Display
}
]
};
evt = newEvent;
const final = evt.RecognitionStatus === 'Success';
if (final) {
const nbest = evt.NBest;
evt = {
is_final: true,
alternatives: [
{
confidence: nbest[0].Confidence,
transcript: nbest[0].Display
}
]
};
}
else {
evt = {
is_final: false,
alternatives: [
{
transcript: evt.Text
}
]
};
}
}
this.logger.debug(evt, 'TaskGather:_onTranscription');
if (evt.is_final) this._resolve('speech', evt);
else if (this.partialResultHook) {
this.cs.requestor.request(this.partialResultHook, Object.assign({speech: evt}, this.cs.callInfo))
.catch((err) => this.logger.info(err, 'GatherTask:_onTranscription error'));
else {
const recognizeSuccess = evt.stability > GATHER_STABILITY_THRESHOLD;
/*
we need to make sure to only send something on barge in if we have
something valid therefore we need to check the recognition
stability, which applies to GOOGLE
for MS we will have a final event, meaning we will not run into
the current if else branch.
For AWS we still need more testing
*/
if (recognizeSuccess &&
this.bargein &&
evt.alternatives[0].transcript.split(' ').length >= this.minBargeinWordCount) {
this.logger.debug('Gather:_onTranscription - killing audio due to bargein');
this._killAudio(cs);
this._resolve('speech', evt);
}
if (this.partialResultHook) {
this.cs.requestor.request(this.partialResultHook, Object.assign({speech: evt}, this.cs.callInfo))
.catch((err) => this.logger.info(err, 'GatherTask:_onTranscription error'));
}
}
}
_onEndOfUtterance(cs, ep) {
@@ -281,7 +371,8 @@ class TaskGather extends Task {
this._clearTimer();
if (reason.startsWith('dtmf')) {
await this.performAction({digits: this.digitBuffer, reason: 'dtmfDetected'});
if (this.parentTask) this.parentTask.emit('dtmf-collected', {reason, digits: this.digitBuffer});
else await this.performAction({digits: this.digitBuffer, reason: 'dtmfDetected'});
}
else if (reason.startsWith('speech')) {
if (this.parentTask) this.parentTask.emit('transcription', evt);

View File

@@ -21,15 +21,26 @@ class TaskSay extends Task {
const {updateSpeechCredentialLastUsed} = require('../utils/db-utils')(this.logger, srf);
const {writeAlerts, AlertType, stats} = srf.locals;
const {synthAudio} = srf.locals.dbHelpers;
const hasVerbLevelTts = this.synthesizer.vendor && this.synthesizer.vendor !== 'default';
const vendor = hasVerbLevelTts ? this.synthesizer.vendor : cs.speechSynthesisVendor ;
const language = hasVerbLevelTts ? this.synthesizer.language : cs.speechSynthesisLanguage ;
const voice = hasVerbLevelTts ? this.synthesizer.voice : cs.speechSynthesisVoice ;
const vendor = this.synthesizer.vendor && this.synthesizer.vendor !== 'default'
? this.synthesizer.vendor
: cs.speechSynthesisVendor;
const language = this.synthesizer.language && this.synthesizer.language !== 'default'
? this.synthesizer.language
: cs.speechSynthesisLanguage ;
const voice = this.synthesizer.voice && this.synthesizer.voice !== 'default'
? this.synthesizer.voice
: cs.speechSynthesisVoice;
const engine = this.synthesizer.engine || 'standard';
const salt = cs.callSid;
const credentials = cs.getSpeechCredentials(vendor, 'tts');
this.logger.info({language, voice}, `Task:say - using vendor: ${vendor}`);
this.logger.debug({language,
voice,
localSynthesizer: this.synthesizer,
speechSynthesisVendor: cs.speechSynthesisVendor,
speechSynthesisLanguage: cs.speechSynthesisLanguage,
speechSynthesisVoice: cs.speechSynthesisVoice
}, `Task:say - using vendor: ${vendor}`);
this.ep = ep;
try {
if (!credentials) {
@@ -79,7 +90,11 @@ class TaskSay extends Task {
const {memberId, confName, confUuid} = cs;
await this.playToConfMember(this.ep, memberId, confName, confUuid, filepath[segment]);
}
else await ep.play(filepath[segment]);
else {
this.logger.debug(`Say:exec sending command to play file ${filepath[segment]}`);
await ep.play(filepath[segment]);
this.logger.debug(`Say:exec completed play file ${filepath[segment]}`);
}
} while (!this.killed && ++segment < filepath.length);
}
} catch (err) {

View File

@@ -100,7 +100,15 @@
"numDigits": "number",
"partialResultHook": "object|string",
"speechTimeout": "number",
"listenDuringPrompt": "boolean",
"bargein": "boolean",
"minBargeinWordCount": "number",
"dtmfBargein": "boolean",
"minDigits": "number",
"maxDigits": "number",
"interDigitTimeout": "number",
"timeout": "number",
"listenAfterSpeech": "boolean",
"recognizer": "#recognizer",
"play": "#play",
"say": "#say"
@@ -338,6 +346,7 @@
"type": "string",
"enum": ["GET", "POST"]
},
"headers": "object",
"name": "string",
"number": "string",
"sipUri": "string",
@@ -389,6 +398,7 @@
"enum": ["google", "aws", "microsoft", "default"]
},
"language": "string",
"vad": "#vad",
"hints": "array",
"altLanguages": "array",
"profanityFilter": "boolean",
@@ -457,5 +467,15 @@
"required": [
"name"
]
},
"vad": {
"properties": {
"enable": "boolean",
"voiceMs": "number",
"mode": "number"
},
"required": [
"enable"
]
}
}

View File

@@ -22,6 +22,10 @@ class TaskTranscribe extends Task {
this.interim = !!recognizer.interim;
this.separateRecognitionPerChannel = recognizer.separateRecognitionPerChannel;
/* vad: if provided, we dont connect to recognizer until voice activity is detected */
const {enable, voiceMs = 0, mode = -1} = recognizer.vad || {};
this.vad = {enable, voiceMs, mode};
/* google-specific options */
this.hints = recognizer.hints || [];
this.profanityFilter = recognizer.profanityFilter;
@@ -105,6 +109,12 @@ class TaskTranscribe extends Task {
async _startTranscribing(cs, ep) {
const opts = {};
if (this.vad.enable) {
opts.START_RECOGNIZING_ON_VAD = 1;
if (this.vad.voiceMs) opts.RECOGNIZER_VAD_VOICE_MS = this.vad.voiceMs;
if (this.vad.mode >= 0 && this.vad.mode <= 3) opts.RECOGNIZER_VAD_MODE = this.vad.mode;
}
ep.addCustomEventListener(GoogleTranscriptionEvents.Transcription, this._onTranscription.bind(this, cs, ep));
ep.addCustomEventListener(GoogleTranscriptionEvents.NoAudioDetected, this._onNoAudio.bind(this, cs, ep));
ep.addCustomEventListener(GoogleTranscriptionEvents.MaxDurationExceeded,

View File

@@ -45,6 +45,7 @@ class SnsNotifier extends Emitter {
}, 'response from SNS SubscribeURL');
const data = await this.describeInstance();
this.lifecycleState = data.AutoScalingInstances[0].LifecycleState;
this.emit('SubscriptionConfirmation', {publicIp: this.publicIp});
break;
case 'Notification':

View File

@@ -60,10 +60,16 @@ class SingleDialer extends Emitter {
opts.headers = opts.headers || {};
opts.headers = {
...opts.headers,
...(this.target.headers || {}),
'X-Jambonz-Routing': this.target.type,
'X-Jambonz-FS-UUID': srf.locals.fsUUID,
'X-Call-Sid': this.callSid
};
if (srf.locals.fsUUID) {
opts.headers = {
...opts.headers,
'X-Jambonz-FS-UUID': srf.locals.fsUUID,
};
}
this.ms = ms;
let uri, to;
try {
@@ -144,6 +150,7 @@ class SingleDialer extends Emitter {
* (a) create a CallInfo for this call
* (a) create a logger for this call
*/
req.srf = srf;
this.callInfo = new CallInfo({
direction: CallDirection.Outbound,
parentCallInfo: this.parentCallInfo,
@@ -215,6 +222,7 @@ class SingleDialer extends Emitter {
if (this.confirmHook) this._executeApp(this.confirmHook);
else this.emit('accept');
} catch (err) {
this.inviteInProgress = null;
const status = {callStatus: CallStatus.Failed};
if (err instanceof SipError) {
status.sipStatus = err.status;

View File

@@ -28,6 +28,10 @@ module.exports = (logger) => {
lifecycleEmitter = await require('./aws-sns-lifecycle')(logger);
lifecycleEmitter
.on('SubscriptionConfirmation', ({publicIp}) => {
const {srf} = require('../..');
srf.locals.publicIp = publicIp;
})
.on(LifeCycleEvents.ScaleIn, () => {
logger.info('AWS scale-in notification: begin drying up calls');
dryUpCalls = true;

244
package-lock.json generated
View File

@@ -1,33 +1,34 @@
{
"name": "jambonz-feature-server",
"version": "v0.7.2",
"version": "v0.7.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "jambonz-feature-server",
"version": "v0.7.2",
"version": "v0.7.3",
"license": "MIT",
"dependencies": {
"@cognigy/socket-client": "^4.5.5",
"@jambonz/db-helpers": "^0.6.16",
"@jambonz/http-health-check": "^0.0.1",
"@jambonz/mw-registrar": "^0.2.1",
"@jambonz/realtimedb-helpers": "^0.4.19",
"@jambonz/realtimedb-helpers": "^0.4.26",
"@jambonz/stats-collector": "^0.1.6",
"@jambonz/time-series": "^0.1.5",
"aws-sdk": "^2.1060.0",
"@jambonz/time-series": "^0.1.6",
"aws-sdk": "^2.1073.0",
"bent": "^7.3.12",
"cidr-matcher": "^2.1.1",
"debug": "^4.3.2",
"deepcopy": "^2.1.0",
"drachtio-fsmrf": "^2.0.13",
"drachtio-srf": "^4.4.55",
"drachtio-srf": "^4.4.61",
"express": "^4.17.1",
"helmet": "^5.0.2",
"ip": "^1.1.5",
"moment": "^2.29.1",
"parse-url": "^5.0.7",
"pino": "^6.13.2",
"pino": "^6.13.4",
"to-snake-case": "^1.0.0",
"uuid": "^8.3.2",
"verify-aws-sns-signature": "^0.0.6",
@@ -38,6 +39,7 @@
"clear-module": "^4.1.1",
"eslint": "^7.20.0",
"eslint-plugin-promise": "^4.3.1",
"husky": "7.0.4",
"nyc": "^15.1.0",
"tape": "^5.2.2"
},
@@ -545,16 +547,16 @@
}
},
"node_modules/@jambonz/realtimedb-helpers": {
"version": "0.4.19",
"resolved": "https://registry.npmjs.org/@jambonz/realtimedb-helpers/-/realtimedb-helpers-0.4.19.tgz",
"integrity": "sha512-wEc7OXogQ5SZ9mgLNxviBNY0WvUKGGztyDzze3oi44edsZp0vNneVHUmdZuDzuDvUMBqsvCa0fvri8LGaxovlw==",
"version": "0.4.26",
"resolved": "https://registry.npmjs.org/@jambonz/realtimedb-helpers/-/realtimedb-helpers-0.4.26.tgz",
"integrity": "sha512-vGNC5IsYj7Qj7mOfgfti0/ZouYs+9GHEX4v7w3JguPW1NqUbvFayPs3xo49di3NJsHV0NnKWx2rMgrZzvWTgTA==",
"dependencies": {
"@google-cloud/text-to-speech": "^3.4.0",
"@jambonz/promisify-redis": "^0.0.6",
"aws-sdk": "^2.1060.0",
"aws-sdk": "^2.1072.0",
"bent": "^7.3.12",
"debug": "^4.3.3",
"microsoft-cognitiveservices-speech-sdk": "^1.19.0",
"microsoft-cognitiveservices-speech-sdk": "^1.20.0",
"redis": "^3.1.2"
}
},
@@ -568,9 +570,9 @@
}
},
"node_modules/@jambonz/time-series": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/@jambonz/time-series/-/time-series-0.1.5.tgz",
"integrity": "sha512-JDkAshqq9VRdIY7S/Edz9iIyKNoyCoUMfn0IUVyUG4Hf53fmhYRCnFnDTdMFAs6Y4amE39m3968nrZRr+lVIqQ==",
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/@jambonz/time-series/-/time-series-0.1.6.tgz",
"integrity": "sha512-EFO1ZFUazHLCzDYkAbpke0IfmPRogLkGg+KGWwz3SGpnuiltfohQ3TsJ5KG8Gp9mXqdpkyAioWSdaJxGDquthQ==",
"dependencies": {
"debug": "^4.3.1",
"influx": "^5.8.0"
@@ -907,14 +909,14 @@
}
},
"node_modules/aws-sdk": {
"version": "2.1060.0",
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1060.0.tgz",
"integrity": "sha512-c734/CZiVSsuVnEkx/7dodI8ndgOnxiCTwwlEFlMxdAZfLLJplteFwi6c/J2GZQktvz2ysV/HVtNKcJkasYJzw==",
"version": "2.1073.0",
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1073.0.tgz",
"integrity": "sha512-TtyHDL4ZEs8Zh/DqWY/hv745DTWrIwOyBAvfjBJ45RE9h0TjpWqCIowEtb6gRPAKyPPyfGH4s+rEYu07vNK1Hg==",
"dependencies": {
"buffer": "4.9.2",
"events": "1.1.1",
"ieee754": "1.1.13",
"jmespath": "0.15.0",
"jmespath": "0.16.0",
"querystring": "0.2.0",
"sax": "1.2.1",
"url": "0.10.3",
@@ -1603,9 +1605,9 @@
}
},
"node_modules/drachtio-sip": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/drachtio-sip/-/drachtio-sip-0.6.2.tgz",
"integrity": "sha512-BkiRZq3Yq2WVSGY3M7Hv4yX4dIW/o0/4xNMcm26IxT71YIRy07UtbQUHaMI3P2HfPu5zK6RoQW2MHrxPXtz6ZQ==",
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/drachtio-sip/-/drachtio-sip-0.6.3.tgz",
"integrity": "sha512-sQQ2JdRQ58z+WbkxORlWKZCeinu499tugfsdh7jRBWX6SO4odDevT5JL+42dMlwrL83CZUL6w2Xjgu0uaABoMQ==",
"dependencies": {
"debug": "^4.3.1",
"eslint-plugin-promise": "^5.1.0",
@@ -1613,9 +1615,9 @@
}
},
"node_modules/drachtio-sip/node_modules/eslint-plugin-promise": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.1.1.tgz",
"integrity": "sha512-XgdcdyNzHfmlQyweOPTxmc7pIsS6dE4MvwhXWMQ2Dxs1XAL2GJDilUsjWen6TWik0aSI+zD/PqocZBblcm9rdA==",
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.2.0.tgz",
"integrity": "sha512-SftLb1pUG01QYq2A/hGAWfDRXqYD82zE7j7TopDOyNdU+7SvvoXREls/+PRTY17vUXzXnZA/zfnyKgRH6x4JJw==",
"engines": {
"node": "^10.12.0 || >=12.0.0"
},
@@ -1624,15 +1626,15 @@
}
},
"node_modules/drachtio-srf": {
"version": "4.4.59",
"resolved": "https://registry.npmjs.org/drachtio-srf/-/drachtio-srf-4.4.59.tgz",
"integrity": "sha512-hrW9bZ8TZR9JQ3pqI+nyrI1eAzEOwHuvm1lNL1fbmZmRddKJzYdylkgVoyURs/OlT/nANy/M43GrQjcGP4psPw==",
"version": "4.4.61",
"resolved": "https://registry.npmjs.org/drachtio-srf/-/drachtio-srf-4.4.61.tgz",
"integrity": "sha512-HZwKTAR6V7dc84BV50h5xAopkQ1k8wUy04JXDmq2/O+uryANFwaklICidg1oJkIrnYUPWQn/1IfZnqGSv9O2Sw==",
"dependencies": {
"async": "^1.4.2",
"debug": "^3.2.7",
"delegates": "^0.1.0",
"deprecate": "^1.1.1",
"drachtio-sip": "^0.6.2",
"drachtio-sip": "^0.6.3",
"node-noop": "0.0.1",
"only": "0.0.2",
"sdp-transform": "^2.14.1",
@@ -1640,7 +1642,7 @@
"sip-methods": "^0.3.0",
"sip-status": "^0.1.0",
"utils-merge": "1.0.0",
"uuid": "^3.4.0"
"uuid": "^8.3.2"
},
"engines": {
"node": ">= 6.9.3"
@@ -1659,15 +1661,6 @@
"ms": "^2.1.1"
}
},
"node_modules/drachtio-srf/node_modules/uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
"bin": {
"uuid": "bin/uuid"
}
},
"node_modules/duplexify": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz",
@@ -2259,11 +2252,6 @@
"resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz",
"integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig=="
},
"node_modules/fastify-warning": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/fastify-warning/-/fastify-warning-0.2.0.tgz",
"integrity": "sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw=="
},
"node_modules/file-entry-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.0.tgz",
@@ -2719,6 +2707,14 @@
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz",
"integrity": "sha1-B8tKXfJa3Z6Cbrxn3Mn9idsn2Eo="
},
"node_modules/helmet": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/helmet/-/helmet-5.0.2.tgz",
"integrity": "sha512-QWlwUZZ8BtlvwYVTSDTBChGf8EOcQ2LkGMnQJxSzD1mUu8CCjXJZq/BXP8eWw4kikRnzlhtYo3lCk0ucmYA3Vg==",
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/hot-shots": {
"version": "8.5.2",
"resolved": "https://registry.npmjs.org/hot-shots/-/hot-shots-8.5.2.tgz",
@@ -2763,6 +2759,21 @@
"node": ">= 6"
}
},
"node_modules/husky": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz",
"integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==",
"dev": true,
"bin": {
"husky": "lib/bin.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/typicode"
}
},
"node_modules/iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -3311,9 +3322,9 @@
}
},
"node_modules/jmespath": {
"version": "0.15.0",
"resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz",
"integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=",
"version": "0.16.0",
"resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz",
"integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==",
"engines": {
"node": ">= 0.6.0"
}
@@ -3511,9 +3522,9 @@
}
},
"node_modules/microsoft-cognitiveservices-speech-sdk": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/microsoft-cognitiveservices-speech-sdk/-/microsoft-cognitiveservices-speech-sdk-1.19.0.tgz",
"integrity": "sha512-FYyXdJcTLX8Iunnn9XHzTfR+43YdEZn1q89KX6Vzqtaa4hz/LemdC9Zni50VIfkXMNtq2sJFYf5wKXvxm1wQHA==",
"version": "1.20.0",
"resolved": "https://registry.npmjs.org/microsoft-cognitiveservices-speech-sdk/-/microsoft-cognitiveservices-speech-sdk-1.20.0.tgz",
"integrity": "sha512-/KWNHQb36nhIkBr6HClh+T+gHicgmC5JKJhCnQmL6XGAAndLtew0aRbh7cMK10IFNTgozGKiejhrfnwiYH3IBA==",
"hasInstallScript": true,
"dependencies": {
"agent-base": "^6.0.1",
@@ -3525,7 +3536,7 @@
"simple-lru-cache": "0.0.2",
"url-parse": "^1.4.7",
"uuid": "^8.3.0",
"ws": "^7.3.1"
"ws": "^7.5.6"
}
},
"node_modules/microsoft-cognitiveservices-speech-sdk/node_modules/https-proxy-agent": {
@@ -4047,15 +4058,15 @@
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
},
"node_modules/pino": {
"version": "6.13.3",
"resolved": "https://registry.npmjs.org/pino/-/pino-6.13.3.tgz",
"integrity": "sha512-tJy6qVgkh9MwNgqX1/oYi3ehfl2Y9H0uHyEEMsBe74KinESIjdMrMQDWpcZPpPicg3VV35d/GLQZmo4QgU2Xkg==",
"version": "6.13.4",
"resolved": "https://registry.npmjs.org/pino/-/pino-6.13.4.tgz",
"integrity": "sha512-g4tHSISmQJYUEKEMVdaZ+ZokWwFnTwZL5JPn+lnBVZ1BuBbrSchrXwQINknkM5+Q4fF6U9NjiI8PWwwMDHt9zA==",
"dependencies": {
"fast-redact": "^3.0.0",
"fast-safe-stringify": "^2.0.8",
"fastify-warning": "^0.2.0",
"flatstr": "^1.0.12",
"pino-std-serializers": "^3.1.0",
"process-warning": "^1.0.0",
"quick-format-unescaped": "^4.0.3",
"sonic-boom": "^1.0.2"
},
@@ -4100,6 +4111,11 @@
"node": ">=8"
}
},
"node_modules/process-warning": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/process-warning/-/process-warning-1.0.0.tgz",
"integrity": "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q=="
},
"node_modules/progress": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
@@ -5114,9 +5130,9 @@
}
},
"node_modules/url-parse": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz",
"integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==",
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.4.tgz",
"integrity": "sha512-ITeAByWWoqutFClc/lRZnFplgXgEZr3WJ6XngMM/N9DMIm4K8zXPCZ1Jdu0rERwO84w1WC5wkle2ubwTA4NTBg==",
"dependencies": {
"querystringify": "^2.1.1",
"requires-port": "^1.0.0"
@@ -5343,9 +5359,9 @@
}
},
"node_modules/ws": {
"version": "7.5.5",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz",
"integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==",
"version": "7.5.7",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz",
"integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==",
"engines": {
"node": ">=8.3.0"
},
@@ -5876,16 +5892,16 @@
}
},
"@jambonz/realtimedb-helpers": {
"version": "0.4.19",
"resolved": "https://registry.npmjs.org/@jambonz/realtimedb-helpers/-/realtimedb-helpers-0.4.19.tgz",
"integrity": "sha512-wEc7OXogQ5SZ9mgLNxviBNY0WvUKGGztyDzze3oi44edsZp0vNneVHUmdZuDzuDvUMBqsvCa0fvri8LGaxovlw==",
"version": "0.4.26",
"resolved": "https://registry.npmjs.org/@jambonz/realtimedb-helpers/-/realtimedb-helpers-0.4.26.tgz",
"integrity": "sha512-vGNC5IsYj7Qj7mOfgfti0/ZouYs+9GHEX4v7w3JguPW1NqUbvFayPs3xo49di3NJsHV0NnKWx2rMgrZzvWTgTA==",
"requires": {
"@google-cloud/text-to-speech": "^3.4.0",
"@jambonz/promisify-redis": "^0.0.6",
"aws-sdk": "^2.1060.0",
"aws-sdk": "^2.1072.0",
"bent": "^7.3.12",
"debug": "^4.3.3",
"microsoft-cognitiveservices-speech-sdk": "^1.19.0",
"microsoft-cognitiveservices-speech-sdk": "^1.20.0",
"redis": "^3.1.2"
}
},
@@ -5899,9 +5915,9 @@
}
},
"@jambonz/time-series": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/@jambonz/time-series/-/time-series-0.1.5.tgz",
"integrity": "sha512-JDkAshqq9VRdIY7S/Edz9iIyKNoyCoUMfn0IUVyUG4Hf53fmhYRCnFnDTdMFAs6Y4amE39m3968nrZRr+lVIqQ==",
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/@jambonz/time-series/-/time-series-0.1.6.tgz",
"integrity": "sha512-EFO1ZFUazHLCzDYkAbpke0IfmPRogLkGg+KGWwz3SGpnuiltfohQ3TsJ5KG8Gp9mXqdpkyAioWSdaJxGDquthQ==",
"requires": {
"debug": "^4.3.1",
"influx": "^5.8.0"
@@ -6178,14 +6194,14 @@
}
},
"aws-sdk": {
"version": "2.1060.0",
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1060.0.tgz",
"integrity": "sha512-c734/CZiVSsuVnEkx/7dodI8ndgOnxiCTwwlEFlMxdAZfLLJplteFwi6c/J2GZQktvz2ysV/HVtNKcJkasYJzw==",
"version": "2.1073.0",
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1073.0.tgz",
"integrity": "sha512-TtyHDL4ZEs8Zh/DqWY/hv745DTWrIwOyBAvfjBJ45RE9h0TjpWqCIowEtb6gRPAKyPPyfGH4s+rEYu07vNK1Hg==",
"requires": {
"buffer": "4.9.2",
"events": "1.1.1",
"ieee754": "1.1.13",
"jmespath": "0.15.0",
"jmespath": "0.16.0",
"querystring": "0.2.0",
"sax": "1.2.1",
"url": "0.10.3",
@@ -6746,9 +6762,9 @@
}
},
"drachtio-sip": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/drachtio-sip/-/drachtio-sip-0.6.2.tgz",
"integrity": "sha512-BkiRZq3Yq2WVSGY3M7Hv4yX4dIW/o0/4xNMcm26IxT71YIRy07UtbQUHaMI3P2HfPu5zK6RoQW2MHrxPXtz6ZQ==",
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/drachtio-sip/-/drachtio-sip-0.6.3.tgz",
"integrity": "sha512-sQQ2JdRQ58z+WbkxORlWKZCeinu499tugfsdh7jRBWX6SO4odDevT5JL+42dMlwrL83CZUL6w2Xjgu0uaABoMQ==",
"requires": {
"debug": "^4.3.1",
"eslint-plugin-promise": "^5.1.0",
@@ -6756,23 +6772,23 @@
},
"dependencies": {
"eslint-plugin-promise": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.1.1.tgz",
"integrity": "sha512-XgdcdyNzHfmlQyweOPTxmc7pIsS6dE4MvwhXWMQ2Dxs1XAL2GJDilUsjWen6TWik0aSI+zD/PqocZBblcm9rdA==",
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.2.0.tgz",
"integrity": "sha512-SftLb1pUG01QYq2A/hGAWfDRXqYD82zE7j7TopDOyNdU+7SvvoXREls/+PRTY17vUXzXnZA/zfnyKgRH6x4JJw==",
"requires": {}
}
}
},
"drachtio-srf": {
"version": "4.4.59",
"resolved": "https://registry.npmjs.org/drachtio-srf/-/drachtio-srf-4.4.59.tgz",
"integrity": "sha512-hrW9bZ8TZR9JQ3pqI+nyrI1eAzEOwHuvm1lNL1fbmZmRddKJzYdylkgVoyURs/OlT/nANy/M43GrQjcGP4psPw==",
"version": "4.4.61",
"resolved": "https://registry.npmjs.org/drachtio-srf/-/drachtio-srf-4.4.61.tgz",
"integrity": "sha512-HZwKTAR6V7dc84BV50h5xAopkQ1k8wUy04JXDmq2/O+uryANFwaklICidg1oJkIrnYUPWQn/1IfZnqGSv9O2Sw==",
"requires": {
"async": "^1.4.2",
"debug": "^3.2.7",
"delegates": "^0.1.0",
"deprecate": "^1.1.1",
"drachtio-sip": "^0.6.2",
"drachtio-sip": "^0.6.3",
"node-noop": "0.0.1",
"only": "0.0.2",
"sdp-transform": "^2.14.1",
@@ -6780,7 +6796,7 @@
"sip-methods": "^0.3.0",
"sip-status": "^0.1.0",
"utils-merge": "1.0.0",
"uuid": "^3.4.0"
"uuid": "^8.3.2"
},
"dependencies": {
"async": {
@@ -6795,11 +6811,6 @@
"requires": {
"ms": "^2.1.1"
}
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
}
}
},
@@ -7272,11 +7283,6 @@
"resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz",
"integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig=="
},
"fastify-warning": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/fastify-warning/-/fastify-warning-0.2.0.tgz",
"integrity": "sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw=="
},
"file-entry-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.0.tgz",
@@ -7628,6 +7634,11 @@
}
}
},
"helmet": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/helmet/-/helmet-5.0.2.tgz",
"integrity": "sha512-QWlwUZZ8BtlvwYVTSDTBChGf8EOcQ2LkGMnQJxSzD1mUu8CCjXJZq/BXP8eWw4kikRnzlhtYo3lCk0ucmYA3Vg=="
},
"hot-shots": {
"version": "8.5.2",
"resolved": "https://registry.npmjs.org/hot-shots/-/hot-shots-8.5.2.tgz",
@@ -7663,6 +7674,12 @@
"debug": "4"
}
},
"husky": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz",
"integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==",
"dev": true
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -8059,9 +8076,9 @@
}
},
"jmespath": {
"version": "0.15.0",
"resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz",
"integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc="
"version": "0.16.0",
"resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz",
"integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw=="
},
"js-tokens": {
"version": "4.0.0",
@@ -8217,9 +8234,9 @@
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
},
"microsoft-cognitiveservices-speech-sdk": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/microsoft-cognitiveservices-speech-sdk/-/microsoft-cognitiveservices-speech-sdk-1.19.0.tgz",
"integrity": "sha512-FYyXdJcTLX8Iunnn9XHzTfR+43YdEZn1q89KX6Vzqtaa4hz/LemdC9Zni50VIfkXMNtq2sJFYf5wKXvxm1wQHA==",
"version": "1.20.0",
"resolved": "https://registry.npmjs.org/microsoft-cognitiveservices-speech-sdk/-/microsoft-cognitiveservices-speech-sdk-1.20.0.tgz",
"integrity": "sha512-/KWNHQb36nhIkBr6HClh+T+gHicgmC5JKJhCnQmL6XGAAndLtew0aRbh7cMK10IFNTgozGKiejhrfnwiYH3IBA==",
"requires": {
"agent-base": "^6.0.1",
"asn1.js-rfc2560": "^5.0.1",
@@ -8230,7 +8247,7 @@
"simple-lru-cache": "0.0.2",
"url-parse": "^1.4.7",
"uuid": "^8.3.0",
"ws": "^7.3.1"
"ws": "^7.5.6"
},
"dependencies": {
"https-proxy-agent": {
@@ -8632,15 +8649,15 @@
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
},
"pino": {
"version": "6.13.3",
"resolved": "https://registry.npmjs.org/pino/-/pino-6.13.3.tgz",
"integrity": "sha512-tJy6qVgkh9MwNgqX1/oYi3ehfl2Y9H0uHyEEMsBe74KinESIjdMrMQDWpcZPpPicg3VV35d/GLQZmo4QgU2Xkg==",
"version": "6.13.4",
"resolved": "https://registry.npmjs.org/pino/-/pino-6.13.4.tgz",
"integrity": "sha512-g4tHSISmQJYUEKEMVdaZ+ZokWwFnTwZL5JPn+lnBVZ1BuBbrSchrXwQINknkM5+Q4fF6U9NjiI8PWwwMDHt9zA==",
"requires": {
"fast-redact": "^3.0.0",
"fast-safe-stringify": "^2.0.8",
"fastify-warning": "^0.2.0",
"flatstr": "^1.0.12",
"pino-std-serializers": "^3.1.0",
"process-warning": "^1.0.0",
"quick-format-unescaped": "^4.0.3",
"sonic-boom": "^1.0.2"
}
@@ -8673,6 +8690,11 @@
"fromentries": "^1.2.0"
}
},
"process-warning": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/process-warning/-/process-warning-1.0.0.tgz",
"integrity": "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q=="
},
"progress": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
@@ -9476,9 +9498,9 @@
}
},
"url-parse": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz",
"integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==",
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.4.tgz",
"integrity": "sha512-ITeAByWWoqutFClc/lRZnFplgXgEZr3WJ6XngMM/N9DMIm4K8zXPCZ1Jdu0rERwO84w1WC5wkle2ubwTA4NTBg==",
"requires": {
"querystringify": "^2.1.1",
"requires-port": "^1.0.0"
@@ -9662,9 +9684,9 @@
}
},
"ws": {
"version": "7.5.5",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz",
"integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==",
"version": "7.5.7",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz",
"integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==",
"requires": {}
},
"xml2js": {

View File

@@ -1,6 +1,6 @@
{
"name": "jambonz-feature-server",
"version": "v0.7.2",
"version": "v0.7.3",
"main": "app.js",
"engines": {
"node": ">= 10.16.0"
@@ -23,28 +23,30 @@
"start": "node app",
"test": "NODE_ENV=test JAMBONES_HOSTING=1 DRACHTIO_HOST=127.0.0.1 DRACHTIO_PORT=9060 DRACHTIO_SECRET=cymru JAMBONES_MYSQL_HOST=127.0.0.1 JAMBONES_MYSQL_PORT=3360 JAMBONES_MYSQL_USER=jambones_test JAMBONES_MYSQL_PASSWORD=jambones_test JAMBONES_MYSQL_DATABASE=jambones_test JAMBONES_REDIS_HOST=127.0.0.1 JAMBONES_REDIS_PORT=16379 JAMBONES_LOGLEVEL=debug ENABLE_METRICS=0 HTTP_PORT=3000 JAMBONES_SBCS=172.38.0.10 JAMBONES_FREESWITCH=127.0.0.1:8022:ClueCon:docker-host JAMBONES_TIME_SERIES_HOST=127.0.0.1 JAMBONES_NETWORK_CIDR=172.38.0.0/16 node test/ ",
"coverage": "./node_modules/.bin/nyc --reporter html --report-dir ./coverage npm run test",
"jslint": "eslint app.js lib"
"jslint": "eslint app.js lib",
"prepare": "husky install"
},
"dependencies": {
"@cognigy/socket-client": "^4.5.5",
"@jambonz/db-helpers": "^0.6.16",
"@jambonz/http-health-check": "^0.0.1",
"@jambonz/mw-registrar": "^0.2.1",
"@jambonz/realtimedb-helpers": "^0.4.19",
"@jambonz/realtimedb-helpers": "^0.4.26",
"@jambonz/stats-collector": "^0.1.6",
"@jambonz/time-series": "^0.1.5",
"aws-sdk": "^2.1060.0",
"@jambonz/time-series": "^0.1.6",
"aws-sdk": "^2.1073.0",
"bent": "^7.3.12",
"cidr-matcher": "^2.1.1",
"debug": "^4.3.2",
"deepcopy": "^2.1.0",
"drachtio-fsmrf": "^2.0.13",
"drachtio-srf": "^4.4.55",
"drachtio-srf": "^4.4.61",
"express": "^4.17.1",
"helmet": "^5.0.2",
"ip": "^1.1.5",
"moment": "^2.29.1",
"parse-url": "^5.0.7",
"pino": "^6.13.2",
"pino": "^6.13.4",
"to-snake-case": "^1.0.0",
"uuid": "^8.3.2",
"verify-aws-sns-signature": "^0.0.6",
@@ -55,6 +57,7 @@
"clear-module": "^4.1.1",
"eslint": "^7.20.0",
"eslint-plugin-promise": "^4.3.1",
"husky": "7.0.4",
"nyc": "^15.1.0",
"tape": "^5.2.2"
}