botium-core 1.13.18 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/botium-cjs.js +326 -387
  2. package/dist/botium-cjs.js.map +1 -1
  3. package/dist/botium-es.js +326 -385
  4. package/dist/botium-es.js.map +1 -1
  5. package/package.json +21 -25
  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 +17 -5
  15. package/src/scripting/ScriptingMemory.js +0 -24
  16. package/src/scripting/logichook/LogicHookConsts.js +5 -1
  17. package/src/scripting/logichook/LogicHookUtils.js +27 -47
  18. package/src/scripting/logichook/asserter/ButtonsAsserter.js +5 -5
  19. package/src/scripting/logichook/logichooks/ConditionalBusinessHoursLogicHook.js +56 -0
  20. package/src/scripting/logichook/logichooks/ConditionalCapabilityValueBasedLogicHook.js +37 -0
  21. package/src/scripting/logichook/logichooks/ConditionalJsonPathBasedLogicHook.js +31 -0
  22. package/src/scripting/logichook/logichooks/ConditionalTimeBasedLogicHook.js +46 -0
  23. package/test/compiler/precompilerscript.spec.js +24 -26
  24. package/test/connectors/pluginconnectorcontainer.spec.js +60 -0
  25. package/test/connectors/simplerest.spec.js +24 -27
  26. package/test/convo/fillAndApplyScriptingMemory.spec.js +1 -47
  27. package/test/hooks/customhooks.spec.js +3 -25
  28. package/test/logichooks/hookfromsrc.spec.js +13 -3
  29. package/test/plugins/plugins.spec.js +29 -2
  30. package/test/scripting/logichooks/CustomConditionalLogicHook.js +21 -0
  31. package/test/scripting/logichooks/conditionalStepBusinessHoursLogicHook.spec.js +130 -0
  32. package/test/scripting/logichooks/conditionalStepCapabilityValueBasedLogicHook.spec.js +35 -0
  33. package/test/scripting/logichooks/conditionalStepJsonPathBasedLogicHook.spec.js +35 -0
  34. package/test/scripting/logichooks/conditionalStepTimeBasedLogicHook.spec.js +91 -0
  35. package/test/scripting/logichooks/convos/conditional_steps.convo.txt +12 -0
  36. package/test/scripting/logichooks/convos/conditional_steps_business_hours.convo.txt +16 -0
  37. package/test/scripting/logichooks/convos/conditional_steps_cap_value_based.convo.txt +12 -0
  38. package/test/scripting/logichooks/convos/conditional_steps_followed_by_bot_msg.convo.txt +15 -0
  39. package/test/scripting/logichooks/convos/conditional_steps_followed_by_me.convo.txt +18 -0
  40. package/test/scripting/logichooks/convos/conditional_steps_json_path_based.convo.txt.convo.txt +12 -0
  41. package/test/scripting/logichooks/convos/conditional_steps_multiple_condition_groups.convo.txt +20 -0
  42. package/test/scripting/logichooks/convos/conditional_steps_multiple_condition_groups_no_assertion.convo.txt +20 -0
  43. package/test/scripting/logichooks/convos/conditional_steps_time_based.convo.txt +12 -0
  44. package/test/scripting/logichooks/customConditionalStepLogicHook.spec.js +105 -0
  45. package/test/scripting/scriptingProvider.spec.js +1 -1
  46. package/test/security/allowUnsafe.spec.js +20 -129
  47. package/LICENSES-3RDPARTY.txt +0 -6450
  48. package/test/scripting/asserters/convos/customembeddedasserterwithhugo.convo.txt +0 -7
  49. package/test/scripting/asserters/convos/customembeddedasserterwithouthugo.convo.txt +0 -7
  50. package/test/scripting/asserters/customEmbeddedAsserter.json +0 -14
  51. package/test/scripting/asserters/customEmbeddedAsserter.spec.js +0 -55
  52. package/test/scripting/logichooks/convos/custom_embedded.convo.txt +0 -8
  53. package/test/scripting/logichooks/convos/custom_embedded_skip.convo.txt +0 -11
  54. package/test/scripting/logichooks/convos/custom_embedded_skip_followed_by_me.convo.txt +0 -11
  55. package/test/scripting/logichooks/convos/custom_embedded_skip_followed_by_nothing.convo.txt +0 -8
  56. package/test/scripting/logichooks/customEmbedded.json +0 -14
  57. package/test/scripting/logichooks/customEmbedded.spec.js +0 -44
  58. package/test/scripting/logichooks/customEmbeddedSkip.json +0 -14
  59. package/test/scripting/logichooks/customEmbeddedSkip.spec.js +0 -58
  60. package/test/security/convos/withscriptingmemoryfunction.convo.txt +0 -5
package/dist/botium-es.js CHANGED
@@ -11,7 +11,6 @@ import lodash from 'lodash';
11
11
  import boolean$1 from 'boolean';
12
12
  import events from 'events';
13
13
  import debug$n from 'debug';
14
- import vm2 from 'vm2';
15
14
  import isClass from 'is-class';
16
15
  import crypto from 'crypto';
17
16
  import globby from 'globby';
@@ -21,7 +20,6 @@ import uuid from 'uuid';
21
20
  import jsonpath from 'jsonpath';
22
21
  import isJson$1 from 'is-json';
23
22
  import wordErrorRate from 'word-error-rate';
24
- import esprima from 'esprima';
25
23
  import markdownIt from 'markdown-it';
26
24
  import xlsx from 'xlsx';
27
25
  import sync from 'csv-parse/sync';
@@ -37,7 +35,7 @@ import express from 'express';
37
35
  import bodyParser from 'body-parser';
38
36
 
39
37
  var name = "botium-core";
40
- var version$1 = "1.13.18";
38
+ var version$1 = "1.14.0";
41
39
  var description = "The Selenium for Chatbots";
42
40
  var main = "index.js";
43
41
  var module = "dist/botium-es.js";
@@ -55,7 +53,6 @@ var scripts = {
55
53
  link: "npm link botium-connector-dialogflow botium-connector-webdriverio botium-connector-directline3 botium-connector-watson botium-connector-alexa-smapi botium-connector-echo",
56
54
  test: "cross-env NODE_PATH=\"./test/plugins/plugindir/fromfolder:./test/plugins/plugindir/fromfile:./test/security/resources\" mocha \"./test/**/*.spec.js\"",
57
55
  "coverage:report": "nyc report --reporter=lcov npm test",
58
- "license-checker": "license-checker > LICENSES-3RDPARTY.txt",
59
56
  "update-dependencies": "npm-check-updates --reject globby,rollup -u --timeout 120000"
60
57
  };
