botium-core 1.13.0 → 1.13.3

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.
Files changed (57) hide show
  1. package/.eslintrc.js +6 -3
  2. package/dist/botium-cjs.js +305 -123
  3. package/dist/botium-cjs.js.map +1 -1
  4. package/dist/botium-es.js +323 -142
  5. package/dist/botium-es.js.map +1 -1
  6. package/package.json +17 -15
  7. package/src/Capabilities.js +2 -1
  8. package/src/containers/plugins/SimpleRestContainer.js +23 -16
  9. package/src/grid/inbound/proxy.js +2 -1
  10. package/src/helpers/RetryHelper.js +13 -7
  11. package/src/scripting/Convo.js +36 -10
  12. package/src/scripting/MatchFunctions.js +10 -0
  13. package/src/scripting/ScriptingProvider.js +106 -37
  14. package/src/scripting/logichook/LogicHookConsts.js +1 -1
  15. package/src/scripting/logichook/LogicHookUtils.js +1 -1
  16. package/src/scripting/logichook/asserter/WerAsserter.js +59 -0
  17. package/src/scripting/logichook/logichooks/UpdateCustomLogicHook.js +3 -2
  18. package/test/compiler/compilercsv.spec.js +104 -3
  19. package/test/compiler/compilerjson.spec.js +0 -2
  20. package/test/compiler/compilerxlsx.spec.js +1 -1
  21. package/test/compiler/convos/csv/utterances_liveperson2.csv +12 -0
  22. package/test/connectors/simplerest.spec.js +1012 -969
  23. package/test/convo/fillAndApplyScriptingMemory.spec.js +804 -785
  24. package/test/convo/partialconvo.spec.js +345 -339
  25. package/test/convo/retryconvo.spec.js +134 -0
  26. package/test/driver/capabilities.spec.js +156 -151
  27. package/test/logichooks/hookfromsrc.spec.js +79 -73
  28. package/test/plugins/plugins.spec.js +44 -42
  29. package/test/scripting/asserters/buttonsAsserter.spec.js +257 -240
  30. package/test/scripting/asserters/cardsAsserter.spec.js +214 -212
  31. package/test/scripting/asserters/convos/wer_threshold_nok.yml +7 -0
  32. package/test/scripting/asserters/convos/wer_threshold_ok.yml +7 -0
  33. package/test/scripting/asserters/intentConfidenceAsserter.spec.js +34 -35
  34. package/test/scripting/asserters/jsonpathAsserter.spec.js +307 -308
  35. package/test/scripting/asserters/mediaAsserter.spec.js +236 -234
  36. package/test/scripting/asserters/werAsserter.spec.js +51 -0
  37. package/test/scripting/logichooks/setClearScriptingMemory.spec.js +202 -192
  38. package/test/scripting/matching/matchingmode.spec.js +306 -258
  39. package/test/scripting/scriptingProvider.spec.js +666 -633
  40. package/test/scripting/scriptingmemory/fillScriptingMemoryFromFile.spec.js +299 -281
  41. package/test/scripting/scriptingmemory/useScriptingMemoryForAssertion.spec.js +94 -80
  42. package/test/scripting/userinputs/defaultUserInputs.spec.js +233 -127
  43. package/test/scripting/userinputs/mediaInputConvos.spec.js +409 -403
  44. package/test/scripting/utteranceexpansion/associateByIndex.spec.js +259 -0
  45. package/test/scripting/utteranceexpansion/convos/associate_utterances_by_index.json +33 -0
  46. package/test/scripting/utteranceexpansion/convos/media.convo.txt +19 -0
  47. package/test/scripting/utteranceexpansion/files/step0voice0.wav +0 -0
  48. package/test/scripting/utteranceexpansion/files/step0voice1.wav +0 -0
  49. package/test/scripting/utteranceexpansion/files/step0voice2.wav +0 -0
  50. package/test/scripting/utteranceexpansion/files/step1voice0.wav +0 -0
  51. package/test/scripting/utteranceexpansion/files/step2voice0.wav +0 -0
  52. package/test/scripting/utteranceexpansion/files/step2voice1.wav +0 -0
  53. package/test/scripting/utteranceexpansion/files/step2voice2.wav +0 -0
  54. package/test/scripting/utteranceexpansion/files/step2voice4.wav +0 -0
  55. package/test/scripting/utteranceexpansion/files/step2voice5.wav +0 -0
  56. package/test/security/allowUnsafe.spec.js +274 -268
  57. package/test/utils.spec.js +40 -38
@@ -14,7 +14,7 @@ var randomatic = require('randomatic');
14
14
  var lodash = require('lodash');
15
15
  var boolean$1 = require('boolean');
16
16
  var events = require('events');
17
- var debug$l = require('debug');
17
+ var debug$m = require('debug');
18
18
  var vm2 = require('vm2');
19
19
  var isClass = require('is-class');
20
20
  var crypto = require('crypto');
@@ -24,6 +24,7 @@ var promise = require('promise.allsettled');
24
24
  var uuid = require('uuid');
25
25
  var jsonpath = require('jsonpath');
26
26
  var isJson$1 = require('is-json');
27
+ var wordErrorRate = require('word-error-rate');
27
28
  var esprima = require('esprima');
28
29
  var markdownIt = require('markdown-it');
29
30
  var xlsx = require('xlsx');
@@ -53,7 +54,7 @@ var randomatic__default = /*#__PURE__*/_interopDefaultLegacy(randomatic);
53
54
  var lodash__default = /*#__PURE__*/_interopDefaultLegacy(lodash);
54
55
  var boolean__default = /*#__PURE__*/_interopDefaultLegacy(boolean$1);
55
56
  var events__default = /*#__PURE__*/_interopDefaultLegacy(events);
56
- var debug__default = /*#__PURE__*/_interopDefaultLegacy(debug$l);
57
+ var debug__default = /*#__PURE__*/_interopDefaultLegacy(debug$m);
57
58
  var vm2__default = /*#__PURE__*/_interopDefaultLegacy(vm2);
58
59
  var isClass__default = /*#__PURE__*/_interopDefaultLegacy(isClass);
59
60
  var crypto__default = /*#__PURE__*/_interopDefaultLegacy(crypto);
@@ -63,6 +64,7 @@ var promise__default = /*#__PURE__*/_interopDefaultLegacy(promise);
63
64
  var uuid__default = /*#__PURE__*/_interopDefaultLegacy(uuid);
64
65
  var jsonpath__default = /*#__PURE__*/_interopDefaultLegacy(jsonpath);
65
66
  var isJson__default = /*#__PURE__*/_interopDefaultLegacy(isJson$1);
67
+ var wordErrorRate__default = /*#__PURE__*/_interopDefaultLegacy(wordErrorRate);
66
68
  var esprima__default = /*#__PURE__*/_interopDefaultLegacy(esprima);
67
69
  var markdownIt__default = /*#__PURE__*/_interopDefaultLegacy(markdownIt);
68
70
  var xlsx__default = /*#__PURE__*/_interopDefaultLegacy(xlsx);
