@jambonz/node-red-contrib-jambonz 2.4.30 → 2.4.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jambonz/node-red-contrib-jambonz",
3
- "version": "2.4.30",
3
+ "version": "2.4.32",
4
4
  "description": "Node-RED nodes for jambonz platform",
5
5
  "keywords": [
6
6
  "node-red"
@@ -64,7 +64,7 @@
64
64
  "hash-sum": "^2.0.0",
65
65
  "is-utf8": "^0.2.1",
66
66
  "media-typer": "^1.1.0",
67
- "multer": "^1.4.5-lts.1",
67
+ "multer": "^2.0.1",
68
68
  "mustache": "^4.2.0",
69
69
  "on-headers": "^1.0.2",
70
70
  "raw-body": "^2.5.2",
@@ -20,8 +20,9 @@
20
20
  trunk: {value: ''},
21
21
  trunkType: {value: 'str'},
22
22
  dest: {value: 'phone', required: true},
23
- timeout: {validate: RED.validators.regex(/^\d*$/) },
24
- tag: {required: true},
23
+ timeout: {value: '' },
24
+ timeoutType: {value: 'num'},
25
+ tag: {value: '{}'},
25
26
  tagType: {value: 'json'},
26
27
  application: {value: ''},
27
28
  appName: {},
@@ -113,6 +114,11 @@
113
114
  default: $('#node-input-trunkType').val(),
114
115
  types: ['str', 'msg', 'flow', 'global', 'jsonata', 'env', mustacheType],
115
116
  typeField: $('#node-input-trunkType')
117
+ });
118
+ $('#node-input-timeout').typedInput({
119
+ default: $('#node-input-timeoutType').val(),
120
+ types: ['num', 'msg', 'flow', 'global', 'jsonata', 'env'],
121
+ typeField: $('#node-input-timeoutType')
116
122
  });
