Compare commits

..

16 Commits

Author SHA1 Message Date
Sam Machin
24d9740618 add x-reason to sip-decline (#1518)
* add x-ver to sip-decline

* lint

* Update sip_decline.js

---------

Co-authored-by: Dave Horton <daveh@beachdognet.com>
2026-03-29 16:19:15 -04:00
rhondahollis
39746598b5 add null check for eventHook (#1534)
* add null check for eventHook

* move guard to superclass, remove logging that adds no value

---------

Co-authored-by: rhonda hollis <rhonda@jambonz.org>
Co-authored-by: Dave Horton <daveh@beachdognet.com>
2026-03-29 16:13:35 -04:00
Sam Machin
315eb98d86 add sp_sid to alerts (#1533)
* add sp_sid to alerts

* bump time-series

---------

Co-authored-by: Dave Horton <daveh@beachdognet.com>
2026-03-29 16:07:08 -04:00
Dave Horton
df30496dac fix uncaught exception referencing this.ep in freeswitch hangup scenario (#1532) 2026-03-27 08:31:32 -04:00
Sam Machin
5d6751782a Fix/hangup call (#1530)
* Update error.js

* Update error.js
2026-03-26 08:20:28 -04:00
rhondahollis
6147ec3f6a ensure sbcCallId is added to callInfo (#1529)
Co-authored-by: rhonda hollis <rhonda@jambonz.org>
2026-03-25 17:00:05 -04:00
Ed Robbins
18a13971ca respond to re-INVITE during race condition. (#1527) 2026-03-20 10:41:07 -04:00
Dave Horton
5bd1c53f7d fixed faulty commit https://github.com/jambonz/jambonz-feature-server/pull/1528 2026-03-20 09:17:00 -04:00
Anton Voylenko
5a759791f9 chore: bump node (#1528) 2026-03-20 08:57:16 -04:00
Sam Machin
1f5fa8d49e Update gather.js (#1526) 2026-03-19 15:29:03 -04:00
Anton Voylenko
cf0b392c99 Append sip realm for rest dial (#1525)
* feat: append sip realm for rest dial

* fix: check account sip realm
2026-03-17 07:30:21 -04:00
Anton Voylenko
68339ced0b fix: conference mute and mute status (#1218) 2026-03-12 07:55:49 -04:00
Ed Robbins
1560efaf03 remove sensitive data from log statement (#1522) 2026-03-05 10:04:20 -05:00
Dave Horton
782ce8154e update drachtio-srf (#1521) 2026-03-05 09:33:59 -05:00
Dave Horton
0267acf9e1 anchor media on dial if we are recording (#1520) 2026-02-23 18:13:25 -05:00
rhondahollis
9090006703 update drachtio-srf to v5.0.19 (#1519)
Co-authored-by: rhonda hollis <rhonda@jambonz.org>
2026-02-20 16:19:28 -05:00
24 changed files with 361 additions and 242 deletions

View File

@@ -1,10 +1,10 @@
FROM --platform=linux/amd64 node:20-alpine as base
FROM --platform=linux/amd64 node:24-alpine AS base
RUN apk --update --no-cache add --virtual .builds-deps build-base python3
WORKDIR /opt/app/
FROM base as build
FROM base AS build
COPY package.json package-lock.json ./

View File

@@ -18,6 +18,7 @@ const { createCallSchema, customSanitizeFunction } = require('../schemas/create-
const { selectHostPort } = require('../../utils/network');
const { JAMBONES_DIAL_SBC_FOR_REGISTERED_USER } = require('../../config');
const { createMediaEndpoint } = require('../../utils/media-endpoint');
const { DbErrorBadRequest } = require('../utils/errors');
const removeNullProperties = (obj) => (Object.keys(obj).forEach((key) => obj[key] === null && delete obj[key]), obj);
const removeNulls = (req, res, next) => {
@@ -122,8 +123,16 @@ router.post('/',
}
break;
case 'user':
uri = `sip:${target.name}`;
to = target.name;
let targetName = target.name;
if (!targetName.includes('@')) {
if (!account.sip_realm) {
throw new DbErrorBadRequest('no sip realm configured for account');
}
logger.debug(`appending sip realm ${account.sip_realm} to target name ${targetName}`);
targetName = `${targetName}@${account.sip_realm}`;
}
uri = `sip:${targetName}`;
to = targetName;
if (target.overrideTo) {
Object.assign(opts.headers, {
'X-Override-To': target.overrideTo
@@ -237,6 +246,7 @@ router.post('/',
if ('WS' === app.call_hook?.method || /^wss?:/.test(app.call_hook.url)) {
logger.debug({call_hook: app.call_hook}, 'creating websocket for call hook');
app.requestor = new WsRequestor(logger, account.account_sid, app.call_hook, account.webhook_secret) ;
app.requestor.service_provider_sid = account.service_provider_sid;
if (app.call_hook.url === app.call_status_hook?.url || !app.call_status_hook?.url) {
logger.debug('reusing websocket for call status hook');
app.notifier = app.requestor;
@@ -246,9 +256,11 @@ router.post('/',
else {
logger.debug({call_hook: app.call_hook}, 'creating http client for call hook');
app.requestor = new HttpRequestor(logger, account.account_sid, app.call_hook, account.webhook_secret);
app.requestor.service_provider_sid = account.service_provider_sid;
}
if (!app.notifier && app.call_status_hook) {
app.notifier = new HttpRequestor(logger, account.account_sid, app.call_status_hook, account.webhook_secret);
app.notifier.service_provider_sid = account.service_provider_sid;
logger.debug({call_status_hook: app.call_status_hook}, 'creating http client for call status hook');
}
else if (!app.notifier) {
@@ -331,6 +343,12 @@ router.post('/',
}
});
connectStream(dlg.remote.sdp);
/* ensure sbcCallid is set even if no provisional response was received */
if (!cs.callInfo.sbcCallid && dlg.res.has('X-CID')) {
cs.callInfo.sbcCallid = dlg.res.get('X-CID');
}
cs.emit('callStatusChange', {
callStatus: CallStatus.InProgress,
sipStatus: 200,

View File

@@ -6,8 +6,8 @@ function sysError(logger, res, err) {
return res.status(400).json({msg: err.message});
}
if (err instanceof DbErrorUnprocessableRequest) {
logger.info(err, 'unprocessable request');
return res.status(422).json({msg: err.message});
logger.info({message: err.message}, 'unprocessable request');
return res.status(422).send(err.message);
}
if (err.code === 'ER_DUP_ENTRY') {
logger.info(err, 'duplicate entry on insert');

View File

@@ -23,10 +23,12 @@ router.post('/:partner', async(req, res) => {
if ('WS' === hook?.method) {
app.requestor = new WsRequestor(logger, account.account_sid, hook, account.webhook_secret) ;
app.requestor.service_provider_sid = account.service_provider_sid;
app.notifier = app.requestor;
}
else {
app.requestor = new HttpRequestor(logger, account.account_sid, hook, account.webhook_secret);
app.requestor.service_provider_sid = account.service_provider_sid;
app.notifier = {request: () => {}};
}

View File

@@ -211,7 +211,9 @@ module.exports = function(srf, logger) {
if (account?.enable_debug_log) {
req.locals.logger.level = 'debug';
}
logger.debug({accountInfo: req.locals?.accountInfo?.account}, `retrieved account info for ${account_sid}`);
// eslint-disable-next-line no-unused-vars
const {bucket_credential, ...safeAccount} = req.locals?.accountInfo?.account || {};
logger.debug({accountInfo: safeAccount}, `retrieved account info for ${account_sid}`);
next();
} catch (err) {
span.end();
@@ -329,14 +331,19 @@ module.exports = function(srf, logger) {
if ('WS' === app.call_hook?.method ||
app.call_hook?.url.startsWith('ws://') || app.call_hook?.url.startsWith('wss://')) {
const requestor = new WsRequestor(logger, account_sid, app.call_hook, accountInfo.account.webhook_secret) ;
requestor.service_provider_sid = accountInfo.account.service_provider_sid;
app2.requestor = requestor;
app2.notifier = requestor;
app2.call_hook.method = 'WS';
}
else {
app2.requestor = new HttpRequestor(logger, account_sid, app.call_hook, accountInfo.account.webhook_secret);
if (app.call_status_hook) app2.notifier = new HttpRequestor(logger, account_sid, app.call_status_hook,
accountInfo.account.webhook_secret);
app2.requestor.service_provider_sid = accountInfo.account.service_provider_sid;
if (app.call_status_hook) {
app2.notifier = new HttpRequestor(logger, account_sid, app.call_status_hook,
accountInfo.account.webhook_secret);
app2.notifier.service_provider_sid = accountInfo.account.service_provider_sid;
}
else app2.notifier = {request: () => {}, close: () => {}};
}
@@ -476,6 +483,7 @@ module.exports = function(srf, logger) {
span?.end();
writeAlerts({
account_sid: req.locals.account_sid,
service_provider_sid: req.locals.service_provider_sid,
target_sid: req.locals.callSid,
alert_type: AlertType.INVALID_APP_PAYLOAD,
message: `${err?.message}`.trim()

View File

@@ -200,6 +200,10 @@ class CallSession extends Emitter {
return this.backgroundTaskManager.isTaskRunning('listen');
}
get isBackGroundRecord() {
return this.backgroundTaskManager.isTaskRunning('record');
}
/**
* SIP call-id for the call
*/
@@ -448,6 +452,10 @@ class CallSession extends Emitter {
return this.callInfo.accountSid;
}
get serviceProviderSid() {
return this.accountInfo?.account?.service_provider_sid;
}
/**
* returns true if this session was transferred from another server
*/
@@ -633,6 +641,7 @@ class CallSession extends Emitter {
writeAlerts({
alert_type: 'bot-action-delay-giveup',
account_sid: this.accountSid,
service_provider_sid: this.serviceProviderSid,
message: 'Call terminated due to bot action delay timeout',
target_sid: this.callSid
});
@@ -1090,6 +1099,7 @@ class CallSession extends Emitter {
writeAlerts({
alert_type: AlertType.TTS_FAILURE,
account_sid: this.accountSid,
service_provider_sid: this.serviceProviderSid,
vendor,
target_sid: this.callSid
}).catch((err) => this.logger.error({err}, 'Error writing tts alert'));
@@ -1289,6 +1299,7 @@ class CallSession extends Emitter {
writeAlerts({
alert_type: type === 'tts' ? AlertType.TTS_NOT_PROVISIONED : AlertType.STT_NOT_PROVISIONED,
account_sid: this.accountSid,
service_provider_sid: this.serviceProviderSid,
vendor,
label,
target_sid: this.callSid
@@ -2052,6 +2063,7 @@ Duration=${duration} `
writeAlerts({
alert_type: 'error-updating-call',
account_sid: this.accountSid,
service_provider_sid: this.serviceProviderSid,
message: err.message,
target_sid: callSid
});
@@ -2249,6 +2261,7 @@ Duration=${duration} `
await writeAlerts({
alert_type: AlertType.WEBHOOK_CONNECTION_FAILURE,
account_sid: this.accountSid,
service_provider_sid: this.serviceProviderSid,
detail: `Session:reconnect error ${err}`,
url: this.application.call_hook.url,
});
@@ -2311,7 +2324,8 @@ Duration=${duration} `
break;
case 'mute:status':
this._lccMuteStatus(data, call_sid);
const status = typeof (data) === 'string' ? data : data.mute_status;
this._lccMuteStatus(status === 'mute', call_sid);
break;
case 'conf:mute-status':
@@ -2471,7 +2485,7 @@ Duration=${duration} `
this.logger.info(`allocated endpoint ${ep.uuid}`);
this.ep.on('destroy', () => {
this.logger.debug(`endpoint was destroyed!! ${this.ep.uuid}`);
this.logger.debug(`endpoint was destroyed!! ${this.ep?.uuid}`);
});
if (this.direction === CallDirection.Inbound || this.application?.transferredCall) {
@@ -2780,6 +2794,7 @@ Duration=${duration} `
}
} catch (err) {
this.logger.error(err, 'Error handling reinvite');
res.send(err.status || 500);
}
}
@@ -2879,6 +2894,7 @@ Duration=${duration} `
this.logger.debug({accountSid: this.accountSid, webhook: r[0]}, 'performQueueWebhook: webhook found');
this.queueEventHookRequestor = new HttpRequestor(this.logger, this.accountSid,
r[0], this.webhook_secret);
this.queueEventHookRequestor.service_provider_sid = this.serviceProviderSid;
this.queueEventHook = r[0];
}
} catch (err) {
@@ -3215,6 +3231,7 @@ Duration=${duration} `
await writeAlerts({
alert_type: AlertType.TTS_STREAMING_CONNECTION_FAILURE,
account_sid: this.accountSid,
service_provider_sid: this.serviceProviderSid,
vendor
});
} catch (error) {

View File

@@ -15,6 +15,7 @@ class TaskAlert extends Task {
await super.exec(cs);
writeAlerts({
account_sid,
service_provider_sid: cs.serviceProviderSid,
alert_type: AlertType.APPLICATION,
detail: `Application SID ${application_sid}`,
message: this.message,

View File

@@ -469,6 +469,7 @@ class Conference extends Task {
assert (cs.isInConference);
const mute = opts.conf_mute_status === 'mute';
this.logger.info(`Conference:doConferenceMute ${mute ? 'muting' : 'unmuting'} member`);
this.ep.api(`conference ${this.confName} ${mute ? 'mute' : 'unmute'} ${this.memberId}`)
.catch((err) => this.logger.info({err}, 'Error muting or unmuting participant'));
}
@@ -570,8 +571,8 @@ class Conference extends Task {
/**
* mute or unmute side of the call
*/
mute(callSid, doMute) {
this.doConferenceMute(this.callSession, {conf_mute_status: doMute});
async mute(callSid, doMute) {
this.doConferenceMute(this.callSession, {conf_mute_status: doMute ? 'mute' : 'unmute'});
}
/**

View File

@@ -160,6 +160,7 @@ class TaskDial extends Task {
const keepAnchor = this.data.anchorMedia ||
this.isTranscoding ||
this.cs.isBackGroundListen ||
this.cs.isBackGroundRecord ||
this.cs.onHoldMusic ||
ANCHOR_MEDIA_ALWAYS ||
this.listenTask ||

View File

@@ -726,6 +726,7 @@ class TaskGather extends SttTask {
this.logger.error(err, 'TaskGather:_startTranscribing error');
writeAlerts({
account_sid: this.cs.accountSid,
service_provider_sid: this.cs.serviceProviderSid,
alert_type: AlertType.STT_FAILURE,
vendor: this.vendor,
detail: err.message,
@@ -1205,6 +1206,7 @@ class TaskGather extends SttTask {
const errMessage = evt.error || evt.Message;
writeAlerts({
account_sid: cs.accountSid,
service_provider_sid: cs.serviceProviderSid,
alert_type: AlertType.STT_FAILURE,
message: `Custom speech vendor ${this.vendor} error: ${errMessage}`,
vendor: this.vendor,
@@ -1424,7 +1426,27 @@ class TaskGather extends SttTask {
returnedVerbs = await this.performAction({speech:evt, reason: 'stt-low-confidence', ...latencies});
}
}
} catch (err) { /*already logged error*/ }
} catch (err) {
this.logger.info({err}, 'TaskGather:_resolve - error performing action');
this.notifyError({msg: 'invalid actionHook response', details: err.message});
const {writeAlerts, AlertType} = this.cs.srf.locals;
writeAlerts({
account_sid: this.cs.accountSid,
service_provider_sid: this.cs.serviceProviderSid,
alert_type: AlertType.INVALID_APP_PAYLOAD,
target_sid: this.cs.callSid,
message: `actionHook returned invalid verb syntax: ${err.message}`
}).catch((err) => this.logger.info({err}, 'TaskGather:_resolve - error generating alert'));
try {
const obj = Object.assign({}, this.cs.callInfo.toJSON(), {
error: 'invalid actionHook response',
reason: err.message
});
await this.cs.notifier.request('call:status', this.cs.call_status_hook, obj);
} catch (statusErr) {
this.logger.info({statusErr}, 'TaskGather:_resolve - error sending statusHook');
}
}
// Gather got response from hook, cancel actionHookDelay processing
if (this.cs.actionHookDelayProcessor) {

View File

@@ -105,6 +105,7 @@ class TaskLlm extends Task {
}
async sendEventHook(data) {
if (!this.eventHook) return;
await this.cs?.requestor.request('llm:event', this.eventHook, data);
}

View File

@@ -105,6 +105,7 @@ class TaskPlay extends Task {
this.emit('playDone');
writeAlerts({
account_sid: cs.accountSid,
service_provider_sid: cs.serviceProviderSid,
alert_type: AlertType.PLAY_FILENOTFOUND,
url: this.url,
target_sid: cs.callSid

View File

@@ -26,6 +26,7 @@ class TaskRedirect extends Task {
try {
const requestor = new WsRequestor(this.logger, cs.accountSid, {url: this.actionHook},
cs.accountInfo.account.webhook_secret) ;
requestor.service_provider_sid = cs.serviceProviderSid;
cs.requestor.emit('handover', requestor);
} catch (err) {
this.logger.info(err, `TaskRedirect error redirecting to ${this.actionHook}`);
@@ -40,6 +41,7 @@ class TaskRedirect extends Task {
this.logger.info(`Task:redirect updating base url to ${newBaseUrl}`);
const newRequestor = new HttpRequestor(this.logger, cs.accountSid, {url: this.actionHook},
cs.accountInfo.account.webhook_secret);
newRequestor.service_provider_sid = cs.serviceProviderSid;
cs.requestor.emit('handover', newRequestor);
} catch (err) {
this.logger.info(err, `TaskRedirect error updating base url to ${this.actionHook}`);
@@ -56,11 +58,15 @@ class TaskRedirect extends Task {
const isStatusHookAbsolute = cs.notifier?._isAbsoluteUrl(this.statusHook);
if (isStatusHookAbsolute) {
if (cs.notifier instanceof WsRequestor) {
cs.application.notifier = new WsRequestor(this.logger, cs.accountSid, {url: this.statusHook},
const notifier = new WsRequestor(this.logger, cs.accountSid, {url: this.statusHook},
cs.accountInfo.account.webhook_secret);
notifier.service_provider_sid = cs.serviceProviderSid;
cs.application.notifier = notifier;
} else {
cs.application.notifier = new HttpRequestor(this.logger, cs.accountSid, {url: this.statusHook},
const notifier = new HttpRequestor(this.logger, cs.accountSid, {url: this.statusHook},
cs.accountInfo.account.webhook_secret);
notifier.service_provider_sid = cs.serviceProviderSid;
cs.application.notifier = notifier;
}
if (oldNotifier?.close) oldNotifier.close();
}

View File

@@ -326,6 +326,7 @@ class TaskSay extends TtsTask {
response_code <= 199 || response_code >= 300) {
writeAlerts({
account_sid,
service_provider_sid: cs.serviceProviderSid,
alert_type: AlertType.TTS_FAILURE,
vendor,
detail: evt.variable_tts_error || `TTS playback failed with response code ${response_code}`,

View File

@@ -17,7 +17,7 @@ class TaskSipDecline extends Task {
async exec(cs, {res}) {
super.exec(cs);
res.send(this.data.status, this.data.reason, {
headers: this.headers
headers: {'X-Reason': 'SIP Decline Verb', ...this.headers}
}, (err) => {
if (!err) {
// Call was successfully declined

View File

@@ -274,6 +274,7 @@ class SttTask extends Task {
this.logger.info(`ERROR stt using ${vendor} requested but creds not supplied`);
writeAlerts({
account_sid: cs.accountSid,
service_provider_sid: cs.serviceProviderSid,
alert_type: AlertType.STT_NOT_PROVISIONED,
vendor,
label,
@@ -473,6 +474,7 @@ class SttTask extends Task {
const {writeAlerts, AlertType} = cs.srf.locals;
writeAlerts({
account_sid: cs.accountSid,
service_provider_sid: cs.serviceProviderSid,
alert_type: AlertType.STT_FAILURE,
message: 'STT failure reported by vendor',
detail: evt.error,
@@ -488,6 +490,7 @@ class SttTask extends Task {
this.logger.info({evt}, `${this.name}:_on${this.vendor}ConnectFailure`);
writeAlerts({
account_sid: cs.accountSid,
service_provider_sid: cs.serviceProviderSid,
alert_type: AlertType.STT_FAILURE,
message: `Failed connecting to ${this.vendor} speech recognizer: ${reason}`,
vendor: this.vendor,

View File

@@ -843,6 +843,7 @@ class TaskTranscribe extends SttTask {
this.logger.info({evt}, 'TaskTranscribe:_onJambonzError');
writeAlerts({
account_sid: cs.accountSid,
service_provider_sid: cs.serviceProviderSid,
alert_type: AlertType.STT_FAILURE,
message: `Custom speech vendor ${this.vendor} error: ${evt.error}`,
vendor: this.vendor,

View File

@@ -282,6 +282,7 @@ class TtsTask extends Task {
if (!credentials) {
writeAlerts({
account_sid,
service_provider_sid: cs.serviceProviderSid,
alert_type: AlertType.TTS_NOT_PROVISIONED,
vendor,
label,
@@ -369,6 +370,7 @@ class TtsTask extends Task {
if (this.otelSpan) this.otelSpan.end();
writeAlerts({
account_sid: cs.accountSid,
service_provider_sid: cs.serviceProviderSid,
alert_type: AlertType.TTS_FAILURE,
vendor,
label,

View File

@@ -219,6 +219,7 @@ module.exports = (logger) => {
logger.error(err, 'amd:_startTranscribing error');
writeAlerts({
account_sid: cs.accountSid,
service_provider_sid: cs.serviceProviderSid,
alert_type: AlertType.STT_FAILURE,
vendor: vendor,
detail: err.message,

View File

@@ -128,6 +128,7 @@ class HttpRequestor extends BaseRequestor {
this.logger.debug({hook}, 'HttpRequestor: switching to websocket connection');
const h = typeof hook === 'object' ? hook : {url: hook};
const requestor = new WsRequestor(this.logger, this.account_sid, h, this.secret);
requestor.service_provider_sid = this.service_provider_sid;
if (type === 'session:redirect') {
this.close();
this.emit('handover', requestor);
@@ -248,7 +249,7 @@ class HttpRequestor extends BaseRequestor {
this.logger.error({err, baseUrl: this.baseUrl, url},
'web callback returned unexpected error');
}
let opts = {account_sid: this.account_sid};
let opts = {account_sid: this.account_sid, service_provider_sid: this.service_provider_sid};
if (err.code === 'ECONNREFUSED') {
opts = {...opts, alert_type: this.Alerter.AlertType.WEBHOOK_CONNECTION_FAILURE, url};
}

View File

@@ -234,6 +234,11 @@ class SingleDialer extends Emitter {
await connectStream(this.dlg.remote.sdp, opts.isVideoCall);
this.dlg.callSid = this.callSid;
this.inviteInProgress = null;
/* ensure sbcCallid is set even if no provisional response was received */
if (!this.callInfo.sbcCallid && this.dlg.res.has('X-CID')) {
this.callInfo.sbcCallid = this.dlg.res.get('X-CID');
}
this.emit('callStatusChange', {
sipStatus: 200,
sipReason: 'OK',
@@ -290,6 +295,7 @@ class SingleDialer extends Emitter {
}
} catch (err) {
this.logger.error(err, 'Error handling reinvite');
res.send(err.status || 500);
}
})
.on('refer', (req, res) => {
@@ -449,6 +455,7 @@ class SingleDialer extends Emitter {
if (app.call_hook?.url) app.call_hook.url += '/adulting';
const requestor = new WsRequestor(logger, this.accountInfo.account.account_sid,
app.call_hook, this.accountInfo.account.webhook_secret);
requestor.service_provider_sid = this.accountInfo.account.service_provider_sid;
app.requestor = requestor;
app.notifier = requestor;
app.call_hook.method = 'WS';
@@ -456,9 +463,13 @@ class SingleDialer extends Emitter {
else {
app.requestor = new HttpRequestor(logger, this.accountInfo.account.account_sid,
app.call_hook, this.accountInfo.account.webhook_secret);
if (app.call_status_hook) app.notifier = new HttpRequestor(logger,
this.accountInfo.account.account_sid, app.call_status_hook,
this.accountInfo.account.webhook_secret);
app.requestor.service_provider_sid = this.accountInfo.account.service_provider_sid;
if (app.call_status_hook) {
app.notifier = new HttpRequestor(logger,
this.accountInfo.account.account_sid, app.call_status_hook,
this.accountInfo.account.webhook_secret);
app.notifier.service_provider_sid = this.accountInfo.account.service_provider_sid;
}
else app.notifier = {request: () => {}, close: () => {}};
}
// Replace old application with new application.

View File

@@ -97,6 +97,7 @@ class WsRequestor extends BaseRequestor {
this.logger.debug({hook}, 'WsRequestor: sending a webhook (HTTP)');
const h = typeof hook === 'object' ? hook : {url: hook};
const requestor = new HttpRequestor(this.logger, this.account_sid, h, this.secret);
requestor.service_provider_sid = this.service_provider_sid;
if (type === 'session:redirect') {
this.close();
this.emit('handover', requestor);
@@ -522,6 +523,7 @@ class WsRequestor extends BaseRequestor {
const {writeAlerts, AlertType} = this.Alerter;
writeAlerts({
account_sid: this.account_sid,
service_provider_sid: this.service_provider_sid,
alert_type: AlertType.INVALID_APP_PAYLOAD,
target_sid: this.call_sid,
message: err.message,

447
package-lock.json generated
View File

@@ -17,7 +17,7 @@
"@jambonz/realtimedb-helpers": "^0.8.15",
"@jambonz/speech-utils": "^0.2.30",
"@jambonz/stats-collector": "^0.1.10",
"@jambonz/time-series": "^0.2.15",
"@jambonz/time-series": "^0.2.17",
"@jambonz/verb-specifications": "^0.0.125",
"@modelcontextprotocol/sdk": "^1.9.0",
"@opentelemetry/api": "^1.8.0",
@@ -30,21 +30,21 @@
"@opentelemetry/sdk-trace-node": "^1.23.0",
"@opentelemetry/semantic-conventions": "^1.23.0",
"bent": "^7.3.12",
"debug": "^4.3.4",
"debug": "^4.4.3",
"deepcopy": "^2.1.0",
"drachtio-fsmrf": "^4.1.2",
"drachtio-srf": "^5.0.18",
"express": "^4.19.2",
"drachtio-srf": "^5.0.20",
"express": "^4.22.1",
"express-validator": "^7.0.1",
"moment": "^2.30.1",
"parse-url": "^9.2.0",
"pino": "^10.1.0",
"pino": "^10.3.1",
"polly-ssml-split": "^0.1.0",
"sdp-transform": "^2.15.0",
"short-uuid": "^5.1.0",
"sinon": "^17.0.1",
"to-snake-case": "^1.0.0",
"undici": "^7.5.0",
"undici": "^7.24.5",
"verify-aws-sns-signature": "^0.1.0",
"ws": "^8.18.0",
"xml2js": "^0.6.2"
@@ -58,7 +58,7 @@
"tape": "^5.7.5"
},
"engines": {
"node": ">= 18.x"
"node": ">= 20.x"
},
"optionalDependencies": {
"bufferutil": "^4.0.8",
@@ -847,13 +847,13 @@
}
},
"node_modules/@aws-sdk/xml-builder": {
"version": "3.972.4",
"resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.4.tgz",
"integrity": "sha512-0zJ05ANfYqI6+rGqj8samZBFod0dPPousBjLEqg8WdxSgbMAkRgLyn81lP215Do0rFJ/17LIXwr7q0yK24mP6Q==",
"version": "3.972.16",
"resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.16.tgz",
"integrity": "sha512-iu2pyvaqmeatIJLURLqx9D+4jKAdTH20ntzB6BFwjyN7V960r4jK32mx0Zf7YbtOYAbmbtQfDNuL60ONinyw7A==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/types": "^4.12.0",
"fast-xml-parser": "5.3.4",
"@smithy/types": "^4.13.1",
"fast-xml-parser": "5.5.8",
"tslib": "^2.6.2"
},
"engines": {
@@ -1270,6 +1270,16 @@
"node": ">=6.9.0"
}
},
"node_modules/@borewit/text-codec": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.2.tgz",
"integrity": "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Borewit"
}
},
"node_modules/@cartesia/cartesia-js": {
"version": "2.2.9",
"resolved": "https://registry.npmjs.org/@cartesia/cartesia-js/-/cartesia-js-2.2.9.tgz",
@@ -1309,9 +1319,9 @@
}
},
"node_modules/@eslint/eslintrc/node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"version": "6.14.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz",
"integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1376,9 +1386,9 @@
}
},
"node_modules/@hono/node-server": {
"version": "1.19.9",
"resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz",
"integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==",
"version": "1.19.11",
"resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.11.tgz",
"integrity": "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==",
"license": "MIT",
"engines": {
"node": ">=18.14.1"
@@ -1627,9 +1637,9 @@
}
},
"node_modules/@jambonz/time-series": {
"version": "0.2.16",
"resolved": "https://registry.npmjs.org/@jambonz/time-series/-/time-series-0.2.16.tgz",
"integrity": "sha512-+WRXZRkLHMEmXjtxGCZta7XVJXOd98+Yz5WsTnXxd3Aa7hg+wJBjmDrVuj8JvTV4nUIBFZ5TuYpIQDVyYJuwlQ==",
"version": "0.2.17",
"resolved": "https://registry.npmjs.org/@jambonz/time-series/-/time-series-0.2.17.tgz",
"integrity": "sha512-bqglB1INDo+jo4XgHHq3twomZc2sTz9eR14t+4tck4TEvHH51ywvsPQqUQ/CqH0PR9rNTQn+yn7+Hq0X88kbtA==",
"license": "MIT",
"dependencies": {
"debug": "^4.3.1",
@@ -3110,9 +3120,9 @@
}
},
"node_modules/@smithy/types": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.12.0.tgz",
"integrity": "sha512-9YcuJVTOBDjg9LWo23Qp0lTQ3D7fQsQtwle0jVfpbUHy9qBwCEgKuVH4FqFB3VYu0nwdHKiEMA+oXz7oV8X1kw==",
"version": "4.13.1",
"resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.13.1.tgz",
"integrity": "sha512-787F3yzE2UiJIQ+wYW1CVg2odHjmaWLGksnKQHUrK/lYZSEcy1msuLVvxaR/sI2/aDe9U+TBuLsXnr3vod1g0g==",
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.6.2"
@@ -3354,21 +3364,29 @@
"node": ">=18.0.0"
}
},
"node_modules/@tokenizer/inflate": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.4.1.tgz",
"integrity": "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==",
"license": "MIT",
"dependencies": {
"debug": "^4.4.3",
"token-types": "^6.1.1"
},
"engines": {
"node": ">=18"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Borewit"
}
},
"node_modules/@tokenizer/token": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz",
"integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==",
"license": "MIT"
},
"node_modules/@tootallnate/once": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
"integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==",
"license": "MIT",
"engines": {
"node": ">= 10"
}
},
"node_modules/@types/async": {
"version": "3.2.25",
"resolved": "https://registry.npmjs.org/@types/async/-/async-3.2.25.tgz",
@@ -3541,9 +3559,9 @@
}
},
"node_modules/ajv": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"version": "8.18.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
"integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==",
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3",
@@ -3790,13 +3808,13 @@
}
},
"node_modules/axios": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz",
"integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==",
"version": "1.13.6",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz",
"integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.4",
"follow-redirects": "^1.15.11",
"form-data": "^4.0.5",
"proxy-from-env": "^1.1.0"
}
},
@@ -3927,9 +3945,9 @@
"license": "MIT"
},
"node_modules/brace-expansion": {
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
"integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4718,9 +4736,9 @@
}
},
"node_modules/drachtio-srf": {
"version": "5.0.18",
"resolved": "https://registry.npmjs.org/drachtio-srf/-/drachtio-srf-5.0.18.tgz",
"integrity": "sha512-gm8kc+w0FuWozR6oprcMqa2oPf9dpMABOrbUZle9XcsvJ+DZxpOk11gBBmtj12oSjPgb5hIi+jxzmI6blKVDRw==",
"version": "5.0.20",
"resolved": "https://registry.npmjs.org/drachtio-srf/-/drachtio-srf-5.0.20.tgz",
"integrity": "sha512-gqWTfqFZhC93TVBaFtRseemmfHPASotMfHhCy/3wQUHZShUl+Zr7Vbq+pLD1kyTNr4/pzpMwEMLd0/6oq/fCtg==",
"license": "MIT",
"dependencies": {
"debug": "^4.4.3",
@@ -5225,9 +5243,9 @@
}
},
"node_modules/eslint/node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"version": "6.14.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz",
"integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -5479,12 +5497,12 @@
}
},
"node_modules/express-rate-limit": {
"version": "8.2.1",
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.2.1.tgz",
"integrity": "sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==",
"version": "8.3.1",
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.3.1.tgz",
"integrity": "sha512-D1dKN+cmyPWuvB+G2SREQDzPY1agpBIcTa9sJxOPMCNeH3gwzhqJRDWCXW3gg0y//+LQ/8j52JbMROWyrKdMdw==",
"license": "MIT",
"dependencies": {
"ip-address": "10.0.1"
"ip-address": "10.1.0"
},
"engines": {
"node": ">= 16"
@@ -5593,10 +5611,10 @@
],
"license": "BSD-3-Clause"
},
"node_modules/fast-xml-parser": {
"version": "5.3.4",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.4.tgz",
"integrity": "sha512-EFd6afGmXlCx8H8WTZHhAoDaWaGyuIBoZJ2mknrNxug+aZKjkp0a0dlars9Izl+jF+7Gu1/5f/2h68cQpe0IiA==",
"node_modules/fast-xml-builder": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.4.tgz",
"integrity": "sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==",
"funding": [
{
"type": "github",
@@ -5605,7 +5623,24 @@
],
"license": "MIT",
"dependencies": {
"strnum": "^2.1.0"
"path-expression-matcher": "^1.1.3"
}
},
"node_modules/fast-xml-parser": {
"version": "5.5.8",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.5.8.tgz",
"integrity": "sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/NaturalIntelligence"
}
],
"license": "MIT",
"dependencies": {
"fast-xml-builder": "^1.1.4",
"path-expression-matcher": "^1.2.0",
"strnum": "^2.2.0"
},
"bin": {
"fxparser": "src/cli/cli.js"
@@ -5657,17 +5692,18 @@
}
},
"node_modules/file-type": {
"version": "16.5.4",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz",
"integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==",
"version": "21.3.4",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.4.tgz",
"integrity": "sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==",
"license": "MIT",
"dependencies": {
"readable-web-to-node-stream": "^3.0.0",
"strtok3": "^6.2.4",
"token-types": "^4.1.1"
"@tokenizer/inflate": "^0.4.1",
"strtok3": "^10.3.4",
"token-types": "^6.1.1",
"uint8array-extras": "^1.4.0"
},
"engines": {
"node": ">=10"
"node": ">=20"
},
"funding": {
"url": "https://github.com/sindresorhus/file-type?sponsor=1"
@@ -5775,9 +5811,9 @@
}
},
"node_modules/flatted": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
"integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
"integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
"dev": true,
"license": "ISC"
},
@@ -5992,9 +6028,9 @@
}
},
"node_modules/gaxios/node_modules/brace-expansion": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz",
"integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
@@ -6037,12 +6073,12 @@
}
},
"node_modules/gaxios/node_modules/minimatch": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"version": "9.0.9",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
"integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
"brace-expansion": "^2.0.2"
},
"engines": {
"node": ">=16 || 14 >=14.17"
@@ -6322,9 +6358,9 @@
}
},
"node_modules/google-gax/node_modules/brace-expansion": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz",
"integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
@@ -6367,12 +6403,12 @@
}
},
"node_modules/google-gax/node_modules/minimatch": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"version": "9.0.9",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
"integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
"brace-expansion": "^2.0.2"
},
"engines": {
"node": ">=16 || 14 >=14.17"
@@ -6634,9 +6670,9 @@
}
},
"node_modules/hono": {
"version": "4.11.9",
"resolved": "https://registry.npmjs.org/hono/-/hono-4.11.9.tgz",
"integrity": "sha512-Eaw2YTGM6WOxA6CXbckaEvslr2Ne4NFsKrvc0v97JD5awbmeBLO5w9Ho9L9kmKonrwF9RJlW6BxT1PVv/agBHQ==",
"version": "4.12.9",
"resolved": "https://registry.npmjs.org/hono/-/hono-4.12.9.tgz",
"integrity": "sha512-wy3T8Zm2bsEvxKZM5w21VdHDDcwVS1yUFFY6i8UobSsKfFceT7TOwhbhfKsDyx7tYQlmRM5FLpIuYvNFyjctiA==",
"license": "MIT",
"engines": {
"node": ">=16.9.0"
@@ -6682,29 +6718,16 @@
}
},
"node_modules/http-proxy-agent": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
"integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==",
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
"integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
"license": "MIT",
"dependencies": {
"@tootallnate/once": "2",
"agent-base": "6",
"debug": "4"
"agent-base": "^7.1.0",
"debug": "^4.3.4"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/http-proxy-agent/node_modules/agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
"license": "MIT",
"dependencies": {
"debug": "4"
},
"engines": {
"node": ">= 6.0.0"
"node": ">= 14"
}
},
"node_modules/https-proxy-agent": {
@@ -6739,23 +6762,24 @@
}
},
"node_modules/ibm-cloud-sdk-core": {
"version": "5.4.5",
"resolved": "https://registry.npmjs.org/ibm-cloud-sdk-core/-/ibm-cloud-sdk-core-5.4.5.tgz",
"integrity": "sha512-7ClYtr/Xob83hypKUa1D9N8/ViH71giKQ0kqjHcoyKum6yvwsWAeFA6zf6WTWb+DdZ1XSBrMPhgCCoy0bqReLg==",
"version": "5.4.9",
"resolved": "https://registry.npmjs.org/ibm-cloud-sdk-core/-/ibm-cloud-sdk-core-5.4.9.tgz",
"integrity": "sha512-340fGcZEwUBdxBOPmn8V8fIiFRWF92yFqSFRNLwPQz4h+PS4jcAyd3JGqU6CpFqzUTt+PatVX/jHFwzUTVdmxQ==",
"license": "Apache-2.0",
"dependencies": {
"@types/debug": "^4.1.12",
"@types/node": "^18.19.80",
"@types/tough-cookie": "^4.0.0",
"axios": "^1.12.2",
"axios": "^1.13.5",
"camelcase": "^6.3.0",
"debug": "^4.3.4",
"dotenv": "^16.4.5",
"extend": "3.0.2",
"file-type": "16.5.4",
"file-type": "^21.3.2",
"form-data": "^4.0.4",
"isstream": "0.1.2",
"jsonwebtoken": "^9.0.3",
"load-esm": "^1.0.3",
"mime-types": "2.1.35",
"retry-axios": "^2.6.0",
"tough-cookie": "^4.1.3"
@@ -6995,9 +7019,9 @@
}
},
"node_modules/ip-address": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz",
"integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==",
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz",
"integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==",
"license": "MIT",
"engines": {
"node": ">= 12"
@@ -7841,6 +7865,25 @@
"node": ">= 0.8.0"
}
},
"node_modules/load-esm": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/load-esm/-/load-esm-1.0.3.tgz",
"integrity": "sha512-v5xlu8eHD1+6r8EHTg6hfmO97LN8ugKtiXcy5e6oN72iD2r6u0RPfLl6fxM+7Wnh2ZRq15o0russMst44WauPA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/Borewit"
},
{
"type": "buymeacoffee",
"url": "https://buymeacoffee.com/borewit"
}
],
"license": "MIT",
"engines": {
"node": ">=13.2.0"
}
},
"node_modules/locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
@@ -8173,9 +8216,9 @@
}
},
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -8928,6 +8971,21 @@
"node": ">=8"
}
},
"node_modules/path-expression-matcher": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.2.0.tgz",
"integrity": "sha512-DwmPWeFn+tq7TiyJ2CxezCAirXjFxvaiD03npak3cRjlP9+OjTmSy1EpIrEbh+l6JgUundniloMLDQ/6VTdhLQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/NaturalIntelligence"
}
],
"license": "MIT",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
@@ -8976,24 +9034,11 @@
"license": "ISC"
},
"node_modules/path-to-regexp": {
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz",
"integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==",
"license": "MIT"
},
"node_modules/peek-readable": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz",
"integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==",
"license": "MIT",
"engines": {
"node": ">=8"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Borewit"
}
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -9002,31 +9047,31 @@
"license": "ISC"
},
"node_modules/pino": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/pino/-/pino-10.1.0.tgz",
"integrity": "sha512-0zZC2ygfdqvqK8zJIr1e+wT1T/L+LF6qvqvbzEQ6tiMAoTqEVK9a1K3YRu8HEUvGEvNqZyPJTtb2sNIoTkB83w==",
"version": "10.3.1",
"resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz",
"integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==",
"license": "MIT",
"dependencies": {
"@pinojs/redact": "^0.4.0",
"atomic-sleep": "^1.0.0",
"on-exit-leak-free": "^2.1.0",
"pino-abstract-transport": "^2.0.0",
"pino-abstract-transport": "^3.0.0",
"pino-std-serializers": "^7.0.0",
"process-warning": "^5.0.0",
"quick-format-unescaped": "^4.0.3",
"real-require": "^0.2.0",
"safe-stable-stringify": "^2.3.1",
"sonic-boom": "^4.0.1",
"thread-stream": "^3.0.0"
"thread-stream": "^4.0.0"
},
"bin": {
"pino": "bin.js"
}
},
"node_modules/pino-abstract-transport": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz",
"integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz",
"integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==",
"license": "MIT",
"dependencies": {
"split2": "^4.0.0"
@@ -9238,9 +9283,9 @@
}
},
"node_modules/qs": {
"version": "6.14.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
"integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
"version": "6.14.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
"integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==",
"license": "BSD-3-Clause",
"dependencies": {
"side-channel": "^1.1.0"
@@ -9320,22 +9365,6 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/readable-web-to-node-stream": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.4.tgz",
"integrity": "sha512-9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/CVPtb/XHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw==",
"license": "MIT",
"dependencies": {
"readable-stream": "^4.7.0"
},
"engines": {
"node": ">=8"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Borewit"
}
},
"node_modules/real-require": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz",
@@ -9570,9 +9599,9 @@
}
},
"node_modules/router/node_modules/path-to-regexp": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz",
"integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==",
"version": "8.4.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.0.tgz",
"integrity": "sha512-PuseHIvAnz3bjrM2rGJtSgo1zjgxapTLZ7x2pjhzWwlp4SJQgK3f3iZIQwkpEnBaKz6seKBADpM4B4ySkuYypg==",
"license": "MIT",
"funding": {
"type": "opencollective",
@@ -10362,9 +10391,9 @@
}
},
"node_modules/strnum": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.2.tgz",
"integrity": "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==",
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.2.tgz",
"integrity": "sha512-DnR90I+jtXNSTXWdwrEy9FakW7UX+qUZg28gj5fk2vxxl7uS/3bpI4fjFYVmdK9etptYBPNkpahuQnEwhwECqA==",
"funding": [
{
"type": "github",
@@ -10374,16 +10403,15 @@
"license": "MIT"
},
"node_modules/strtok3": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz",
"integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==",
"version": "10.3.5",
"resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.5.tgz",
"integrity": "sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==",
"license": "MIT",
"dependencies": {
"@tokenizer/token": "^0.3.0",
"peek-readable": "^4.1.0"
"@tokenizer/token": "^0.3.0"
},
"engines": {
"node": ">=10"
"node": ">=18"
},
"funding": {
"type": "github",
@@ -10493,13 +10521,13 @@
}
},
"node_modules/teeny-request": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-10.1.0.tgz",
"integrity": "sha512-3ZnLvgWF29jikg1sAQ1g0o+lr5JX6sVgYvfUJazn7ZjJroDBUTWp44/+cFVX0bULjv4vci+rBD+oGVAkWqhUbw==",
"version": "10.1.2",
"resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-10.1.2.tgz",
"integrity": "sha512-Xj0ZAQ0CeuQn6UxCDPLbFRlgcSTUEyO3+wiepr2grjIjyL/lMMs1Z4OwXn8kLvn/V1OuaEP0UY7Na6UDNNsYrQ==",
"license": "Apache-2.0",
"dependencies": {
"http-proxy-agent": "^5.0.0",
"https-proxy-agent": "^5.0.0",
"http-proxy-agent": "^7.0.0",
"https-proxy-agent": "^7.0.1",
"node-fetch": "^3.3.2",
"stream-events": "^1.0.5"
},
@@ -10507,31 +10535,6 @@
"node": ">=18"
}
},
"node_modules/teeny-request/node_modules/agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
"license": "MIT",
"dependencies": {
"debug": "4"
},
"engines": {
"node": ">= 6.0.0"
}
},
"node_modules/teeny-request/node_modules/https-proxy-agent": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
"license": "MIT",
"dependencies": {
"agent-base": "6",
"debug": "4"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/teeny-request/node_modules/node-fetch": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
@@ -10573,12 +10576,15 @@
"license": "MIT"
},
"node_modules/thread-stream": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz",
"integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==",
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.0.0.tgz",
"integrity": "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==",
"license": "MIT",
"dependencies": {
"real-require": "^0.2.0"
},
"engines": {
"node": ">=20"
}
},
"node_modules/thriftrw": {
@@ -10640,16 +10646,17 @@
}
},
"node_modules/token-types": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz",
"integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==",
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/token-types/-/token-types-6.1.2.tgz",
"integrity": "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==",
"license": "MIT",
"dependencies": {
"@borewit/text-codec": "^0.2.1",
"@tokenizer/token": "^0.3.0",
"ieee754": "^1.2.1"
},
"engines": {
"node": ">=10"
"node": ">=14.16"
},
"funding": {
"type": "github",
@@ -10824,6 +10831,18 @@
"is-typedarray": "^1.0.0"
}
},
"node_modules/uint8array-extras": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.5.0.tgz",
"integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==",
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/unbox-primitive": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
@@ -10844,9 +10863,9 @@
}
},
"node_modules/undici": {
"version": "7.21.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-7.21.0.tgz",
"integrity": "sha512-Hn2tCQpoDt1wv23a68Ctc8Cr/BHpUSfaPYrkajTXOS9IKpxVRx/X5m1K2YkbK2ipgZgxXSgsUinl3x+2YdSSfg==",
"version": "7.24.5",
"resolved": "https://registry.npmjs.org/undici/-/undici-7.24.5.tgz",
"integrity": "sha512-3IWdCpjgxp15CbJnsi/Y9TCDE7HWVN19j1hmzVhoAkY/+CJx449tVxT5wZc1Gwg8J+P0LWvzlBzxYRnHJ+1i7Q==",
"license": "MIT",
"engines": {
"node": ">=20.18.1"
@@ -10949,9 +10968,9 @@
}
},
"node_modules/utf-8-validate": {
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-6.0.5.tgz",
"integrity": "sha512-EYZR+OpIXp9Y1eG1iueg8KRsY8TuT8VNgnanZ0uA3STqhHQTLwbl+WX76/9X5OY12yQubymBpaBSmMPkSTQcKA==",
"version": "6.0.6",
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-6.0.6.tgz",
"integrity": "sha512-q3l3P9UtEEiAHcsgsqTgf9PPjctrDWoIXW3NpOHFdRDbLvu4DLIcxHangJ4RLrWkBcKjmcs/6NkerI8T/rE4LA==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,

View File

@@ -3,7 +3,7 @@
"version": "0.9.5",
"main": "app.js",
"engines": {
"node": ">= 18.x"
"node": ">= 20.x"
},
"keywords": [
"sip",
@@ -33,7 +33,7 @@
"@jambonz/realtimedb-helpers": "^0.8.15",
"@jambonz/speech-utils": "^0.2.30",
"@jambonz/stats-collector": "^0.1.10",
"@jambonz/time-series": "^0.2.15",
"@jambonz/time-series": "^0.2.17",
"@jambonz/verb-specifications": "^0.0.125",
"@modelcontextprotocol/sdk": "^1.9.0",
"@opentelemetry/api": "^1.8.0",
@@ -46,21 +46,21 @@
"@opentelemetry/sdk-trace-node": "^1.23.0",
"@opentelemetry/semantic-conventions": "^1.23.0",
"bent": "^7.3.12",
"debug": "^4.3.4",
"debug": "^4.4.3",
"deepcopy": "^2.1.0",
"drachtio-fsmrf": "^4.1.2",
"drachtio-srf": "^5.0.18",
"express": "^4.19.2",
"drachtio-srf": "^5.0.20",
"express": "^4.22.1",
"express-validator": "^7.0.1",
"moment": "^2.30.1",
"parse-url": "^9.2.0",
"pino": "^10.1.0",
"pino": "^10.3.1",
"polly-ssml-split": "^0.1.0",
"sdp-transform": "^2.15.0",
"short-uuid": "^5.1.0",
"sinon": "^17.0.1",
"to-snake-case": "^1.0.0",
"undici": "^7.5.0",
"undici": "^7.24.5",
"verify-aws-sns-signature": "^0.1.0",
"ws": "^8.18.0",
"xml2js": "^0.6.2"