botium-core 1.13.19 → 1.14.1

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 (41) hide show
  1. package/dist/botium-cjs.js +328 -395
  2. package/dist/botium-cjs.js.map +1 -1
  3. package/dist/botium-es.js +328 -393
  4. package/dist/botium-es.js.map +1 -1
  5. package/package.json +24 -29
  6. package/samples/extensions/asserterHooks/botium.json +1 -0
  7. package/samples/extensions/logichooks/botium.json +1 -0
  8. package/samples/extensions/logichooks/custom/MyAsserter.js +3 -3
  9. package/src/Capabilities.js +2 -1
  10. package/src/containers/PluginConnectorContainer.js +8 -0
  11. package/src/containers/plugins/SimpleRestContainer.js +17 -9
  12. package/src/containers/plugins/index.js +29 -41
  13. package/src/helpers/HookUtils.js +32 -68
  14. package/src/scripting/Convo.js +26 -9
  15. package/src/scripting/ScriptingMemory.js +0 -24
  16. package/src/scripting/logichook/LogicHookUtils.js +27 -47
  17. package/src/scripting/logichook/logichooks/ConditionalBusinessHoursLogicHook.js +1 -1
  18. package/src/scripting/logichook/logichooks/ConditionalCapabilityValueBasedLogicHook.js +1 -1
  19. package/src/scripting/logichook/logichooks/ConditionalJsonPathBasedLogicHook.js +1 -1
  20. package/src/scripting/logichook/logichooks/ConditionalTimeBasedLogicHook.js +1 -1
  21. package/test/compiler/precompilerscript.spec.js +24 -26
  22. package/test/connectors/pluginconnectorcontainer.spec.js +60 -0
  23. package/test/connectors/simplerest.spec.js +24 -27
  24. package/test/convo/fillAndApplyScriptingMemory.spec.js +1 -47
  25. package/test/hooks/customhooks.spec.js +3 -25
  26. package/test/logichooks/hookfromsrc.spec.js +13 -3
  27. package/test/plugins/plugins.spec.js +29 -2
  28. package/test/scripting/logichooks/convos/conditional_steps_multiple_condition_groups_no_assertion.convo.txt +6 -6
  29. package/test/scripting/logichooks/convos/conditional_steps_multiple_mandatory_condition_groups.convo.txt +20 -0
  30. package/test/scripting/logichooks/convos/conditional_steps_multiple_optional_condition_groups.convo.txt +20 -0
  31. package/test/scripting/logichooks/customConditionalStepLogicHook.spec.js +16 -0
  32. package/test/security/allowUnsafe.spec.js +20 -129
  33. package/LICENSES-3RDPARTY.txt +0 -6450
  34. package/test/scripting/asserters/convos/customembeddedasserterwithhugo.convo.txt +0 -7
  35. package/test/scripting/asserters/convos/customembeddedasserterwithouthugo.convo.txt +0 -7
  36. package/test/scripting/asserters/customEmbeddedAsserter.json +0 -14
  37. package/test/scripting/asserters/customEmbeddedAsserter.spec.js +0 -55
  38. package/test/scripting/logichooks/convos/custom_embedded.convo.txt +0 -8
  39. package/test/scripting/logichooks/customEmbedded.json +0 -14
  40. package/test/scripting/logichooks/customEmbedded.spec.js +0 -44
  41. package/test/security/convos/withscriptingmemoryfunction.convo.txt +0 -5
@@ -15,7 +15,6 @@ var lodash = require('lodash');
15
15
  var boolean$1 = require('boolean');
16
16
  var events = require('events');
17
17
  var debug$n = require('debug');
18
- var vm2 = require('vm2');
19
18
  var isClass = require('is-class');
20
19
  var crypto = require('crypto');
21
20
  var globby = require('globby');
@@ -25,7 +24,6 @@ var uuid = require('uuid');
25
24
  var jsonpath = require('jsonpath');
26
25
  var isJson$1 = require('is-json');
27
26
  var wordErrorRate = require('word-error-rate');
28
- var esprima = require('esprima');
29
27
  var markdownIt = require('markdown-it');
30
28
  var xlsx = require('xlsx');
31
29
  var sync = require('csv-parse/sync');
@@ -55,7 +53,6 @@ var lodash__default = /*#__PURE__*/_interopDefaultLegacy(lodash);
55
53
  var boolean__default = /*#__PURE__*/_interopDefaultLegacy(boolean$1);
56
54
  var events__default = /*#__PURE__*/_interopDefaultLegacy(events);
57
55
  var debug__default = /*#__PURE__*/_interopDefaultLegacy(debug$n);
58
- var vm2__default = /*#__PURE__*/_interopDefaultLegacy(vm2);
59
56
  var isClass__default = /*#__PURE__*/_interopDefaultLegacy(isClass);
60
57
  var crypto__default = /*#__PURE__*/_interopDefaultLegacy(crypto);
61
58
  var globby__default = /*#__PURE__*/_interopDefaultLegacy(globby);
@@ -65,7 +62,6 @@ var uuid__default = /*#__PURE__*/_interopDefaultLegacy(uuid);
65
62
  var jsonpath__default = /*#__PURE__*/_interopDefaultLegacy(jsonpath);
66
63
  var isJson__default = /*#__PURE__*/_interopDefaultLegacy(isJson$1);
67
64
  var wordErrorRate__default = /*#__PURE__*/_interopDefaultLegacy(wordErrorRate);
68
- var esprima__default = /*#__PURE__*/_interopDefaultLegacy(esprima);
69
65
  var markdownIt__default = /*#__PURE__*/_interopDefaultLegacy(markdownIt);
70
66
  var xlsx__default = /*#__PURE__*/_interopDefaultLegacy(xlsx);
71
67
  var sync__default = /*#__PURE__*/_interopDefaultLegacy(sync);
@@ -81,7 +77,7 @@ var express__default = /*#__PURE__*/_interopDefaultLegacy(express);
81
77
  var bodyParser__default = /*#__PURE__*/_interopDefaultLegacy(bodyParser);
82
78
 
83
79
  var name = "botium-core";
84
- var version$1 = "1.13.19";
80
+ var version$1 = "1.14.1";
85
81
  var description = "The Selenium for Chatbots";
86
82
  var main = "index.js";
87
83
  var module$1 = "dist/botium-es.js";
@@ -99,7 +95,6 @@ var scripts = {
99
95
  link: "npm link botium-connector-dialogflow botium-connector-webdriverio botium-connector-directline3 botium-connector-watson botium-connector-alexa-smapi botium-connector-echo",
100
96
  test: "cross-env NODE_PATH=\"./test/plugins/plugindir/fromfolder:./test/plugins/plugindir/fromfile:./test/security/resources\" mocha \"./test/**/*.spec.js\"",
101
97
  "coverage:report": "nyc report --reporter=lcov npm test",
102
- "license-checker": "license-checker > LICENSES-3RDPARTY.txt",
103
98
  "update-dependencies": "npm-check-updates --reject globby,rollup -u --timeout 120000"
104
99
  };
