diff --git a/.gitignore b/.gitignore index 9ed71c24..7be6dec5 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,5 @@ node_modules .DS_Store examples/* + +ecosystem.config.js \ No newline at end of file diff --git a/app.js b/app.js index 1cd6001d..178f04ab 100644 --- a/app.js +++ b/app.js @@ -1,13 +1,23 @@ +const assert = require('assert'); +assert.ok(process.env.JAMBONES_MYSQL_HOST && + process.env.JAMBONES_MYSQL_USER && + process.env.JAMBONES_MYSQL_PASSWORD && + process.env.JAMBONES_MYSQL_DATABASE, 'missing JAMBONES_MYSQL_XXX env vars'); +assert.ok(process.env.DRACHTIO_PORT || process.env.DRACHTIO_HOST, 'missing DRACHTIO_PORT env var'); +assert.ok(process.env.DRACHTIO_SECRET, 'missing DRACHTIO_SECRET env var'); +assert.ok(process.env.JAMBONES_SBCS, 'missing JAMBONES_SBCS env var'); +assert.ok(process.env.JAMBONES_FREESWITCH, 'missing JAMBONES_FREESWITCH env var'); +assert.ok(process.env.JAMBONES_FEATURE_SERVERS, 'missing JAMBONES_FEATURE_SERVERS env var'); + const Srf = require('drachtio-srf'); const srf = new Srf(); const Mrf = require('drachtio-fsmrf'); srf.locals.mrf = new Mrf(srf); -const config = require('config'); -const PORT = process.env.HTTP_PORT || config.get('defaultHttpPort'); +const PORT = process.env.HTTP_PORT || 3000; const opts = Object.assign({ timestamp: () => {return `, "time": "${new Date().toISOString()}"`;} -}, config.get('logging')); -const logger = srf.locals.parentLogger = require('pino')(opts); +}, {level: process.env.JAMBONES_LOGLEVEL || 'info'}); +const logger = require('pino')(opts); const installSrfLocals = require('./lib/utils/install-srf-locals'); installSrfLocals(srf, logger); @@ -18,7 +28,6 @@ const { invokeWebCallback } = require('./lib/middleware')(srf, logger); - // HTTP const express = require('express'); const app = express(); @@ -27,24 +36,15 @@ const httpRoutes = require('./lib/http-routes'); const InboundCallSession = require('./lib/session/inbound-call-session'); - -// disable logging in test mode -if (process.env.NODE_ENV === 'test') { - const noop = () => {}; - logger.info = logger.debug = noop; - logger.child = () => {return {info: noop, error: noop, debug: noop};}; -} - -// config dictates whether to use outbound or inbound connections -if (config.has('drachtio.host')) { - srf.connect(config.get('drachtio')); +if (process.env.DRACHTIO_HOST) { + srf.connect({host: process.env.DRACHTIO_HOST, port: process.env.DRACHTIO_PORT, secret: process.env.DRACHTIO_SECRET }); srf.on('connect', (err, hp) => { logger.info(`connected to drachtio listening on ${hp}`); }); } else { - logger.info(`listening for drachtio server traffic on ${JSON.stringify(config.get('drachtio'))}`); - srf.listen(config.get('drachtio')); + logger.info(`listening for drachtio requests on port ${process.env.DRACHTIO_PORT}`); + srf.listen({port: process.env.DRACHTIO_PORT, secret: process.env.DRACHTIO_SECRET}); } if (process.env.NODE_ENV === 'test') { srf.on('error', (err) => { diff --git a/lib/http-routes/api/create-call.js b/lib/http-routes/api/create-call.js index dcdb126f..9d8dc2bc 100644 --- a/lib/http-routes/api/create-call.js +++ b/lib/http-routes/api/create-call.js @@ -1,4 +1,3 @@ -const config = require('config'); const router = require('express').Router(); const makeTask = require('../../tasks/make_task'); const RestCallSession = require('../../session/rest-call-session'); @@ -7,12 +6,9 @@ const {CallDirection, CallStatus} = require('../../utils/constants'); const SipError = require('drachtio-srf').SipError; const Srf = require('drachtio-srf'); const sysError = require('./error'); -const drachtio = config.get('outdials.drachtio'); -const sbcs = config.get('outdials.sbc'); const Mrf = require('drachtio-fsmrf'); const installSrfLocals = require('../../utils/install-srf-locals'); const Requestor = require('../../utils/requestor'); - let idxDrachtio = 0; let idxSbc = 0; let srfs = []; @@ -51,6 +47,8 @@ function getSrfForOutdial(logger) { if (srfs.length === 0 && initializedSrfs) return reject('no available drachtio servers for outdial'); else if (srfs.length > 0) return resolve(srfs[idxDrachtio++ % srfs.length]); else { + const {srf} = require('../../../'); + const drachtio = srf.locals.drachtio; logger.debug(drachtio, 'getSrfForOutdial - attempting to connect'); initializedSrfs = true; resolve(Promise.race(drachtio.map((d) => connectSrf(logger, d)))); @@ -64,8 +62,8 @@ router.post('/', async(req, res) => { try { let uri, cs, to; const restDial = makeTask(logger, {'rest:dial': req.body}); - const sbcAddress = sbcs[idxSbc++ % sbcs.length]; const srf = await getSrfForOutdial(logger); + const sbcAddress = srf.locals.sbcs[idxSbc++ % srf.locals.sbcs.length]; const target = restDial.to; const opts = { callingNumber: restDial.from }; @@ -86,7 +84,8 @@ router.post('/', async(req, res) => { /* create endpoint for outdial */ const mrf = srf.locals.mrf; - const ms = await mrf.connect(config.get('freeswitch')); + + const ms = await mrf.connect(srf.locals.freeswitch); logger.debug('createCall: successfully connected to media server'); const ep = await ms.createEndpoint(); logger.debug(`createCall: successfully allocated endpoint, sending INVITE to ${sbcAddress}`); @@ -119,8 +118,8 @@ router.post('/', async(req, res) => { * attach our requestor and notifier objects * these will be used for all http requests we make during this call */ - app.requestor = new Requestor(this.logger, app.call_hook); - if (app.call_status_hook) app.notifier = new Requestor(this.logger, app.call_status_hook); + app.requestor = new Requestor(logger, app.call_hook); + if (app.call_status_hook) app.notifier = new Requestor(logger, app.call_status_hook); else app.notifier = {request: () => {}}; /* now launch the outdial */ @@ -128,7 +127,7 @@ router.post('/', async(req, res) => { const dlg = await srf.createUAC(uri, opts, { cbRequest: (err, inviteReq) => { if (err) { - this.logger.error(err, 'createCall Error creating call'); + logger.error(err, 'createCall Error creating call'); res.status(500).send('Call Failure'); ep.destroy(); } diff --git a/lib/middleware.js b/lib/middleware.js index ddd2b326..9c7f47d5 100644 --- a/lib/middleware.js +++ b/lib/middleware.js @@ -6,7 +6,7 @@ const makeTask = require('./tasks/make_task'); const normalizeJamones = require('./utils/normalize-jamones'); module.exports = function(srf, logger) { - const {lookupAppByPhoneNumber, lookupApplicationBySid} = srf.locals.dbHelpers; + const {lookupAppByPhoneNumber, lookupAppBySid, lookupAppByRealm} = srf.locals.dbHelpers; function initLocals(req, res, next) { const callSid = uuidv4(); @@ -19,6 +19,8 @@ module.exports = function(srf, logger) { req.locals.logger.debug(`got application from X-Application-Sid header: ${application_sid}`); req.locals.application_sid = application_sid; } + if (req.has('X-Authenticated-User')) req.locals.originatingUser = req.get('X-Authenticated-User'); + next(); } @@ -50,7 +52,17 @@ module.exports = function(srf, logger) { const logger = req.locals.logger; try { let app; - if (req.locals.application_sid) app = await lookupApplicationBySid(req.locals.application_sid); + if (req.locals.application_sid) app = await lookupAppBySid(req.locals.application_sid); + else if (req.locals.originatingUser) { + const arr = /^(.*)@(.*)/.exec(req.locals.originatingUser); + if (arr) { + const sipRealm = arr[2]; + logger.debug(`looking for device calling app for realm ${sipRealm}`); + app = await lookupAppByRealm(sipRealm); + if (app) logger.debug({app}, `retrieved device calling app for realm ${sipRealm}`); + + } + } else app = await lookupAppByPhoneNumber(req.locals.calledNumber); if (!app || !app.call_hook || !app.call_hook.url) { @@ -66,8 +78,8 @@ module.exports = function(srf, logger) { * create a requestor that we will use for all http requests we make during the call. * also create a notifier for call status events (if not needed, its a no-op). */ - app.requestor = new Requestor(this.logger, app.call_hook); - if (app.call_status_hook) app.notifier = new Requestor(this.logger, app.call_status_hook); + app.requestor = new Requestor(logger, app.call_hook); + if (app.call_status_hook) app.notifier = new Requestor(logger, app.call_status_hook); else app.notifier = {request: () => {}}; req.locals.application = app; diff --git a/lib/session/call-session.js b/lib/session/call-session.js index 3abfd79c..6857f06b 100644 --- a/lib/session/call-session.js +++ b/lib/session/call-session.js @@ -1,5 +1,4 @@ const Emitter = require('events'); -const config = require('config'); const {CallDirection, TaskPreconditions, CallStatus, TaskName} = require('../utils/constants'); const moment = require('moment'); const assert = require('assert'); @@ -227,13 +226,11 @@ class CallSession extends Emitter { * @param {object} [opts.call_hook] - new call_status_hook */ async _lccCallHook(opts) { - const tasks = await this.requestor(opts.call_hook, this.callInfo); - - //TODO: if they gave us a call status hook, we should replace - //the existing one (or just remove this option altogether?) - - this.logger.info({tasks}, 'CallSession:updateCall new task list'); - this.replaceApplication(tasks); + const tasks = await this.requestor.request(opts.call_hook, this.callInfo); + if (tasks && tasks.length > 0) { + this.logger.info({tasks}, 'CallSession:updateCall new task list'); + this.replaceApplication(normalizeJamones(this.logger, tasks).map((tdata) => makeTask(this.logger, tdata))); + } } /** @@ -488,7 +485,7 @@ class CallSession extends Emitter { async getMS() { if (!this.ms) { const mrf = this.srf.locals.mrf; - this.ms = await mrf.connect(config.get('freeswitch')); + this.ms = await mrf.connect(this.srf.locals.freeswitch); } return this.ms; } @@ -503,7 +500,7 @@ class CallSession extends Emitter { // get a media server if (!this.ms) { - this.ms = await mrf.connect(config.get('freeswitch')); + this.ms = await mrf.connect(this.srf.locals.freeswitch); } if (!this.ep) { this.ep = await this.ms.createEndpoint({remoteSdp: this.req.body}); @@ -534,6 +531,7 @@ class CallSession extends Emitter { } // update calls db + this.logger.debug(`updating redis with ${JSON.stringify(this.callInfo)}`); this.updateCallStatus(this.callInfo, this.serviceUrl).catch((err) => this.logger.error(err, 'redis error')); } } diff --git a/lib/tasks/dial.js b/lib/tasks/dial.js index f6351931..999fedc3 100644 --- a/lib/tasks/dial.js +++ b/lib/tasks/dial.js @@ -5,7 +5,6 @@ const assert = require('assert'); const placeCall = require('../utils/place-outdial'); const sessionTracker = require('../session/session-tracker'); const DtmfCollector = require('../utils/dtmf-collector'); -const config = require('config'); const debug = require('debug')('jambonz:feature-server'); function parseDtmfOptions(logger, dtmfCapture) { @@ -129,11 +128,11 @@ class TaskDial extends Task { this._installDtmfDetection(cs, this.epOther, this.parentDtmfCollector); await this._attemptCalls(cs); await this.awaitTaskDone(); - await cs.requestor.request(this.actionHook, Object.assign({}, cs.callInfo, this.results)); + await this.performAction(Object.assign({}, cs.callInfo, this.results)); this._removeDtmfDetection(cs, this.epOther); this._removeDtmfDetection(cs, this.ep); } catch (err) { - this.logger.error(`TaskDial:exec terminating with error ${err.message}`); + this.logger.error({err}, 'TaskDial:exec terminating with error'); this.kill(); } } @@ -147,7 +146,7 @@ class TaskDial extends Task { this.sd.kill(); this.sd = null; } - sessionTracker.remove(this.callSid); + if (this.callSid) sessionTracker.remove(this.callSid); if (this.listenTask) await this.listenTask.kill(); if (this.transcribeTask) await this.transcribeTask.kill(); if (this.timerMaxCallDuration) clearTimeout(this.timerMaxCallDuration); @@ -242,7 +241,7 @@ class TaskDial extends Task { const sbcAddress = cs.direction === CallDirection.Inbound ? `${req.source_address}:${req.source_port}` : - config.get('outdials.sbc'); + srf.locals.sbcs[0]; const opts = { headers: req && req.has('X-CID') ? Object.assign(this.headers, {'X-CID': req.get('X-CID')}) : this.headers, proxy: `sip:${sbcAddress}`, diff --git a/lib/tasks/rest_dial.js b/lib/tasks/rest_dial.js index fdb02f35..2acb10d0 100644 --- a/lib/tasks/rest_dial.js +++ b/lib/tasks/rest_dial.js @@ -1,5 +1,7 @@ const Task = require('./task'); const {TaskName} = require('../utils/constants'); +const makeTask = require('./make_task'); +const normalizeJamones = require('../utils/normalize-jamones'); /** * Manages an outdial made via REST API @@ -44,12 +46,17 @@ class TaskRestDial extends Task { this.req = null; const cs = this.callSession; cs.setDialog(dlg); - const tasks = await cs.requestor.request(this.call_hook, cs.callInfo); - if (tasks && Array.isArray(tasks)) { - this.logger.debug({tasks: tasks}, `TaskRestDial: replacing application with ${tasks.length} tasks`); - cs.replaceApplication(tasks); + + try { + const tasks = await cs.requestor.request(this.call_hook, cs.callInfo); + if (tasks && Array.isArray(tasks)) { + this.logger.debug({tasks: tasks}, `TaskRestDial: replacing application with ${tasks.length} tasks`); + cs.replaceApplication(normalizeJamones(this.logger, tasks).map((tdata) => makeTask(this.logger, tdata))); + } + } catch (err) { + this.logger.error(err, 'TaskRestDial:_onConnect error retrieving or parsing application, ending call'); + this.notifyTaskDone(); } - this.notifyTaskDone(); } _onCallStatus(status) { diff --git a/lib/tasks/specs.json b/lib/tasks/specs.json index ce61a1c6..a2c35b81 100644 --- a/lib/tasks/specs.json +++ b/lib/tasks/specs.json @@ -116,8 +116,15 @@ }, "rest:dial": { "properties": { + "account_sid": "string", + "application_sid": "string", "call_hook": "object|string", + "call_status_hook": "object|string", "from": "string", + "speech_synthesis_vendor": "string", + "speech_synthesis_voice": "string", + "speech_recognizer_vendor": "string", + "speech_recognizer_language": "string", "tag": "object", "to": "#target", "timeout": "number" diff --git a/lib/utils/basic-auth.js b/lib/utils/basic-auth.js deleted file mode 100644 index 1d489860..00000000 --- a/lib/utils/basic-auth.js +++ /dev/null @@ -1,10 +0,0 @@ -const toBase64 = (str) => Buffer.from(str || '', 'utf8').toString('base64'); - -module.exports = (auth) => { - if (!auth || !auth.username || - typeof auth.username !== 'string' || - (auth.password && typeof auth.password !== 'string')) return {}; - const creds = `${auth.username}:${auth.password || ''}`; - const header = `Basic ${toBase64(creds)}`; - return {Authorization: header}; -}; diff --git a/lib/utils/install-srf-locals.js b/lib/utils/install-srf-locals.js index 32e5f819..58ebe533 100644 --- a/lib/utils/install-srf-locals.js +++ b/lib/utils/install-srf-locals.js @@ -1,26 +1,57 @@ -const config = require('config'); const ip = require('ip'); const localIp = ip.address(); -const PORT = process.env.HTTP_PORT || config.get('defaultHttpPort'); +const PORT = process.env.HTTP_PORT || 3000; function installSrfLocals(srf, logger) { if (srf.locals.dbHelpers) return; + const freeswitch = process.env.JAMBONES_FREESWITCH + .split(',') + .map((fs) => { + const arr = /^(.*):(.*):(.*)/.exec(fs); + if (arr) return {address: arr[1], port: arr[2], secret: arr[3]}; + }); + logger.info({freeswitch}, 'freeswitch inventory'); + + const sbcs = process.env.JAMBONES_SBCS + .split(',') + .map((sbc) => sbc.trim()); + logger.info({sbcs}, 'SBC inventory'); + + const drachtio = process.env.JAMBONES_FEATURE_SERVERS + .split(',') + .map((fs) => { + const arr = /^(.*):(.*):(.*)/.exec(fs); + if (arr) return {host: arr[1], port: arr[2], secret: arr[3]}; + }); + logger.info({drachtio}, 'drachtio feature server inventory'); + const { lookupAppByPhoneNumber, - lookupApplicationBySid - } = require('jambonz-db-helpers')(config.get('mysql'), logger); + lookupAppBySid, + lookupAppByRealm + } = require('jambonz-db-helpers')({ + host: process.env.JAMBONES_MYSQL_HOST, + user: process.env.JAMBONES_MYSQL_USER, + password: process.env.JAMBONES_MYSQL_PASSWORD, + database: process.env.JAMBONES_MYSQL_DATABASE, + connectionLimit: process.env.JAMBONES_MYSQL_CONNECTION_LIMIT || 10 + }, logger); const { updateCallStatus, retrieveCall, listCalls, deleteCall - } = require('jambonz-realtimedb-helpers')(config.get('redis'), logger); + } = require('jambonz-realtimedb-helpers')({ + host: process.env.JAMBONES_REDIS_HOST, + port: process.env.JAMBONES_REDIS_PORT || 6379 + }, logger); Object.assign(srf.locals, { dbHelpers: { lookupAppByPhoneNumber, - lookupApplicationBySid, + lookupAppBySid, + lookupAppByRealm, updateCallStatus, retrieveCall, listCalls, @@ -28,7 +59,10 @@ function installSrfLocals(srf, logger) { }, parentLogger: logger, ipv4: localIp, - serviceUrl: `http://${localIp}:${PORT}` + serviceUrl: `http://${localIp}:${PORT}`, + freeswitch: freeswitch[0], + sbcs, + drachtio }); } diff --git a/lib/utils/place-outdial.js b/lib/utils/place-outdial.js index 830a30c1..381b4858 100644 --- a/lib/utils/place-outdial.js +++ b/lib/utils/place-outdial.js @@ -233,7 +233,7 @@ class SingleDialer extends Emitter { this.callInfo.updateCallStatus(callStatus, sipStatus); if (typeof duration === 'number') this.callInfo.duration = duration; try { - this.notifyHook(this.application.call_status_hook); + this.requestor.request(this.application.call_status_hook, this.callInfo.toJSON()); } catch (err) { this.logger.info(err, `SingleDialer:_notifyCallStatusChange error sending ${callStatus} ${sipStatus}`); } diff --git a/lib/utils/requestor.js b/lib/utils/requestor.js index 54eb244b..a9b40bb9 100644 --- a/lib/utils/requestor.js +++ b/lib/utils/requestor.js @@ -1,8 +1,16 @@ const bent = require('bent'); const parseUrl = require('parse-url'); -const basicAuth = require('./basic-auth'); const assert = require('assert'); +const toBase64 = (str) => Buffer.from(str || '', 'utf8').toString('base64'); + +function basicAuth(username, password) { + if (!username || !password) return {}; + const creds = `${username}:${password || ''}`; + const header = `Basic ${toBase64(creds)}`; + return {Authorization: header}; +} + function isRelativeUrl(u) { return typeof u === 'string' && u.startsWith('/'); } @@ -14,25 +22,22 @@ function isAbsoluteUrl(u) { class Requestor { constructor(logger, hook) { + assert(typeof hook === 'object'); + this.logger = logger; this.url = hook.url; this.method = hook.method || 'POST'; - this.authHeader = basicAuth(hook.auth); + this.authHeader = basicAuth(hook.username, hook.password); const u = parseUrl(this.url); const myPort = u.port ? `:${u.port}` : ''; const baseUrl = `${u.protocol}://${u.resource}${myPort}`; - this.get = bent(baseUrl, 'GET', 'json', 200); - this.post = bent(baseUrl, 'POST', 'json', 200); + this.get = bent(baseUrl, 'GET', 'buffer', 200); + this.post = bent(baseUrl, 'POST', 'buffer', 200); assert(isAbsoluteUrl(this.url)); assert(['GET', 'POST'].includes(this.method)); - assert(!this.auth || typeof auth == 'object'); - } - - get hasAuth() { - return 'Authorization' in this.authHeader; } /** @@ -42,23 +47,36 @@ class Requestor { * @param {object|string} hook - may be a absolute or relative url, or an object * @param {string} [hook.url] - an absolute or relative url * @param {string} [hook.method] - 'GET' or 'POST' + * @param {string} [hook.username] - if basic auth is protecting the endpoint + * @param {string} [hook.password] - if basic auth is protecting the endpoint * @param {object} [params] - request parameters */ async request(hook, params) { params = params || null; - if (isRelativeUrl(hook)) { - this.logger.debug({params}, `Requestor:request relative url ${hook}`); - return await this.post(hook, params, this.authHeader); - } - const url = hook.url; + const url = hook.url || hook; const method = hook.method || 'POST'; - const authHeader = isRelativeUrl(url) ? this.authHeader : basicAuth(hook.auth); + const {username, password} = typeof hook === 'object' ? hook : {}; - assert(url); - assert(['GET', 'POST'].includes(method)); - return await this[method.toLowerCase()](url, params, authHeader); + assert.ok(url, 'Requestor:request url was not provided'); + assert.ok, (['GET', 'POST'].includes(method), `Requestor:request method must be 'GET' or 'POST' not ${method}`); + + + this.logger.debug({hook}, `Requestor:request ${method} ${url}`); + const buf = isRelativeUrl(url) ? + await this.post(url, params, this.authHeader) : + await bent(method, 'buffer', 200)(url, params, basicAuth(username, password)); + //this.logger.debug({body: }, `Requestor:request ${method} ${url} succeeded`); + + if (buf && buf.toString().length > 0) { + try { + const json = JSON.parse(buf.toString()); + return json; + } + catch (err) { + this.logger.debug({err, url, method}, `Requestor:request returned non-JSON content: '${buf.toString()}'`); + } + } } - } module.exports = Requestor; diff --git a/package-lock.json b/package-lock.json index b9a1acf4..82d48a68 100644 --- a/package-lock.json +++ b/package-lock.json @@ -625,14 +625,6 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "config": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/config/-/config-3.2.4.tgz", - "integrity": "sha512-H1XIGfnU1EAkfjSLn9ZvYDRx9lOezDViuzLDgiJ/lMeqjYe3q6iQfpcLt2NInckJgpAeekbNhQkmnnbdEDs9rw==", - "requires": { - "json5": "^1.0.1" - } - }, "content-disposition": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", @@ -2123,18 +2115,18 @@ } }, "jambonz-db-helpers": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/jambonz-db-helpers/-/jambonz-db-helpers-0.2.4.tgz", - "integrity": "sha512-qfMKvXv//UDGFveOmeC3Xq2jMvTP7Y1P4F3EPf7VAgD10/ipozLRdEx+o3HlyF9wOeP3syha9ofpnel8VYLGLA==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/jambonz-db-helpers/-/jambonz-db-helpers-0.3.2.tgz", + "integrity": "sha512-j7AEgts+Bj1CFPiM0estFmWmdDTZKWbkeIPY1QT3BR0cLClzjqo9fmdCzLoDtk/NWMy7IPNEQpVHzEejxFHq9g==", "requires": { "debug": "^4.1.1", "mysql2": "^2.0.2" } }, "jambonz-realtimedb-helpers": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/jambonz-realtimedb-helpers/-/jambonz-realtimedb-helpers-0.1.6.tgz", - "integrity": "sha512-5W7hRuPDCGeJfVLrweoNrfzQ7lCWy77+CcF4jqbTrbztZOK1rm0XhC1phCEUbghntmdLjTkwxpzEFxu7kyJKNQ==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/jambonz-realtimedb-helpers/-/jambonz-realtimedb-helpers-0.1.7.tgz", + "integrity": "sha512-eORZH5ODz5F59P/DWUxKLAwnLY3AXkfBG/MdcvJslpXYrk0WiqbdriyCz/xujmNEcftCKVBVCMsMMWcg7YKNeg==", "requires": { "bluebird": "^3.7.2", "debug": "^4.1.1", @@ -2238,14 +2230,6 @@ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "requires": { - "minimist": "^1.2.0" - } - }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", diff --git a/package.json b/package.json index 98b72b1c..bf3e5329 100644 --- a/package.json +++ b/package.json @@ -27,15 +27,14 @@ }, "dependencies": { "bent": "^7.0.6", - "config": "^3.2.4", "debug": "^4.1.1", "drachtio-fn-b2b-sugar": "0.0.12", "drachtio-fsmrf": "^1.5.14", "drachtio-srf": "^4.4.27", "express": "^4.17.1", "ip": "^1.1.5", - "jambonz-db-helpers": "^0.2.4", - "jambonz-realtimedb-helpers": "0.1.6", + "jambonz-db-helpers": "^0.3.2", + "jambonz-realtimedb-helpers": "0.1.7", "moment": "^2.24.0", "parse-url": "^5.0.1", "pino": "^5.14.0"