117
123
  var populateApplications = function() {
118
124
  var serverId = $('#node-input-server option:selected').val();
@@ -256,6 +262,7 @@
256
262
  <div class="form-row">
257
263
  <label for="node-input-timeout">Ring timeout</label>
258
264
  <input type="text" id="node-input-timeout" placeholder="ring no answer timeout in secs (default: 60)">
265
+ <input type="hidden" id="node-input-timeoutType">
259
266
  </div>
260
267
  <div class="form-row">
261
268
  <label for="node-input-tag">Tag data</label>
@@ -22,6 +22,7 @@ module.exports = function(RED) {
22
22
  var from = await new_resolve(RED, config.from, config.fromType, node, msg);
23
23
  var to = await new_resolve(RED, config.to, config.toType, node, msg);
24
24
  var tag = await new_resolve(RED, config.tag, config.tagType, node, msg);
25
+ var timeout = await new_resolve(RED, config.timeout, config.timeoutType, node, msg);
25
26
 
26
27
  const opts = {
27
28
  from,
@@ -64,8 +65,8 @@ module.exports = function(RED) {
64
65
  break;
65
66
  }
66
67
 
67
- if (config.timeout) {
68
- const timeout = parseInt(config.timeout);
68
+ if (timeout) {
69
+ timeout = parseInt(timeout);
69
70
  if (timeout > 0) opts.timeout = timeout;
70
71
  }
71
72
 
@@ -17,6 +17,7 @@
17
17
  actionhookType: {value: 'str'},
18
18
  answeronbridge: {value: false},
19
19
  anchormedia: {value: false},
20
+ exitmediapath: {value: false},
20
21
  callerid: {value: ''},
21
22
  calleridType: {value: ''},
22
23
  callername: {value: ''},
@@ -33,8 +34,14 @@
33
34
  dtmfhookType: {value: 'str'},
34
35
  onholdhook: {value: ''},
35
36
  onholdhookType: {value: 'str'},
36
- timelimit: {validate:RED.validators.regex(/^\d*$/) },
37
- timeout: {validate:RED.validators.regex(/^\d*$/) },
37
+ timelimit: {},
38
+ timelimitType: {value: 'num'},
39
+ timeout: {},
40
+ timeoutType: {value: 'num'},
41
+ boostaudiosignal: { value: "" },
42
+ boostaudiosignalType: { value: "str" },
43
+ tag: {value: '{}'},
44
+ tagType: {value: 'json'},
38
45
  listenurl: {value: ''},
39
46
  listenurlType: {value: 'str'},
40
47
  transcriptionhook: {},
@@ -74,7 +81,8 @@
74
81
  amd_timers_decisionTimeoutMs: {},
75
82
  amd_timers_greetingCompletionTimeoutMs:{},
76
83
  amd_timers_noSpeechTimeoutMs: {},
77
- amd_timers_toneTimeoutMs: {}
84
+ amd_timers_toneTimeoutMs: {},
85
+ amd_digitCount: {},
78
86
  },
79
87
  inputs:1,
80
88
  outputs:1,
@@ -122,6 +130,15 @@
122
130
  types: ['str', 'msg', 'flow', 'global', 'jsonata', 'env', mustacheType],
123
131
  typeField: $('#node-input-onholdhookType')
124
132
  });
133
+ $('#node-input-boostaudiosignal').typedInput({
134
+ types: ['str', 'msg', 'flow', 'global', 'jsonata', 'env', mustacheType],
135
+ typeField: $('#node-input-boostaudiosignalType')
136
+ });
137
+ $('#node-input-tag').typedInput({
138
+ default: $('#node-input-tagType').val(),
139
+ types: ['json', 'msg', 'flow', 'global', 'jsonata', 'env', mustacheType],
140
+ typeField: $('#node-input-tagType')
141
+ });
125
142
  $('#node-input-transcribeurl').typedInput({
126
143
  types: ['str', 'msg', 'flow', 'global', 'jsonata', 'env', mustacheType],
127
144
  typeField: $('#node-input-transcribeurlType')
@@ -154,6 +171,14 @@
154
171
  types: ['num', 'msg', 'flow', 'global', 'jsonata', 'env', mustacheType],
155
172
  typeField: $('#node-input-naicsType')
156
173
  });
174
+ $('#node-input-timeout').typedInput({
175
+ types: ['num', 'msg', 'flow', 'global', 'jsonata', 'env'],
176
+ typeField: $('#node-input-timeoutType')
177
+ });
178
+ $('#node-input-timelimit').typedInput({
179
+ types: ['num', 'msg', 'flow', 'global', 'jsonata', 'env'],
180
+ typeField: $('#node-input-timelimitType')
181
+ });
157
182
 
158
183
  prepareSttControls(node);
159
184
  prepareSttControls(node, '#node-input-amd_recognizer_vendor', '#node-input-amd_recognizer_lang');
@@ -474,6 +499,10 @@
474
499
  <label for="node-input-anchormedia">Anchor media</label>
475
500
  <input type="checkbox" id="node-input-anchormedia">
476
501
  </div>
502
+ <div class="form-row">
503
+ <label for="node-input-exitmediapath">Exit media path</label>
504
+ <input type="checkbox" id="node-input-exitmediapath">
505
+ </div>
477
506
  <div class="form-row">
478
507
  <label for="node-input-callerid">Caller ID</label>
479
508
  <input type="text" id="node-input-callerid" placeholder="caller id to place on outbound call">
@@ -517,10 +546,22 @@
517
546
  <div class="form-row">
518
547
  <label for="node-input-timelimit">Time limit</label>
519
548
  <input type="text" id="node-input-timelimit" placeholder="max duration of call in secs">
549
+ <input type="hidden" id="node-input-timelimitType">
520
550
  </div>
521
551
  <div class="form-row">
522
552
  <label for="node-input-timeout"><i class="icon-tag"></i> Timeout</label>
523
553
  <input type="text" id="node-input-timeout" placeholder="ring no answer timeout in secs (default: 60)">
554
+ <input type="hidden" id="node-input-timeoutType">
555
+ </div>
556
+ <div class="form-row">
557
+ <label for="node-input-boostaudiosignal">Boost audio signal</label>
558
+ <input type="text" id="node-input-boostaudiosignal" placeholder="boost audio volume in decibels">
559
+ <input type="hidden" id="node-input-boostaudiosignalType">
560
+ </div>
561
+ <div class="form-row">
562
+ <label for="node-input-tag">Tag data</label>
563
+ <input type="text" id="node-input-tag" placeholder="tag object">
564
+ <input type="hidden" id="node-input-tagType">
524
565
  </div>
525
566
  <fieldset>
526
567
  <legend>Live audio</legend>
@@ -690,6 +731,10 @@
690
731
  <label for="node-input-amd_thresholdWordCount">Threshold Word Count</label>
691
732
  <input type="text" id="node-input-amd_thresholdWordCount">
692
733
  </div>
734
+ <div class="form-row">
735
+ <label for="node-input-amd_digitCount">Digit Count</label>
736
+ <input type="text" id="node-input-amd_digitCount">
737
+ </div>
693
738
  <div class="form-row">
694
739
  <label for="node-input-amd_timers_decisionTimeoutMs">Decision Timeout</label>
695
740
  <input type="text" id="node-input-amd_timers_decisionTimeoutMs">
package/src/nodes/dial.js CHANGED
@@ -41,8 +41,8 @@ module.exports = function(RED) {
41
41
  verb: 'dial',
42
42
  target,
43
43
  answerOnBridge: config.answeronbridge,
44
- timeLimit: config.timelimit ? parseInt(config.timelimit) : null,
45
- timeout: config.timeout ? parseInt(config.timeout) : null,
44
+ timeLimit: await new_resolve(RED, config.timelimit, config.timelimitType, node, msg),
45
+ timeout: await new_resolve(RED, config.timeout, config.timeoutType, node, msg),
46
46
  callerId: await new_resolve(RED, config.callerid, config.calleridType, node, msg),
47
47
  callerName: await new_resolve(RED, config.callername, config.callernameType, node, msg),
48
48
  actionHook: await new_resolve(RED, config.actionhook, config.actionhookType, node, msg),
@@ -56,10 +56,22 @@ module.exports = function(RED) {
56
56
  data.anchorMedia = config.anchormedia;
57
57
  }
58
58
 
59
+ if (config.hasOwnProperty('exitmediapath')) {
60
+ data.exitMediaPath = config.exitmediapath;
61
+ }
62
+
59
63
  if (config.onholdhook) {
60
64
  data.onHoldHook = await new_resolve(RED, config.onholdhook, config.onholdhookType, node, msg);
61
65
  }
62
66
 
67
+ if (config.tag) {
68
+ data.tag = await new_resolve(RED, config.tag, config.tagType, node, msg);
69
+ }
70
+
71
+ if (config.boostaudiosignal) {
72
+ data.boostAudioSignal = await new_resolve(RED, config.boostaudiosignal, config.boostaudiosignalType, node, msg)
73
+ }
74
+
63
75
  // headers
64
76
  const headers = {};
65
77
  config.headers.forEach(function(h) {
@@ -138,6 +150,7 @@ module.exports = function(RED) {
138
150
  data.amd = {}
139
151
  data.amd.actionHook = _amd_actionHook;
140
152
  config.amd_thresholdWordCount && (data.amd.thresholdWordCount = Number(config.amd_thresholdWordCount))
153
+ config.amd_digitCount && (data.amd.digitCount = Number(config.amd_digitCount))
141
154
  data.amd.timers = {
142
155
  ...(config.amd_timers_decisionTimeoutMs && {decisionTimeoutMs: Number(config.amd_timers_decisionTimeoutMs)}),
143
156
  ...(config.amd_timers_greetingCompletionTimeoutMs && {greetingCompletionTimeoutMs: Number(config.amd_timers_greetingCompletionTimeoutMs)}),
@@ -1,6 +1,14 @@
1
1
  <!-- Javascript -->
2
2
  <script type="text/javascript">
3
-
3
+
4
+ function formatjson(e) {
5
+ e.preventDefault();
6
+ e = s.getValue() || "";
7
+ try {
8
+ e = JSON.stringify(JSON.parse(e), null, 4)
9
+ } catch (e) {}
10
+ s.getSession().setValue(e || "", -1)
11
+ }
4
12
 
5
13
  RED.nodes.registerType('generic',{
6
14
  category: 'jambonz',
@@ -8,20 +16,32 @@
8
16
  defaults: {
9
17
  name: {value: ''},
10
18
  verb: {required: true},
11
- data: {value: '{}'},
12
- dataType: {value: 'json'},
19
+ data: { value: '',
20
+ validate: function(v) {
21
+ return (typeof(JSON.parse(v)) == 'object')
22
+ }
23
+ },
13
24
  },
14
25
  inputs:1,
15
26
  outputs:1,
16
27
  icon: "font-awesome/fa-cubes",
17
28
  label: function() { return this.name || 'generic';},
18
29
  oneditprepare: function() {
19
- $('#node-input-data').typedInput({
20
- default: $('#node-input-dataType').val(),
21
- types: ['json','msg', 'flow', 'global', 'jsonata', 'env'],
22
- typeField: $('#node-input-dataType')
23
- });
24
- }
30
+ this.editor = RED.editor.createEditor({
31
+ id: 'node-input-data-editor',
32
+ mode: 'ace/mode/json',
33
+ value: this.data
34
+ });
35
+ },
36
+ oneditsave: function() {
37
+ this.data = this.editor.getValue();
38
+ this.editor.destroy();
39
+ delete this.editor;
40
+ },
41
+ oneditcancel: function() {
42
+ this.editor.destroy();
43
+ delete this.editor;
44
+ }
25
45
  });
26
46
  </script>
27
47
 
@@ -35,11 +55,12 @@
35
55
  <label for="node-input-verb">Verb</label>
36
56
  <input type="text" id="node-input-verb" placeholder="verb">
37
57
  </div>
38
- <div class="form-row">
39
- <label for="node-input-data">Attributes</label>
40
- <input type="text" id="node-input-data">
41
- <input type="hidden" id="node-input-dataType">
42
- </div>
58
+ <div class="form-row" style="position: relative; height: 250px;">
59
+ <label for="node-input-data"><i class="fa fa-code"></i> Attributes</label>
60
+ <div style="position: absolute; right: 0; bottom: 0; top: 0; left: 100px;">
61
+ <div id="node-input-data-editor" style="width: 100%; height: 100%;"></div>
62
+ </div>
63
+ </div>
43
64
  </script>
44
65
 
45
66
  <!-- Help Text -->
@@ -1,4 +1,5 @@
1
1
  var {appendVerb, new_resolve} = require('./libs')
2
+ const assert = require('node:assert/strict');
2
3
 
3
4
  module.exports = function(RED) {
4
5
  function generic(config) {
@@ -6,12 +7,21 @@ module.exports = function(RED) {
6
7
  var node = this;
7
8
  node.verb = config.verb
8
9
  node.on('input', async function(msg) {
9
- let data = await new_resolve(RED, config.data, config.dataType, node, msg);
10
- appendVerb(msg, {
11
- ...{verb: node.verb},
12
- ...data
13
- });
14
- node.send(msg);
10
+ if (config.data.length==0) config.data='{}';
11
+ const _data = await new_resolve(RED, config.data, 'mustache', node, msg);
12
+ try {
13
+ const data = JSON.parse(_data)
14
+ assert.ok(typeof(data)=='object')
15
+ appendVerb(msg, {
16
+ ...{verb: node.verb},
17
+ ...data
18
+ });
19
+ node.send(msg);
20
+ } catch (error) {
21
+ console.error(error)
22
+ node.error(`Invalid Attributes object: ${_data}`)
23
+ }
24
+
15
25
  });
16
26
  }
17
27
  RED.nodes.registerType('generic', generic);
@@ -355,7 +355,8 @@
355
355
  <div class="form-row">
356
356
  <label for="node-input-action">Action</label>
357
357
  <select id="node-input-action">
358
- <option value="hangup">hangup call</option>
358
+ <option value="hangup">hangup answered call</option>
359
+ <option value="cancel">cancel call</option>
359
360
  <option value="mute">mute caller</option>
360
361
  <option value="unmute">unmute caller</option>
361
362
  <option value="mute_conf">mute conference participants</option>
@@ -508,7 +509,7 @@
508
509
  <div class="form-row">
509
510
  <label for="node-input-dubSay">Say Text</label>
510
511
  <input type="text" id="node-input-dubSay" placeholder="Text">
511
- <input type="hidden" id="node-input-tagType">
512
+ <input type="hidden" id="node-input-dubSayType">
512
513
  </div>
513
514
  <div class="form-row">
514
515
  <label for="node-input-dubLoop">Loop</label>
package/src/nodes/lcc.js CHANGED
@@ -26,6 +26,9 @@ function lcc(config) {
26
26
  case 'hangup':
27
27
  opts.call_status = 'completed';
28
28
  break;
29
+ case 'cancel':
30
+ opts.call_status = 'no-answer';
31
+ break;
29
32
  case 'mute':
30
33
  opts.mute_status = 'mute';
31
34
  break;