105
100
  var repository = {
@@ -113,14 +108,13 @@ var bugs = {
113
108
  };
114
109
  var homepage = "https://www.botium.ai";
115
110
  var dependencies = {
116
- "@babel/runtime": "^7.21.5",
117
- async: "^3.2.4",
111
+ "@babel/runtime": "^7.23.2",
112
+ async: "^3.2.5",
118
113
  "body-parser": "^1.20.2",
119
114
  boolean: "^3.2.0",
120
115
  bottleneck: "^2.19.5",
121
- "csv-parse": "^5.3.10",
116
+ "csv-parse": "^5.5.2",
122
117
  debug: "^4.3.4",
123
- esprima: "^4.0.1",
124
118
  express: "^4.18.2",
125
119
  globby: "11.0.4",
126
120
  ioredis: "^5.3.2",
@@ -128,52 +122,49 @@ var dependencies = {
128
122
  "is-json": "^2.0.1",
129
123
  jsonpath: "^1.1.1",
130
124
  lodash: "^4.17.21",
131
- "markdown-it": "^13.0.1",
125
+ "markdown-it": "^13.0.2",
132
126
  "mime-types": "^2.1.35",
133
127
  mkdirp: "^3.0.1",
134
128
  moment: "^2.29.4",
135
129
  "moment-timezone": "^0.5.43",
136
130
  mustache: "^4.2.0",
137
131
  "promise-retry": "^2.0.1",
138
- "promise.allsettled": "^1.0.6",
132
+ "promise.allsettled": "^1.0.7",
139
133
  randomatic: "^3.1.1",
140
134
  request: "^2.88.2",
141
- rimraf: "^5.0.0",
135
+ rimraf: "^5.0.5",
142
136
  "sanitize-filename": "^1.6.3",
143
137
  slugify: "^1.6.6",
144
- "socket.io": "^4.6.1",
145
- "socket.io-client": "^4.6.1",
138
+ "socket.io": "^4.7.2",
139
+ "socket.io-client": "^4.7.2",
146
140
  "socketio-auth": "^0.1.1",
147
141
  "swagger-jsdoc": "^6.2.8",
148
- "swagger-ui-express": "^4.6.3",
149
- uuid: "^9.0.0",
150
- vm2: "^3.9.17",
142
+ "swagger-ui-express": "^5.0.0",
143
+ uuid: "^9.0.1",
151
144
  "word-error-rate": "0.0.7",
152
145
  "write-yaml": "^1.0.0",
153
146
  xlsx: "^0.18.5",
154
147
  xregexp: "^5.1.1",
155
- yaml: "^2.2.2"
148
+ yaml: "^2.3.4"
156
149
  };
157
150
  var devDependencies = {
158
- "@babel/core": "^7.21.8",
159
- "@babel/node": "^7.20.7",
160
- "@babel/plugin-transform-runtime": "^7.21.4",
161
- "@babel/preset-env": "^7.21.5",
162
- chai: "^4.3.7",
151
+ "@babel/core": "^7.23.3",
152
+ "@babel/node": "^7.22.19",
153
+ "@babel/plugin-transform-runtime": "^7.23.3",
154
+ "@babel/preset-env": "^7.23.3",
155
+ chai: "^4.3.10",
163
156
  "chai-as-promised": "^7.1.1",
164
157
  "cross-env": "^7.0.3",
165
- eslint: "^8.40.0",
166
- "eslint-config-standard": "^17.0.0",
167
- "eslint-plugin-import": "^2.27.5",
168
- "eslint-plugin-mocha": "^10.1.0",
169
- "eslint-plugin-n": "^15.7.0",
158
+ eslint: "^8.53.0",
159
+ "eslint-config-standard": "^17.1.0",
160
+ "eslint-plugin-import": "^2.29.0",
161
+ "eslint-plugin-mocha": "^10.2.0",
162
+ "eslint-plugin-n": "^16.3.1",
170
163
  "eslint-plugin-promise": "^6.1.1",
171
164
  "eslint-plugin-standard": "^4.1.0",
172
- "license-checker": "^25.0.1",
173
- "license-compatibility-checker": "^0.3.5",
174
165
  mocha: "^10.2.0",
175
- nock: "^13.3.1",
176
- "npm-check-updates": "^16.10.12",
166
+ nock: "^13.3.8",
167
+ "npm-check-updates": "^16.14.6",
177
168
  nyc: "^15.1.0",
178
169
  rollup: "2.79.1",
179
170
  "rollup-plugin-babel": "^4.4.0",
@@ -222,6 +213,7 @@ var Capabilities = {
222
213
  TESTSESSIONNAME: 'TESTSESSIONNAME',
223
214
  TESTCASENAME: 'TESTCASENAME',
224
215
  TEMPDIR: 'TEMPDIR',
216
+ SAFEDIR: 'SAFEDIR',
225
217
  CLEANUPTEMPDIR: 'CLEANUPTEMPDIR',
226
218
  WAITFORBOTTIMEOUT: 'WAITFORBOTTIMEOUT',
227
219
  CONTAINERMODE: 'CONTAINERMODE',
@@ -231,7 +223,7 @@ var Capabilities = {
231
223
  BOTIUMGRIDURL: 'BOTIUMGRIDURL',
232
224
  BOTIUMAPITOKEN: 'BOTIUMAPITOKEN',
233
225
  BOTIUMGRIDSLOT: 'BOTIUMGRIDSLOT',
234
- // Simple Reset Bot Settings
226
+ // Simple Rest Bot Settings
235
227
  SIMPLEREST_PING_URL: 'SIMPLEREST_PING_URL',
236
228
  SIMPLEREST_PING_VERB: 'SIMPLEREST_PING_VERB',
237
229
  SIMPLEREST_PING_BODY: 'SIMPLEREST_PING_BODY',
@@ -396,6 +388,7 @@ Capabilities.PROJECTNAME;
396
388
  Capabilities.TESTSESSIONNAME;
397
389
  Capabilities.TESTCASENAME;
398
390
  Capabilities.TEMPDIR;
391
+ Capabilities.SAFEDIR;
399
392
  Capabilities.CLEANUPTEMPDIR;
400
393
  Capabilities.WAITFORBOTTIMEOUT;
401
394
  Capabilities.CONTAINERMODE;
@@ -914,140 +907,6 @@ function getCjsExportFromNamespace (n) {
914
907
  return n && n['default'] || n;
915
908
  }
916
909
 
917
- const BotiumError$7 = class BotiumError extends Error {
918
- /**
919
- *
920
- * @param message
921
- * @param context A JSON with struct
922
- * {
923
- * type: 'some free text to identity the exception type',
924
- * source: 'source of the event',
925
- * ...
926
- */
927
- constructor(message, context, supressChildCheck) {
928
- super(message.message || message);
929
- if (!supressChildCheck && _getChildErrorsFromContext(context)) {
930
- throw Error('Create BotiumError with child errors using the fromList() method!');
931
- }
932
- // Saving class name in the property of our custom error as a shortcut.
933
- this.name = this.constructor.name;
934
-
935
- // Capturing stack trace, excluding constructor call from it.
936
- Error.captureStackTrace(this, this.constructor);
937
- this.context = context || {};
938
- this.context.message = message.message || message;
939
- }
940
- isAsserterError() {
941
- if (this.context) {
942
- const errArr = lodash__default["default"].isArray(this.context) ? this.context : [this.context];
943
- const hasNotAsserterError = errArr.findIndex(errDetail => {
944
- if (errDetail.type === 'list') {
945
- if (errDetail.errors) {
946
- return errDetail.errors.findIndex(e => e.type !== 'asserter') >= 0;
947
- } else {
948
- return true;
949
- }
950
- } else {
951
- return errDetail.type !== 'asserter';
952
- }
953
- }) >= 0;
954
- if (hasNotAsserterError) return false;
955
- return true;
956
- } else {
957
- return false;
958
- }
959
- }
960
- prettify(includeJson) {
961
- const lines = [];
962
- if (this.context) {
963
- const errArr = lodash__default["default"].isArray(this.context) ? this.context : [this.context];
964
- errArr.forEach(errDetail => {
965
- lines.push('########################################');
966
- if (errDetail.type === 'asserter') {
967
- const segments = [];
968
- segments.push(`ASSERTION FAILED in ${errDetail.source}${errDetail.subtype ? ` (${errDetail.subtype})` : ''}`);
969
- errDetail.cause && errDetail.cause.expected && !errDetail.cause.not && segments.push(` - Expected: ${JSON.stringify(errDetail.cause.expected)} `);
970
- errDetail.cause && errDetail.cause.expected && errDetail.cause.not && segments.push(` - NOT Expected: ${JSON.stringify(errDetail.cause.expected)} `);
971
- errDetail.cause && errDetail.cause.actual && segments.push(` - Actual: ${JSON.stringify(errDetail.cause.actual)}`);
972
- errDetail.cause && !errDetail.cause.actual && segments.push(' - Actual: empty');
973
- lines.push(segments.join(''));
974
- errDetail.input && errDetail.input.messageText && lines.push(`INPUT: ${errDetail.input.messageText}`);
975
- } else if (errDetail.message) {
976
- lines.push(`${errDetail.message}`);
977
- }
978
- if (errDetail.transcript && errDetail.transcript.length > 0) {
979
- lines.push('------------ TRANSCRIPT ----------------------------');
980
- errDetail.transcript.forEach(transcriptStep => {
981
- if (transcriptStep.actual) {
982
- lines.push(transcriptStep.actual.prettify());
983
- }
984
- });
985
- }
986
- if (includeJson) {
987
- lines.push('------------ JSON CONTENT ----------------------------');
988
- try {
989
- const jsonOutput = JSON.stringify(errDetail);
990
- lines.push(jsonOutput);
991
- } catch (jsonErr) {
992
- lines.push(`JSON Output not possible: ${jsonErr.message}`);
993
- }
994
- }
995
- });
996
- }
997
- if (lines.length > 0) {
998
- return lines.join('\r\n');
999
- } else {
1000
- return null;
1001
- }
1002
- }
1003
- };
1004
- const _getChildErrorsFromContext = context => {
1005
- if (context && context.errors && lodash__default["default"].isArray(context.errors)) {
1006
- return context.errors;
1007
- }
1008
- return false;
1009
- };
1010
- const botiumErrorFromErr$2 = (message, err) => {
1011
- if (err instanceof BotiumError$7) {
1012
- return new BotiumError$7(message, err.context, true);
1013
- } else {
1014
- return new BotiumError$7(message, {
1015
- err
1016
- }, true);
1017
- }
1018
- };
1019
- const botiumErrorFromList$2 = (errors, {
1020
- type = 'list',
1021
- source = 'BotiumError',
1022
- flat = true
1023
- }) => {
1024
- const message = errors.map(err => err.message || err.toString()).join(',\n');
1025
- let children = [];
1026
- for (const error of errors) {
1027
- if (error instanceof BotiumError$7) {
1028
- const childErrors = flat && _getChildErrorsFromContext(error.context);
1029
- if (childErrors && childErrors.length) {
1030
- children = children.concat(childErrors);
1031
- } else if (error.context) {
1032
- children.push(error.context);
1033
- }
1034
- } else {
1035
- children.push(error);
1036
- }
1037
- }
1038
- const result = new BotiumError$7(message, {
1039
- errors: children,
1040
- type,
1041
- source
1042
- }, true);
1043
- return result;
1044
- };
1045
- var BotiumError_1 = {
1046
- BotiumError: BotiumError$7,
1047
- botiumErrorFromErr: botiumErrorFromErr$2,
1048
- botiumErrorFromList: botiumErrorFromList$2
1049
- };
1050
-
1051
910
  const LOGIC_HOOK_INCLUDE$1 = 'INCLUDE';
1052
911
  var LogicHookConsts = {
1053
912
  LOGIC_HOOK_INCLUDE: LOGIC_HOOK_INCLUDE$1,
@@ -1234,13 +1093,7 @@ LogicHookConsts.DEFAULT_ASSERTERS;
1234
1093
  LogicHookConsts.DEFAULT_LOGIC_HOOKS;
1235
1094
  LogicHookConsts.DEFAULT_USER_INPUTS;
1236
1095
 
1237
- const {
1238
- NodeVM: NodeVM$2
1239
- } = vm2__default["default"];
1240
1096
  const debug$m = debug__default["default"]('botium-core-asserterUtils');
1241
- const {
1242
- BotiumError: BotiumError$6
1243
- } = BotiumError_1;
1244
1097
  const {
1245
1098
  DEFAULT_ASSERTERS,
1246
1099
  DEFAULT_LOGIC_HOOKS,
@@ -1362,21 +1215,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1362
1215
  }, this.caps, args);
1363
1216
  }
1364
1217
  }
1365
- const _checkUnsafe = () => {
1366
- if (!this.caps[Capabilities.SECURITY_ALLOW_UNSAFE]) {
1367
- throw new BotiumError$6('Security Error. Using unsafe component is not allowed', {
1368
- type: 'security',
1369
- subtype: 'allow unsafe',
1370
- source: path__default["default"].basename(__filename),
1371
- cause: {
1372
- src: !!src,
1373
- ref,
1374
- args,
1375
- hookType
1376
- }
1377
- });
1378
- }
1379
- };
1218
+ const allowUnsafe = !!this.caps[Capabilities.SECURITY_ALLOW_UNSAFE];
1380
1219
  if (!src) {
1381
1220
  const packageName = `botium-${hookType}-${ref}`;
1382
1221
  try {
@@ -1397,10 +1236,10 @@ var LogicHookUtils_1 = class LogicHookUtils {
1397
1236
  ...this.buildScriptContext
1398
1237
  }, this.caps, args);
1399
1238
  } else {
1400
- throw new Error(`${packageName} class or function or PluginClass field expected`);
1239
+ throw new Error('Either class or function or PluginClass field expected');
1401
1240
  }
1402
1241
  } catch (err) {
1403
- throw new Error(`Failed to fetch hook ${ref} ${hookType} from guessed package ${packageName} - ${err.message}`);
1242
+ throw new Error(`Logic Hook specification ${ref} ${hookType} (${packageName}) invalid: ${err.message}`);
1404
1243
  }
1405
1244
  }
1406
1245
  if (isClass__default["default"](src)) {
@@ -1411,7 +1250,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1411
1250
  ...this.buildScriptContext
1412
1251
  }, this.caps, args);