61
58
  var repository = {
@@ -69,14 +66,13 @@ var bugs = {
69
66
  };
70
67
  var homepage = "https://www.botium.ai";
71
68
  var dependencies = {
72
- "@babel/runtime": "^7.21.5",
69
+ "@babel/runtime": "^7.22.15",
73
70
  async: "^3.2.4",
74
71
  "body-parser": "^1.20.2",
75
72
  boolean: "^3.2.0",
76
73
  bottleneck: "^2.19.5",
77
- "csv-parse": "^5.3.10",
74
+ "csv-parse": "^5.5.0",
78
75
  debug: "^4.3.4",
79
- esprima: "^4.0.1",
80
76
  express: "^4.18.2",
81
77
  globby: "11.0.4",
82
78
  ioredis: "^5.3.2",
@@ -88,47 +84,45 @@ var dependencies = {
88
84
  "mime-types": "^2.1.35",
89
85
  mkdirp: "^3.0.1",
90
86
  moment: "^2.29.4",
87
+ "moment-timezone": "^0.5.43",
91
88
  mustache: "^4.2.0",
92
89
  "promise-retry": "^2.0.1",
93
- "promise.allsettled": "^1.0.6",
90
+ "promise.allsettled": "^1.0.7",
94
91
  randomatic: "^3.1.1",
95
92
  request: "^2.88.2",
96
- rimraf: "^5.0.0",
93
+ rimraf: "^5.0.1",
97
94
  "sanitize-filename": "^1.6.3",
98
95
  slugify: "^1.6.6",
99
- "socket.io": "^4.6.1",
100
- "socket.io-client": "^4.6.1",
96
+ "socket.io": "^4.7.2",
97
+ "socket.io-client": "^4.7.2",
101
98
  "socketio-auth": "^0.1.1",
102
99
  "swagger-jsdoc": "^6.2.8",
103
- "swagger-ui-express": "^4.6.3",
100
+ "swagger-ui-express": "^5.0.0",
104
101
  uuid: "^9.0.0",
105
- vm2: "^3.9.17",
106
102
  "word-error-rate": "0.0.7",
107
103
  "write-yaml": "^1.0.0",
108
104
  xlsx: "^0.18.5",
109
105
  xregexp: "^5.1.1",
110
- yaml: "^2.2.2"
106
+ yaml: "^2.3.2"
111
107
  };
112
108
  var devDependencies = {
113
- "@babel/core": "^7.21.8",
114
- "@babel/node": "^7.20.7",
115
- "@babel/plugin-transform-runtime": "^7.21.4",
116
- "@babel/preset-env": "^7.21.5",
117
- chai: "^4.3.7",
109
+ "@babel/core": "^7.22.17",
110
+ "@babel/node": "^7.22.15",
111
+ "@babel/plugin-transform-runtime": "^7.22.15",
112
+ "@babel/preset-env": "^7.22.15",
113
+ chai: "^4.3.8",
118
114
  "chai-as-promised": "^7.1.1",
119
115
  "cross-env": "^7.0.3",
120
- eslint: "^8.40.0",
121
- "eslint-config-standard": "^17.0.0",
122
- "eslint-plugin-import": "^2.27.5",
116
+ eslint: "^8.49.0",
117
+ "eslint-config-standard": "^17.1.0",
118
+ "eslint-plugin-import": "^2.28.1",
123
119
  "eslint-plugin-mocha": "^10.1.0",
124
- "eslint-plugin-n": "^15.7.0",
120
+ "eslint-plugin-n": "^16.1.0",
125
121
  "eslint-plugin-promise": "^6.1.1",
126
122
  "eslint-plugin-standard": "^4.1.0",
127
- "license-checker": "^25.0.1",
128
- "license-compatibility-checker": "^0.3.5",
129
123
  mocha: "^10.2.0",
130
- nock: "^13.3.1",
131
- "npm-check-updates": "^16.10.12",
124
+ nock: "^13.3.3",
125
+ "npm-check-updates": "^16.13.3",
132
126
  nyc: "^15.1.0",
133
127
  rollup: "2.79.1",
134
128
  "rollup-plugin-babel": "^4.4.0",
@@ -177,6 +171,7 @@ var Capabilities = {
177
171
  TESTSESSIONNAME: 'TESTSESSIONNAME',
178
172
  TESTCASENAME: 'TESTCASENAME',
179
173
  TEMPDIR: 'TEMPDIR',
174
+ SAFEDIR: 'SAFEDIR',
180
175
  CLEANUPTEMPDIR: 'CLEANUPTEMPDIR',
181
176
  WAITFORBOTTIMEOUT: 'WAITFORBOTTIMEOUT',
182
177
  CONTAINERMODE: 'CONTAINERMODE',
@@ -186,7 +181,7 @@ var Capabilities = {
186
181
  BOTIUMGRIDURL: 'BOTIUMGRIDURL',
187
182
  BOTIUMAPITOKEN: 'BOTIUMAPITOKEN',
188
183
  BOTIUMGRIDSLOT: 'BOTIUMGRIDSLOT',
189
- // Simple Reset Bot Settings
184
+ // Simple Rest Bot Settings
190
185
  SIMPLEREST_PING_URL: 'SIMPLEREST_PING_URL',
191
186
  SIMPLEREST_PING_VERB: 'SIMPLEREST_PING_VERB',
192
187
  SIMPLEREST_PING_BODY: 'SIMPLEREST_PING_BODY',
@@ -351,6 +346,7 @@ Capabilities.PROJECTNAME;
351
346
  Capabilities.TESTSESSIONNAME;
352
347
  Capabilities.TESTCASENAME;
353
348
  Capabilities.TEMPDIR;
349
+ Capabilities.SAFEDIR;
354
350
  Capabilities.CLEANUPTEMPDIR;
355
351
  Capabilities.WAITFORBOTTIMEOUT;
356
352
  Capabilities.CONTAINERMODE;
@@ -869,140 +865,6 @@ function getCjsExportFromNamespace (n) {
869
865
  return n && n['default'] || n;
870
866
  }
871
867
 
872
- const BotiumError$7 = class BotiumError extends Error {
873
- /**
874
- *
875
- * @param message
876
- * @param context A JSON with struct
877
- * {
878
- * type: 'some free text to identity the exception type',
879
- * source: 'source of the event',
880
- * ...
881
- */
882
- constructor(message, context, supressChildCheck) {
883
- super(message.message || message);
884
- if (!supressChildCheck && _getChildErrorsFromContext(context)) {
885
- throw Error('Create BotiumError with child errors using the fromList() method!');
886
- }
887
- // Saving class name in the property of our custom error as a shortcut.
888
- this.name = this.constructor.name;
889
-
890
- // Capturing stack trace, excluding constructor call from it.
891
- Error.captureStackTrace(this, this.constructor);
892
- this.context = context || {};
893
- this.context.message = message.message || message;
894
- }
895
- isAsserterError() {
896
- if (this.context) {
897
- const errArr = lodash.isArray(this.context) ? this.context : [this.context];
898
- const hasNotAsserterError = errArr.findIndex(errDetail => {
899
- if (errDetail.type === 'list') {
900
- if (errDetail.errors) {
901
- return errDetail.errors.findIndex(e => e.type !== 'asserter') >= 0;
902
- } else {
903
- return true;
904
- }
905
- } else {
906
- return errDetail.type !== 'asserter';
907
- }
908
- }) >= 0;
909
- if (hasNotAsserterError) return false;
910
- return true;
911
- } else {
912
- return false;
913
- }
914
- }
915
- prettify(includeJson) {
916
- const lines = [];
917
- if (this.context) {
918
- const errArr = lodash.isArray(this.context) ? this.context : [this.context];
919
- errArr.forEach(errDetail => {
920
- lines.push('########################################');
921
- if (errDetail.type === 'asserter') {
922
- const segments = [];
923
- segments.push(`ASSERTION FAILED in ${errDetail.source}${errDetail.subtype ? ` (${errDetail.subtype})` : ''}`);
924
- errDetail.cause && errDetail.cause.expected && !errDetail.cause.not && segments.push(` - Expected: ${JSON.stringify(errDetail.cause.expected)} `);
925
- errDetail.cause && errDetail.cause.expected && errDetail.cause.not && segments.push(` - NOT Expected: ${JSON.stringify(errDetail.cause.expected)} `);
926
- errDetail.cause && errDetail.cause.actual && segments.push(` - Actual: ${JSON.stringify(errDetail.cause.actual)}`);
927
- errDetail.cause && !errDetail.cause.actual && segments.push(' - Actual: empty');
928
- lines.push(segments.join(''));
929
- errDetail.input && errDetail.input.messageText && lines.push(`INPUT: ${errDetail.input.messageText}`);
930
- } else if (errDetail.message) {
931
- lines.push(`${errDetail.message}`);
932
- }
933
- if (errDetail.transcript && errDetail.transcript.length > 0) {
934
- lines.push('------------ TRANSCRIPT ----------------------------');
935
- errDetail.transcript.forEach(transcriptStep => {
936
- if (transcriptStep.actual) {
937
- lines.push(transcriptStep.actual.prettify());
938
- }
939
- });
940
- }
941
- if (includeJson) {
942
- lines.push('------------ JSON CONTENT ----------------------------');
943
- try {
944
- const jsonOutput = JSON.stringify(errDetail);
945
- lines.push(jsonOutput);
946
- } catch (jsonErr) {
947
- lines.push(`JSON Output not possible: ${jsonErr.message}`);
948
- }
949
- }
950
- });
951
- }
952
- if (lines.length > 0) {
953
- return lines.join('\r\n');
954
- } else {
955
- return null;
956
- }
957
- }
958
- };
959
- const _getChildErrorsFromContext = context => {
960
- if (context && context.errors && lodash.isArray(context.errors)) {
961
- return context.errors;
962
- }
963
- return false;
964
- };
965
- const botiumErrorFromErr$2 = (message, err) => {
966
- if (err instanceof BotiumError$7) {
967
- return new BotiumError$7(message, err.context, true);
968
- } else {
969
- return new BotiumError$7(message, {
970
- err
971
- }, true);
972
- }
973
- };
974
- const botiumErrorFromList$2 = (errors, {
975
- type = 'list',
976
- source = 'BotiumError',
977
- flat = true
978
- }) => {
979
- const message = errors.map(err => err.message || err.toString()).join(',\n');
980
- let children = [];
981
- for (const error of errors) {
982
- if (error instanceof BotiumError$7) {
983
- const childErrors = flat && _getChildErrorsFromContext(error.context);
984
- if (childErrors && childErrors.length) {
985
- children = children.concat(childErrors);
986
- } else if (error.context) {
987
- children.push(error.context);
988
- }
989
- } else {
990
- children.push(error);
991
- }
992
- }
993
- const result = new BotiumError$7(message, {
994
- errors: children,
995
- type,
996
- source
997
- }, true);
998
- return result;
999
- };
1000
- var BotiumError_1 = {
1001
- BotiumError: BotiumError$7,
1002
- botiumErrorFromErr: botiumErrorFromErr$2,
1003
- botiumErrorFromList: botiumErrorFromList$2
1004
- };
1005
-
1006
868
  const LOGIC_HOOK_INCLUDE$1 = 'INCLUDE';
1007
869
  var LogicHookConsts = {
1008
870
  LOGIC_HOOK_INCLUDE: LOGIC_HOOK_INCLUDE$1,
@@ -1160,6 +1022,18 @@ var LogicHookConsts = {
1160
1022
  }, {
1161
1023
  name: LOGIC_HOOK_INCLUDE$1,
1162
1024
  className: 'IncludeLogicHook'
1025
+ }, {
1026
+ name: 'CONDITIONAL_STEP_TIME_BASED',
1027
+ className: 'ConditionalTimeBasedLogicHook'
1028
+ }, {
1029
+ name: 'CONDITIONAL_STEP_BUSINESS_HOURS',
1030
+ className: 'ConditionalBusinessHoursLogicHook'
1031
+ }, {
1032
+ name: 'CONDITIONAL_STEP_CAPABILITY_VALUE_BASED',
1033
+ className: 'ConditionalCapabilityValueBasedLogicHook'
1034
+ }, {
1035
+ name: 'CONDITIONAL_STEP_JSON_PATH_BASED',
1036
+ className: 'ConditionalJsonPathBasedLogicHook.js'
1163
1037
  }],
1164
1038
  DEFAULT_USER_INPUTS: [{
1165
1039
  name: 'BUTTON',
@@ -1177,13 +1051,7 @@ LogicHookConsts.DEFAULT_ASSERTERS;
1177
1051
  LogicHookConsts.DEFAULT_LOGIC_HOOKS;
1178
1052
  LogicHookConsts.DEFAULT_USER_INPUTS;
1179
1053
 
1180
- const {
1181
- NodeVM: NodeVM$2
1182
- } = vm2;
1183
1054
  const debug$m = debug$n('botium-core-asserterUtils');
1184
- const {
1185
- BotiumError: BotiumError$6
1186
- } = BotiumError_1;
1187
1055
  const {
1188
1056
  DEFAULT_ASSERTERS,
1189
1057
  DEFAULT_LOGIC_HOOKS,
@@ -1305,21 +1173,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1305
1173
  }, this.caps, args);
1306
1174
  }
1307
1175
  }
1308
- const _checkUnsafe = () => {
1309
- if (!this.caps[Capabilities.SECURITY_ALLOW_UNSAFE]) {
1310
- throw new BotiumError$6('Security Error. Using unsafe component is not allowed', {
1311
- type: 'security',
1312
- subtype: 'allow unsafe',
1313
- source: path.basename(__filename),
1314
- cause: {
1315
- src: !!src,
1316
- ref,
1317
- args,
1318
- hookType
1319
- }
1320
- });
1321
- }
1322
- };
1176
+ const allowUnsafe = !!this.caps[Capabilities.SECURITY_ALLOW_UNSAFE];
1323
1177
  if (!src) {
1324
1178
  const packageName = `botium-${hookType}-${ref}`;
1325
1179
  try {
@@ -1340,10 +1194,10 @@ var LogicHookUtils_1 = class LogicHookUtils {
1340
1194
  ...this.buildScriptContext
1341
1195
  }, this.caps, args);
1342
1196
  } else {
1343
- throw new Error(`${packageName} class or function or PluginClass field expected`);
1197
+ throw new Error('Either class or function or PluginClass field expected');
1344
1198
  }
1345
1199
  } catch (err) {
1346
- throw new Error(`Failed to fetch hook ${ref} ${hookType} from guessed package ${packageName} - ${err.message}`);
1200
+ throw new Error(`Logic Hook specification ${ref} ${hookType} (${packageName}) invalid: ${err.message}`);
1347
1201
  }
1348
1202
  }
1349
1203
  if (isClass(src)) {
@@ -1354,7 +1208,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1354
1208
  ...this.buildScriptContext
1355
1209
  }, this.caps, args);
1356
1210
  } catch (err) {
1357
- throw new Error(`Failed to load package ${ref} from provided class - ${err.message}`);
1211
+ throw new Error(`Logic Hook specification ${ref} from class invalid: ${err.message}`);
1358
1212
  }
