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

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.32",
3
+ "version": "2.5.0",
4
4
  "description": "Node-RED nodes for jambonz platform",
5
5
  "keywords": [
6
6
  "node-red"
@@ -41,6 +41,10 @@
41
41
  "dialogflow": "src/nodes/dialogflow.js",
42
42
  "leave": "src/nodes/leave.js",
43
43
  "rasa": "src/nodes/rasa.js",
44
+ "answer": "src/nodes/answer.js",
45
+ "dub": "src/nodes/dub.js",
46
+ "generic": "src/nodes/generic-verb.js",
47
+ "alert": "src/nodes/alert.js",
44
48
  "userauth": "src/nodes/userauth.js",
45
49
  "create call": "src/nodes/create_call.js",
46
50
  "create sms": "src/nodes/create_sms.js",
@@ -48,10 +52,7 @@
48
52
  "get_alerts": "src/nodes/get_alerts.js",
49
53
  "get_call": "src/nodes/get_call.js",
50
54
  "get_calls": "src/nodes/get_calls.js",
51
- "get_recent_calls": "src/nodes/get_recent_calls.js",
52
- "answer": "src/nodes/answer.js",
53
- "dub": "src/nodes/dub.js",
54
- "generic": "src/nodes/generic-verb.js"
55
+ "get_recent_calls": "src/nodes/get_recent_calls.js"
55
56
  }
56
57
  },
57
58
  "author": "Dave Horton",
@@ -64,9 +65,9 @@
64
65
  "hash-sum": "^2.0.0",
65
66
  "is-utf8": "^0.2.1",
66
67
  "media-typer": "^1.1.0",
67
- "multer": "^2.0.1",
68
+ "multer": "^2.0.2",
68
69
  "mustache": "^4.2.0",
69
- "on-headers": "^1.0.2",
70
+ "on-headers": "^1.1.0",
70
71
  "raw-body": "^2.5.2",
71
72
  "s3-upload-stream": "^1.0.7",
72
73
  "undici": "^5.28.5",
@@ -123,9 +123,14 @@
123
123
 