1413
1252
  } catch (err) {
1414
- throw new Error(`Failed to load package ${ref} from provided class - ${err.message}`);
1253
+ throw new Error(`Logic Hook specification ${ref} from class invalid: ${err.message}`);
1415
1254
  }
1416
1255
  }
1417
1256
  if (lodash__default["default"].isFunction(src)) {
@@ -1421,7 +1260,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1421
1260
  ...this.buildScriptContext
1422
1261
  }, this.caps, args);
1423
1262
  } catch (err) {
1424
- throw new Error(`Failed to load package ${ref} from provided function - ${err.message}`);
1263
+ throw new Error(`Logic Hook specification ${ref} from function invalid: ${err.message}`);
1425
1264
  }
1426
1265
  }
1427
1266
  if (lodash__default["default"].isObject(src) && !lodash__default["default"].isString(src)) {
@@ -1431,26 +1270,15 @@ var LogicHookUtils_1 = class LogicHookUtils {
1431
1270
  const script = src[key];
1432
1271
  if (lodash__default["default"].isFunction(script)) {
1433
1272
  return script(args);
1434
- } else if (lodash__default["default"].isString(script)) {
1435
- try {
1436
- const vm = new NodeVM$2({
1437
- eval: false,
1438
- require: false,
1439
- sandbox: args
1440
- });
1441
- return vm.run(script);
1442
- } catch (err) {
1443
- throw new Error(`Script ${key} is not valid - ${err.message || err}`);
1444
- }
1445
1273
  } else {
1446
- throw new Error(`Script "${key}" is not valid - only functions and javascript code accepted`);
1274
+ throw new Error(`Script ${key} is not valid - only functions accepted`);
1447
1275
  }
1448
1276
  };
1449
1277
  return result;
1450
1278
  }, {});
1451
1279
  return hookObject;
1452
1280
  } catch (err) {
1453
- throw new Error(`Failed to load package ${ref} ${hookType} from provided src function - ${err.message}`);
1281
+ throw new Error(`Logic Hook specification ${ref} ${hookType} from provided src (${util__default["default"].inspect(src)}) invalid: ${err.message}`);
1454
1282
  }
1455
1283
  }
1456
1284
  if (lodash__default["default"].isString(src)) {
@@ -1461,8 +1289,8 @@ var LogicHookUtils_1 = class LogicHookUtils {
1461
1289
  }];
1462
1290
  if (src.indexOf('/') >= 0) {
1463
1291
  tryLoads.push({
1464
- tryLoadPackageName: src.substr(0, src.lastIndexOf('/')),
1465
- tryLoadAsserterByName: src.substr(src.lastIndexOf('/') + 1)
1292
+ tryLoadPackageName: src.substring(0, src.lastIndexOf('/')),
1293
+ tryLoadAsserterByName: src.substring(src.lastIndexOf('/') + 1)
1466
1294
  });
1467
1295
  }
1468
1296
  const tryLoadFromSource = (tryRequire, tryAsserterName) => {
@@ -1500,28 +1328,33 @@ var LogicHookUtils_1 = class LogicHookUtils {
1500
1328
  ...this.buildScriptContext
1501
1329
  }, this.caps, args);
1502
1330
  } else {
1503
- throw new Error(`${src} class or function expected`);
1331
+ throw new Error('Expected class or function');
1504
1332
  }
1505
1333
  };
1506
1334
  for (const tryLoad of tryLoads) {
1507
- const tryLoadFile = path__default["default"].resolve(process.cwd(), tryLoad.tryLoadPackageName);
1508
- if (fs__default["default"].existsSync(tryLoadFile)) {
1509
- _checkUnsafe();
1335
+ if (this.caps.SAFEDIR) {
1336
+ const tryLoadFile = path__default["default"].resolve(this.caps.SAFEDIR, tryLoad.tryLoadPackageName);
1337
+ if (tryLoadFile.startsWith(path__default["default"].resolve(this.caps.SAFEDIR))) {
1338
+ if (fs__default["default"].existsSync(tryLoadFile)) {
1339
+ try {
1340
+ return tryLoadFromSource(tryLoadFile, tryLoad.tryLoadAsserterByName);
1341
+ } catch (err) {
1342
+ loadErr.push(`Logic Hook specification ${ref} ${hookType} from "${src}" invalid: ${err.message} `);
1343
+ }
1344
+ }
1345
+ }
1346
+ }
1347
+ if (allowUnsafe || tryLoad.tryLoadPackageName.startsWith('botium-')) {
1510
1348
  try {
1511
- return tryLoadFromSource(tryLoadFile, tryLoad.tryLoadAsserterByName);
1349
+ return tryLoadFromSource(tryLoad.tryLoadPackageName, tryLoad.tryLoadAsserterByName);
1512
1350
  } catch (err) {
1513
- loadErr.push(`Failed to fetch ${ref} ${hookType} from ${src} - ${err.message} `);
1351
+ loadErr.push(`Logic Hook specification ${ref} ${hookType} from "${src}" invalid: ${err.message} `);
1514
1352
  }
1515
1353
  }
1516
- try {
1517
- return tryLoadFromSource(tryLoad.tryLoadPackageName, tryLoad.tryLoadAsserterByName);
1518
- } catch (err) {
1519
- loadErr.push(`Failed to fetch ${ref} ${hookType} from ${src} - ${err.message} `);
1520
- }
1521
1354
  }
1522
1355
  loadErr.forEach(debug$m);
1523
1356
  }