1359
1213
  }
1360
1214
  if (lodash.isFunction(src)) {
@@ -1364,7 +1218,7 @@ var LogicHookUtils_1 = class LogicHookUtils {
1364
1218
  ...this.buildScriptContext
1365
1219
  }, this.caps, args);
1366
1220
  } catch (err) {
1367
- throw new Error(`Failed to load package ${ref} from provided function - ${err.message}`);
1221
+ throw new Error(`Logic Hook specification ${ref} from function invalid: ${err.message}`);
1368
1222
  }
1369
1223
  }
1370
1224
  if (lodash.isObject(src) && !lodash.isString(src)) {
@@ -1374,26 +1228,15 @@ var LogicHookUtils_1 = class LogicHookUtils {
1374
1228
  const script = src[key];
1375
1229
  if (lodash.isFunction(script)) {
1376
1230
  return script(args);
1377
- } else if (lodash.isString(script)) {
1378
- try {
1379
- const vm = new NodeVM$2({
1380
- eval: false,
1381
- require: false,
1382
- sandbox: args
1383
- });
1384
- return vm.run(script);
1385
- } catch (err) {
1386
- throw new Error(`Script ${key} is not valid - ${err.message || err}`);
1387
- }
1388
1231
  } else {
1389
- throw new Error(`Script "${key}" is not valid - only functions and javascript code accepted`);
1232
+ throw new Error(`Script ${key} is not valid - only functions accepted`);
1390
1233
  }
1391
1234
  };
1392
1235
  return result;
1393
1236
  }, {});
1394
1237
  return hookObject;
1395
1238
  } catch (err) {
1396
- throw new Error(`Failed to load package ${ref} ${hookType} from provided src function - ${err.message}`);
1239
+ throw new Error(`Logic Hook specification ${ref} ${hookType} from provided src (${util.inspect(src)}) invalid: ${err.message}`);
1397
1240
  }
1398
1241
  }
1399
1242
  if (lodash.isString(src)) {
@@ -1404,8 +1247,8 @@ var LogicHookUtils_1 = class LogicHookUtils {
1404
1247
  }];
1405
1248
  if (src.indexOf('/') >= 0) {
1406
1249
  tryLoads.push({
1407
- tryLoadPackageName: src.substr(0, src.lastIndexOf('/')),
1408
- tryLoadAsserterByName: src.substr(src.lastIndexOf('/') + 1)
1250
+ tryLoadPackageName: src.substring(0, src.lastIndexOf('/')),
1251
+ tryLoadAsserterByName: src.substring(src.lastIndexOf('/') + 1)
1409
1252
  });
1410
1253
  }
1411
1254
  const tryLoadFromSource = (tryRequire, tryAsserterName) => {
@@ -1443,28 +1286,33 @@ var LogicHookUtils_1 = class LogicHookUtils {
1443
1286
  ...this.buildScriptContext
1444
1287
  }, this.caps, args);
1445
1288
  } else {
1446
- throw new Error(`${src} class or function expected`);
1289
+ throw new Error('Expected class or function');
1447
1290
  }
1448
1291
  };