124
124
  function testCredentials() {
125
125
  let baseUrl
126
+
126
127
  const accountSid = $("#node-config-input-accountSid").val();
127
128
  const token = $("#node-config-input-apiToken").val();
128
129
  const status = $("#node-config-test-status");
130
+ if (!['str', 'https://api.jambonz.cloud'].includes($("#node-config-input-urlType").val()) || ($("#node-config-input-apiTokenType").val() != 'str') || ($("#node-config-input-accountSidType").val() != 'str')){
131
+ status.text('Cannot test credentials using TypedInputs');
132
+ return;
133
+ }
129
134
  status.text('');
130
135
  if ($("#node-config-input-urlType").val() == 'str'){
131
136
  baseUrl = $("#node-config-input-url").val();
@@ -0,0 +1,75 @@
1
+ <!-- Javascript -->
2
+ <script type="text/javascript">
3
+ var mustacheType = {
4
+ value: "mustache",
5
+ label: "mustache",
6
+ hasvalue: true,
7
+ icon: "resources/@jambonz/node-red-contrib-jambonz/icons/mustache.svg",
8
+ };
9
+ RED.nodes.registerType("alert", {
10
+ category: "jambonz",
11
+ color: "#bbabaa",
12
+ defaults: {
13
+ name: { value: "" },
14
+ message: { value: "" },
15
+ messageType: { value: "str" },
16
+ },
17
+ inputs: 1,
18
+ outputs: 1,
19
+ icon: "font-awesome/fa-cubes",
20
+ label: function () {
21
+ return this.name || "alert";
22
+ },
23
+ oneditprepare: function () {
24
+ $("#node-input-message").typedInput({
25
+ default: $("#node-input-messageType").val(),
26
+ types: ["str", "msg", "flow", "global", mustacheType],
27
+ typeField: $("#node-input-messageType"),
28
+ });
29
+ },
30
+ });
31
+ </script>
32
+
33
+ <!-- HTML -->
34
+ <script type="text/html" data-template-name="alert">
35
+ <div class="form-row">
36
+ <label for="node-input-name"><i class="icon-tag"></i> Name</label>
37
+ <input type="text" id="node-input-name" placeholder="Name" />
38
+ </div>
39
+ <div class="form-row">
40
+ <label for="node-input-message">Message</label>
41
+ <input
42
+ type="text"
43
+ id="node-input-message"
44
+ placeholder="Alert message"
45
+ />
46
+ <input type="hidden" id="node-input-messageType" />
47
+ </div>
48
+ </script>
49
+
50
+ <!-- Help Text -->
51
+ <script type="text/html" data-help-name="alert">
52
+ <p>Raise an alert in the jambonz platform.</p>
53
+ <h3>Properties</h3>
54
+ <p><code>Message</code> - an alert message</p>
55
+
56
+ <h3>Outputs</h3>
57
+ <dl class="message-properties">
58
+ <dt>jambonz<span class="property-type">object</span></dt>
59
+ <dd>
60
+ <code>msg.jambonz</code> will contain any previous actions provided
61
+ to the input with the new <code>alert</code> action appended
62
+ </dd>
63
+ </dl>
64
+
65
+ <h3>Details</h3>
66
+ The alert verb raises an alert in the jambonz platform
67
+ <h3>References</h3>
68
+ <ul>
69
+ <li>
70
+ <a href="https://docs.jambonz.org/verbs/verbs/alert"
71
+ >Jambonz alert reference</a
72
+ >
73
+ </li>
74
+ </ul>
75
+ </script>
@@ -0,0 +1,23 @@
1
+ var { appendVerb, new_resolve } = require("./libs");
2
+
3
+ module.exports = function (RED) {
4
+ /** alert */
5
+ function alert(config) {
6
+ RED.nodes.createNode(this, config);
7
+ var node = this;
8
+ node.on("input", async function (msg) {
9
+ appendVerb(msg, {
10
+ verb: "alert",
11
+ message: await new_resolve(
12
+ RED,
13
+ config.message,
14
+ config.messageType,
15
+ node,
16
+ msg
17
+ ),
18
+ });
19
+ node.send(msg);
20
+ });
21
+ }
22
+ RED.nodes.registerType("alert", alert);
23
+ };
@@ -5,7 +5,9 @@
5
5
  defaults: {
6
6
  name: {},
7
7
  urlType: {},
8
- url: {type: 'text'}
8
+ url: {type: 'text'},
9
+ accountSidType: {value: 'str'},
10
+ apiTokenType: {value: 'str'}
9
11
  },
10
12
  credentials: {
11
13
  accountSid: {type: 'text'},
@@ -15,10 +17,17 @@
15
17
  oneditprepare: function() {
16
18
  $('#btn-test-credentials').on('click', testCredentials);
17
19
  $('#node-config-input-url').typedInput({
18
- types: ['str',
19
- {value: 'https://api.jambonz.cloud', label : 'jambonz.cloud', hasValue: false}],
20
+ types: ['str', 'env', 'msg', 'flow', 'global', {value: 'https://api.jambonz.cloud', label : 'jambonz.cloud', hasValue: false}],
20
21
  typeField: $('#node-config-input-urlType')
21
22
  });
23
+ $('#node-config-input-accountSid').typedInput({
24
+ types: ['str', 'env', 'msg', 'flow', 'global'],
25
+ typeField: $('#node-config-input-accountSidType')
26
+ });
27
+ $('#node-config-input-apiToken').typedInput({
28
+ types: ['str', 'env', 'msg', 'flow', 'global'],
29
+ typeField: $('#node-config-input-apiTokenType')
30
+ });
22
31
  },
23
32
  oneditsave: function() {
24
33
  const baseUrl = $('#node-config-input-url').val();
@@ -72,10 +81,13 @@
72
81
  <div class="form-row">
73
82
  <label for="node-config-input-accountSid">Account SID</label>
74
83
  <input type="text" id="node-config-input-accountSid">
84
+ <input type="hidden" id="node-config-input-accountSidType">
75
85
  </div>
76
86
  <div class="form-row">
77
87
  <label for="node-config-input-apiToken">API token</label>
78
88
  <input type="text" id="node-config-input-apiToken">
89
+ <input type="hidden" id="node-config-input-apiTokenType">
90
+
79
91
  </div>
80
92
  <div class="form-row">
81
93
  <button id="btn-test-credentials"><i class="fa fa-lock"></i> Test Credentials</button>
package/src/nodes/auth.js CHANGED
@@ -1,15 +1,14 @@
1
1
  module.exports = function(RED) {
2
2
  function jambonz_auth(config) {
3
3
  RED.nodes.createNode(this, config);
4
- this.accountSid = config.accountSid;
5
- this.apiKey = config.apiKey;
4
+ var node = this;
6
5
  this.name = config.name;
7
- this.urlType = config.urlType
8
- if (this.urlType == 'str'){
9
- this.url = config.url;
10
- } else {
11
- this.url = config.urlType;
12
- }
6
+ this.url = config.url;
7
+ this.urlType = config.urlType;
8
+ this.accountSid = config.accountSid;
9
+ this.accountSidType = config.accountSidType;
10
+ this.apiToken = config.apiToken;
11
+ this.apiTokenType = config.apiTokenType;
13
12
  }
14
13
 
15
14
  RED.nodes.registerType('jambonz_auth', jambonz_auth, {
@@ -17,7 +16,9 @@ module.exports = function(RED) {
17
16
  url: {type: 'text'},
18
17
  urlType: {},
19
18
  accountSid: {type: 'text'},
20
- apiToken: {type: 'text'}
19
+ accountSidType: {},
20
+ apiToken: {type: 'text'},
21
+ apiTokenType: {}
21
22
  }
22
23
  });
23
24
 
@@ -19,6 +19,12 @@
19
19
  toType: {value: ''},
20
20
  trunk: {value: ''},
21
21
  trunkType: {value: 'str'},
22
+ sipauth_user: {value: ''},
23
+ sipauth_userType: {value: 'str'},
24
+ sipauth_password: {value: ''},
25
+ sipauth_passwordType: {value: 'str'},
26
+ sip_proxy: {value: ''},
27
+ sip_proxyType: {value: 'str'},
22
28
  dest: {value: 'phone', required: true},
23
29
  timeout: {value: '' },
24
30
  timeoutType: {value: 'num'},
@@ -56,7 +62,17 @@
56
62
  return(true)
57
63
  }
58
64
  }},
59
- recognizerlang: {value: 'default'}
65
+ recognizerlang: {value: 'default'},
66
+ amd_actionHook : {},
67
+ amd_actionHookType: {value: 'str'},
68
+ amd_recognizer_vendor: {value: 'default'},
69
+ amd_recognizer_lang: {value: 'default'},
70
+ amd_thresholdWordCount: {},
71
+ amd_timers_decisionTimeoutMs: {},
72
+ amd_timers_greetingCompletionTimeoutMs:{},
73
+ amd_timers_noSpeechTimeoutMs: {},
74
+ amd_timers_toneTimeoutMs: {},
75
+ amd_digitCount: {}
60
76
  },
61
77
  inputs:1,
62
78
  outputs:1,
@@ -70,6 +86,7 @@
70
86
  var serverElem = $('#node-input-server');
71
87
  var applicationElem = $('#node-input-application');
72
88
  var trunkDiv = $('#trunk');
89
+ var sipDiv = $('#sip');
73
90
  prepareTtsControls(node);
74
91
  prepareSttControls(node);
75
92
 
@@ -77,6 +94,8 @@
77
94
  var selectedDest = destElem.find(':selected').val();
78
95
  if ('phone' === selectedDest) trunkDiv.show();
79
96
  else trunkDiv.hide();
97
+ if ('sip' === selectedDest) sipDiv.show();
98
+ else sipDiv.hide();
80
99
  }