1524
- throw new Error(`Failed to fetch ${ref} ${hookType}, no idea how to load ...`);
1357
+ throw new Error(`Logic Hook specification ${ref} ${hookType} from "${util__default["default"].inspect(src)}" invalid : no loader available`);
1525
1358
  }
1526
1359
  };
1527
1360
 
@@ -2328,19 +2161,150 @@ var helper = {
2328
2161
  toPercent: toPercent$1
2329
2162
  };
2330
2163
 
2164
+ const BotiumError$4 = class BotiumError extends Error {
2165
+ /**
2166
+ *
2167
+ * @param message
2168
+ * @param context A JSON with struct
2169
+ * {
2170
+ * type: 'some free text to identity the exception type',
2171
+ * source: 'source of the event',
2172
+ * ...
2173
+ */
2174
+ constructor(message, context, supressChildCheck) {
2175
+ super(message.message || message);
2176
+ if (!supressChildCheck && _getChildErrorsFromContext(context)) {
2177
+ throw Error('Create BotiumError with child errors using the fromList() method!');
2178
+ }
2179
+ // Saving class name in the property of our custom error as a shortcut.
2180
+ this.name = this.constructor.name;
2181
+
2182
+ // Capturing stack trace, excluding constructor call from it.
2183
+ Error.captureStackTrace(this, this.constructor);
2184
+ this.context = context || {};
2185
+ this.context.message = message.message || message;
2186
+ }
2187
+ isAsserterError() {
2188
+ if (this.context) {
2189
+ const errArr = lodash__default["default"].isArray(this.context) ? this.context : [this.context];
2190
+ const hasNotAsserterError = errArr.findIndex(errDetail => {
2191
+ if (errDetail.type === 'list') {
2192
+ if (errDetail.errors) {
2193
+ return errDetail.errors.findIndex(e => e.type !== 'asserter') >= 0;
2194
+ } else {
2195
+ return true;
2196
+ }
2197
+ } else {
2198
+ return errDetail.type !== 'asserter';
2199
+ }
2200
+ }) >= 0;
2201
+ if (hasNotAsserterError) return false;
2202
+ return true;
2203
+ } else {
2204
+ return false;
2205
+ }
2206
+ }
2207
+ prettify(includeJson) {
2208
+ const lines = [];
2209
+ if (this.context) {
2210
+ const errArr = lodash__default["default"].isArray(this.context) ? this.context : [this.context];
2211
+ errArr.forEach(errDetail => {
2212
+ lines.push('########################################');
2213
+ if (errDetail.type === 'asserter') {
2214
+ const segments = [];
2215
+ segments.push(`ASSERTION FAILED in ${errDetail.source}${errDetail.subtype ? ` (${errDetail.subtype})` : ''}`);
2216
+ errDetail.cause && errDetail.cause.expected && !errDetail.cause.not && segments.push(` - Expected: ${JSON.stringify(errDetail.cause.expected)} `);
2217
+ errDetail.cause && errDetail.cause.expected && errDetail.cause.not && segments.push(` - NOT Expected: ${JSON.stringify(errDetail.cause.expected)} `);
2218
+ errDetail.cause && errDetail.cause.actual && segments.push(` - Actual: ${JSON.stringify(errDetail.cause.actual)}`);
2219
+ errDetail.cause && !errDetail.cause.actual && segments.push(' - Actual: empty');
2220
+ lines.push(segments.join(''));
2221
+ errDetail.input && errDetail.input.messageText && lines.push(`INPUT: ${errDetail.input.messageText}`);
2222
+ } else if (errDetail.message) {
2223
+ lines.push(`${errDetail.message}`);
2224
+ }
2225
+ if (errDetail.transcript && errDetail.transcript.length > 0) {
2226
+ lines.push('------------ TRANSCRIPT ----------------------------');
2227
+ errDetail.transcript.forEach(transcriptStep => {
2228
+ if (transcriptStep.actual) {
2229
+ lines.push(transcriptStep.actual.prettify());
2230
+ }
2231
+ });
2232
+ }
2233
+ if (includeJson) {
2234
+ lines.push('------------ JSON CONTENT ----------------------------');
2235
+ try {
2236
+ const jsonOutput = JSON.stringify(errDetail);
2237
+ lines.push(jsonOutput);
2238
+ } catch (jsonErr) {
2239
+ lines.push(`JSON Output not possible: ${jsonErr.message}`);
2240
+ }
2241
+ }
2242
+ });
2243
+ }
2244
+ if (lines.length > 0) {
2245
+ return lines.join('\r\n');
2246
+ } else {
2247
+ return null;
2248
+ }
2249
+ }
2250
+ };
2251
+ const _getChildErrorsFromContext = context => {
2252
+ if (context && context.errors && lodash__default["default"].isArray(context.errors)) {
2253
+ return context.errors;
2254
+ }
2255
+ return false;
2256
+ };
2257
+ const botiumErrorFromErr$2 = (message, err) => {
2258
+ if (err instanceof BotiumError$4) {
2259
+ return new BotiumError$4(message, err.context, true);
2260
+ } else {
2261
+ return new BotiumError$4(message, {
2262
+ err
2263
+ }, true);
2264
+ }
2265
+ };
2266
+ const botiumErrorFromList$2 = (errors, {
2267
+ type = 'list',
2268
+ source = 'BotiumError',
2269
+ flat = true
2270
+ }) => {
2271
+ const message = errors.map(err => err.message || err.toString()).join(',\n');
2272
+ let children = [];
2273
+ for (const error of errors) {
2274
+ if (error instanceof BotiumError$4) {
2275
+ const childErrors = flat && _getChildErrorsFromContext(error.context);
2276
+ if (childErrors && childErrors.length) {
2277
+ children = children.concat(childErrors);
2278
+ } else if (error.context) {
2279
+ children.push(error.context);
2280
+ }
2281
+ } else {
2282
+ children.push(error);
2283
+ }
2284
+ }
2285
+ const result = new BotiumError$4(message, {
2286
+ errors: children,
2287
+ type,
2288
+ source
2289
+ }, true);
2290
+ return result;
2291
+ };
2292
+ var BotiumError_1 = {
2293
+ BotiumError: BotiumError$4,
2294
+ botiumErrorFromErr: botiumErrorFromErr$2,
2295
+ botiumErrorFromList: botiumErrorFromList$2
2296
+ };
2297
+
2331
2298
  const debug$k = debug__default["default"]('botium-core-ScriptingMemory');
2332
2299
  const {
2333
2300
  v1: uuidv1
2334
2301
  } = uuid__default["default"];
2335
- const {
2336
- NodeVM: NodeVM$1
2337
- } = vm2__default["default"];
2338
2302
  const {
2339
2303
  quoteRegexpString: quoteRegexpString$1,
2340
2304
  toString: toString$2
2341
2305
  } = helper;
2342
2306
  const {
2343
- BotiumError: BotiumError$5
2307
+ BotiumError: BotiumError$3
2344
2308
  } = BotiumError_1;
2345
2309
 
2346
2310
  // If they got parameter, then it will be a string always.
@@ -2497,28 +2461,6 @@ const SCRIPTING_FUNCTIONS_RAW = {
2497
2461
  if (root && root.length > 0) return root[0];else return '';
2498
2462
  },
2499
2463
  numberOfArguments: 1
2500
- },
2501
- $func: {
2502
- handler: (caps, code) => {
2503
- if (code == null) {
2504
- throw Error('func function used without args!');
2505
- }
2506
- try {
2507
- const vm = new NodeVM$1({
2508
- eval: false,
2509
- require: false,
2510
- env: caps[Capabilities.SECURITY_ALLOW_UNSAFE] ? process.env : {},
2511
- sandbox: {
2512
- caps,
2513
- moment: moment__default["default"]
2514
- }
2515
- });
2516
- return vm.run(`module.exports = (${code})`);
2517
- } catch (err) {
2518
- throw Error(`func function execution failed - ${err}`);
2519
- }
2520
- },
2521
- numberOfArguments: 1
2522
2464
  }
2523
2465
  };