1449
1292
  for (const tryLoad of tryLoads) {
1450
- const tryLoadFile = path.resolve(process.cwd(), tryLoad.tryLoadPackageName);
1451
- if (fs.existsSync(tryLoadFile)) {
1452
- _checkUnsafe();
1293
+ if (this.caps.SAFEDIR) {
1294
+ const tryLoadFile = path.resolve(this.caps.SAFEDIR, tryLoad.tryLoadPackageName);
1295
+ if (tryLoadFile.startsWith(path.resolve(this.caps.SAFEDIR))) {
1296
+ if (fs.existsSync(tryLoadFile)) {
1297
+ try {
1298
+ return tryLoadFromSource(tryLoadFile, tryLoad.tryLoadAsserterByName);
1299
+ } catch (err) {
1300
+ loadErr.push(`Logic Hook specification ${ref} ${hookType} from "${src}" invalid: ${err.message} `);
1301
+ }
1302
+ }
1303
+ }
1304
+ }
1305
+ if (allowUnsafe || tryLoad.tryLoadPackageName.startsWith('botium-')) {
1453
1306
  try {
1454
- return tryLoadFromSource(tryLoadFile, tryLoad.tryLoadAsserterByName);
1307
+ return tryLoadFromSource(tryLoad.tryLoadPackageName, tryLoad.tryLoadAsserterByName);
1455
1308
  } catch (err) {
1456
- loadErr.push(`Failed to fetch ${ref} ${hookType} from ${src} - ${err.message} `);
1309
+ loadErr.push(`Logic Hook specification ${ref} ${hookType} from "${src}" invalid: ${err.message} `);
1457
1310
  }
1458
1311
  }
1459
- try {
1460
- return tryLoadFromSource(tryLoad.tryLoadPackageName, tryLoad.tryLoadAsserterByName);
1461
- } catch (err) {
1462
- loadErr.push(`Failed to fetch ${ref} ${hookType} from ${src} - ${err.message} `);
1463
- }
1464
1312
  }
1465
1313
  loadErr.forEach(debug$m);
1466
1314
  }
1467
- throw new Error(`Failed to fetch ${ref} ${hookType}, no idea how to load ...`);
1315
+ throw new Error(`Logic Hook specification ${ref} ${hookType} from "${util.inspect(src)}" invalid : no loader available`);
1468
1316
  }
1469
1317
  };
1470
1318
 
@@ -2271,19 +2119,150 @@ var helper = {
2271
2119
  toPercent: toPercent$1
2272
2120
  };
2273
2121
 
2122
+ const BotiumError$4 = class BotiumError extends Error {
2123
+ /**
2124
+ *
2125
+ * @param message
2126
+ * @param context A JSON with struct
2127
+ * {
2128
+ * type: 'some free text to identity the exception type',
2129
+ * source: 'source of the event',
2130
+ * ...
2131
+ */
2132
+ constructor(message, context, supressChildCheck) {
2133
+ super(message.message || message);
2134
+ if (!supressChildCheck && _getChildErrorsFromContext(context)) {
2135
+ throw Error('Create BotiumError with child errors using the fromList() method!');
2136
+ }
2137
+ // Saving class name in the property of our custom error as a shortcut.
2138
+ this.name = this.constructor.name;
2139
+
2140
+ // Capturing stack trace, excluding constructor call from it.
2141
+ Error.captureStackTrace(this, this.constructor);
2142
+ this.context = context || {};
2143
+ this.context.message = message.message || message;
2144
+ }
2145
+ isAsserterError() {
2146
+ if (this.context) {
2147
+ const errArr = lodash.isArray(this.context) ? this.context : [this.context];
2148
+ const hasNotAsserterError = errArr.findIndex(errDetail => {
2149
+ if (errDetail.type === 'list') {
2150
+ if (errDetail.errors) {
2151
+ return errDetail.errors.findIndex(e => e.type !== 'asserter') >= 0;
2152
+ } else {
2153
+ return true;
2154
+ }
2155
+ } else {
2156
+ return errDetail.type !== 'asserter';
2157
+ }
2158
+ }) >= 0;
2159
+ if (hasNotAsserterError) return false;
2160
+ return true;
2161
+ } else {
2162
+ return false;
2163
+ }
2164
+ }
2165
+ prettify(includeJson) {
2166
+ const lines = [];
2167
+ if (this.context) {
2168
+ const errArr = lodash.isArray(this.context) ? this.context : [this.context];
2169
+ errArr.forEach(errDetail => {
2170
+ lines.push('########################################');
2171
+ if (errDetail.type === 'asserter') {
2172
+ const segments = [];
2173
+ segments.push(`ASSERTION FAILED in ${errDetail.source}${errDetail.subtype ? ` (${errDetail.subtype})` : ''}`);
2174
+ errDetail.cause && errDetail.cause.expected && !errDetail.cause.not && segments.push(` - Expected: ${JSON.stringify(errDetail.cause.expected)} `);
2175
+ errDetail.cause && errDetail.cause.expected && errDetail.cause.not && segments.push(` - NOT Expected: ${JSON.stringify(errDetail.cause.expected)} `);
2176
+ errDetail.cause && errDetail.cause.actual && segments.push(` - Actual: ${JSON.stringify(errDetail.cause.actual)}`);
2177
+ errDetail.cause && !errDetail.cause.actual && segments.push(' - Actual: empty');
2178
+ lines.push(segments.join(''));
2179
+ errDetail.input && errDetail.input.messageText && lines.push(`INPUT: ${errDetail.input.messageText}`);
2180
+ } else if (errDetail.message) {
2181
+ lines.push(`${errDetail.message}`);
2182
+ }
2183
+ if (errDetail.transcript && errDetail.transcript.length > 0) {
2184
+ lines.push('------------ TRANSCRIPT ----------------------------');
2185
+ errDetail.transcript.forEach(transcriptStep => {
2186
+ if (transcriptStep.actual) {
2187
+ lines.push(transcriptStep.actual.prettify());
2188
+ }
2189
+ });
2190
+ }
2191
+ if (includeJson) {
2192
+ lines.push('------------ JSON CONTENT ----------------------------');
2193
+ try {
2194
+ const jsonOutput = JSON.stringify(errDetail);
2195
+ lines.push(jsonOutput);
2196
+ } catch (jsonErr) {
2197
+ lines.push(`JSON Output not possible: ${jsonErr.message}`);
2198
+ }
2199
+ }
2200
+ });
2201
+ }
2202
+ if (lines.length > 0) {
2203
+ return lines.join('\r\n');
2204
+ } else {
2205
+ return null;
2206
+ }
2207
+ }
2208
+ };
2209
+ const _getChildErrorsFromContext = context => {
2210
+ if (context && context.errors && lodash.isArray(context.errors)) {
2211
+ return context.errors;
2212
+ }
2213
+ return false;
2214
+ };
2215
+ const botiumErrorFromErr$2 = (message, err) => {
2216
+ if (err instanceof BotiumError$4) {
2217
+ return new BotiumError$4(message, err.context, true);
2218
+ } else {
2219
+ return new BotiumError$4(message, {
2220
+ err
2221
+ }, true);
2222
+ }
2223
+ };
2224
+ const botiumErrorFromList$2 = (errors, {
2225
+ type = 'list',
2226
+ source = 'BotiumError',
2227
+ flat = true
2228
+ }) => {
2229
+ const message = errors.map(err => err.message || err.toString()).join(',\n');
2230
+ let children = [];
2231
+ for (const error of errors) {
2232
+ if (error instanceof BotiumError$4) {
2233
+ const childErrors = flat && _getChildErrorsFromContext(error.context);
2234
+ if (childErrors && childErrors.length) {
2235
+ children = children.concat(childErrors);
2236
+ } else if (error.context) {
2237
+ children.push(error.context);
2238
+ }
2239
+ } else {
2240
+ children.push(error);
2241
+ }
2242
+ }
2243
+ const result = new BotiumError$4(message, {
2244
+ errors: children,
2245
+ type,
2246
+ source
2247
+ }, true);
2248
+ return result;
2249
+ };
2250
+ var BotiumError_1 = {
2251
+ BotiumError: BotiumError$4,
2252
+ botiumErrorFromErr: botiumErrorFromErr$2,
2253
+ botiumErrorFromList: botiumErrorFromList$2
2254
+ };
2255
+
2274
2256
  const debug$k = debug$n('botium-core-ScriptingMemory');
2275
2257
  const {
2276
2258
  v1: uuidv1
2277
2259
  } = uuid;
2278
- const {
2279
- NodeVM: NodeVM$1
2280
- } = vm2;
2281
2260
  const {
2282
2261
  quoteRegexpString: quoteRegexpString$1,
2283
2262
  toString: toString$2
2284
2263
  } = helper;
2285
2264
  const {
2286
- BotiumError: BotiumError$5
2265
+ BotiumError: BotiumError$3
2287
2266
  } = BotiumError_1;
2288
2267
 
2289
2268
  // If they got parameter, then it will be a string always.
@@ -2440,28 +2419,6 @@ const SCRIPTING_FUNCTIONS_RAW = {
2440
2419
  if (root && root.length > 0) return root[0];else return '';
2441
2420
  },
2442
2421
  numberOfArguments: 1