81
100
 
82
101
  destElem.change(onDestChanged);
@@ -119,15 +138,35 @@
119
138
  default: $('#node-input-timeoutType').val(),
120
139
  types: ['num', 'msg', 'flow', 'global', 'jsonata', 'env'],
121
140
  typeField: $('#node-input-timeoutType')
141
+ });
142
+ $('#node-input-amd_actionHook').typedInput({
143
+ default: $('#node-input-amd_actionHookType').val(),
144
+ types: ['str','msg', 'flow', 'global', 'jsonata', 'env', mustacheType],
145
+ typeField: $('#node-input-amd_actionHookType')
146
+ });
147
+ $('#node-input-sipauth_user').typedInput({
148
+ default: $('#node-input-sipauth_userType').val(),
149
+ types: ['str','msg', 'flow', 'global', 'jsonata', 'env', mustacheType],
150
+ typeField: $('#node-input-sipauth_userType')
151
+ });
152
+ $('#node-input-sipauth_password').typedInput({
153
+ default: $('#node-input-sipauth_passwordType').val(),
154
+ types: ['str','msg', 'flow', 'global', 'jsonata', 'env', mustacheType],
155
+ typeField: $('#node-input-sipauth_passwordType')
156
+ });
157
+ $('#node-input-sip_proxy').typedInput({
158
+ default: $('#node-input-sip_proxyType').val(),
159
+ types: ['str','msg', 'flow', 'global', 'jsonata', 'env', mustacheType],
160
+ typeField: $('#node-input-sip_proxyType')
122
161
  });