@@ -79,7 +81,7 @@ var express__default = /*#__PURE__*/_interopDefaultLegacy(express);
79
81
  var bodyParser__default = /*#__PURE__*/_interopDefaultLegacy(bodyParser);
80
82
 
81
83
  var name = "botium-core";
82
- var version$1 = "1.13.0";
84
+ var version$1 = "1.13.3";
83
85
  var description = "The Selenium for Chatbots";
84
86
  var main = "index.js";
85
87
  var module$1 = "dist/botium-es.js";
@@ -111,17 +113,17 @@ var bugs = {
111
113
  };
112
114
  var homepage = "https://www.botium.ai";
113
115
  var dependencies = {
114
- "@babel/runtime": "^7.18.3",
116
+ "@babel/runtime": "^7.18.6",
115
117
  async: "^3.2.4",
116
118
  "body-parser": "^1.20.0",
117
119
  boolean: "^3.2.0",
118
120
  bottleneck: "^2.19.5",
119
- "csv-parse": "^5.2.0",
121
+ "csv-parse": "^5.3.0",
120
122
  debug: "^4.3.4",
121
123
  esprima: "^4.0.1",
122
124
  express: "^4.18.1",
123
125
  globby: "11.0.4",
124
- ioredis: "^5.0.6",
126
+ ioredis: "^5.1.0",
125
127
  "is-class": "^0.0.9",
126
128
  "is-json": "^2.0.1",
127
129
  jsonpath: "^1.1.1",
@@ -129,7 +131,7 @@ var dependencies = {
129
131
  "markdown-it": "^13.0.1",
130
132
  "mime-types": "^2.1.35",
131
133
  mkdirp: "^1.0.4",
132
- moment: "^2.29.3",
134
+ moment: "^2.29.4",
133
135
  mustache: "^4.2.0",
134
136
  "promise-retry": "^2.0.1",
135
137
  "promise.allsettled": "^1.0.5",
@@ -144,33 +146,35 @@ var dependencies = {
144
146
  "swagger-jsdoc": "^6.2.1",
145
147
  "swagger-ui-express": "^4.4.0",
146
148
  uuid: "^8.3.2",
147
- vm2: "^3.9.9",
149
+ vm2: "^3.9.10",
150
+ "word-error-rate": "0.0.7",
148
151
  "write-yaml": "^1.0.0",
149
152
  xlsx: "^0.18.5",
150
153
  xregexp: "^5.1.1",
151
154
  yaml: "^2.1.1"
152
155
  };
153
156
  var devDependencies = {
154
- "@babel/core": "^7.18.5",
155
- "@babel/node": "^7.18.5",
156
- "@babel/plugin-transform-runtime": "^7.18.5",
157
- "@babel/preset-env": "^7.18.2",
157
+ "@babel/core": "^7.18.6",
158
+ "@babel/node": "^7.18.6",
159
+ "@babel/plugin-transform-runtime": "^7.18.6",
160
+ "@babel/preset-env": "^7.18.6",
158
161
  chai: "^4.3.6",
159
162
  "chai-as-promised": "^7.1.1",
160
163
  "cross-env": "^7.0.3",
161
- eslint: "^8.18.0",
164
+ eslint: "^8.19.0",
162
165
  "eslint-config-standard": "^17.0.0",
163
166
  "eslint-plugin-import": "^2.26.0",
164
- "eslint-plugin-n": "^15.2.3",
167
+ "eslint-plugin-mocha": "^10.1.0",
168
+ "eslint-plugin-n": "^15.2.4",
165
169
  "eslint-plugin-promise": "^6.0.0",
166
170
  "eslint-plugin-standard": "^4.1.0",
167
171
  "license-checker": "^25.0.1",
168
172
  "license-compatibility-checker": "^0.3.5",
169
173
  mocha: "^10.0.0",
170
- nock: "^13.2.7",
171
- "npm-check-updates": "^14.0.1",
174
+ nock: "^13.2.8",
175
+ "npm-check-updates": "^15.2.6",
172
176
  nyc: "^15.1.0",
173
- rollup: "^2.75.6",
177
+ rollup: "^2.76.0",
174
178
  "rollup-plugin-babel": "^4.4.0",
175
179
  "rollup-plugin-commonjs": "^10.1.0",
176
180
  "rollup-plugin-json": "^4.0.0",
@@ -340,8 +344,9 @@ var Capabilities = {
340
344
  SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS: 'SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS',
341
345
  SCRIPTING_ENABLE_SKIP_ASSERT_ERRORS: 'SCRIPTING_ENABLE_SKIP_ASSERT_ERRORS',
342
346
  SCRIPTING_FORCE_BOT_CONSUMED: 'SCRIPTING_FORCE_BOT_CONSUMED',
343
- // regexp, regexpIgnoreCase, wildcard, wildcardIgnoreCase, wildcardExact, wildcardExactIgnoreCase, include, includeIgnoreCase, equals, equalsIgnoreCase
347
+ // regexp, regexpIgnoreCase, wildcard, wildcardIgnoreCase, wildcardExact, wildcardExactIgnoreCase, include, includeIgnoreCase, equals, equalsIgnoreCase, wer
344
348
  SCRIPTING_MATCHING_MODE: 'SCRIPTING_MATCHING_MODE',
349
+ SCRIPTING_MATCHING_MODE_ARGS: 'SCRIPTING_MATCHING_MODE_ARGS',
345
350
  // all, first, random
346
351
  SCRIPTING_UTTEXPANSION_MODE: 'SCRIPTING_UTTEXPANSION_MODE',
347
352
  SCRIPTING_UTTEXPANSION_RANDOM_COUNT: 'SCRIPTING_UTTEXPANSION_RANDOM_COUNT',
@@ -495,6 +500,7 @@ Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS;
495
500
  Capabilities.SCRIPTING_ENABLE_SKIP_ASSERT_ERRORS;
496
501
  Capabilities.SCRIPTING_FORCE_BOT_CONSUMED;
497
502
  Capabilities.SCRIPTING_MATCHING_MODE;
503
+ Capabilities.SCRIPTING_MATCHING_MODE_ARGS;
498
504
  Capabilities.SCRIPTING_UTTEXPANSION_MODE;
499
505
  Capabilities.SCRIPTING_UTTEXPANSION_RANDOM_COUNT;
500
506
  Capabilities.SCRIPTING_UTTEXPANSION_INCOMPREHENSION;
@@ -1180,6 +1186,9 @@ var LogicHookConsts = {
1180
1186
  }, {
1181
1187
  name: 'TEXT_IC',
1182
1188
  className: 'TextEqualsAnyICAsserter'
1189
+ }, {
1190
+ name: 'TEXT_WER',
1191
+ className: 'WerAsserter'
1183
1192
  }, {
1184
1193
  name: 'BOT_CONSUMED',
1185
1194
  className: 'BotRepliesConsumedAsserter'
@@ -1231,7 +1240,7 @@ LogicHookConsts.DEFAULT_USER_INPUTS;
1231
1240
  const {
1232
1241
  NodeVM: NodeVM$2
1233
1242
  } = vm2__default["default"];
1234
- const debug$k = debug__default["default"]('botium-core-asserterUtils');
1243
+ const debug$l = debug__default["default"]('botium-core-asserterUtils');
1235
1244
  const {
1236
1245
  BotiumError: BotiumError$6
1237
1246
  } = BotiumError_1;
@@ -1296,7 +1305,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1296
1305
  _fetchAsserters() {
1297
1306
  this.caps[Capabilities.ASSERTERS].forEach(asserter => {
1298
1307
  if (this.asserters[asserter.ref]) {
1299
- debug$k(`${asserter.ref} asserter already exists, overwriting.`);
1308
+ debug$l(`${asserter.ref} asserter already exists, overwriting.`);
1300
1309
  }
1301
1310
 
1302
1311
  this.asserters[asserter.ref] = this._loadClass(asserter, 'asserter');
@@ -1310,7 +1319,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1310
1319
  _fetchLogicHooks() {
1311
1320
  this.caps[Capabilities.LOGIC_HOOKS].forEach(logicHook => {
1312
1321
  if (this.logicHooks[logicHook.ref]) {
1313
- debug$k(`${logicHook.ref} logic hook already exists, overwriting.`);
1322
+ debug$l(`${logicHook.ref} logic hook already exists, overwriting.`);
1314
1323
  }
1315
1324
 
1316
1325
  this.logicHooks[logicHook.ref] = this._loadClass(logicHook, 'logichook');
@@ -1324,7 +1333,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1324
1333
  _fetchUserInputs() {
1325
1334
  this.caps[Capabilities.USER_INPUTS].forEach(userInput => {
1326
1335
  if (this.userInputs[userInput.ref]) {
1327
- debug$k(`${userInput.ref} userinput already exists, overwriting.`);
1336
+ debug$l(`${userInput.ref} userinput already exists, overwriting.`);
1328
1337
  }
1329
1338
 
1330
1339
  this.userInputs[userInput.ref] = this._loadClass(userInput, 'userinput');
@@ -1467,7 +1476,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1467
1476
  });
1468
1477
  return vm.run(script);
1469
1478
  } catch (err) {
1470
- throw new Error(`${err.message || err}`);
1479
+ throw new Error(`Script ${key} is not valid - ${err.message || err}`);
1471
1480
  }
1472
1481
  } else {
1473
1482
  throw new Error(`Script "${key}" is not valid - only functions and javascript code accepted`);
@@ -1558,7 +1567,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1558
1567
  }
1559
1568
  }
1560
1569
 
1561
- loadErr.forEach(debug$k);
1570
+ loadErr.forEach(debug$l);
1562
1571
  }
1563
1572
 
1564
1573
  throw new Error(`Failed to fetch ${ref} ${hookType}, no idea how to load ...`);
@@ -2417,7 +2426,7 @@ var helper = {
2417
2426
  linesToScriptingMemories: linesToScriptingMemories$2
2418
2427
  };
2419
2428
 
2420
- const debug$j = debug__default["default"]('botium-core-ScriptingMemory');
2429
+ const debug$k = debug__default["default"]('botium-core-ScriptingMemory');
2421
2430
  const {
2422
2431
  v1: uuidv1
2423
2432
  } = uuid__default["default"];
@@ -2675,7 +2684,7 @@ const extractVarNames = text => {
2675
2684
  };
2676
2685
 
2677
2686
  const fill = (container, scriptingMemory, result, utterance, scriptingEvents) => {
2678
- debug$j(`fill start: ${util__default["default"].inspect(scriptingMemory)}`);
2687
+ debug$k(`fill start: ${util__default["default"].inspect(scriptingMemory)}`);
2679
2688
  let varRegex;
2680
2689
 
2681
2690
  switch (container.caps[Capabilities.SCRIPTING_MEMORY_MATCHING_MODE]) {
@@ -2719,14 +2728,14 @@ const fill = (container, scriptingMemory, result, utterance, scriptingEvents) =>
2719
2728
  const varName = varMatches[i - 1];
2720
2729
 
2721
2730
  if (RESERVED_WORDS.indexOf(varName) >= 0) {
2722
- debug$j(`fill Variable "${varName}" is not overwritten, because it is reserved word. `);
2731
+ debug$k(`fill Variable "${varName}" is not overwritten, because it is reserved word. `);
2723
2732
  } else {
2724
2733
  scriptingMemory[varName] = resultMatches[i];
2725
2734
  }
2726
2735
  }
2727
2736
  }
2728
2737
  });
2729
- debug$j(`fill end: ${util__default["default"].inspect(scriptingMemory)}`);
2738
+ debug$k(`fill end: ${util__default["default"].inspect(scriptingMemory)}`);
2730
2739
  }
2731
2740
  };
2732
2741
 
@@ -2745,6 +2754,47 @@ ScriptingMemory.extractVarNames;
2745
2754
  ScriptingMemory.RESERVED_WORDS;
2746
2755
  ScriptingMemory.SCRIPTING_FUNCTIONS;
2747
2756
 
2757
+ const debug$j = debug__default["default"]('botium-core-RetryHelper');
2758
+ var RetryHelper_1 = class RetryHelper {
2759
+ constructor(caps, section, options = {}) {
2760
+ this.retryErrorPatterns = [];
2761
+ const onErrorRegexp = caps[`RETRY_${section.toUpperCase()}_ONERROR_REGEXP`] || [];
2762
+
2763
+ if (onErrorRegexp) {
2764
+ if (lodash__default["default"].isArray(onErrorRegexp)) {
2765
+ onErrorRegexp.forEach(r => {
2766
+ if (lodash__default["default"].isString(r)) this.retryErrorPatterns.push(new RegExp(r, 'i'));else this.retryErrorPatterns.push(r);
2767
+ });
2768
+ } else if (lodash__default["default"].isString(onErrorRegexp)) {
2769
+ this.retryErrorPatterns.push(new RegExp(onErrorRegexp, 'i'));
2770
+ } else {
2771
+ this.retryErrorPatterns.push(onErrorRegexp);
2772
+ }
2773
+ } // to turn on retries, NUMRETRIES or ONERROR_REGEXP has to be set
2774
+
2775
+
2776
+ this.retrySettings = {
2777
+ retries: caps[`RETRY_${section.toUpperCase()}_NUMRETRIES`] || (!lodash__default["default"].isNil(options.numRetries) ? options.numRetries : this.retryErrorPatterns.length === 0 ? 0 : 1),
2778
+ factor: caps[`RETRY_${section.toUpperCase()}_FACTOR`] || (lodash__default["default"].isNil(options.factor) ? 1 : options.factor),
2779
+ minTimeout: caps[`RETRY_${section.toUpperCase()}_MINTIMEOUT`] || (lodash__default["default"].isNil(options.minTimeout) ? 1000 : options.minTimeout)
2780
+ };
2781
+ debug$j(`Retry for ${section} is ${this.retrySettings.retries > 0 ? 'enabled' : 'disabled'}. Settings: ${JSON.stringify(this.retrySettings)} Patterns: ${JSON.stringify(this.retryErrorPatterns.map(r => r.toString()))}`);
2782
+ }
2783
+
2784
+ shouldRetry(err) {
2785
+ if (!err) return false;
2786
+ if (this.retryErrorPatterns.length === 0) return true;
2787
+ const errString = util__default["default"].inspect(err);
2788
+
2789
+ for (const re of this.retryErrorPatterns) {
2790
+ if (errString.match(re)) return true;
2791
+ }
2792
+
2793
+ return false;
2794
+ }
2795
+
2796
+ };
2797
+
2748
2798
  const debug$i = debug__default["default"]('botium-core-Convo');
2749
2799
  const {
2750
2800
  BotiumError: BotiumError$4,
@@ -2841,7 +2891,7 @@ class ConvoStep$1 {
2841
2891
  }
2842
2892
 
2843
2893
  toString() {
2844
- return (this.stepTag ? this.stepTag + ': ' : '') + '#' + this.sender + ' - ' + (this.optional ? '?' : '') + (this.not ? '!' : '') + (this.messageText || '') + (this.asserters && this.asserters.length > 0 ? ' ' + this.asserters.map(a => a.toString()).join(' ASS: ') : '') + (this.logicHooks && this.logicHooks.length > 0 ? ' ' + this.logicHooks.map(l => l.toString()).join(' LH: ') : '') + (this.userInputs && this.userInputs.length > 0 ? ' ' + this.userInputs.map(u => u.toString()).join(' UI: ') : '');
2894
+ return (this.stepTag ? this.stepTag + ': ' : '') + '#' + this.sender + ' - ' + (this.optional ? '?' : '') + (this.not ? '!' : '') + (this.messageText || '') + (this.asserters && this.asserters.length > 0 ? ' ' + this.asserters.map(a => a.toString()).join(' ') : '') + (this.logicHooks && this.logicHooks.length > 0 ? ' ' + this.logicHooks.map(l => l.toString()).join(' ') : '') + (this.userInputs && this.userInputs.length > 0 ? ' ' + this.userInputs.map(u => u.toString()).join(' ') : '');
2845
2895
  }
2846
2896
 
2847
2897
  }
@@ -2876,6 +2926,16 @@ class Transcript {
2876
2926
 
2877
2927
  }
2878
2928
 
2929
+ class TranscriptAttachment {
2930
+ constructor(fromJson = {}) {
2931
+ this.name = fromJson.name;
2932
+ this.mimeType = fromJson.mimeType;
2933
+ this.base64 = fromJson.base64;
2934
+ this.href = fromJson.href;
2935
+ }
2936
+
2937
+ }
2938
+
2879
2939
  class TranscriptStep {
2880
2940
  constructor({
2881
2941
  expected,
@@ -2970,6 +3030,26 @@ class Convo$6 {
2970
3030
  }
2971
3031
 
2972
3032
  async Run(container) {
3033
+ const retryHelper = new RetryHelper_1(container.caps, 'CONVO');
3034
+ return promiseRetry__default["default"](async (retry, number) => {
3035
+ return this.RunImpl(container).catch(err => {
3036
+ const retryRemaining = retryHelper.retrySettings.retries - number + 1;
3037
+
3038
+ if (retryHelper.shouldRetry(err)) {
3039
+ debug$i(`Convo failed with error "${err.message || JSON.stringify(err)}". Retry ${retryRemaining > 0 ? 'enabled' : 'disabled'} (remaining #${retryRemaining}/${retryHelper.retrySettings.retries}, criterion matches)`);
3040
+ retry(err);
3041
+ } else {
3042
+ if (retryHelper.retryErrorPatterns.length > 0) {
3043
+ debug$i(`Convo failed with error "${err.message || JSON.stringify(err)}". Retry 'disabled' (remaining (#${retryRemaining}/${retryHelper.retrySettings.retries}), criterion does not match)`);
3044
+ }
3045
+
3046
+ throw err;
3047
+ }
3048
+ });
3049
+ }, retryHelper.retrySettings);
3050
+ }
3051
+
3052
+ async RunImpl(container) {
2973
3053
  const transcript = new Transcript({
2974
3054
  steps: [],
2975
3055
  attachments: [],
@@ -3636,45 +3716,16 @@ class Convo$6 {
3636
3716
  }
3637
3717
 
3638
3718
  var Convo_1 = {
3639
- ConvoHeader: ConvoHeader$1,
3640
3719
  Convo: Convo$6,
3641
- ConvoStep: ConvoStep$1
3642
- };
3643
-
3644
- var RetryHelper_1 = class RetryHelper {
3645
- constructor(caps, section) {
3646
- this.retrySettings = {
3647
- retries: caps[`RETRY_${section.toUpperCase()}_NUMRETRIES`] || 1,
3648
- factor: caps[`RETRY_${section.toUpperCase()}_FACTOR`] || 1,
3649
- minTimeout: caps[`RETRY_${section.toUpperCase()}_MINTIMEOUT`] || 1000
3650
- };
3651
- this.retryErrorPatterns = [];
3652
- const onErrorRegexp = caps[`RETRY_${section.toUpperCase()}_ONERROR_REGEXP`] || [];
3653
-
3654
- if (onErrorRegexp) {
3655
- if (lodash__default["default"].isArray(onErrorRegexp)) {
3656
- onErrorRegexp.forEach(r => {
3657
- if (lodash__default["default"].isString(r)) this.retryErrorPatterns.push(new RegExp(r, 'i'));else this.retryErrorPatterns.push(r);
3658
- });
3659
- } else if (lodash__default["default"].isString(onErrorRegexp)) {
3660
- this.retryErrorPatterns.push(new RegExp(onErrorRegexp, 'i'));
3661
- } else {
3662
- this.retryErrorPatterns.push(onErrorRegexp);
3663
- }
3664
- }
3665
- }
3666
-
3667
- shouldRetry(err) {
3668
- if (!err || this.retryErrorPatterns.length === 0) return false;
3669
- const errString = util__default["default"].inspect(err);
3670
-
3671
- for (const re of this.retryErrorPatterns) {
3672
- if (errString.match(re)) return true;
3673
- }
3674
-
3675
- return false;
3676
- }
3677
-
3720
+ ConvoHeader: ConvoHeader$1,
3721
+ ConvoStep: ConvoStep$1,
3722
+ ConvoStepAssert,
3723
+ ConvoStepLogicHook,
3724
+ ConvoStepUserInput,
3725
+ Transcript,
3726
+ TranscriptAttachment,
3727
+ TranscriptStep,
3728
+ TranscriptError
3678
3729
  };
3679
3730
 
3680
3731
  const {
@@ -3762,6 +3813,12 @@ const equals = ignoreCase => (botresponse, utterance) => {
3762
3813
  return botresponse === utterance;
3763
3814
  };
3764
3815
 
3816
+ const wer = () => (botresponse, utterance, args) => {
3817
+ botresponse = _normalize(botresponse || '');
3818
+ utterance = toString(utterance || '');
3819
+ return wordErrorRate__default["default"].wordErrorRate(botresponse, utterance) <= args[0];
3820
+ };
3821
+
3765
3822
  const getMatchFunction$1 = matchingMode => {
3766
3823
  if (matchingMode === 'regexp' || matchingMode === 'regexpIgnoreCase') {
3767
3824
  return regexp(matchingMode === 'regexpIgnoreCase');
@@ -3773,6 +3830,8 @@ const getMatchFunction$1 = matchingMode => {
3773
3830
  return include(matchingMode === 'includeIgnoreCase' || matchingMode === 'includeLowerCase');
3774
3831
  } else if (matchingMode === 'equals' || matchingMode === 'equalsIgnoreCase') {
3775
3832
  return equals(matchingMode === 'equalsIgnoreCase');
3833
+ } else if (matchingMode === 'wer') {
3834
+ return wer();
3776
3835
  } else {
3777
3836
  return equals(false);
3778
3837
  }
@@ -3784,6 +3843,7 @@ var MatchFunctions = {
3784
3843
  wildcardExact,
3785
3844
  include,
3786
3845
  equals,
3846
+ wer,
3787
3847
  getMatchFunction: getMatchFunction$1
3788
3848
  };
3789
3849
 
@@ -6148,7 +6208,9 @@ var ScriptingProvider_1 = class ScriptingProvider {
6148
6208
 
6149
6209
  debug$9(`assertBotResponse ${stepTag} ${meMsg ? `(${meMsg}) ` : ''}BOT: ${botresponse} = ${tomatch} ...`);
6150
6210
 
6151
- const found = lodash__default["default"].find(tomatch, utt => this.matchFn(botresponse, utt));
6211
+ const found = lodash__default["default"].find(tomatch, utt => this.matchFn(botresponse, utt, this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS]));
6212
+
6213
+ const asserterType = this.caps[Capabilities.SCRIPTING_MATCHING_MODE] === 'wer' ? 'WerAsserter' : 'TextMatchAsserter';
6152
6214
 
6153
6215
  if (lodash__default["default"].isNil(found)) {
6154
6216
  let message = `${stepTag}: Bot response `;
@@ -6159,7 +6221,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6159
6221
  message += `${tomatch.map(e => e ? '"' + e + '"' : '<any response>').join(', ')}`;
6160
6222
  throw new BotiumError$2(message, {
6161
6223
  type: 'asserter',
6162
- source: 'TextMatchAsserter',
6224
+ source: asserterType,
6163
6225
  context: {
6164
6226
  stepTag
6165
6227
  },
@@ -6178,7 +6240,9 @@ var ScriptingProvider_1 = class ScriptingProvider {
6178
6240
 
6179
6241
  debug$9(`assertBotNotResponse ${stepTag} ${meMsg ? `(${meMsg}) ` : ''}BOT: ${botresponse} != ${nottomatch} ...`);
6180
6242
 
6181
- const found = lodash__default["default"].find(nottomatch, utt => this.matchFn(botresponse, utt));
6243
+ const found = lodash__default["default"].find(nottomatch, utt => this.matchFn(botresponse, utt, this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS]));
6244
+
6245
+ const asserterType = this.caps[Capabilities.SCRIPTING_MATCHING_MODE] === 'wer' ? 'WerAsserter' : 'TextMatchAsserter';
6182
6246
 
6183
6247
  if (!lodash__default["default"].isNil(found)) {
6184
6248
  let message = `${stepTag}: Bot response `;
@@ -6189,7 +6253,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6189
6253
  message += `${nottomatch.map(e => e ? '"' + e + '"' : '<any response>').join(', ')}`;
6190
6254
  throw new BotiumError$2(message, {
6191
6255
  type: 'asserter',
6192
- source: 'TextMatchAsserter',
6256
+ source: asserterType,
6193
6257
  context: {
6194
6258
  stepTag
6195
6259
  },
@@ -6436,7 +6500,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6436
6500
  }
6437
6501
 
6438
6502
  Match(botresponse, utterance) {
6439
- return this.matchFn(botresponse, utterance);
6503
+ return this.matchFn(botresponse, utterance, this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS]);
6440
6504
  }
6441
6505
 
6442
6506
  Compile(scriptBuffer, scriptFormat, scriptType) {
@@ -6956,11 +7020,12 @@ var ScriptingProvider_1 = class ScriptingProvider {
6956
7020
  * @param currentConvo
6957
7021
  * @param convoStepIndex
6958
7022
  * @param convoStepsStack list of ConvoSteps
7023
+ * @param context {width: }
6959
7024
  * @private
6960
7025
  */
6961
7026
 
6962
7027
 
6963
- _expandConvo(expandedConvos, currentConvo, convoStepIndex = 0, convoStepsStack = []) {
7028
+ _expandConvo(expandedConvos, currentConvo, convoStepIndex = 0, convoStepsStack = [], context = {}) {
6964
7029
  const utterancePostfix = (lineTag, uttOrUserInput) => {
6965
7030
  const naming = this.caps[Capabilities.SCRIPTING_UTTEXPANSION_NAMING_MODE] || Defaults$1.capabilities[Capabilities.SCRIPTING_UTTEXPANSION_NAMING_MODE];
6966
7031
 
@@ -6987,7 +7052,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6987
7052
  const currentStepsStack = convoStepsStack.slice();
6988
7053
  currentStepsStack.push(lodash__default["default"].cloneDeep(currentStep));
6989
7054
 
6990
- this._expandConvo(expandedConvos, currentConvo, convoStepIndex + 1, currentStepsStack);
7055
+ this._expandConvo(expandedConvos, currentConvo, convoStepIndex + 1, currentStepsStack, context);
6991
7056
  } else if (currentStep.sender === 'me') {
6992
7057
  let useUnexpanded = true;
6993
7058
 
@@ -7008,39 +7073,87 @@ var ScriptingProvider_1 = class ScriptingProvider {
7008
7073
 
7009
7074
  if (this.utterances[uttName]) {
7010
7075
  const allutterances = this.utterances[uttName].utterances;
7011
- let sampleutterances = allutterances;
7012
-
7013
- if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'first') {
7014
- sampleutterances = [allutterances[0]];
7015
- } else if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'random') {
7016
- sampleutterances = allutterances.map(x => ({
7017
- x,
7018
- r: Math.random()
7019
- })).sort((a, b) => a.r - b.r).map(a => a.x).slice(0, this.caps[Capabilities.SCRIPTING_UTTEXPANSION_RANDOM_COUNT]);
7020
- }
7021
7076
 
7022
- sampleutterances.forEach((utt, index) => {
7023
- const lineTag = `${index + 1}`.padStart(`${sampleutterances.length}`.length, '0');
7077
+ const processSampleUtterances = (sampleutterances, myContext) => {
7078
+ sampleutterances.forEach((utt, index) => {
7079
+ processSampleUtterance(utt, sampleutterances.length, index, Object.assign({
7080
+ indexExpansionModeIndex: index
7081
+ }, myContext || context));
7082
+ });
7083
+ };
7084
+
7085
+ const processSampleUtterance = (sampleutterance, length, index, myContext) => {
7086
+ const lineTag = `${index + 1}`.padStart(`${length}`.length, '0');
7024
7087
  const currentStepsStack = convoStepsStack.slice();
7025
7088
 
7026
7089
  if (uttArgs) {
7027
- utt = util__default["default"].format(utt, ...uttArgs);
7090
+ sampleutterance = util__default["default"].format(sampleutterance, ...uttArgs);
7028
7091
  }
7029
7092
 
7030
7093
  currentStepsStack.push(Object.assign(lodash__default["default"].cloneDeep(currentStep), {
7031
- messageText: utt
7094
+ messageText: sampleutterance
7032
7095
  }));
7033
7096
 
7034
7097
  const currentConvoLabeled = lodash__default["default"].cloneDeep(currentConvo);
7035
7098
 
7036
7099
  Object.assign(currentConvoLabeled.header, {
7037
- name: `${currentConvo.header.name}/${uttName}-${utterancePostfix(lineTag, utt)}`
7100
+ name: `${currentConvo.header.name}/${uttName}-${utterancePostfix(lineTag, sampleutterance)}`
7038
7101
  });
7039
7102
  if (!currentConvoLabeled.sourceTag) currentConvoLabeled.sourceTag = {};
7040
7103
  if (!currentConvoLabeled.sourceTag.origConvoName) currentConvoLabeled.sourceTag.origConvoName = currentConvo.header.name;
7041
7104
 
7042
- this._expandConvo(expandedConvos, currentConvoLabeled, convoStepIndex + 1, currentStepsStack);
7043
- });
7105
+ this._expandConvo(expandedConvos, currentConvoLabeled, convoStepIndex + 1, currentStepsStack, myContext || context);
7106
+ };
7107
+
7108
+ if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'index') {
7109
+ if (lodash__default["default"].isNil(context.indexExpansionModeWidth)) {
7110
+ // executed for the first found utterance
7111
+ processSampleUtterances(allutterances, Object.assign({}, context, {
7112
+ indexExpansionModeWidth: allutterances.length
7113
+ }));
7114
+ } else {
7115
+ if (lodash__default["default"].isNil(context.indexExpansionModeIndex)) {
7116
+ throw new Error('indexExpansionModeIndex must be set!');
7117
+ } // executing the current 'thread', if current utterance has no example to current index, fallback to the last one
7118
+
7119
+
7120
+ const localIndex = Math.min(context.indexExpansionModeIndex, allutterances.length - 1);
7121
+
7122
+ if (localIndex < context.indexExpansionModeIndex && context.indexExpansionModeIndex === context.indexExpansionModeWidth - 1) {
7123
+ debug$9(`While expanding convos by index found in utterance "${uttName}" less examples (${allutterances.length}) as expected (${context.indexExpansionModeWidth})`);
7124
+ }
7125
+
7126
+ const myContext = Object.assign({}, context, {
7127
+ indexExpansionModeWidth: Math.max(allutterances.length, context.indexExpansionModeWidth)
7128
+ });
7129
+ processSampleUtterance(allutterances[localIndex], allutterances.length, localIndex, myContext);
7130
+
7131
+ if (allutterances.length > context.indexExpansionModeWidth && context.indexExpansionModeIndex + 1 === context.indexExpansionModeWidth) {
7132
+ debug$9(`While expanding convos by index found in utterance "${uttName}" more examples (${allutterances.length}) as expected (${context.indexExpansionModeWidth})`);
7133
+
7134
+ for (let i = context.indexExpansionModeWidth; i < allutterances.length; i++) {
7135
+ // if we found a utterance with more examples as any utterances before, we have to start new 'thread'
7136
+ const myContext = Object.assign({}, context, {
7137
+ indexExpansionModeWidth: allutterances.length,
7138
+ indexExpansionModeIndex: i
7139
+ });
7140
+ processSampleUtterance(allutterances[i], allutterances.length, i, myContext);
7141
+ }
7142
+ }
7143
+ }
7144
+ } else {
7145
+ if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'first') {
7146
+ processSampleUtterances([allutterances[0]]);
7147
+ } else if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'random') {
7148
+ processSampleUtterances(allutterances.map(x => ({
7149
+ x,
7150
+ r: Math.random()
7151
+ })).sort((a, b) => a.r - b.r).map(a => a.x).slice(0, this.caps[Capabilities.SCRIPTING_UTTEXPANSION_RANDOM_COUNT]));
7152
+ } else {
7153
+ processSampleUtterances(allutterances);
7154
+ }
7155
+ }
7156
+
7044
7157
  useUnexpanded = false;
7045
7158
  }
7046
7159
  }
@@ -7057,19 +7170,17 @@ var ScriptingProvider_1 = class ScriptingProvider {
7057
7170
  });
7058
7171
 
7059
7172
  if (expandedUserInputs && expandedUserInputs.length > 0) {
7060
- let sampleinputs = expandedUserInputs;
7061
-
7062
- if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'first') {
7063
- sampleinputs = [expandedUserInputs[0]];
7064
- } else if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'random') {
7065
- sampleinputs = expandedUserInputs.map(x => ({
7066
- x,
7067
- r: Math.random()
7068
- })).sort((a, b) => a.r - b.r).map(a => a.x).slice(0, this.caps[Capabilities.SCRIPTING_UTTEXPANSION_RANDOM_COUNT]);
7069
- }
7173
+ // let sampleinputs = expandedUserInputs
7174
+ const processSampleInputs = (sampleinputs, myContext, uiIndex) => {
7175
+ sampleinputs.forEach((input, index) => {
7176
+ processSampleInput(input, sampleinputs.length, index, Object.assign({
7177
+ indexExpansionModeIndex: index
7178
+ }, myContext || context), uiIndex);
7179
+ });
7180
+ };
7070
7181
 
7071
- sampleinputs.forEach((sampleinput, index) => {
7072
- const lineTag = `${index + 1}`.padStart(`${sampleinputs.length}`.length, '0');
7182
+ const processSampleInput = (sampleinput, length, index, myContext, uiIndex) => {
7183
+ const lineTag = `${index + 1}`.padStart(`${length}`.length, '0');
7073
7184
  const currentStepsStack = convoStepsStack.slice();
7074
7185
 
7075
7186
  const currentStepMod = lodash__default["default"].cloneDeep(currentStep);
@@ -7083,8 +7194,56 @@ var ScriptingProvider_1 = class ScriptingProvider {
7083
7194
  name: `${currentConvo.header.name}/${ui.name}-${utterancePostfix(lineTag, sampleinput.args && sampleinput.args.length ? sampleinput.args.join(', ') : 'no-args')}`
7084
7195
  });
7085
7196
 
7086
- this._expandConvo(expandedConvos, currentConvoLabeled, convoStepIndex + 1, currentStepsStack);
7087
- });
7197
+ this._expandConvo(expandedConvos, currentConvoLabeled, convoStepIndex + 1, currentStepsStack, myContext || context);
7198
+ };
7199
+
7200
+ if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'index') {
7201
+ if (lodash__default["default"].isNil(context.indexExpansionModeWidth)) {
7202
+ processSampleInputs(expandedUserInputs, Object.assign({}, context, {
7203
+ indexExpansionModeWidth: expandedUserInputs.length
7204
+ }), uiIndex);
7205
+ } else {
7206
+ if (lodash__default["default"].isNil(context.indexExpansionModeIndex)) {
7207
+ throw new Error('indexExpansionModeIndex must be set!');
7208
+ } // executing the current 'thread', if current utterance has no example to current index, fallback to the last one
7209
+
7210
+
7211
+ const localIndex = Math.min(context.indexExpansionModeIndex, expandedUserInputs.length - 1);
7212
+
7213
+ if (localIndex < context.indexExpansionModeIndex && context.indexExpansionModeIndex === context.indexExpansionModeWidth - 1) {
7214
+ debug$9(`While expanding convos by index found user input "${ui.name}, ${ui.args}" less examples (${expandedUserInputs.length}) as expected (${context.indexExpansionModeWidth})`);
7215
+ }
7216
+
7217
+ const myContext = Object.assign({}, context, {
7218
+ indexExpansionModeWidth: Math.max(expandedUserInputs.length, context.indexExpansionModeWidth)
7219
+ });
7220
+ processSampleInput(expandedUserInputs[localIndex], expandedUserInputs.length, localIndex, myContext, uiIndex);
7221
+
7222
+ if (expandedUserInputs.length > context.indexExpansionModeWidth && context.indexExpansionModeIndex + 1 === context.indexExpansionModeWidth) {
7223
+ debug$9(`While expanding convos by index found user input "${ui.name}, ${ui.args}" more examples (${expandedUserInputs.length}) as expected (${context.indexExpansionModeWidth})`);
7224
+
7225
+ for (let i = context.indexExpansionModeWidth; i < expandedUserInputs.length; i++) {
7226
+ const myContext = Object.assign({}, context, {
7227
+ indexExpansionModeWidth: expandedUserInputs.length,
7228
+ indexExpansionModeIndex: i
7229
+ });
7230
+ processSampleInput(expandedUserInputs[i], expandedUserInputs.length, i, myContext, uiIndex);
7231
+ }
7232
+ }
7233
+ }
7234
+ } else {
7235
+ if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'first') {
7236
+ processSampleInputs([expandedUserInputs[0]], context, uiIndex);
7237
+ } else if (this.caps[Capabilities.SCRIPTING_UTTEXPANSION_MODE] === 'random') {
7238
+ processSampleInputs(expandedUserInputs.map(x => ({
7239
+ x,
7240
+ r: Math.random()
7241
+ })).sort((a, b) => a.r - b.r).map(a => a.x).slice(0, this.caps[Capabilities.SCRIPTING_UTTEXPANSION_RANDOM_COUNT]), context, uiIndex);
7242
+ } else {
7243
+ processSampleInputs(expandedUserInputs, context, uiIndex);
7244
+ }
7245
+ }
7246
+
7088
7247
  useUnexpanded = false;
7089
7248
  }
7090
7249
  }
@@ -7095,7 +7254,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
7095
7254
  const currentStepsStack = convoStepsStack.slice();
7096
7255
  currentStepsStack.push(lodash__default["default"].cloneDeep(currentStep));
7097
7256
 
7098
- this._expandConvo(expandedConvos, currentConvo, convoStepIndex + 1, currentStepsStack);
7257
+ this._expandConvo(expandedConvos, currentConvo, convoStepIndex + 1, currentStepsStack, context);
7099
7258
  }
7100
7259
  }
7101
7260
  } else {
@@ -8151,7 +8310,8 @@ const setupEndpoints = ({
8151
8310
  processEvent({
8152
8311
  originalUrl: req.originalUrl,
8153
8312
  originalMethod: req.method,
8154
- body: req.body
8313
+ body: req.body,
8314
+ headers: req.headers
8155
8315
  });
8156
8316
  res.status(200).json({}).end();
8157
8317
  } else {
@@ -8256,7 +8416,7 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8256
8416
  });
8257
8417
 
8258
8418
  for (const event of sortedEvents) {
8259
- setTimeout(() => this._processBodyAsync(event.body, true, !!this.caps[Capabilities.SIMPLEREST_INBOUND_UPDATE_CONTEXT]), 0);
8419
+ setTimeout(() => this._processBodyAsync(event.body, event.headers, true, !!this.caps[Capabilities.SIMPLEREST_INBOUND_UPDATE_CONTEXT]), 0);
8260
8420
  }
8261
8421
  }, debounceTimeout);
8262
8422
  }
@@ -8351,12 +8511,15 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8351
8511
  this._startPolling().then(() => startPollingComplete()).catch(startPollingComplete);
8352
8512
  }, pingComplete => {
8353
8513
  if (this.caps[Capabilities.SIMPLEREST_PING_URL]) {
8354
- this._makeCall('SIMPLEREST_PING').then(body => {
8514
+ this._makeCall('SIMPLEREST_PING').then(({
8515
+ body,
8516
+ headers
8517
+ }) => {
8355
8518
  if (this.caps[Capabilities.SIMPLEREST_PING_UPDATE_CONTEXT] || this.caps[Capabilities.SIMPLEREST_PING_PROCESS_RESPONSE]) {
8356
8519
  return this._parseResponseBody(body).then(body => {
8357
8520
  if (body) {
8358
8521
  debug$4(`Ping Uri ${this.caps[Capabilities.SIMPLEREST_PING_URL]} returned JSON response: ${Utils.shortenJsonString(body)}`);
8359
- return this._processBodyAsync(body, !!this.caps[Capabilities.SIMPLEREST_PING_PROCESS_RESPONSE], !!this.caps[Capabilities.SIMPLEREST_PING_UPDATE_CONTEXT]);
8522
+ return this._processBodyAsync(body, headers, !!this.caps[Capabilities.SIMPLEREST_PING_PROCESS_RESPONSE], !!this.caps[Capabilities.SIMPLEREST_PING_UPDATE_CONTEXT]);
8360
8523
  } else {
8361
8524
  debug$4(`Ping Uri ${this.caps[Capabilities.SIMPLEREST_PING_URL]} didn't return JSON response, ignoring it.`);
8362
8525
  }
@@ -8384,12 +8547,15 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8384
8547
  this.processInbound = true;
8385
8548
 
8386
8549
  if (this.caps[Capabilities.SIMPLEREST_START_URL]) {
8387
- this._makeCall('SIMPLEREST_START').then(body => {
8550
+ this._makeCall('SIMPLEREST_START').then(({
8551
+ body,
8552
+ headers
8553
+ }) => {
8388
8554
  if (this.caps[Capabilities.SIMPLEREST_START_UPDATE_CONTEXT] || this.caps[Capabilities.SIMPLEREST_START_PROCESS_RESPONSE]) {
8389
8555
  return this._parseResponseBody(body).then(body => {
8390
8556
  if (body) {
8391
8557
  debug$4(`Start Uri ${this.caps[Capabilities.SIMPLEREST_START_URL]} returned JSON response: ${Utils.shortenJsonString(body)}`);
8392
- return this._processBodyAsync(body, !!this.caps[Capabilities.SIMPLEREST_START_PROCESS_RESPONSE], !!this.caps[Capabilities.SIMPLEREST_START_UPDATE_CONTEXT]);
8558
+ return this._processBodyAsync(body, headers, !!this.caps[Capabilities.SIMPLEREST_START_PROCESS_RESPONSE], !!this.caps[Capabilities.SIMPLEREST_START_UPDATE_CONTEXT]);
8393
8559
  } else {
8394
8560
  debug$4(`Start Uri ${this.caps[Capabilities.SIMPLEREST_START_URL]} didn't return JSON response, ignoring it.`);
8395
8561
  }
@@ -8441,10 +8607,10 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8441
8607
  } // Separated just for better module testing
8442
8608
 
8443
8609
 
8444
- async _processBodyAsync(body, isFromUser, updateContext) {
8610
+ async _processBodyAsync(body, headers, isFromUser, updateContext) {
8445
8611
  const p = async () => {
8446
8612
  try {
8447
- const results = await this._processBodyAsyncImpl(body, isFromUser, updateContext);
8613
+ const results = await this._processBodyAsyncImpl(body, headers, isFromUser, updateContext);
8448
8614
 
8449
8615
  if (results) {
8450
8616
  for (const result of results) {
@@ -8475,7 +8641,12 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8475
8641
  } // Separated just for better module testing
8476
8642
 
8477
8643
 
8478
- async _processBodyAsyncImpl(body, isFromUser, updateContext) {
8644
+ async _processBodyAsyncImpl(body, headers, isFromUser, updateContext) {
8645
+ this.view.response = {
8646
+ body,
8647
+ headers
8648
+ };
8649
+
8479
8650
  if (updateContext) {
8480
8651
  const mergeMode = this.caps[Capabilities.SIMPLEREST_CONTEXT_MERGE_OR_REPLACE];
8481
8652
  const jsonPathsContext = getAllCapValues(Capabilities.SIMPLEREST_CONTEXT_JSONPATH, this.caps);
@@ -8685,7 +8856,7 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8685
8856
  }
8686
8857
 
8687
8858
  if (body) {
8688
- debug$4(`got response code: ${response.statusCode}, body: ${Utils.shortenJsonString(body)}`);
8859
+ debug$4(`got response code: ${response.statusCode}, body: ${Utils.shortenJsonString(body)}, headers: ${Utils.shortenJsonString(response.headers)}`);
8689
8860
 
8690
8861
  this._storeCookiesFromResponse(response);
8691
8862
 
@@ -8701,7 +8872,7 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8701
8872
  }
8702
8873
 
8703
8874
  if (body) {
8704
- this._processBodyAsync(body, isFromUser, updateContext).then(() => resolve(this)).then(() => this._emptyWaitProcessQueue());
8875
+ this._processBodyAsync(body, response.headers, isFromUser, updateContext).then(() => resolve(this)).then(() => this._emptyWaitProcessQueue());
8705
8876
  } else {
8706
8877
  debug$4('ignoring response body (no string and no JSON object)');
8707
8878
  resolve(this);
@@ -8763,6 +8934,10 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8763
8934
  try {
8764
8935
  requestOptions.body = this._getMustachedCap(Capabilities.SIMPLEREST_BODY_TEMPLATE, !bodyRaw);
8765
8936
  requestOptions.json = !bodyRaw;
8937
+
8938
+ if (requestOptions.json && (!requestOptions.body || Object.keys(requestOptions.body).length === 0)) {
8939
+ debug$4(`warning: requestOptions.body content seems to be empty - ${requestOptions.body} - capability: "${this.caps[Capabilities.SIMPLEREST_BODY_TEMPLATE]}"`);
8940
+ }
8766
8941
  } catch (err) {
8767
8942
  throw new Error(`composing body from SIMPLEREST_BODY_TEMPLATE failed (${err.message})`);
8768
8943
  }
@@ -8861,10 +9036,13 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8861
9036
  this._storeCookiesFromResponse(response);
8862
9037
 
8863
9038
  if (debug$4.enabled && body) {
8864
- debug$4(Utils.shortenJsonString(body));
9039
+ debug$4(`body: ${Utils.shortenJsonString(body)}, headers: ${Utils.shortenJsonString(response.headers)}`);
8865
9040
  }
8866
9041
 
8867
- return body;
9042
+ return {
9043
+ body,
9044
+ headers: response.headers
9045
+ };
8868
9046
  }
8869
9047
  }
8870
9048
  }
@@ -8908,7 +9086,11 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8908
9086
  try {
8909
9087
  return JSON.parse(raw);
8910
9088
  } catch (err) {
8911
- return new Error(`JSON parsing failed - try to use {{#fnc.jsonify}}{{xxx}}{{/fnc.jsonify}} to escape JSON special characters (ERR: ${err.message})`);
9089
+ if (debug$4.enabled) {
9090
+ debug$4(`JSON parsing failed (${err.message}) for: ${Utils.shortenJsonString(raw)}`);
9091
+ }
9092
+
9093
+ throw new Error(`JSON parsing failed - try to use {{#fnc.jsonify}}{{xxx}}{{/fnc.jsonify}} to escape JSON special characters (ERR: ${err.message})`);
8912
9094
  }
8913
9095
  } else {
8914
9096
  return raw;
@@ -8953,7 +9135,7 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8953
9135
 
8954
9136
  this._processOrderedInboundEventsArrayAsync();
8955
9137
  } else {
8956
- setTimeout(() => this._processBodyAsync(event.body, true, !!this.caps[Capabilities.SIMPLEREST_INBOUND_UPDATE_CONTEXT]), 0);
9138
+ setTimeout(() => this._processBodyAsync(event.body, event.headers, true, !!this.caps[Capabilities.SIMPLEREST_INBOUND_UPDATE_CONTEXT]), 0);
8957
9139
  }
8958
9140
  }
8959
9141
 
@@ -9094,7 +9276,7 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
9094
9276
  debug$4(Utils.shortenJsonString(body));
9095
9277
  }
9096
9278
  } else if (body) {
9097
- debug$4(`_runPolling: got response code: ${response.statusCode}, body: ${Utils.shortenJsonString(body)}`);
9279
+ debug$4(`_runPolling: got response code: ${response.statusCode}, body: ${Utils.shortenJsonString(body)}, headers: ${Utils.shortenJsonString(response.headers)}`);
9098
9280
 
9099
9281
  this._storeCookiesFromResponse(response);
9100
9282
 
@@ -9106,7 +9288,7 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
9106
9288
  }
9107
9289
 
9108
9290
  if (body) {
9109
- setTimeout(() => this._processBodyAsync(body, true, !!this.caps[Capabilities.SIMPLEREST_POLL_UPDATE_CONTEXT]), 0);
9291
+ setTimeout(() => this._processBodyAsync(body, response.headers, true, !!this.caps[Capabilities.SIMPLEREST_POLL_UPDATE_CONTEXT]), 0);
9110
9292
  } else {
9111
9293
  debug$4('_runPolling: ignoring response body (no string and no JSON object)');
9112
9294
  }