2524
2466
  const SCRIPTING_FUNCTIONS$1 = lodash__default["default"].mapValues(SCRIPTING_FUNCTIONS_RAW, (funcOrStruct, name) => {
@@ -2527,7 +2469,7 @@ const SCRIPTING_FUNCTIONS$1 = lodash__default["default"].mapValues(SCRIPTING_FUN
2527
2469
  return {
2528
2470
  handler: (caps, ...rest) => {
2529
2471
  if (!caps[Capabilities.SECURITY_ALLOW_UNSAFE] && funcOrStruct.unsafe) {
2530
- throw new BotiumError$5(`Security Error. Using unsafe scripting memory function ${name} is not allowed`, {
2472
+ throw new BotiumError$3(`Security Error. Using unsafe scripting memory function ${name} is not allowed`, {
2531
2473
  type: 'security',
2532
2474
  subtype: 'allow unsafe',
2533
2475
  source: path__default["default"].basename(__filename),
@@ -2667,7 +2609,7 @@ ScriptingMemory.SCRIPTING_FUNCTIONS;
2667
2609
 
2668
2610
  const debug$j = debug__default["default"]('botium-core-Convo');
2669
2611
  const {
2670
- BotiumError: BotiumError$4,
2612
+ BotiumError: BotiumError$2,
2671
2613
  botiumErrorFromErr: botiumErrorFromErr$1,
2672
2614
  botiumErrorFromList: botiumErrorFromList$1
2673
2615
  } = BotiumError_1;
@@ -2969,6 +2911,8 @@ class Convo$6 {
2969
2911
  let botMsg = null;
2970
2912
  let waitForBotSays = true;
2971
2913
  let skipTranscriptStep = false;
2914
+ let conditionalGroupId = null;
2915
+ let conditionMetInGroup = false;
2972
2916
  for (let i = 0; i < this.conversation.length; i++) {
2973
2917
  const convoStep = this.conversation[i];
2974
2918
  const currentStepIndex = i;
@@ -3091,7 +3035,6 @@ class Convo$6 {
3091
3035
  throw failErr;
3092
3036
  }
3093
3037
  } else if (convoStep.sender === 'bot') {
3094
- const previousWaitForBotSays = waitForBotSays;
3095
3038
  if (waitForBotSays) {
3096
3039
  botMsg = null;
3097
3040
  } else {
@@ -3148,24 +3091,40 @@ class Convo$6 {
3148
3091
  throw failErr;
3149
3092
  }
3150
3093
  if (convoStep.conditional) {
3151
- const nextConvoStep = this.conversation[i + 1];
3152
- if (!previousWaitForBotSays) {
3153
- skipTranscriptStep = true;
3154
- }
3155
3094
  waitForBotSays = false;
3095
+ let endOfConditionalGroup = false;
3096
+ conditionalGroupId = convoStep.logicHooks.find(lh => lh.name.startsWith('CONDITIONAL_STEP')).args[1];
3097
+ const nextConvoStep = this.conversation[i + 1];
3156
3098
  if (!nextConvoStep || nextConvoStep.sender !== 'bot' || !nextConvoStep.logicHooks || !nextConvoStep.logicHooks.some(lh => lh.name.toUpperCase().startsWith('CONDITIONAL_STEP'))) {
3157
- waitForBotSays = true;
3099
+ endOfConditionalGroup = true;
3158
3100
  } else {
3159
- const conditionalLogicHook = convoStep.logicHooks.find(lh => lh.name.startsWith('CONDITIONAL_STEP'));
3160
3101
  const nextConditionalLogicHook = nextConvoStep.logicHooks.find(lh => lh.name.startsWith('CONDITIONAL_STEP'));
3161
- waitForBotSays = conditionalLogicHook.args[1] !== nextConditionalLogicHook.args[1];
3102
+ endOfConditionalGroup = conditionalGroupId !== nextConditionalLogicHook.args[1];
3162
3103
  }
3163
- if (convoStep.conditional.skip) {
3104
+ if (convoStep.conditional.skip || conditionMetInGroup) {
3105
+ skipTranscriptStep = true;
3106
+ if (endOfConditionalGroup && !conditionMetInGroup && !convoStep.optional) {
3107
+ const failErr = new BotiumError$2(`${this.header.name}/${convoStep.stepTag}: Non of the conditions are met in ${conditionalGroupId ? `'${conditionalGroupId}' ` : ''}condition group`);
3108
+ debug$j(failErr);
3109
+ throw failErr;
3110
+ }
3111
+ if (endOfConditionalGroup) {
3112
+ waitForBotSays = !convoStep.optional;
3113
+ conditionalGroupId = undefined;
3114
+ conditionMetInGroup = false;
3115
+ }
3164
3116
  continue;
3117
+ } else {
3118
+ conditionMetInGroup = true;
3119
+ if (endOfConditionalGroup) {
3120
+ waitForBotSays = !convoStep.optional;
3121
+ conditionalGroupId = undefined;
3122
+ conditionMetInGroup = false;
3123
+ }
3165
3124
  }
3166
3125
  }
3167
3126
  if (!botMsg || !botMsg.messageText && !botMsg.media && !botMsg.buttons && !botMsg.cards && !botMsg.sourceData && !botMsg.nlp) {
3168
- const failErr = new BotiumError$4(`${this.header.name}/${convoStep.stepTag}: bot says nothing`);
3127
+ const failErr = new BotiumError$2(`${this.header.name}/${convoStep.stepTag}: bot says nothing`);
3169
3128
  debug$j(failErr);
3170
3129
  try {
3171
3130
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep);
@@ -3251,7 +3210,7 @@ class Convo$6 {
3251
3210
  try {
3252
3211
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep);
3253
3212
  } catch (failErr) {}
3254
- if (container.caps[Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS] && err instanceof BotiumError$4) {
3213
+ if (container.caps[Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS] && err instanceof BotiumError$2) {
3255
3214
  assertErrors.push(err);
3256
3215
  } else {
3257
3216
  throw failErr;
@@ -3267,7 +3226,7 @@ class Convo$6 {
3267
3226
  }
3268
3227
  }
3269
3228
  } else {
3270
- const failErr = new BotiumError$4(`${this.header.name}/${convoStep.stepTag}: invalid sender - ${util__default["default"].inspect(convoStep.sender)}`);
3229
+ const failErr = new BotiumError$2(`${this.header.name}/${convoStep.stepTag}: invalid sender - ${util__default["default"].inspect(convoStep.sender)}`);
3271
3230
  debug$j(failErr);
3272
3231
  try {
3273
3232
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr);
@@ -3276,7 +3235,7 @@ class Convo$6 {
3276
3235
  }
3277
3236
  } catch (err) {
3278
3237
  if (lastMeConvoStep) {
3279
- if (err instanceof BotiumError$4 && err.context) {
3238
+ if (err instanceof BotiumError$2 && err.context) {
3280
3239
  err.context.input = new ConvoStep$1(lastMeConvoStep);
3281
3240
  err.context.transcript = [...transcriptSteps, {
3282
3241
  ...transcriptStep
@@ -3289,7 +3248,7 @@ class Convo$6 {
3289
3248
  }
3290
3249
  }
3291
3250
  transcriptStep.err = err;
3292
- if (err instanceof BotiumError$4 && container.caps[Capabilities.SCRIPTING_ENABLE_SKIP_ASSERT_ERRORS]) {
3251
+ if (err instanceof BotiumError$2 && container.caps[Capabilities.SCRIPTING_ENABLE_SKIP_ASSERT_ERRORS]) {
3293
3252
  if (!err.isAsserterError()) {
3294
3253
  throw err;
3295
3254
  }
@@ -3322,10 +3281,10 @@ class Convo$6 {
3322
3281
  if (expected === null || expected === undefined) return;
3323
3282
  if (lodash__default["default"].isArray(expected)) {
3324
3283
  if (!lodash__default["default"].isArray(result)) {
3325
- throw new BotiumError$4(`${this.header.name}/${convoStep.stepTag}: bot response expected array, got "${result}"`);
3284
+ throw new BotiumError$2(`${this.header.name}/${convoStep.stepTag}: bot response expected array, got "${result}"`);
3326
3285
  }
3327
3286
  if (expected.length !== result.length) {
3328
- throw new BotiumError$4(`${this.header.name}/${convoStep.stepTag}: bot response expected array length ${expected.length}, got ${result.length}`);
3287
+ throw new BotiumError$2(`${this.header.name}/${convoStep.stepTag}: bot response expected array length ${expected.length}, got ${result.length}`);
3329
3288
  }
3330
3289
  for (let i = 0; i < expected.length; i++) {
3331
3290
  this._compareObject(container, scriptingMemory, convoStep, result[i], expected[i]);
@@ -3335,7 +3294,7 @@ class Convo$6 {
3335
3294
  if (Object.prototype.hasOwnProperty.call(result, key)) {
3336
3295
  this._compareObject(container, scriptingMemory, convoStep, result[key], expected[key]);
3337
3296
  } else {
3338
- throw new BotiumError$4(`${this.header.name}/${convoStep.stepTag}: bot response "${result}" missing expected property: ${key}`);
3297
+ throw new BotiumError$2(`${this.header.name}/${convoStep.stepTag}: bot response "${result}" missing expected property: ${key}`);
3339
3298
  }
3340
3299
  });
3341
3300
  } else {
@@ -3464,14 +3423,14 @@ class Convo$6 {
3464
3423
  includeLogicHooks.forEach(includeLogicHook => {
3465
3424
  const alreadyThereAt = parentPConvos.indexOf(includeLogicHook);
3466
3425
  if (alreadyThereAt >= 0) {
3467
- throw new BotiumError$4(`Partial convos are included circular. "${includeLogicHook}" is referenced by "/${parentPConvos.slice(0, alreadyThereAt).join('/')}" and by "/${parentPConvos.join('/')}" `);
3426
+ throw new BotiumError$2(`Partial convos are included circular. "${includeLogicHook}" is referenced by "/${parentPConvos.slice(0, alreadyThereAt).join('/')}" and by "/${parentPConvos.join('/')}" `);
3468
3427
  }
3469
3428
  if (!partialConvos || Object.keys(partialConvos).length === 0) {
3470
- throw new BotiumError$4(`Cant find partial convo with name ${includeLogicHook} (There are no partial convos)`);
3429
+ throw new BotiumError$2(`Cant find partial convo with name ${includeLogicHook} (There are no partial convos)`);
3471
3430
  }
3472
3431
  const partialConvo = partialConvos[includeLogicHook];
3473
3432
  if (!partialConvo) {
3474
- throw new BotiumError$4(`Cant find partial convo with name ${includeLogicHook} (available partial convos: ${Object.keys(partialConvos).join(',')})`);
3433
+ throw new BotiumError$2(`Cant find partial convo with name ${includeLogicHook} (available partial convos: ${Object.keys(partialConvos).join(',')})`);
3475
3434
  }
3476
3435
  _getEffectiveConversationRecursive(partialConvo.conversation, [...parentPConvos, includeLogicHook], result, true);
3477
3436
  debug$j(`Partial convo ${includeLogicHook} included`);
@@ -3806,44 +3765,21 @@ var JsonToJson = {
3806
3765
  precompile: precompile$2
3807
3766
  };
3808
3767
 
3809
- const {
3810
- NodeVM
3811
- } = vm2__default["default"];
3812
3768
  const debug$h = debug__default["default"]('botium-core-HookUtils');
3813
- const {
3814
- BotiumError: BotiumError$3
3815
- } = BotiumError_1;
3816
- const executeHook$2 = async (caps, hook, args) => {
3817
- return executeHookSync$1(caps, hook, args);
3769
+ const executeHook$2 = async (caps, hook, ...args) => {
3770
+ return executeHookSync$1(caps, hook, ...args);
3818
3771
  };
3819
- const executeHookSync$1 = (caps, hook, args) => {
3772
+ const executeHookSync$1 = (caps, hook, ...args) => {
3820
3773
  if (!hook) {
3821
3774
  return;
3822
3775
  }
3823
3776
  if (lodash__default["default"].isFunction(hook)) {
3824
3777
  try {
3825
- return hook(args);
3778
+ return hook(...args);
3826
3779
  } catch (err) {
3827
3780
  throw new Error(`Calling Hook function failed: ${err.message}`);
3828
3781
  }
3829
3782
  }
3830
- if (lodash__default["default"].isString(hook)) {
3831
- try {
3832
- const vm = new NodeVM({
3833
- eval: false,
3834
- require: false,
3835
- sandbox: args
3836
- });
3837
- const r = vm.run(hook);
3838
- if (lodash__default["default"].isFunction(r)) {
3839
- return r(args);
3840
- } else {
3841
- return r;
3842
- }
3843
- } catch (err) {
3844
- throw new Error(`Calling Hook Javascript code failed: ${err.message}`);
3845
- }
3846
- }
3847
3783
  throw new Error(`Unknown hook ${typeof hook}`);
3848
3784
  };
3849
3785
  const getHook$3 = (caps, data) => {
@@ -3856,46 +3792,40 @@ const getHook$3 = (caps, data) => {
3856
3792
  return data;
3857
3793
  }
3858
3794
  if (lodash__default["default"].isString(data)) {
3859
- let resultWithRequire;
3860
- let tryLoadFile = path__default["default"].resolve(process.cwd(), data);
3861
- if (fs__default["default"].existsSync(tryLoadFile)) {
3862
- try {
3863
- resultWithRequire = commonjsRequire(tryLoadFile);
3864
- } catch (err) {}
3865
- } else {
3866
- tryLoadFile = data;
3867
- try {
3868
- resultWithRequire = commonjsRequire(data);
3869
- } catch (err) {}
3870
- }
3871
- if (resultWithRequire) {
3872
- if (!allowUnsafe) {
3873
- throw new BotiumError$3('Security Error. Using unsafe custom hook with require is not allowed', {
3874
- type: 'security',
3875
- subtype: 'allow unsafe',
3876
- source: path__default["default"].basename(__filename),
3877
- cause: {
3878
- SECURITY_ALLOW_UNSAFE: caps[Capabilities.SECURITY_ALLOW_UNSAFE],
3879
- hookData: data
3795
+ if (caps.SAFEDIR) {
3796
+ const tryLoadFile = path__default["default"].resolve(caps.SAFEDIR, data);
3797
+ if (tryLoadFile.startsWith(path__default["default"].resolve(caps.SAFEDIR))) {
3798
+ if (fs__default["default"].existsSync(tryLoadFile)) {
3799
+ try {
3800
+ const resultWithRequire = commonjsRequire(tryLoadFile);
3801
+ if (lodash__default["default"].isFunction(resultWithRequire)) {
3802
+ debug$h(`found hook, type: safedir, in ${tryLoadFile}`);
3803
+ return resultWithRequire;
3804
+ } else {
3805
+ throw new Error(`Expected function from hook specification "${util__default["default"].inspect(data)}", got: "${util__default["default"].inspect(resultWithRequire)}"`);
3806
+ }
3807
+ } catch (err) {
3808
+ debug$h(`Failed loading hook, type: safedir, from ${tryLoadFile} failed: ${err.message || err}`);
3880
3809
  }
3881
- });
3882
- }
3883
- if (lodash__default["default"].isFunction(resultWithRequire)) {
3884
- debug$h(`found hook, type: require, in ${tryLoadFile}`);
3885
- return resultWithRequire;
3886
- } else {
3887
- throw new Error(`Cant load hook ${tryLoadFile} because it is not a function`);
3810
+ }
3888
3811
  }
3889
3812
  }
3890
- try {
3891
- esprima__default["default"].parseScript(data);
3892
- } catch (err) {
3893
- throw new Error(`Cant load hook, syntax is not valid - ${util__default["default"].inspect(err)}`);
3813
+ if (allowUnsafe || data.startsWith('botium-')) {
3814
+ const tryLoadFile = data;
3815
+ try {
3816
+ const resultWithRequire = commonjsRequire(tryLoadFile);
3817
+ if (lodash__default["default"].isFunction(resultWithRequire)) {
3818
+ debug$h(`found hook, type: require, in ${tryLoadFile}`);
3819
+ return resultWithRequire;
3820
+ } else {
3821
+ throw new Error(`Expected function from hook specification "${util__default["default"].inspect(data)}", got: "${util__default["default"].inspect(resultWithRequire)}"`);
3822
+ }
3823
+ } catch (err) {
3824
+ debug$h(`Failed loading hook, type: require, from ${tryLoadFile} failed: ${err.message || err}`);
3825
+ }
3894
3826
  }
3895
- debug$h('Found hook, type: JavaScript as String');
3896
- return data;
3897
3827
  }
3898
- throw new Error(`Not valid hook ${util__default["default"].inspect(data)}`);
3828
+ throw new Error(`Hook specification "${util__default["default"].inspect(data)}" invalid: no loader available`);
3899
3829
  };
3900
3830
  var HookUtils = {
3901
3831
  getHook: getHook$3,
@@ -5391,7 +5321,7 @@ const {
5391
5321
  ConvoStep
5392
5322
  } = Convo_1;
5393
5323
  const {
5394
- BotiumError: BotiumError$2,
5324
+ BotiumError: BotiumError$1,
5395
5325
  botiumErrorFromList,
5396
5326
  botiumErrorFromErr
5397
5327
  } = BotiumError_1;
@@ -5667,7 +5597,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5667
5597
  const werArgs = this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS];
5668
5598
  const threshold = [',', '.'].find(p => `${werArgs[0]}`.includes(p)) ? parseFloat(werArgs[0]) : parseInt(werArgs[0]) / 100;
5669
5599
  const message = `${stepTag}: Word Error Rate (${toPercent(wer)}) higher than accepted (${toPercent(threshold)})`;
5670
- throw new BotiumError$2(message, {
5600
+ throw new BotiumError$1(message, {
5671
5601
  type: 'asserter',
5672
5602
  source: asserterType,
5673
5603
  params: {
@@ -5689,7 +5619,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5689
5619
  message += ' expected to match ';
5690
5620
  message += tomatch && tomatch.length > 1 ? 'one of ' : '';
5691
5621
  message += `${tomatch.map(e => e ? '"' + e + '"' : '<any response>').join(', ')}`;
5692
- throw new BotiumError$2(message, {
5622
+ throw new BotiumError$1(message, {
5693
5623
  type: 'asserter',
5694
5624
  source: asserterType,
5695
5625
  params: {
@@ -5722,7 +5652,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5722
5652
  const werArgs = this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS];
5723
5653
  const threshold = [',', '.'].find(p => `${werArgs[0]}`.includes(p)) ? parseFloat(werArgs[0]) : parseInt(werArgs[0]) / 100;
5724
5654
  const message = `${stepTag}: Word Error Rate (${toPercent(wer)}) lower than accepted (${toPercent(threshold)})`;
5725
- throw new BotiumError$2(message, {
5655
+ throw new BotiumError$1(message, {
5726
5656
  type: 'asserter',
5727
5657
  source: asserterType,
5728
5658
  params: {
@@ -5744,7 +5674,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5744
5674
  message += ' expected NOT to match ';
5745
5675
  message += nottomatch && nottomatch.length > 1 ? 'one of ' : '';
5746
5676
  message += `${nottomatch.map(e => e ? '"' + e + '"' : '<any response>').join(', ')}`;
5747
- throw new BotiumError$2(message, {
5677
+ throw new BotiumError$1(message, {
5748
5678
  type: 'asserter',
5749
5679
  source: asserterType,
5750
5680
  params: {
@@ -5794,7 +5724,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5794
5724
  if (asserter[notAsserterType]) {
5795
5725
  return p(this.retryHelperAsserter, () => asserter[notAsserterType](params));
5796
5726
  } else {
5797
- return pnot(this.retryHelperAsserter, () => asserter[asserterType](params), new BotiumError$2(`${convoStep.stepTag}: Expected asserter ${asserter.name || asserterSpec.name} with args "${params.args}" to fail`, {
5727
+ return pnot(this.retryHelperAsserter, () => asserter[asserterType](params), new BotiumError$1(`${convoStep.stepTag}: Expected asserter ${asserter.name || asserterSpec.name} with args "${params.args}" to fail`, {
5798
5728
  type: 'asserter',
5799
5729
  source: asserter.name || asserterSpec.name,
5800
5730
  params: {
@@ -6189,7 +6119,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6189
6119
  return !entry.header.name;
6190
6120
  });
6191
6121
  if (aggregatedNoNames.length) {
6192
- throw new BotiumError$2('Scripting Memory Definition(s) without name', {
6122
+ throw new BotiumError$1('Scripting Memory Definition(s) without name', {
6193
6123
  type: 'Scripting Memory',
6194
6124
  subtype: 'Scripting Memory without name',
6195
6125
  source: 'ScriptingProvider',
@@ -6204,7 +6134,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6204
6134
  return !entry.values || !Object.keys(entry.values).length;
6205
6135
  });
6206
6136
  if (aggregatedNoVariables.length) {
6207
- throw new BotiumError$2(`Scripting Memory Definition(s) ${aggregatedNoVariables.map(e => e.header.name).join(', ')} without variable`, {
6137
+ throw new BotiumError$1(`Scripting Memory Definition(s) ${aggregatedNoVariables.map(e => e.header.name).join(', ')} without variable`, {
6208
6138
  type: 'Scripting Memory',
6209
6139
  subtype: 'Scripting Memory without variable',
6210
6140
  source: 'ScriptingProvider',
@@ -6219,7 +6149,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6219
6149
  return !lodash__default["default"].isUndefined(entry.values['']);
6220
6150
  });
6221
6151
  if (aggregatedNoVariableNames.length) {
6222
- throw new BotiumError$2(`Scripting Memory Definition(s) ${aggregatedNoVariableNames.map(e => e.header.name).join(', ')} without variable name`, {
6152
+ throw new BotiumError$1(`Scripting Memory Definition(s) ${aggregatedNoVariableNames.map(e => e.header.name).join(', ')} without variable name`, {
6223
6153
  type: 'Scripting Memory',
6224
6154
  subtype: 'Scripting Memory without variable name',
6225
6155
  source: 'ScriptingProvider',
@@ -6247,7 +6177,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6247
6177
  }
6248
6178
  }
6249
6179
  if (aggregatedDuplicates.length) {
6250
- throw new BotiumError$2(`Scripting Memory Definition name(s) "${lodash__default["default"].uniq(aggregatedDuplicates.map(d => d.scriptingMemory.header.name)).join(', ')}" are not unique`, {
6180
+ throw new BotiumError$1(`Scripting Memory Definition name(s) "${lodash__default["default"].uniq(aggregatedDuplicates.map(d => d.scriptingMemory.header.name)).join(', ')}" are not unique`, {
6251
6181
  type: 'Scripting Memory',
6252
6182
  subtype: 'Scripting Memory name collision',
6253
6183
  source: 'ScriptingProvider',
@@ -6278,7 +6208,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6278
6208
  }
6279
6209
  }
6280
6210
  if (aggregatedIntersections.length) {
6281
- throw new BotiumError$2(`Scripting Memory Definitions "${aggregatedIntersections.map(i => i.scriptingMemory.header.name).join(', ')}" are invalid because variable name collision"`, {
6211
+ throw new BotiumError$1(`Scripting Memory Definitions "${aggregatedIntersections.map(i => i.scriptingMemory.header.name).join(', ')}" are invalid because variable name collision"`, {
6282
6212
  type: 'Scripting Memory',
6283
6213
  subtype: 'Scripting Memory variable name collision',
6284
6214
  source: 'ScriptingProvider',
@@ -6841,7 +6771,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6841
6771
  }
6842
6772
  } else if (scriptingMemories) {
6843
6773
  if (!scriptingMemories.header || !scriptingMemories.header.name) {
6844
- throw new BotiumError$2('Scripting Memory Definition has no name', {
6774
+ throw new BotiumError$1('Scripting Memory Definition has no name', {
6845
6775
  type: 'Compiler',
6846
6776
  subtype: 'Scripting memory without name',
6847
6777
  source: 'ScriptingProvider',
@@ -6851,7 +6781,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6851
6781
  });
6852
6782
  }
6853
6783
  if (!scriptingMemories.values || !Object.keys(scriptingMemories.values).length) {
6854
- throw new BotiumError$2('Scripting Memory Definition has no variables', {
6784
+ throw new BotiumError$1('Scripting Memory Definition has no variables', {
6855
6785
  type: 'Compiler',
6856
6786
  subtype: 'Scripting memory without variable',
6857
6787
  source: 'ScriptingProvider',
@@ -6861,7 +6791,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6861
6791
  });
6862
6792
  }
6863
6793
  if (scriptingMemories.values && !lodash__default["default"].isUndefined(scriptingMemories.values[''])) {
6864
- throw new BotiumError$2('Scripting Memory Definition variable has no name', {
6794
+ throw new BotiumError$1('Scripting Memory Definition variable has no name', {
6865
6795
  type: 'Compiler',
6866
6796
  subtype: 'Scripting memory without variable name',
6867
6797
  source: 'ScriptingProvider',
@@ -7748,7 +7678,7 @@ const {
7748
7678
  escapeJSONString
7749
7679
  } = Utils;
7750
7680
  const {
7751
- BotiumError: BotiumError$1
7681
+ BotiumError
7752
7682
  } = BotiumError_1;
7753
7683
  mustache__default["default"].escape = s => s;
7754
7684
  var SimpleRestContainer_1 = class SimpleRestContainer {
@@ -8045,22 +7975,32 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8045
7975
  }
8046
7976
  const result = [];
8047
7977
  if (isFromUser) {
8048
- const _extractFrom = (root, jsonPaths) => {
8049
- const flattened = [];
7978
+ const _extractFrom = (root, jsonPaths, acceptFn = null) => {
7979
+ const result = [];
8050
7980
  for (const jsonPath of jsonPaths) {
7981
+ const jsonPathRes = [];
8051
7982
  const rb = jsonpath__default["default"].query(root, jsonPath);
8052
7983
  if (lodash__default["default"].isArray(rb)) {
8053
- lodash__default["default"].flattenDeep(rb).forEach(r => flattened.push(r));
8054
- } else if (rb) {
8055
- flattened.push(rb);
7984
+ lodash__default["default"].flattenDeep(rb).forEach(r => jsonPathRes.push(r));
7985
+ } else {
7986
+ jsonPathRes.push(rb);
7987
+ }
7988
+ if (acceptFn) {
7989
+ result.push(...jsonPathRes.filter(r => acceptFn(root, jsonPath, r)));
7990
+ } else {
7991
+ result.push(...jsonPathRes);
8056
7992
  }
8057
7993
  }
8058
- return flattened;
7994
+ return result;
8059
7995
  };
8060
7996
  const jsonPathRoots = [];
8061
7997
  const jsonPathsBody = getAllCapValues(Capabilities.SIMPLEREST_BODY_JSONPATH, this.caps);
8062
7998
  if (jsonPathsBody.length > 0) {
8063
- jsonPathRoots.push(..._extractFrom(body, jsonPathsBody));
7999
+ jsonPathRoots.push(..._extractFrom(body, jsonPathsBody, (root, jsonPath, r) => {
8000
+ if (r && lodash__default["default"].isObject(r)) return true;
8001
+ debug$4(`Ignoring result body from ${jsonPath} - not a querieable object (${util__default["default"].inspect(r)})`);
8002
+ return false;
8003
+ }));
8064
8004
  } else {
8065
8005
  jsonPathRoots.push(body);
8066
8006
  }
@@ -8219,7 +8159,7 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8219
8159
  const jsonBody = Utils.toJsonWeak(body);
8220
8160
  const errKey = Object.keys(jsonBody).find(k => k.startsWith('err') || k.startsWith('fail'));
8221
8161
  if (errKey) {
8222
- return reject(new BotiumError$1(`got error response: ${response.statusCode}/${response.statusMessage} - ${jsonBody[errKey]}`, {
8162
+ return reject(new BotiumError(`got error response: ${response.statusCode}/${response.statusMessage} - ${jsonBody[errKey]}`, {
8223
8163
  message: Utils.shortenJsonString(body)
8224
8164
  }));
8225
8165
  }
@@ -8674,9 +8614,6 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8674
8614
  };
8675
8615
 
8676
8616
  const debug$3 = debug__default["default"]('botium-connector-PluginConnectorContainer-helper');
8677
- const {
8678
- BotiumError
8679
- } = BotiumError_1;
8680
8617
  const pluginResolver = containermode => {
8681
8618
  if (containermode === 'simplerest') {
8682
8619
  return SimpleRestContainer_1;
@@ -8727,20 +8664,6 @@ const loadConnectorModule = (PluginClass, args) => {
8727
8664
  };
8728
8665
  const tryLoadPlugin$1 = (containermode, modulepath, args) => {
8729
8666
  const pluginLoaderSpec = modulepath || containermode;
8730
- const _checkUnsafe = (caps, mode, cause) => {
8731
- if (!caps[Capabilities.SECURITY_ALLOW_UNSAFE]) {
8732
- throw new BotiumError(`Security Error. Using unsafe connector mode "${mode}" is not allowed`, {
8733
- type: 'security',
8734
- subtype: 'allow unsafe',
8735
- source: 'src/containers/plugins/index.js',
8736
- cause: {
8737
- SECURITY_ALLOW_UNSAFE: caps[Capabilities.SECURITY_ALLOW_UNSAFE],
8738
- mode,
8739
- ...cause
8740
- }
8741
- });
8742
- }
8743
- };
8744
8667
  if (pluginResolver(pluginLoaderSpec)) {
8745
8668
  const pluginInstance = new (pluginResolver(pluginLoaderSpec))(args);
8746
8669
  debug$3('Botium plugin loaded from internal plugin resolver');
@@ -8752,44 +8675,47 @@ const tryLoadPlugin$1 = (containermode, modulepath, args) => {
8752
8675
  return pluginInstance;
8753
8676
  }
8754
8677
  const loadErr = [];
8678
+ const allowUnsafe = !!args.caps[Capabilities.SECURITY_ALLOW_UNSAFE];
8755
8679
  if (lodash__default["default"].isString(pluginLoaderSpec)) {
8756
- const tryLoadFile = path__default["default"].resolve(process.cwd(), pluginLoaderSpec);
8757
- if (fs__default["default"].existsSync(tryLoadFile)) {
8758
- _checkUnsafe(args.caps, 'Using work dir', {
8759
- modulepath,
8760
- containermode
8761
- });
8680
+ if (args.caps.SAFEDIR) {
8681
+ const tryLoadFile = path__default["default"].resolve(args.caps.SAFEDIR, pluginLoaderSpec);
8682
+ if (tryLoadFile.startsWith(path__default["default"].resolve(args.caps.SAFEDIR))) {
8683
+ if (fs__default["default"].existsSync(tryLoadFile)) {
8684
+ try {
8685
+ let plugin = commonjsRequire(tryLoadFile);
8686
+ if (plugin.default) {
8687
+ plugin = plugin.default;
8688
+ }
8689
+ if (!plugin.PluginVersion || !plugin.PluginClass) {
8690
+ loadErr.push(`Invalid Botium plugin loaded from ${tryLoadFile}, expected PluginVersion, PluginClass fields`);
8691
+ } else {
8692
+ const pluginInstance = loadConnectorModule(plugin.PluginClass, args);
8693
+ debug$3(`Botium plugin loaded from ${tryLoadFile}`);
8694
+ return pluginInstance;
8695
+ }
8696
+ } catch (err) {
8697
+ loadErr.push(`Loading Botium plugin from ${tryLoadFile} failed - ${err.message}`);
8698
+ }
8699
+ }
8700
+ }
8701
+ }
8702
+ if (allowUnsafe) {
8762
8703
  try {
8763
- let plugin = commonjsRequire(tryLoadFile);
8704
+ let plugin = commonjsRequire(pluginLoaderSpec);
8764
8705
  if (plugin.default) {
8765
8706
  plugin = plugin.default;
8766
8707
  }
8767
8708
  if (!plugin.PluginVersion || !plugin.PluginClass) {
8768
- loadErr.push(`Invalid Botium plugin loaded from ${tryLoadFile}, expected PluginVersion, PluginClass fields`);
8709
+ loadErr.push(`Invalid Botium plugin loaded from ${pluginLoaderSpec}, expected PluginVersion, PluginClass fields`);
8769
8710
  } else {
8770
8711
  const pluginInstance = loadConnectorModule(plugin.PluginClass, args);
8771
- debug$3(`Botium plugin loaded from ${tryLoadFile}`);
8712
+ debug$3(`Botium plugin loaded from ${pluginLoaderSpec}. Plugin version is ${getModuleVersionSafe(pluginLoaderSpec)}`);
8772
8713
  return pluginInstance;
8773
8714
  }
8774
8715
  } catch (err) {
8775
- loadErr.push(`Loading Botium plugin from ${tryLoadFile} failed - ${err.message}`);
8716
+ loadErr.push(`Loading Botium plugin from ${pluginLoaderSpec} failed - ${err.message}`);
8776
8717
  }
8777
8718
  }
8778
- try {
8779
- let plugin = commonjsRequire(pluginLoaderSpec);
8780
- if (plugin.default) {
8781
- plugin = plugin.default;
8782
- }
8783
- if (!plugin.PluginVersion || !plugin.PluginClass) {
8784
- loadErr.push(`Invalid Botium plugin loaded from ${pluginLoaderSpec}, expected PluginVersion, PluginClass fields`);
8785
- } else {
8786
- const pluginInstance = loadConnectorModule(plugin.PluginClass, args);
8787
- debug$3(`Botium plugin loaded from ${pluginLoaderSpec}. Plugin version is ${getModuleVersionSafe(pluginLoaderSpec)}`);
8788
- return pluginInstance;
8789
- }
8790
- } catch (err) {
8791
- loadErr.push(`Loading Botium plugin from ${pluginLoaderSpec} failed - ${err.message}`);
8792
- }
8793
8719
  const tryLoadPackage = `botium-connector-${pluginLoaderSpec}`;
8794
8720
  try {
8795
8721
  let plugin = commonjsRequire(tryLoadPackage);
@@ -8953,6 +8879,13 @@ var PluginConnectorContainer_1 = class PluginConnectorContainer extends BaseCont
8953
8879
  return Promise.reject(new Error(`Clean - Botium plugin failed: ${util__default["default"].inspect(err)}`));
8954
8880
  }
8955
8881
  }
8882
+ GetMetaData() {
8883
+ try {
8884
+ return this.pluginInstance.GetMetaData ? this.pluginInstance.GetMetaData() || Promise.resolve() : Promise.resolve();
8885
+ } catch (err) {
8886
+ return Promise.reject(new Error(`GetMetaData - Botium plugin failed: ${util__default["default"].inspect(err)}`));
8887
+ }
8888
+ }
8956
8889
  };
8957
8890
 
8958
8891
  var require$$3 = getCjsExportFromNamespace(_package$1);