123
162
  var populateApplications = function() {
124
163
  var serverId = $('#node-input-server option:selected').val();
125
164
  $.ajax({
126
165
  url: `_jambonz/applications/${serverId}`,
127
166
  dataType: 'json',
128
- timeout: 500,
167
+ timeout: 5000,
129
168
  error: (err) => {
130
- console.log(err);
169
+ console.error(`Unable to get application list ${err.statusText}`);
131
170
  },
132
171
  success: (res) => {
133
172
  applicationElem.find('option').remove();
@@ -240,9 +279,18 @@
240
279
  <input type="text" id="node-input-callername" placeholder="calling party name">
241
280
  <input type="hidden" id="node-input-callernameType">
242
281
  </div>
282
+ <div class="form-row">
283
+ <label for="node-input-dest">Dest Type</label>
284
+ <select id="node-input-dest">
285
+ <option value="phone">phone number</option>
286
+ <option value="user">registered sip device/user</option>
287
+ <option value="sip">sip endpoint</option>
288
+ <option value="ms-teams">Microsoft teams</option>
289
+ </select>
290
+ </div>
243
291
  <div class="form-row">
244
292
  <label for="node-input-to">To</label>
245
- <input type="text" id="node-input-to" placeholder="called party info">
293
+ <input type="text" id="node-input-to" placeholder="destination">
246
294
  <input type="hidden" id="node-input-toType">
247
295
  </div>
248
296
  <div class="form-row" id ="trunk">
@@ -250,15 +298,24 @@
250
298
  <input type="text" id="node-input-trunk" placeholder="Specify the name of the trunk used for this outbound call">
251
299
  <input type="hidden" id="node-input-trunkType">
252
300
  </div>
301
+ <div id="sip">
253
302
  <div class="form-row">
254
- <label for="node-input-dest">Call type</label>
255
- <select id="node-input-dest">
256
- <option value="phone">phone number</option>
257
- <option value="user">registered sip device/user</option>
258
- <option value="sip">sip endpoint</option>
259
- <option value="ms-teams">Microsoft teams</option>
260
- </select>
303
+ <label for="node-input-sipauth_user">SIP Auth Username</label>
304
+ <input type="text" id="node-input-sipauth_user" placeholder="Username for SIP Authentication">
305
+ <input type="hidden" id="node-input-sipauth_userType">
306
+ </div>
307
+ <div class="form-row">
308
+ <label for="node-input-sipauth_password">SIP Auth Password</label>
309
+ <input type="text" id="node-input-sipauth_password" placeholder="Passwrd for SIP Authentication">
310
+ <input type="hidden" id="node-input-sipauth_passwordType">
261
311
  </div>
312
+ <div class="form-row">
313
+ <label for="node-input-sip_proxy">SIP Proxy</label>
314
+ <input type="text" id="node-input-sip_proxy" placeholder="SIP Proxy">
315
+ <input type="hidden" id="node-input-sip_proxyType">
316
+ </div>
317
+ </div>
318
+
262
319
  <div class="form-row">
263
320
  <label for="node-input-timeout">Ring timeout</label>
264
321
  <input type="text" id="node-input-timeout" placeholder="ring no answer timeout in secs (default: 60)">
@@ -292,6 +349,55 @@
292
349
  <ol id="node-input-headers-container"></ol>
293
350
  </div>
294
351
  </fieldset>
352
+ <fieldset>
353
+ <legend>Answering Machine Detection</legend>
354
+ <div class="form-row">
355
+ <label for="node-input-amd_actionHook">actionHook</label>
356
+ <input type="text" id="node-input-amd_actionHook">
357
+ <input type="hidden" id="node-input-amd_actionHookType">
358
+ </div>
359
+ <div class="form-row">
360
+ <label for="node-input-amd_recognizer_vendor">Vendor</label>
361
+ <select id="node-input-amd_recognizer_vendor">
362
+ <option value="default" selected>--application default--</option>
363
+ <option value="google">Google</option>
364
+ <option value="aws">AWS</option>
365
+ <option value="deepgram">deepgram</option>
366
+ <option value="microsoft">microsoft</option>
367
+ <option value="ibm">ibm</option>
368
+ <option value="nuance">nuance</option>
369
+ </select>
370
+ </div>
371
+ <div class="form-row">
372
+ <label for="node-input-amd_recognizer_lang">Language</label>
373
+ <select id="node-input-amd_recognizer_lang">
374
+ </select>
375
+ </div>
376
+ <div class="form-row">
377
+ <label for="node-input-amd_thresholdWordCount">Threshold Word Count</label>
378
+ <input type="text" id="node-input-amd_thresholdWordCount">
379
+ </div>
380
+ <div class="form-row">
381
+ <label for="node-input-amd_digitCount">Digit Count</label>
382
+ <input type="text" id="node-input-amd_digitCount">
383
+ </div>
384
+ <div class="form-row">
385
+ <label for="node-input-amd_timers_decisionTimeoutMs">Decision Timeout</label>
386
+ <input type="text" id="node-input-amd_timers_decisionTimeoutMs">
387
+ </div>
388
+ <div class="form-row">
389
+ <label for="node-input-amd_timers_greetingCompletionTimeoutMs">Greeting Completion Timeout</label>
390
+ <input type="text" id="node-input-amd_timers_greetingCompletionTimeoutMs">
391
+ </div>
392
+ <div class="form-row">
393
+ <label for="node-input-amd_timers_noSpeechTimeoutMs">No-Speech Timeout</label>
394
+ <input type="text" id="node-input-amd_timers_noSpeechTimeoutMs">
395
+ </div>
396
+ <div class="form-row">
397
+ <label for="node-input-amd_timers_toneTimeoutMs">Tone Timeout</label>
398
+ <input type="text" id="node-input-amd_timers_toneTimeoutMs">
399
+ </div>
400
+ </fieldset>
295
401
  <div id="url-options">
296
402
  <fieldset>
297
403
  <legend>Webhook options</legend>
@@ -10,8 +10,10 @@ module.exports = function(RED) {
10
10
  node.on('input', async (msg, send, done) => {
11
11
  send = send || function() { node.send.apply(node, arguments);};
12
12
 
13
- const {accountSid, apiToken} = server.credentials;
14
- const url = server.url
13
+ const url = await new_resolve(RED, server.url, server.urlType, node, msg);
14
+ const accountSid = await new_resolve(RED, server.credentials.accountSid, server.accountSidType, node, msg);
15
+ const apiToken = await new_resolve(RED, server.credentials.apiToken, server.apiTokenType, node, msg);
16
+
15
17
  if (!url || !accountSid || !apiToken) {
16
18
  node.error(`invalid / missing credentials, skipping create-call node: ${JSON.stringify(server.credentials)}`);
17
19
  send(msg);
@@ -82,7 +84,12 @@ module.exports = function(RED) {
82
84
  opts.to.name = to;
83
85
  break;
84
86
  case 'sip':
87
+ var sipauth_user = await new_resolve(RED, config.sipauth_user, config.sipauth_userType, node, msg);
88
+ var sipauth_password = await new_resolve(RED, config.sipauth_password, config.sipauth_passwordType, node, msg);
89
+ var sip_proxy = await new_resolve(RED, config.sip_proxy, config.sip_proxyType, node, msg);
85
90
  opts.to.sipUri = to;
91
+ sip_proxy ? opts.to.proxy = sip_proxy : null
92
+ sipauth_user ? opts.to.auth = { username :sipauth_user, password: sipauth_password} : null
86
93
  break;
87
94
  case 'ms-teams':
88
95
  opts.to.user = to;
@@ -93,6 +100,33 @@ module.exports = function(RED) {
93
100
  send(msg);
94
101
  return;
95
102
  }
103
+
104
+ // AMD
105
+ const _amd_actionHook = await new_resolve(RED, config.amd_actionHook, config.amd_actionHookType, node, msg)
106
+ if (_amd_actionHook){
107
+ opts.amd = {}
108
+ opts.amd.actionHook = _amd_actionHook;
109
+ config.amd_thresholdWordCount && (opts.amd.thresholdWordCount = Number(config.amd_thresholdWordCount))
110
+ config.amd_digitCount && (opts.amd.digitCount = Number(config.amd_digitCount))
111
+ opts.amd.timers = {
112
+ ...(config.amd_timers_decisionTimeoutMs && {decisionTimeoutMs: Number(config.amd_timers_decisionTimeoutMs)}),
113
+ ...(config.amd_timers_greetingCompletionTimeoutMs && {greetingCompletionTimeoutMs: Number(config.amd_timers_greetingCompletionTimeoutMs)}),
114
+ ...(config.amd_timers_noSpeechTimeoutMs && {noSpeechTimeoutMs: Number(config.amd_timers_noSpeechTimeoutMs)}),
115
+ ...(config.amd_timers_toneTimeoutMs && {toneTimeoutMs: Number(config.amd_timers_toneTimeoutMs)}),
116
+ }
117
+ //If none of the timer values are set remove the object
118
+ if (Object.keys(opts.amd.timers).length == 0){
119
+ delete(opts.amd.timers)
120
+ }
121
+ //If custom recogniser is used
122
+ if (config.amd_recognizer_vendor != 'default'){
123
+ opts.amd.recognizer = {
124
+ ...(config.amd_recognizer_vendor && {vendor : config.amd_recognizer_vendor}),
125
+ ...(config.amd_recognizer_lang && {language : config.amd_recognizer_lang})
126
+ }
127
+ }
128
+ }
129
+
96
130
  try {
97
131
  const response = await doCreateCall(node, url, accountSid, apiToken, opts);
98
132
  msg.statusCode = 201;
@@ -6,8 +6,19 @@ module.exports = function(RED) {
6
6
  RED.nodes.createNode(this, config);
7
7
  var node = this;
8
8
  const server = RED.nodes.getNode(config.server);
9
- const {accountSid, apiToken} = server.credentials;
9
+
10
10
  node.on('input', async (msg, send, done) => {
11
+ const url = await new_resolve(RED, server.url, server.urlType, node, msg);
12
+ const accountSid = await new_resolve(RED, server.credentials.accountSid, server.accountSidType, node, msg);
13
+ const apiToken = await new_resolve(RED, server.credentials.apiToken, server.apiTokenType, node, msg);
14
+
15
+ if (!url || !accountSid || !apiToken) {
16
+ node.error(`invalid / missing credentials ${JSON.stringify(server.credentials)}`);
17
+ send(msg);
18
+ if (done) done();
19
+ return;
20
+ }
21
+
11
22
  const data = {
12
23
  page: await new_resolve(RED, config.page, config.pageType, node, msg),
13
24
  count: await new_resolve(RED, config.count, config.countType, node, msg),
@@ -16,7 +27,7 @@ module.exports = function(RED) {
16
27
  Object.keys(data).forEach((k) => data[k] == null || data[k] == '' && delete data[k]);
17
28
  const params = new URLSearchParams(data).toString()
18
29
  try {
19
- const response = await fetch(`${server.url}/v1/Accounts/${accountSid}/Alerts?${params}`, {
30
+ const response = await fetch(`${url}/v1/Accounts/${accountSid}/Alerts?${params}`, {
20
31
  method: 'GET',
21
32
  headers: {
22
33
  'Authorization': `Bearer ${apiToken}`
@@ -6,8 +6,19 @@ module.exports = function (RED) {
6
6
  RED.nodes.createNode(this, config);
7
7
  var node = this;
8
8
  const server = RED.nodes.getNode(config.server);
9
- const { accountSid, apiToken } = server.credentials;
9
+
10
10
  node.on("input", async (msg, send, done) => {
11
+ const url = await new_resolve(RED, server.url, server.urlType, node, msg);
12
+ const accountSid = await new_resolve(RED, server.credentials.accountSid, server.accountSidType, node, msg);
13
+ const apiToken = await new_resolve(RED, server.credentials.apiToken, server.apiTokenType, node, msg);
14
+
15
+ if (!url || !accountSid || !apiToken) {
16
+ node.error(`invalid / missing credentials ${JSON.stringify(server.credentials)}`);
17
+ send(msg);
18
+ if (done) done();
19
+ return;
20
+ }
21
+
11
22
  const callSid = await new_resolve(RED, config.callSid, config.callSidType, node, msg);
12
23
  if (!callSid) {
13
24
  if (done) done(new Error('CallSid empty'));
@@ -15,7 +26,7 @@ module.exports = function (RED) {
15
26
  return;
16
27
  }
17
28
  try {
18
- const response = await fetch(`${server.url}/v1/Accounts/${accountSid}/Calls/${callSid}`, {
29
+ const response = await fetch(`${url}/v1/Accounts/${accountSid}/Calls/${callSid}`, {
19
30
  method: 'GET',
20
31
  headers: {
21
32
  'Authorization': `Bearer ${apiToken}`
@@ -6,8 +6,18 @@ module.exports = function (RED) {
6
6
  RED.nodes.createNode(this, config);
7
7
  var node = this;
8
8
  const server = RED.nodes.getNode(config.server);
9
- const { accountSid, apiToken } = server.credentials;
10
9
  node.on("input", async (msg, send, done) => {
10
+ const url = await new_resolve(RED, server.url, server.urlType, node, msg);
11
+ const accountSid = await new_resolve(RED, server.credentials.accountSid, server.accountSidType, node, msg);
12
+ const apiToken = await new_resolve(RED, server.credentials.apiToken, server.apiTokenType, node, msg);
13
+
14
+ if (!url || !accountSid || !apiToken) {
15
+ node.error(`invalid / missing credentials ${JSON.stringify(server.credentials)}`);
16
+ send(msg);
17
+ if (done) done();
18
+ return;
19
+ }
20
+
11
21
  const data = {
12
22
  direction: await new_resolve(RED, config.direction, config.directionType, node, msg),
13
23
  from: await new_resolve(RED, config.from, config.fromType, node, msg),
@@ -19,7 +29,7 @@ module.exports = function (RED) {
19
29
  );
20
30
  const params = new URLSearchParams(data).toString();
21
31
  try {
22
- const response = await fetch(`${server.url}/v1/Accounts/${accountSid}/Calls${ params ? '?' + params : ''}`, {
32
+ const response = await fetch(`${url}/v1/Accounts/${accountSid}/Calls${ params ? '?' + params : ''}`, {
23
33
  method: 'GET',
24
34
  headers: {
25
35
  'Authorization': `Bearer ${apiToken}`
@@ -6,8 +6,18 @@ module.exports = function(RED) {
6
6
  RED.nodes.createNode(this, config);
7
7
  var node = this;
8
8
  const server = RED.nodes.getNode(config.server);
9
- const {accountSid, apiToken} = server.credentials;
10
9
  node.on('input', async (msg, send, done) => {
10
+ const url = await new_resolve(RED, server.url, server.urlType, node, msg);
11
+ const accountSid = await new_resolve(RED, server.credentials.accountSid, server.accountSidType, node, msg);
12
+ const apiToken = await new_resolve(RED, server.credentials.apiToken, server.apiTokenType, node, msg);
13
+
14
+ if (!url || !accountSid || !apiToken) {
15
+ node.error(`invalid / missing credentials ${JSON.stringify(server.credentials)}`);
16
+ send(msg);
17
+ if (done) done();
18
+ return;
19
+ }
20
+
11
21
  const data = {
12
22
  direction: await new_resolve(RED, config.direction, config.directionType, node, msg),
13
23
  trunk: await new_resolve(RED, config.trunk, config.trunkType, node, msg),
@@ -18,7 +28,7 @@ module.exports = function(RED) {
18
28
  Object.keys(data).forEach((k) => data[k] == null || data[k] == '' && delete data[k]);
19
29
  const params = new URLSearchParams(data).toString();
20
30
  try {
21
- const response = await fetch(`${server.url}/v1/Accounts/${accountSid}/RecentCalls?${params}`, {
31
+ const response = await fetch(`${url}/v1/Accounts/${accountSid}/RecentCalls?${params}`, {
22
32
  method: 'GET',
23
33
  headers: {
24
34
  'Authorization': `Bearer ${apiToken}`
package/src/nodes/lcc.js CHANGED
@@ -11,9 +11,11 @@ function lcc(config) {
11
11
  node.on('input', async (msg, send, done) => {
12
12
  send = send || function() { node.send.apply(node, arguments);};
13
13
 
14
- const {accountSid, apiToken} = server.credentials;
15
- const url = server.url;
14
+ const url = await new_resolve(RED, server.url, server.urlType, node, msg);
15
+ const accountSid = await new_resolve(RED, server.credentials.accountSid, server.accountSidType, node, msg);
16
+ const apiToken = await new_resolve(RED, server.credentials.apiToken, server.apiTokenType, node, msg);
16
17
  const callSid = await new_resolve(RED, config.callSid, config.callSidType, node, msg);
18
+
17
19
  if (!url || !accountSid || !apiToken || !callSid) {
18
20
  node.log(`invalid / missing credentials or callSid, skipping LCC node: ${JSON.stringify(server.credentials)}`);
19
21
  send(msg);
@@ -16,6 +16,10 @@
16
16
  </script>
17
17
 
18
18
  <script type="text/html" data-template-name="audio in">
19
+ <div class="form-row ui-state-error">
20
+ <strong>Attention:</strong>
21
+ This node has been deprecated. <a href="https://github.com/jambonz/node-red-contrib-jambonz/issues/53" target="_blank">See issue #53<i class="fa fa-external-link external-link"></i></a> for more details.
22
+ </div>
19
23
  <div class="form-row">
20
24
  <label for="node-input-name"><i class="icon-tag"></i> Name</label>
21
25
  <input type="text" id="node-input-name" placeholder="Name">
@@ -35,6 +39,10 @@
35
39
  </script>
36
40
 
37
41
  <script type="text/html" data-help-name="audio in">
42
+ <div class="ui-state-error">
43
+ <strong>Attention:</strong>
44
+ This node has been deprecated.
45
+ </div>
38
46
  <p>Receives audio from jambonz and uploads to S3</p>
39
47
  <h3>Outputs</h3>
40
48
  <dl class="message-properties">
@@ -24,6 +24,8 @@ module.exports = function(RED) {
24
24
  RED.nodes.createNode(this, n);
25
25
  var node = this;
26
26
 
27
+ node.warn("This node has been deprecated. See https://github.com/jambonz/node-red-contrib-jambonz/issues/53");
28
+
27
29
  // Get AWS Creds
28
30
  const awsCreds = RED.nodes.getNode(n.aws);
29
31
  if (awsCreds && awsCreds.credentials) {