2443
- },
2444
- $func: {
2445
- handler: (caps, code) => {
2446
- if (code == null) {
2447
- throw Error('func function used without args!');
2448
- }
2449
- try {
2450
- const vm = new NodeVM$1({
2451
- eval: false,
2452
- require: false,
2453
- env: caps[Capabilities.SECURITY_ALLOW_UNSAFE] ? process.env : {},
2454
- sandbox: {
2455
- caps,
2456
- moment
2457
- }
2458
- });
2459
- return vm.run(`module.exports = (${code})`);
2460
- } catch (err) {
2461
- throw Error(`func function execution failed - ${err}`);
2462
- }
2463
- },
2464
- numberOfArguments: 1
2465
2422
  }
2466
2423
  };
2467
2424
  const SCRIPTING_FUNCTIONS$1 = lodash.mapValues(SCRIPTING_FUNCTIONS_RAW, (funcOrStruct, name) => {
@@ -2470,7 +2427,7 @@ const SCRIPTING_FUNCTIONS$1 = lodash.mapValues(SCRIPTING_FUNCTIONS_RAW, (funcOrS
2470
2427
  return {
2471
2428
  handler: (caps, ...rest) => {
2472
2429
  if (!caps[Capabilities.SECURITY_ALLOW_UNSAFE] && funcOrStruct.unsafe) {
2473
- throw new BotiumError$5(`Security Error. Using unsafe scripting memory function ${name} is not allowed`, {
2430
+ throw new BotiumError$3(`Security Error. Using unsafe scripting memory function ${name} is not allowed`, {
2474
2431
  type: 'security',
2475
2432
  subtype: 'allow unsafe',
2476
2433
  source: path.basename(__filename),
@@ -2610,7 +2567,7 @@ ScriptingMemory.SCRIPTING_FUNCTIONS;
2610
2567
 
2611
2568
  const debug$j = debug$n('botium-core-Convo');
2612
2569
  const {
2613
- BotiumError: BotiumError$4,
2570
+ BotiumError: BotiumError$2,
2614
2571
  botiumErrorFromErr: botiumErrorFromErr$1,
2615
2572
  botiumErrorFromList: botiumErrorFromList$1
2616
2573
  } = BotiumError_1;
@@ -3034,6 +2991,7 @@ class Convo$6 {
3034
2991
  throw failErr;
3035
2992
  }
3036
2993
  } else if (convoStep.sender === 'bot') {
2994
+ const previousWaitForBotSays = waitForBotSays;
3037
2995
  if (waitForBotSays) {
3038
2996
  botMsg = null;
3039
2997
  } else {
@@ -3089,16 +3047,25 @@ class Convo$6 {
3089
3047
  } catch (failErr) {}
3090
3048
  throw failErr;
3091
3049
  }
3092
- if (convoStep.skip === true) {
3093
- skipTranscriptStep = true;
3050
+ if (convoStep.conditional) {
3094
3051
  const nextConvoStep = this.conversation[i + 1];
3095
- if (nextConvoStep && nextConvoStep.sender === 'bot') {
3096
- waitForBotSays = false;
3052
+ if (!previousWaitForBotSays) {
3053
+ skipTranscriptStep = true;
3054
+ }
3055
+ waitForBotSays = false;
3056
+ if (!nextConvoStep || nextConvoStep.sender !== 'bot' || !nextConvoStep.logicHooks || !nextConvoStep.logicHooks.some(lh => lh.name.toUpperCase().startsWith('CONDITIONAL_STEP'))) {
3057
+ waitForBotSays = true;
3058
+ } else {
3059
+ const conditionalLogicHook = convoStep.logicHooks.find(lh => lh.name.startsWith('CONDITIONAL_STEP'));
3060
+ const nextConditionalLogicHook = nextConvoStep.logicHooks.find(lh => lh.name.startsWith('CONDITIONAL_STEP'));
3061
+ waitForBotSays = conditionalLogicHook.args[1] !== nextConditionalLogicHook.args[1];
3062
+ }
3063
+ if (convoStep.conditional.skip) {
3064
+ continue;
3097
3065
  }
3098
- continue;
3099
3066
  }
3100
3067
  if (!botMsg || !botMsg.messageText && !botMsg.media && !botMsg.buttons && !botMsg.cards && !botMsg.sourceData && !botMsg.nlp) {
3101
- const failErr = new BotiumError$4(`${this.header.name}/${convoStep.stepTag}: bot says nothing`);
3068
+ const failErr = new BotiumError$2(`${this.header.name}/${convoStep.stepTag}: bot says nothing`);
3102
3069
  debug$j(failErr);
3103
3070
  try {
3104
3071
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep);
@@ -3184,7 +3151,7 @@ class Convo$6 {
3184
3151
  try {
3185
3152
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr, lastMeConvoStep);
3186
3153
  } catch (failErr) {}
3187
- if (container.caps[Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS] && err instanceof BotiumError$4) {
3154
+ if (container.caps[Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS] && err instanceof BotiumError$2) {
3188
3155
  assertErrors.push(err);
3189
3156
  } else {
3190
3157
  throw failErr;
@@ -3200,7 +3167,7 @@ class Convo$6 {
3200
3167
  }
3201
3168
  }
3202
3169
  } else {
3203
- const failErr = new BotiumError$4(`${this.header.name}/${convoStep.stepTag}: invalid sender - ${util.inspect(convoStep.sender)}`);
3170
+ const failErr = new BotiumError$2(`${this.header.name}/${convoStep.stepTag}: invalid sender - ${util.inspect(convoStep.sender)}`);
3204
3171
  debug$j(failErr);
3205
3172
  try {
3206
3173
  this.scriptingEvents.fail && this.scriptingEvents.fail(failErr);
@@ -3209,7 +3176,7 @@ class Convo$6 {
3209
3176
  }
3210
3177
  } catch (err) {
3211
3178
  if (lastMeConvoStep) {
3212
- if (err instanceof BotiumError$4 && err.context) {
3179
+ if (err instanceof BotiumError$2 && err.context) {
3213
3180
  err.context.input = new ConvoStep$1(lastMeConvoStep);
3214
3181
  err.context.transcript = [...transcriptSteps, {
3215
3182
  ...transcriptStep
@@ -3222,7 +3189,7 @@ class Convo$6 {
3222
3189
  }
3223
3190
  }
3224
3191
  transcriptStep.err = err;
3225
- if (err instanceof BotiumError$4 && container.caps[Capabilities.SCRIPTING_ENABLE_SKIP_ASSERT_ERRORS]) {
3192
+ if (err instanceof BotiumError$2 && container.caps[Capabilities.SCRIPTING_ENABLE_SKIP_ASSERT_ERRORS]) {
3226
3193
  if (!err.isAsserterError()) {
3227
3194
  throw err;
3228
3195
  }
@@ -3255,10 +3222,10 @@ class Convo$6 {
3255
3222
  if (expected === null || expected === undefined) return;
3256
3223
  if (lodash.isArray(expected)) {
3257
3224
  if (!lodash.isArray(result)) {
3258
- throw new BotiumError$4(`${this.header.name}/${convoStep.stepTag}: bot response expected array, got "${result}"`);
3225
+ throw new BotiumError$2(`${this.header.name}/${convoStep.stepTag}: bot response expected array, got "${result}"`);
3259
3226
  }
3260
3227
  if (expected.length !== result.length) {
3261
- throw new BotiumError$4(`${this.header.name}/${convoStep.stepTag}: bot response expected array length ${expected.length}, got ${result.length}`);
3228
+ throw new BotiumError$2(`${this.header.name}/${convoStep.stepTag}: bot response expected array length ${expected.length}, got ${result.length}`);
3262
3229
  }
3263
3230
  for (let i = 0; i < expected.length; i++) {
3264
3231
  this._compareObject(container, scriptingMemory, convoStep, result[i], expected[i]);
@@ -3268,7 +3235,7 @@ class Convo$6 {
3268
3235
  if (Object.prototype.hasOwnProperty.call(result, key)) {
3269
3236
  this._compareObject(container, scriptingMemory, convoStep, result[key], expected[key]);
3270
3237
  } else {
3271
- throw new BotiumError$4(`${this.header.name}/${convoStep.stepTag}: bot response "${result}" missing expected property: ${key}`);
3238
+ throw new BotiumError$2(`${this.header.name}/${convoStep.stepTag}: bot response "${result}" missing expected property: ${key}`);
3272
3239
  }
3273
3240
  });
3274
3241
  } else {
@@ -3397,14 +3364,14 @@ class Convo$6 {
3397
3364
  includeLogicHooks.forEach(includeLogicHook => {
3398
3365
  const alreadyThereAt = parentPConvos.indexOf(includeLogicHook);
3399
3366
  if (alreadyThereAt >= 0) {
3400
- throw new BotiumError$4(`Partial convos are included circular. "${includeLogicHook}" is referenced by "/${parentPConvos.slice(0, alreadyThereAt).join('/')}" and by "/${parentPConvos.join('/')}" `);
3367
+ throw new BotiumError$2(`Partial convos are included circular. "${includeLogicHook}" is referenced by "/${parentPConvos.slice(0, alreadyThereAt).join('/')}" and by "/${parentPConvos.join('/')}" `);
3401
3368
  }
3402
3369
  if (!partialConvos || Object.keys(partialConvos).length === 0) {
3403
- throw new BotiumError$4(`Cant find partial convo with name ${includeLogicHook} (There are no partial convos)`);
3370
+ throw new BotiumError$2(`Cant find partial convo with name ${includeLogicHook} (There are no partial convos)`);
3404
3371
  }
3405
3372
  const partialConvo = partialConvos[includeLogicHook];
3406
3373
  if (!partialConvo) {
3407
- throw new BotiumError$4(`Cant find partial convo with name ${includeLogicHook} (available partial convos: ${Object.keys(partialConvos).join(',')})`);
3374
+ throw new BotiumError$2(`Cant find partial convo with name ${includeLogicHook} (available partial convos: ${Object.keys(partialConvos).join(',')})`);
3408
3375
  }
3409
3376
  _getEffectiveConversationRecursive(partialConvo.conversation, [...parentPConvos, includeLogicHook], result, true);
3410
3377
  debug$j(`Partial convo ${includeLogicHook} included`);
@@ -3739,44 +3706,21 @@ var JsonToJson = {
3739
3706
  precompile: precompile$2
3740
3707
  };
3741
3708
 
3742
- const {
3743
- NodeVM
3744
- } = vm2;
3745
3709
  const debug$h = debug$n('botium-core-HookUtils');
3746
- const {
3747
- BotiumError: BotiumError$3
3748
- } = BotiumError_1;
3749
- const executeHook$2 = async (caps, hook, args) => {
3750
- return executeHookSync$1(caps, hook, args);
3710
+ const executeHook$2 = async (caps, hook, ...args) => {
3711
+ return executeHookSync$1(caps, hook, ...args);
3751
3712
  };
3752
- const executeHookSync$1 = (caps, hook, args) => {
3713
+ const executeHookSync$1 = (caps, hook, ...args) => {
3753
3714
  if (!hook) {
3754
3715
  return;
3755
3716
  }
3756
3717
  if (lodash.isFunction(hook)) {
3757
3718
  try {
3758
- return hook(args);
3719
+ return hook(...args);
3759
3720
  } catch (err) {
3760
3721
  throw new Error(`Calling Hook function failed: ${err.message}`);
3761
3722
  }
3762
3723
  }
3763
- if (lodash.isString(hook)) {
3764
- try {
3765
- const vm = new NodeVM({
3766
- eval: false,
3767
- require: false,
3768
- sandbox: args
3769
- });
3770
- const r = vm.run(hook);
3771
- if (lodash.isFunction(r)) {
3772
- return r(args);
3773
- } else {
3774
- return r;
3775
- }
3776
- } catch (err) {
3777
- throw new Error(`Calling Hook Javascript code failed: ${err.message}`);
3778
- }
3779
- }
3780
3724
  throw new Error(`Unknown hook ${typeof hook}`);
3781
3725
  };
3782
3726
  const getHook$3 = (caps, data) => {
@@ -3789,46 +3733,40 @@ const getHook$3 = (caps, data) => {
3789
3733
  return data;
3790
3734
  }
3791
3735
  if (lodash.isString(data)) {
3792
- let resultWithRequire;
3793
- let tryLoadFile = path.resolve(process.cwd(), data);
3794
- if (fs.existsSync(tryLoadFile)) {
3795
- try {
3796
- resultWithRequire = commonjsRequire(tryLoadFile);
3797
- } catch (err) {}
3798
- } else {
3799
- tryLoadFile = data;
3800
- try {
3801
- resultWithRequire = commonjsRequire(data);
3802
- } catch (err) {}
3803
- }
3804
- if (resultWithRequire) {
3805
- if (!allowUnsafe) {
3806
- throw new BotiumError$3('Security Error. Using unsafe custom hook with require is not allowed', {
3807
- type: 'security',
3808
- subtype: 'allow unsafe',
3809
- source: path.basename(__filename),
3810
- cause: {
3811
- SECURITY_ALLOW_UNSAFE: caps[Capabilities.SECURITY_ALLOW_UNSAFE],
3812
- hookData: data
3736
+ if (caps.SAFEDIR) {
3737
+ const tryLoadFile = path.resolve(caps.SAFEDIR, data);
3738
+ if (tryLoadFile.startsWith(path.resolve(caps.SAFEDIR))) {
3739
+ if (fs.existsSync(tryLoadFile)) {
3740
+ try {
3741
+ const resultWithRequire = commonjsRequire(tryLoadFile);
3742
+ if (lodash.isFunction(resultWithRequire)) {
3743
+ debug$h(`found hook, type: safedir, in ${tryLoadFile}`);
3744
+ return resultWithRequire;
3745
+ } else {
3746
+ throw new Error(`Expected function from hook specification "${util.inspect(data)}", got: "${util.inspect(resultWithRequire)}"`);
3747
+ }
3748
+ } catch (err) {
3749
+ debug$h(`Failed loading hook, type: safedir, from ${tryLoadFile} failed: ${err.message || err}`);
3813
3750
  }
3814
- });
3815
- }
3816
- if (lodash.isFunction(resultWithRequire)) {
3817
- debug$h(`found hook, type: require, in ${tryLoadFile}`);
3818
- return resultWithRequire;
3819
- } else {
3820
- throw new Error(`Cant load hook ${tryLoadFile} because it is not a function`);
3751
+ }
3821
3752
  }
3822
3753
  }
3823
- try {
3824
- esprima.parseScript(data);
3825
- } catch (err) {
3826
- throw new Error(`Cant load hook, syntax is not valid - ${util.inspect(err)}`);
3754
+ if (allowUnsafe || data.startsWith('botium-')) {
3755
+ const tryLoadFile = data;
3756
+ try {
3757
+ const resultWithRequire = commonjsRequire(tryLoadFile);
3758
+ if (lodash.isFunction(resultWithRequire)) {
3759
+ debug$h(`found hook, type: require, in ${tryLoadFile}`);
3760
+ return resultWithRequire;
3761
+ } else {
3762
+ throw new Error(`Expected function from hook specification "${util.inspect(data)}", got: "${util.inspect(resultWithRequire)}"`);
3763
+ }
3764
+ } catch (err) {
3765
+ debug$h(`Failed loading hook, type: require, from ${tryLoadFile} failed: ${err.message || err}`);
3766
+ }
3827
3767
  }
3828
- debug$h('Found hook, type: JavaScript as String');
3829
- return data;
3830
3768
  }
3831
- throw new Error(`Not valid hook ${util.inspect(data)}`);
3769
+ throw new Error(`Hook specification "${util.inspect(data)}" invalid: no loader available`);
3832
3770
  };
3833
3771
  var HookUtils = {
3834
3772
  getHook: getHook$3,
@@ -5324,7 +5262,7 @@ const {
5324
5262
  ConvoStep
5325
5263
  } = Convo_1;
5326
5264
  const {
5327
- BotiumError: BotiumError$2,
5265
+ BotiumError: BotiumError$1,
5328
5266
  botiumErrorFromList,
5329
5267
  botiumErrorFromErr
5330
5268
  } = BotiumError_1;
@@ -5600,7 +5538,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5600
5538
  const werArgs = this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS];
5601
5539
  const threshold = [',', '.'].find(p => `${werArgs[0]}`.includes(p)) ? parseFloat(werArgs[0]) : parseInt(werArgs[0]) / 100;
5602
5540
  const message = `${stepTag}: Word Error Rate (${toPercent(wer)}) higher than accepted (${toPercent(threshold)})`;
5603
- throw new BotiumError$2(message, {
5541
+ throw new BotiumError$1(message, {
5604
5542
  type: 'asserter',
5605
5543
  source: asserterType,
5606
5544
  params: {
@@ -5622,7 +5560,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5622
5560
  message += ' expected to match ';
5623
5561
  message += tomatch && tomatch.length > 1 ? 'one of ' : '';
5624
5562
  message += `${tomatch.map(e => e ? '"' + e + '"' : '<any response>').join(', ')}`;
5625
- throw new BotiumError$2(message, {
5563
+ throw new BotiumError$1(message, {
5626
5564
  type: 'asserter',
5627
5565
  source: asserterType,
5628
5566
  params: {
@@ -5655,7 +5593,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5655
5593
  const werArgs = this.caps[Capabilities.SCRIPTING_MATCHING_MODE_ARGS];
5656
5594
  const threshold = [',', '.'].find(p => `${werArgs[0]}`.includes(p)) ? parseFloat(werArgs[0]) : parseInt(werArgs[0]) / 100;
5657
5595
  const message = `${stepTag}: Word Error Rate (${toPercent(wer)}) lower than accepted (${toPercent(threshold)})`;
5658
- throw new BotiumError$2(message, {
5596
+ throw new BotiumError$1(message, {
5659
5597
  type: 'asserter',
5660
5598
  source: asserterType,
5661
5599
  params: {
@@ -5677,7 +5615,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5677
5615
  message += ' expected NOT to match ';
5678
5616
  message += nottomatch && nottomatch.length > 1 ? 'one of ' : '';
5679
5617
  message += `${nottomatch.map(e => e ? '"' + e + '"' : '<any response>').join(', ')}`;
5680
- throw new BotiumError$2(message, {
5618
+ throw new BotiumError$1(message, {
5681
5619
  type: 'asserter',
5682
5620
  source: asserterType,
5683
5621
  params: {
@@ -5727,7 +5665,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
5727
5665
  if (asserter[notAsserterType]) {
5728
5666
  return p(this.retryHelperAsserter, () => asserter[notAsserterType](params));
5729
5667
  } else {
5730
- return pnot(this.retryHelperAsserter, () => asserter[asserterType](params), new BotiumError$2(`${convoStep.stepTag}: Expected asserter ${asserter.name || asserterSpec.name} with args "${params.args}" to fail`, {
5668
+ return pnot(this.retryHelperAsserter, () => asserter[asserterType](params), new BotiumError$1(`${convoStep.stepTag}: Expected asserter ${asserter.name || asserterSpec.name} with args "${params.args}" to fail`, {
5731
5669
  type: 'asserter',
5732
5670
  source: asserter.name || asserterSpec.name,
5733
5671
  params: {
@@ -6122,7 +6060,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6122
6060
  return !entry.header.name;
6123
6061
  });
6124
6062
  if (aggregatedNoNames.length) {
6125
- throw new BotiumError$2('Scripting Memory Definition(s) without name', {
6063
+ throw new BotiumError$1('Scripting Memory Definition(s) without name', {
6126
6064
  type: 'Scripting Memory',
6127
6065
  subtype: 'Scripting Memory without name',
6128
6066
  source: 'ScriptingProvider',
@@ -6137,7 +6075,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6137
6075
  return !entry.values || !Object.keys(entry.values).length;
6138
6076
  });
6139
6077
  if (aggregatedNoVariables.length) {
6140
- throw new BotiumError$2(`Scripting Memory Definition(s) ${aggregatedNoVariables.map(e => e.header.name).join(', ')} without variable`, {
6078
+ throw new BotiumError$1(`Scripting Memory Definition(s) ${aggregatedNoVariables.map(e => e.header.name).join(', ')} without variable`, {
6141
6079
  type: 'Scripting Memory',
6142
6080
  subtype: 'Scripting Memory without variable',
6143
6081
  source: 'ScriptingProvider',
@@ -6152,7 +6090,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6152
6090
  return !lodash.isUndefined(entry.values['']);
6153
6091
  });
6154
6092
  if (aggregatedNoVariableNames.length) {
6155
- throw new BotiumError$2(`Scripting Memory Definition(s) ${aggregatedNoVariableNames.map(e => e.header.name).join(', ')} without variable name`, {
6093
+ throw new BotiumError$1(`Scripting Memory Definition(s) ${aggregatedNoVariableNames.map(e => e.header.name).join(', ')} without variable name`, {
6156
6094
  type: 'Scripting Memory',
6157
6095
  subtype: 'Scripting Memory without variable name',
6158
6096
  source: 'ScriptingProvider',
@@ -6180,7 +6118,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6180
6118
  }
6181
6119
  }
6182
6120
  if (aggregatedDuplicates.length) {
6183
- throw new BotiumError$2(`Scripting Memory Definition name(s) "${lodash.uniq(aggregatedDuplicates.map(d => d.scriptingMemory.header.name)).join(', ')}" are not unique`, {
6121
+ throw new BotiumError$1(`Scripting Memory Definition name(s) "${lodash.uniq(aggregatedDuplicates.map(d => d.scriptingMemory.header.name)).join(', ')}" are not unique`, {
6184
6122
  type: 'Scripting Memory',
6185
6123
  subtype: 'Scripting Memory name collision',
6186
6124
  source: 'ScriptingProvider',
@@ -6211,7 +6149,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6211
6149
  }
6212
6150
  }
6213
6151
  if (aggregatedIntersections.length) {
6214
- throw new BotiumError$2(`Scripting Memory Definitions "${aggregatedIntersections.map(i => i.scriptingMemory.header.name).join(', ')}" are invalid because variable name collision"`, {
6152
+ throw new BotiumError$1(`Scripting Memory Definitions "${aggregatedIntersections.map(i => i.scriptingMemory.header.name).join(', ')}" are invalid because variable name collision"`, {
6215
6153
  type: 'Scripting Memory',
6216
6154
  subtype: 'Scripting Memory variable name collision',
6217
6155
  source: 'ScriptingProvider',
@@ -6774,7 +6712,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6774
6712
  }
6775
6713
  } else if (scriptingMemories) {
6776
6714
  if (!scriptingMemories.header || !scriptingMemories.header.name) {
6777
- throw new BotiumError$2('Scripting Memory Definition has no name', {
6715
+ throw new BotiumError$1('Scripting Memory Definition has no name', {
6778
6716
  type: 'Compiler',
6779
6717
  subtype: 'Scripting memory without name',
6780
6718
  source: 'ScriptingProvider',
@@ -6784,7 +6722,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6784
6722
  });
6785
6723
  }
6786
6724
  if (!scriptingMemories.values || !Object.keys(scriptingMemories.values).length) {
6787
- throw new BotiumError$2('Scripting Memory Definition has no variables', {
6725
+ throw new BotiumError$1('Scripting Memory Definition has no variables', {
6788
6726
  type: 'Compiler',
6789
6727
  subtype: 'Scripting memory without variable',
6790
6728
  source: 'ScriptingProvider',
@@ -6794,7 +6732,7 @@ var ScriptingProvider_1 = class ScriptingProvider {
6794
6732
  });
6795
6733
  }
6796
6734
  if (scriptingMemories.values && !lodash.isUndefined(scriptingMemories.values[''])) {
6797
- throw new BotiumError$2('Scripting Memory Definition variable has no name', {
6735
+ throw new BotiumError$1('Scripting Memory Definition variable has no name', {
6798
6736
  type: 'Compiler',
6799
6737
  subtype: 'Scripting memory without variable name',
6800
6738
  source: 'ScriptingProvider',
@@ -7681,7 +7619,7 @@ const {
7681
7619
  escapeJSONString
7682
7620
  } = Utils;
7683
7621
  const {
7684
- BotiumError: BotiumError$1
7622
+ BotiumError
7685
7623
  } = BotiumError_1;
7686
7624
  mustache.escape = s => s;
7687
7625
  var SimpleRestContainer_1 = class SimpleRestContainer {
@@ -7978,22 +7916,32 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
7978
7916
  }
7979
7917
  const result = [];
7980
7918
  if (isFromUser) {
7981
- const _extractFrom = (root, jsonPaths) => {
7982
- const flattened = [];
7919
+ const _extractFrom = (root, jsonPaths, acceptFn = null) => {
7920
+ const result = [];
7983
7921
  for (const jsonPath of jsonPaths) {
7922
+ const jsonPathRes = [];
7984
7923
  const rb = jsonpath.query(root, jsonPath);
7985
7924
  if (lodash.isArray(rb)) {
7986
- lodash.flattenDeep(rb).forEach(r => flattened.push(r));
7987
- } else if (rb) {
7988
- flattened.push(rb);
7925
+ lodash.flattenDeep(rb).forEach(r => jsonPathRes.push(r));
7926
+ } else {
7927
+ jsonPathRes.push(rb);
7928
+ }
7929
+ if (acceptFn) {
7930
+ result.push(...jsonPathRes.filter(r => acceptFn(root, jsonPath, r)));
7931
+ } else {
7932
+ result.push(...jsonPathRes);
7989
7933
  }
7990
7934
  }
7991
- return flattened;
7935
+ return result;
7992
7936
  };
7993
7937
  const jsonPathRoots = [];
7994
7938
  const jsonPathsBody = getAllCapValues(Capabilities.SIMPLEREST_BODY_JSONPATH, this.caps);
7995
7939
  if (jsonPathsBody.length > 0) {
7996
- jsonPathRoots.push(..._extractFrom(body, jsonPathsBody));
7940
+ jsonPathRoots.push(..._extractFrom(body, jsonPathsBody, (root, jsonPath, r) => {
7941
+ if (r && lodash.isObject(r)) return true;
7942
+ debug$4(`Ignoring result body from ${jsonPath} - not a querieable object (${util.inspect(r)})`);
7943
+ return false;
7944
+ }));
7997
7945
  } else {
7998
7946
  jsonPathRoots.push(body);
7999
7947
  }
@@ -8152,7 +8100,7 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8152
8100
  const jsonBody = Utils.toJsonWeak(body);
8153
8101
  const errKey = Object.keys(jsonBody).find(k => k.startsWith('err') || k.startsWith('fail'));
8154
8102
  if (errKey) {
8155
- return reject(new BotiumError$1(`got error response: ${response.statusCode}/${response.statusMessage} - ${jsonBody[errKey]}`, {
8103
+ return reject(new BotiumError(`got error response: ${response.statusCode}/${response.statusMessage} - ${jsonBody[errKey]}`, {
8156
8104
  message: Utils.shortenJsonString(body)
8157
8105
  }));
8158
8106
  }
@@ -8607,9 +8555,6 @@ var SimpleRestContainer_1 = class SimpleRestContainer {
8607
8555
  };
8608
8556
 
8609
8557
  const debug$3 = debug$n('botium-connector-PluginConnectorContainer-helper');
8610
- const {
8611
- BotiumError
8612
- } = BotiumError_1;
8613
8558
  const pluginResolver = containermode => {
8614
8559
  if (containermode === 'simplerest') {
8615
8560
  return SimpleRestContainer_1;
@@ -8660,20 +8605,6 @@ const loadConnectorModule = (PluginClass, args) => {
8660
8605
  };
8661
8606
  const tryLoadPlugin$1 = (containermode, modulepath, args) => {
8662
8607
  const pluginLoaderSpec = modulepath || containermode;
8663
- const _checkUnsafe = (caps, mode, cause) => {
8664
- if (!caps[Capabilities.SECURITY_ALLOW_UNSAFE]) {
8665
- throw new BotiumError(`Security Error. Using unsafe connector mode "${mode}" is not allowed`, {
8666
- type: 'security',
8667
- subtype: 'allow unsafe',
8668
- source: 'src/containers/plugins/index.js',
8669
- cause: {
8670
- SECURITY_ALLOW_UNSAFE: caps[Capabilities.SECURITY_ALLOW_UNSAFE],
8671
- mode,
8672
- ...cause
8673
- }
8674
- });
8675
- }
8676
- };
8677
8608
  if (pluginResolver(pluginLoaderSpec)) {
8678
8609
  const pluginInstance = new (pluginResolver(pluginLoaderSpec))(args);
8679
8610
  debug$3('Botium plugin loaded from internal plugin resolver');
@@ -8685,44 +8616,47 @@ const tryLoadPlugin$1 = (containermode, modulepath, args) => {
8685
8616
  return pluginInstance;
8686
8617
  }
8687
8618
  const loadErr = [];
8619
+ const allowUnsafe = !!args.caps[Capabilities.SECURITY_ALLOW_UNSAFE];
8688
8620
  if (lodash.isString(pluginLoaderSpec)) {
8689
- const tryLoadFile = path.resolve(process.cwd(), pluginLoaderSpec);
8690
- if (fs.existsSync(tryLoadFile)) {
8691
- _checkUnsafe(args.caps, 'Using work dir', {
8692
- modulepath,
8693
- containermode
8694
- });
8621
+ if (args.caps.SAFEDIR) {
8622
+ const tryLoadFile = path.resolve(args.caps.SAFEDIR, pluginLoaderSpec);
8623
+ if (tryLoadFile.startsWith(path.resolve(args.caps.SAFEDIR))) {
8624
+ if (fs.existsSync(tryLoadFile)) {
8625
+ try {
8626
+ let plugin = commonjsRequire(tryLoadFile);
8627
+ if (plugin.default) {
8628
+ plugin = plugin.default;
8629
+ }
8630
+ if (!plugin.PluginVersion || !plugin.PluginClass) {
8631
+ loadErr.push(`Invalid Botium plugin loaded from ${tryLoadFile}, expected PluginVersion, PluginClass fields`);
8632
+ } else {
8633
+ const pluginInstance = loadConnectorModule(plugin.PluginClass, args);
8634
+ debug$3(`Botium plugin loaded from ${tryLoadFile}`);
8635
+ return pluginInstance;
8636
+ }
8637
+ } catch (err) {
8638
+ loadErr.push(`Loading Botium plugin from ${tryLoadFile} failed - ${err.message}`);
8639
+ }
8640
+ }
8641
+ }
8642
+ }
8643
+ if (allowUnsafe) {
8695
8644
  try {
8696
- let plugin = commonjsRequire(tryLoadFile);
8645
+ let plugin = commonjsRequire(pluginLoaderSpec);
8697
8646
  if (plugin.default) {
8698
8647
  plugin = plugin.default;
8699
8648
  }
8700
8649
  if (!plugin.PluginVersion || !plugin.PluginClass) {
8701
- loadErr.push(`Invalid Botium plugin loaded from ${tryLoadFile}, expected PluginVersion, PluginClass fields`);
8650
+ loadErr.push(`Invalid Botium plugin loaded from ${pluginLoaderSpec}, expected PluginVersion, PluginClass fields`);
8702
8651
  } else {
8703
8652
  const pluginInstance = loadConnectorModule(plugin.PluginClass, args);
8704
- debug$3(`Botium plugin loaded from ${tryLoadFile}`);
8653
+ debug$3(`Botium plugin loaded from ${pluginLoaderSpec}. Plugin version is ${getModuleVersionSafe(pluginLoaderSpec)}`);
8705
8654
  return pluginInstance;
8706
8655
  }
8707
8656
  } catch (err) {
8708
- loadErr.push(`Loading Botium plugin from ${tryLoadFile} failed - ${err.message}`);
8657
+ loadErr.push(`Loading Botium plugin from ${pluginLoaderSpec} failed - ${err.message}`);
8709
8658
  }
8710
8659
  }
8711
- try {
8712
- let plugin = commonjsRequire(pluginLoaderSpec);
8713
- if (plugin.default) {
8714
- plugin = plugin.default;
8715
- }
8716
- if (!plugin.PluginVersion || !plugin.PluginClass) {
8717
- loadErr.push(`Invalid Botium plugin loaded from ${pluginLoaderSpec}, expected PluginVersion, PluginClass fields`);
8718
- } else {
8719
- const pluginInstance = loadConnectorModule(plugin.PluginClass, args);
8720
- debug$3(`Botium plugin loaded from ${pluginLoaderSpec}. Plugin version is ${getModuleVersionSafe(pluginLoaderSpec)}`);
8721
- return pluginInstance;
8722
- }
8723
- } catch (err) {
8724
- loadErr.push(`Loading Botium plugin from ${pluginLoaderSpec} failed - ${err.message}`);
8725
- }
8726
8660
  const tryLoadPackage = `botium-connector-${pluginLoaderSpec}`;
8727
8661
  try {
8728
8662
  let plugin = commonjsRequire(tryLoadPackage);
@@ -8886,6 +8820,13 @@ var PluginConnectorContainer_1 = class PluginConnectorContainer extends BaseCont
8886
8820
  return Promise.reject(new Error(`Clean - Botium plugin failed: ${util.inspect(err)}`));
8887
8821
  }
8888
8822
  }
8823
+ GetMetaData() {
8824
+ try {
8825
+ return this.pluginInstance.GetMetaData ? this.pluginInstance.GetMetaData() || Promise.resolve() : Promise.resolve();
8826
+ } catch (err) {
8827
+ return Promise.reject(new Error(`GetMetaData - Botium plugin failed: ${util.inspect(err)}`));
8828
+ }
8829
+ }
8889
8830
  };
8890
8831
 
8891
8832
  var require$$3 = getCjsExportFromNamespace(_package$1);