botium-core 1.14.10 → 1.15.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/botium-cjs.js +216 -115
- package/dist/botium-cjs.js.map +1 -1
- package/dist/botium-es.js +215 -114
- package/dist/botium-es.js.map +1 -1
- package/package.json +4 -4
- package/samples/connectors/simplerest-async/jokebot.js +24 -18
- package/src/Capabilities.js +3 -0
- package/src/containers/BaseContainer.js +1 -2
- package/src/containers/plugins/SimpleRestContainer.js +158 -89
- package/src/scripting/Convo.js +2 -2
- package/src/scripting/helper.js +59 -22
- package/src/scripting/logichook/asserter/BaseTextAsserter.js +1 -2
- package/src/scripting/logichook/asserter/ButtonsAsserter.js +3 -4
- package/src/scripting/logichook/userinput/MediaInput.js +14 -17
- package/test/compiler/compilertxt.spec.js +18 -0
- package/test/compiler/convos/txt/convos_jsonmessage.convo.txt +10 -0
- package/test/connectors/simplerest.spec.js +290 -42
- package/test/hooks/customhooks.spec.js +3 -5
- package/test/scripting/helper.spec.js +21 -0
- package/test/scripting/scriptingProvider.spec.js +34 -0
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "botium-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.3",
|
|
4
4
|
"description": "The Selenium for Chatbots",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "dist/botium-es.js",
|
|
7
7
|
"engines": {
|
|
8
|
-
"node": ">=
|
|
8
|
+
"node": ">=18.17"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"postinstall": "node ./report.js",
|
|
@@ -54,7 +54,6 @@
|
|
|
54
54
|
"promise-retry": "^2.0.1",
|
|
55
55
|
"promise.allsettled": "^1.0.7",
|
|
56
56
|
"randomatic": "^3.1.1",
|
|
57
|
-
"request": "^2.88.2",
|
|
58
57
|
"rimraf": "^5.0.5",
|
|
59
58
|
"sanitize-filename": "^1.6.3",
|
|
60
59
|
"slugify": "^1.6.6",
|
|
@@ -64,6 +63,7 @@
|
|
|
64
63
|
"swagger-jsdoc": "^6.2.8",
|
|
65
64
|
"swagger-ui-express": "^5.0.0",
|
|
66
65
|
"tinyglobby": "^0.2.10",
|
|
66
|
+
"undici": "^6.21.0",
|
|
67
67
|
"uuid": "^9.0.1",
|
|
68
68
|
"word-error-rate": "0.0.7",
|
|
69
69
|
"write-yaml": "^1.0.0",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"eslint-plugin-promise": "^6.1.1",
|
|
88
88
|
"eslint-plugin-standard": "^4.1.0",
|
|
89
89
|
"mocha": "^10.3.0",
|
|
90
|
-
"nock": "^
|
|
90
|
+
"nock": "^14.0.0-beta.19",
|
|
91
91
|
"npm-check-updates": "^16.14.15",
|
|
92
92
|
"nyc": "^15.1.0",
|
|
93
93
|
"rollup": "2.79.1",
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
const request = require('request')
|
|
2
1
|
const express = require('express')
|
|
3
2
|
const bodyParser = require('body-parser')
|
|
4
3
|
const _ = require('lodash')
|
|
@@ -13,32 +12,39 @@ const jokes = [
|
|
|
13
12
|
'A blonde was bragging about her knowledge of state capitals. She proudly says, Go ahead, ask me, I know all of them. A friend says, OK, what\'s the capital of Wisconsin? The blonde replies, Oh, that\'s easy: W.'
|
|
14
13
|
]
|
|
15
14
|
|
|
16
|
-
sendAsyncText = async (req, res, text) => {
|
|
15
|
+
const sendAsyncText = async (req, res, text) => {
|
|
17
16
|
const callbackUri = req.body.callbackUri
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
try {
|
|
19
|
+
const response = await fetch(callbackUri, {
|
|
21
20
|
method: 'POST',
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
headers: {
|
|
22
|
+
'Content-Type': 'application/json'
|
|
23
|
+
},
|
|
24
|
+
body: JSON.stringify({
|
|
24
25
|
conversationId: req.body.conversationId,
|
|
25
26
|
responses: [
|
|
26
27
|
{
|
|
27
28
|
text
|
|
28
29
|
}
|
|
29
30
|
]
|
|
30
|
-
}
|
|
31
|
-
json: true
|
|
32
|
-
}, (err, response, body) => {
|
|
33
|
-
if (err) {
|
|
34
|
-
console.log('failed async response: ' + err)
|
|
35
|
-
reject(err)
|
|
36
|
-
} else {
|
|
37
|
-
console.log('async response got response ' + response.statusCode)
|
|
38
|
-
resolve()
|
|
39
|
-
}
|
|
31
|
+
})
|
|
40
32
|
})
|
|
41
|
-
|
|
33
|
+
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
const error = `Failed async response: ${response.status} ${response.statusText}`
|
|
36
|
+
console.log(error)
|
|
37
|
+
// just backward compatibility. Currently I get 401 error, but the chat itself is working.
|
|
38
|
+
// If I activate this, then the chat will not work at all.
|
|
39
|
+
// I suppose api key is not good,
|
|
40
|
+
// throw new Error(error);
|
|
41
|
+
} else {
|
|
42
|
+
console.log('Async response got response ' + response.status)
|
|
43
|
+
}
|
|
44
|
+
} catch (err) {
|
|
45
|
+
console.error('Error in sendAsyncText:', err.message)
|
|
46
|
+
throw err
|
|
47
|
+
}
|
|
42
48
|
}
|
|
43
49
|
|
|
44
50
|
app.post('/joke', async (req, res) => {
|
|
@@ -55,7 +61,7 @@ app.post('/joke', async (req, res) => {
|
|
|
55
61
|
responses: [
|
|
56
62
|
{
|
|
57
63
|
text: 'ok, not funny'
|
|
58
|
-
}
|
|
64
|
+
}
|
|
59
65
|
]
|
|
60
66
|
})
|
|
61
67
|
})
|
package/src/Capabilities.js
CHANGED
|
@@ -56,6 +56,7 @@ module.exports = {
|
|
|
56
56
|
SIMPLEREST_HEADERS_TEMPLATE: 'SIMPLEREST_HEADERS_TEMPLATE',
|
|
57
57
|
SIMPLEREST_BODY_TEMPLATE: 'SIMPLEREST_BODY_TEMPLATE',
|
|
58
58
|
SIMPLEREST_BODY_RAW: 'SIMPLEREST_BODY_RAW',
|
|
59
|
+
SIMPLEREST_BODY_FROM_JSON: 'SIMPLEREST_BODY_FROM_JSON',
|
|
59
60
|
SIMPLEREST_START_HOOK: 'SIMPLEREST_START_HOOK',
|
|
60
61
|
SIMPLEREST_STOP_HOOK: 'SIMPLEREST_STOP_HOOK',
|
|
61
62
|
SIMPLEREST_REQUEST_HOOK: 'SIMPLEREST_REQUEST_HOOK',
|
|
@@ -133,6 +134,8 @@ module.exports = {
|
|
|
133
134
|
SCRIPTING_CSV_UTTERANCE_STARTROW_HEADER: 'SCRIPTING_CSV_UTTERANCE_STARTROW_HEADER',
|
|
134
135
|
SCRIPTING_CSV_UTTERANCE_STOP_ON_EMPTY: 'SCRIPTING_CSV_UTTERANCE_STOP_ON_EMPTY',
|
|
135
136
|
SCRIPTING_NORMALIZE_TEXT: 'SCRIPTING_NORMALIZE_TEXT',
|
|
137
|
+
SCRIPTING_NORMALIZE_TEXT_REMOVE_CHARACTERES: 'SCRIPTING_NORMALIZE_TEXT_REMOVE_CHARACTERES',
|
|
138
|
+
SCRIPTING_NORMALIZE_TEXT_REMOVE_REGEXP: 'SCRIPTING_NORMALIZE_TEXT_REMOVE_REGEXP',
|
|
136
139
|
SCRIPTING_ENABLE_MEMORY: 'SCRIPTING_ENABLE_MEMORY',
|
|
137
140
|
SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS: 'SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS',
|
|
138
141
|
SCRIPTING_ENABLE_SKIP_ASSERT_ERRORS: 'SCRIPTING_ENABLE_SKIP_ASSERT_ERRORS',
|
|
@@ -3,7 +3,6 @@ const async = require('async')
|
|
|
3
3
|
const rimraf = require('rimraf')
|
|
4
4
|
const Bottleneck = require('bottleneck')
|
|
5
5
|
const _ = require('lodash')
|
|
6
|
-
const request = require('request')
|
|
7
6
|
const debug = require('debug')('botium-connector-BaseContainer')
|
|
8
7
|
|
|
9
8
|
const Events = require('../Events')
|
|
@@ -239,7 +238,7 @@ module.exports = class BaseContainer {
|
|
|
239
238
|
|
|
240
239
|
async _RunCustomHook (name, hook, args) {
|
|
241
240
|
try {
|
|
242
|
-
await executeHook(this.caps, hook, Object.assign({ container: this,
|
|
241
|
+
await executeHook(this.caps, hook, Object.assign({ container: this, fetch }, args))
|
|
243
242
|
} catch (err) {
|
|
244
243
|
debug(`_RunCustomHook ${name} finished with error: ${err.message || util.inspect(err)}`)
|
|
245
244
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const util = require('util')
|
|
2
2
|
const async = require('async')
|
|
3
|
-
const request = require('request')
|
|
4
3
|
const Mustache = require('mustache')
|
|
5
4
|
const jp = require('jsonpath')
|
|
6
5
|
const mime = require('mime-types')
|
|
@@ -8,6 +7,7 @@ const { v4: uuidv4 } = require('uuid')
|
|
|
8
7
|
const Redis = require('ioredis')
|
|
9
8
|
const _ = require('lodash')
|
|
10
9
|
const debug = require('debug')('botium-connector-simplerest')
|
|
10
|
+
const { ProxyAgent, Agent } = require('undici')
|
|
11
11
|
|
|
12
12
|
const { startProxy } = require('../../grid/inbound/proxy')
|
|
13
13
|
const botiumUtils = require('../../helpers/Utils')
|
|
@@ -77,6 +77,17 @@ module.exports = class SimpleRestContainer {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
Build () {
|
|
80
|
+
const agentOptions = {
|
|
81
|
+
connect: {
|
|
82
|
+
rejectUnauthorized: !!this.caps[Capabilities.SIMPLEREST_STRICT_SSL] // Equivalent to strictSSL of request module
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (this.caps[Capabilities.SIMPLEREST_PROXY_URL]) {
|
|
86
|
+
this.dispatcher = new ProxyAgent(this.caps[Capabilities.SIMPLEREST_PROXY_URL], agentOptions)
|
|
87
|
+
} else {
|
|
88
|
+
this.dispatcher = new Agent(agentOptions)
|
|
89
|
+
}
|
|
90
|
+
|
|
80
91
|
return this._buildInbound()
|
|
81
92
|
}
|
|
82
93
|
|
|
@@ -235,6 +246,31 @@ module.exports = class SimpleRestContainer {
|
|
|
235
246
|
return this._cleanInbound()
|
|
236
247
|
}
|
|
237
248
|
|
|
249
|
+
_fetchify (requestOptions) {
|
|
250
|
+
requestOptions.signal = AbortSignal.timeout(requestOptions.timeout)
|
|
251
|
+
delete requestOptions.timeout
|
|
252
|
+
|
|
253
|
+
if (requestOptions.body && !_.isString(requestOptions.body)) {
|
|
254
|
+
requestOptions.body = JSON.stringify(requestOptions.body)
|
|
255
|
+
if (!requestOptions.headers) requestOptions.headers = {}
|
|
256
|
+
if (!requestOptions.headers['Content-Type'] && !requestOptions.headers['content-type']) {
|
|
257
|
+
requestOptions.headers['Content-Type'] = 'application/json'
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (requestOptions.form) {
|
|
262
|
+
if (requestOptions.body) {
|
|
263
|
+
debug('Request.form and request.body are mutually exclusive')
|
|
264
|
+
}
|
|
265
|
+
requestOptions.body = new URLSearchParams(requestOptions.form).toString()
|
|
266
|
+
// it is set automatically by fetch
|
|
267
|
+
// requestOptions.headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
|
268
|
+
delete requestOptions.form
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return requestOptions
|
|
272
|
+
}
|
|
273
|
+
|
|
238
274
|
// Separated just for better module testing
|
|
239
275
|
async _processBodyAsync (body, headers, isFromUser, updateContext) {
|
|
240
276
|
const p = async () => {
|
|
@@ -511,12 +547,25 @@ module.exports = class SimpleRestContainer {
|
|
|
511
547
|
|
|
512
548
|
this.waitProcessQueue = []
|
|
513
549
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
550
|
+
try {
|
|
551
|
+
fetch(requestOptions.uri, requestOptions).then(async (bodyRaw) => {
|
|
552
|
+
let body
|
|
553
|
+
try {
|
|
554
|
+
if (bodyRaw.headers.get('content-type').includes('application/json')) {
|
|
555
|
+
try {
|
|
556
|
+
body = await bodyRaw.json()
|
|
557
|
+
} catch (err) {
|
|
558
|
+
body = await bodyRaw.text()
|
|
559
|
+
debug(`failed to parse body as text, using text instead: ${body}`)
|
|
560
|
+
}
|
|
561
|
+
} else {
|
|
562
|
+
body = await bodyRaw.text()
|
|
563
|
+
}
|
|
564
|
+
} catch (err) {
|
|
565
|
+
return reject(new Error(`cant parse body: ${err.message}`))
|
|
566
|
+
}
|
|
567
|
+
if (!bodyRaw.ok) {
|
|
568
|
+
debug(`got error response: ${bodyRaw.status}/${bodyRaw.statusText}`)
|
|
520
569
|
if (debug.enabled && body) {
|
|
521
570
|
debug(botiumUtils.shortenJsonString(body))
|
|
522
571
|
}
|
|
@@ -524,40 +573,45 @@ module.exports = class SimpleRestContainer {
|
|
|
524
573
|
const jsonBody = botiumUtils.toJsonWeak(body)
|
|
525
574
|
const errKey = Object.keys(jsonBody).find(k => k.startsWith('err') || k.startsWith('fail'))
|
|
526
575
|
if (errKey) {
|
|
527
|
-
return reject(new BotiumError(`got error response: ${
|
|
576
|
+
return reject(new BotiumError(`got error response: ${bodyRaw.status}/${bodyRaw.statusText} - ${jsonBody[errKey]}`, {
|
|
528
577
|
message: botiumUtils.shortenJsonString(body)
|
|
529
578
|
}))
|
|
530
579
|
}
|
|
531
580
|
}
|
|
532
|
-
return reject(new Error(`got error response: ${
|
|
581
|
+
return reject(new Error(`got error response: ${bodyRaw.status}/${bodyRaw.statusText}`))
|
|
533
582
|
}
|
|
534
|
-
|
|
535
583
|
if (body) {
|
|
536
|
-
debug(`got response code: ${
|
|
537
|
-
this._storeCookiesFromResponse(
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
584
|
+
debug(`got response code: ${bodyRaw.status}/${bodyRaw.statusText}, body: ${botiumUtils.shortenJsonString(body)}, headers: ${botiumUtils.shortenJsonString(bodyRaw.headers)}`)
|
|
585
|
+
this._storeCookiesFromResponse(bodyRaw)
|
|
586
|
+
|
|
587
|
+
this._parseResponseBody(body)
|
|
588
|
+
.then((parsedBody) => {
|
|
589
|
+
body = parsedBody
|
|
590
|
+
if (body) {
|
|
591
|
+
this._processBodyAsync(body, bodyRaw.headers, isFromUser, updateContext).then(() => resolve(this)).then(() => this._emptyWaitProcessQueue())
|
|
592
|
+
} else {
|
|
593
|
+
debug('ignoring response body (no string and no JSON object)')
|
|
594
|
+
resolve(this)
|
|
595
|
+
this._emptyWaitProcessQueue()
|
|
596
|
+
}
|
|
597
|
+
})
|
|
598
|
+
.catch((err) => {
|
|
599
|
+
debug(`ignoring not JSON formatted response body: ${err.message}`)
|
|
600
|
+
resolve(this)
|
|
601
|
+
this._emptyWaitProcessQueue()
|
|
602
|
+
})
|
|
554
603
|
} else {
|
|
555
|
-
debug(`got response code: ${
|
|
604
|
+
debug(`got response code: ${bodyRaw.status}/${bodyRaw.statusText}, empty body`)
|
|
556
605
|
resolve(this)
|
|
557
606
|
this._emptyWaitProcessQueue()
|
|
558
607
|
}
|
|
559
|
-
}
|
|
560
|
-
|
|
608
|
+
}).catch((err) => {
|
|
609
|
+
// rest request failed: fetch failed - Cause code: ECONNREFUSED - Cause message: connect ECONNREFUSED 127.0.0.1:3006
|
|
610
|
+
return reject(new Error(`rest request failed: ${err.message}${err.cause && err.cause.code ? ' - Cause code: ' + err.cause.code : ''}${err.cause && err.cause.message ? ' - Cause message: ' + err.cause.message : ''}`))
|
|
611
|
+
})
|
|
612
|
+
} catch (err) {
|
|
613
|
+
return reject(new Error(`rest request failed: ${err.message}`))
|
|
614
|
+
}
|
|
561
615
|
}))
|
|
562
616
|
}
|
|
563
617
|
|
|
@@ -580,7 +634,6 @@ module.exports = class SimpleRestContainer {
|
|
|
580
634
|
const requestOptions = {
|
|
581
635
|
uri,
|
|
582
636
|
method: this._getCapValue(Capabilities.SIMPLEREST_VERB) || this._getCapValue(Capabilities.SIMPLEREST_METHOD),
|
|
583
|
-
followAllRedirects: true,
|
|
584
637
|
timeout
|
|
585
638
|
}
|
|
586
639
|
|
|
@@ -592,7 +645,14 @@ module.exports = class SimpleRestContainer {
|
|
|
592
645
|
throw new Error(`composing headers from SIMPLEREST_HEADERS_TEMPLATE failed (${err.message})`)
|
|
593
646
|
}
|
|
594
647
|
}
|
|
595
|
-
|
|
648
|
+
// It is possible to mix json, and non-json request messages. So it can happen that both
|
|
649
|
+
// SIMPLEREST_BODY_FROM_JSON and SIMPLEREST_BODY_TEMPLATE are set
|
|
650
|
+
if (this.caps[Capabilities.SIMPLEREST_BODY_FROM_JSON] && msg.sourceData && Object.keys(msg.sourceData).length > 0) {
|
|
651
|
+
requestOptions.body = msg.sourceData
|
|
652
|
+
requestOptions.json = true
|
|
653
|
+
if (!requestOptions.headers) requestOptions.headers = {}
|
|
654
|
+
requestOptions.headers['Content-Type'] = 'application/json'
|
|
655
|
+
} else if (this.caps[Capabilities.SIMPLEREST_BODY_TEMPLATE]) {
|
|
596
656
|
const bodyRaw = this._getCapValue(Capabilities.SIMPLEREST_BODY_RAW)
|
|
597
657
|
if (bodyRaw) {
|
|
598
658
|
this.view.msg.messageText = nonEncodedMessage
|
|
@@ -605,6 +665,10 @@ module.exports = class SimpleRestContainer {
|
|
|
605
665
|
if (requestOptions.json && (!requestOptions.body || Object.keys(requestOptions.body).length === 0)) {
|
|
606
666
|
debug(`warning: requestOptions.body content seems to be empty - ${requestOptions.body} - capability: "${this.caps[Capabilities.SIMPLEREST_BODY_TEMPLATE]}"`)
|
|
607
667
|
}
|
|
668
|
+
if (!bodyRaw) {
|
|
669
|
+
if (!requestOptions.headers) requestOptions.headers = {}
|
|
670
|
+
requestOptions.headers['Content-Type'] = 'application/json'
|
|
671
|
+
}
|
|
608
672
|
} catch (err) {
|
|
609
673
|
throw new Error(`composing body from SIMPLEREST_BODY_TEMPLATE failed (${err.message})`)
|
|
610
674
|
}
|
|
@@ -646,48 +710,53 @@ module.exports = class SimpleRestContainer {
|
|
|
646
710
|
}
|
|
647
711
|
}
|
|
648
712
|
this._addRequestOptions(requestOptions)
|
|
713
|
+
this._fetchify(requestOptions)
|
|
649
714
|
await executeHook(this.caps, this.requestHook, Object.assign({ requestOptions }, this.view))
|
|
650
715
|
this._addRequestCookies(requestOptions)
|
|
651
716
|
|
|
652
717
|
return requestOptions
|
|
653
718
|
}
|
|
654
719
|
|
|
655
|
-
async _waitForUrlResponse (
|
|
720
|
+
async _waitForUrlResponse (httpConfig, retries) {
|
|
656
721
|
const timeout = ms => new Promise(resolve => setTimeout(resolve, ms))
|
|
657
722
|
|
|
658
723
|
let tries = 0
|
|
659
724
|
|
|
660
725
|
while (true) {
|
|
661
|
-
debug(`_waitForUrlResponse checking url ${
|
|
726
|
+
debug(`_waitForUrlResponse checking url ${httpConfig.uri} before proceed`)
|
|
662
727
|
if (tries > retries) {
|
|
663
728
|
throw new Error(`Failed to ping bot after ${retries} retries`)
|
|
664
729
|
}
|
|
665
730
|
tries++
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
731
|
+
let bodyRaw
|
|
732
|
+
let body
|
|
733
|
+
let err
|
|
734
|
+
try {
|
|
735
|
+
bodyRaw = await this.bottleneck(() => fetch(httpConfig.uri, httpConfig))
|
|
736
|
+
body = await ((httpConfig.json) ? bodyRaw.json() : bodyRaw.text())
|
|
737
|
+
} catch (e) {
|
|
738
|
+
err = e
|
|
739
|
+
}
|
|
671
740
|
if (err) {
|
|
672
|
-
debug(`_waitForUrlResponse error on url check ${
|
|
741
|
+
debug(`_waitForUrlResponse error on url check ${httpConfig.uri}: ${err}`)
|
|
673
742
|
if (tries <= retries) {
|
|
674
|
-
await timeout(
|
|
743
|
+
await timeout(httpConfig.timeout)
|
|
675
744
|
}
|
|
676
|
-
} else if (
|
|
677
|
-
debug(`_waitForUrlResponse on url check ${
|
|
745
|
+
} else if (!bodyRaw.ok) {
|
|
746
|
+
debug(`_waitForUrlResponse on url check ${httpConfig.uri} got error response: ${bodyRaw.status}/${bodyRaw.statusText}`)
|
|
678
747
|
if (debug.enabled && body) {
|
|
679
748
|
debug(botiumUtils.shortenJsonString(body))
|
|
680
749
|
}
|
|
681
750
|
if (tries <= retries) {
|
|
682
|
-
await timeout(
|
|
751
|
+
await timeout(httpConfig.timeout)
|
|
683
752
|
}
|
|
684
753
|
} else {
|
|
685
|
-
debug(`_waitForUrlResponse success on url check ${
|
|
686
|
-
this._storeCookiesFromResponse(
|
|
754
|
+
debug(`_waitForUrlResponse success on url check ${httpConfig.uri}: ${bodyRaw.status}/${bodyRaw.statusText}`)
|
|
755
|
+
this._storeCookiesFromResponse(bodyRaw)
|
|
687
756
|
if (debug.enabled && body) {
|
|
688
|
-
debug(`body: ${botiumUtils.shortenJsonString(body)}, headers: ${botiumUtils.shortenJsonString(
|
|
757
|
+
debug(`body: ${botiumUtils.shortenJsonString(body)}, headers: ${botiumUtils.shortenJsonString(bodyRaw.headers)}`)
|
|
689
758
|
}
|
|
690
|
-
return { body, headers:
|
|
759
|
+
return { body, headers: bodyRaw.headers }
|
|
691
760
|
}
|
|
692
761
|
}
|
|
693
762
|
}
|
|
@@ -848,7 +917,6 @@ module.exports = class SimpleRestContainer {
|
|
|
848
917
|
const pollConfig = {
|
|
849
918
|
method: verb,
|
|
850
919
|
uri,
|
|
851
|
-
followAllRedirects: true,
|
|
852
920
|
timeout
|
|
853
921
|
}
|
|
854
922
|
if (this.caps[Capabilities.SIMPLEREST_POLL_HEADERS]) {
|
|
@@ -864,13 +932,17 @@ module.exports = class SimpleRestContainer {
|
|
|
864
932
|
try {
|
|
865
933
|
pollConfig.body = this._getMustachedCap(Capabilities.SIMPLEREST_POLL_BODY, !bodyRaw)
|
|
866
934
|
pollConfig.json = !bodyRaw
|
|
935
|
+
if (!bodyRaw) {
|
|
936
|
+
if (!pollConfig.headers) pollConfig.headers = {}
|
|
937
|
+
pollConfig.headers['Content-Type'] = 'application/json'
|
|
938
|
+
}
|
|
867
939
|
} catch (err) {
|
|
868
940
|
debug(`_runPolling: composing body from SIMPLEREST_POLL_BODY failed (${err.message})`)
|
|
869
941
|
return
|
|
870
942
|
}
|
|
871
943
|
}
|
|
872
944
|
this._addRequestOptions(pollConfig)
|
|
873
|
-
|
|
945
|
+
this._fetchify(pollConfig)
|
|
874
946
|
try {
|
|
875
947
|
await executeHook(this.caps, this.pollRequestHook, Object.assign({ requestOptions: pollConfig }, this.view))
|
|
876
948
|
} catch (err) {
|
|
@@ -879,34 +951,34 @@ module.exports = class SimpleRestContainer {
|
|
|
879
951
|
}
|
|
880
952
|
this._addRequestCookies(pollConfig)
|
|
881
953
|
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
setTimeout(() => this._processBodyAsync(body, response.headers, true, !!this.caps[Capabilities.SIMPLEREST_POLL_UPDATE_CONTEXT]), 0)
|
|
902
|
-
} else {
|
|
903
|
-
debug('_runPolling: ignoring response body (no string and no JSON object)')
|
|
904
|
-
}
|
|
954
|
+
try {
|
|
955
|
+
const bodyRaw = await fetch(pollConfig.uri, pollConfig)
|
|
956
|
+
let body = await ((pollConfig.json) ? bodyRaw.json() : bodyRaw.text())
|
|
957
|
+
if (!bodyRaw.ok) {
|
|
958
|
+
debug(`_runPolling: got error response: ${bodyRaw.status}/${bodyRaw.statusText}, request: ${JSON.stringify(pollConfig)}`)
|
|
959
|
+
if (debug.enabled && body) {
|
|
960
|
+
debug(botiumUtils.shortenJsonString(body))
|
|
961
|
+
}
|
|
962
|
+
} else if (body) {
|
|
963
|
+
debug(`_runPolling: got response code: ${bodyRaw.status}/${bodyRaw.statusText}, body: ${botiumUtils.shortenJsonString(body)}, headers: ${botiumUtils.shortenJsonString(bodyRaw.headers)}`)
|
|
964
|
+
this._storeCookiesFromResponse(bodyRaw)
|
|
965
|
+
try {
|
|
966
|
+
body = await this._parseResponseBody(body)
|
|
967
|
+
} catch (err) {
|
|
968
|
+
debug(`_runPolling: ignoring not JSON formatted response body: ${err.message}`)
|
|
969
|
+
return
|
|
970
|
+
}
|
|
971
|
+
if (body) {
|
|
972
|
+
setTimeout(() => this._processBodyAsync(body, bodyRaw.headers, true, !!this.caps[Capabilities.SIMPLEREST_POLL_UPDATE_CONTEXT]), 0)
|
|
905
973
|
} else {
|
|
906
|
-
debug(
|
|
974
|
+
debug('_runPolling: ignoring response body (no string and no JSON object)')
|
|
907
975
|
}
|
|
976
|
+
} else {
|
|
977
|
+
debug(`_runPolling: got response code: ${bodyRaw.status}/${bodyRaw.statusText}, empty body`)
|
|
908
978
|
}
|
|
909
|
-
})
|
|
979
|
+
} catch (err) {
|
|
980
|
+
debug(`_runPolling: rest request failed: ${err.message}, request: ${JSON.stringify(pollConfig)}`)
|
|
981
|
+
}
|
|
910
982
|
}
|
|
911
983
|
}
|
|
912
984
|
|
|
@@ -932,7 +1004,6 @@ module.exports = class SimpleRestContainer {
|
|
|
932
1004
|
const httpConfig = {
|
|
933
1005
|
method: verb,
|
|
934
1006
|
uri,
|
|
935
|
-
followAllRedirects: true,
|
|
936
1007
|
timeout
|
|
937
1008
|
}
|
|
938
1009
|
if (this.caps[`${capPrefix}_HEADERS`]) {
|
|
@@ -952,6 +1023,7 @@ module.exports = class SimpleRestContainer {
|
|
|
952
1023
|
}
|
|
953
1024
|
}
|
|
954
1025
|
this._addRequestOptions(httpConfig)
|
|
1026
|
+
this._fetchify(httpConfig)
|
|
955
1027
|
await executeHook(this.caps, this.requestHooks[capPrefix], Object.assign({ requestOptions: httpConfig }, this.view))
|
|
956
1028
|
this._addRequestCookies(httpConfig)
|
|
957
1029
|
|
|
@@ -962,9 +1034,8 @@ module.exports = class SimpleRestContainer {
|
|
|
962
1034
|
}
|
|
963
1035
|
|
|
964
1036
|
_addRequestOptions (httpConfig) {
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
httpConfig.proxy = this.caps[Capabilities.SIMPLEREST_PROXY_URL]
|
|
1037
|
+
if (this.dispatcher) {
|
|
1038
|
+
httpConfig.dispatcher = this.dispatcher
|
|
968
1039
|
}
|
|
969
1040
|
if (this.caps[Capabilities.SIMPLEREST_EXTRA_OPTIONS]) {
|
|
970
1041
|
_.merge(httpConfig, this.caps[Capabilities.SIMPLEREST_EXTRA_OPTIONS])
|
|
@@ -979,25 +1050,23 @@ module.exports = class SimpleRestContainer {
|
|
|
979
1050
|
if (!requestOptions.headers) {
|
|
980
1051
|
requestOptions.headers = {}
|
|
981
1052
|
}
|
|
982
|
-
|
|
1053
|
+
if (this.cookies[url.host]) {
|
|
1054
|
+
requestOptions.headers.Cookie = requestOptions.headers.Cookie ? `${requestOptions.headers.Cookie}; ${this.cookies[url.host]}` : this.cookies[url.host]
|
|
1055
|
+
}
|
|
983
1056
|
}
|
|
984
1057
|
|
|
985
1058
|
_storeCookiesFromResponse (response) {
|
|
986
1059
|
if (!this.caps[Capabilities.SIMPLEREST_COOKIE_REPLICATION] || !response) {
|
|
987
1060
|
return
|
|
988
1061
|
}
|
|
989
|
-
const responseCookies = response.headers
|
|
1062
|
+
const responseCookies = response.headers.get('set-cookie')
|
|
990
1063
|
if (!responseCookies) {
|
|
991
1064
|
return
|
|
992
1065
|
}
|
|
993
|
-
const host =
|
|
994
|
-
let cookie
|
|
995
|
-
responseCookies.forEach(cookieString => {
|
|
996
|
-
cookie = cookie ? `${cookie}; ${cookieString}` : cookieString
|
|
997
|
-
})
|
|
1066
|
+
const host = response?.url ? new URL(response.url).host : null
|
|
998
1067
|
|
|
999
|
-
if (
|
|
1000
|
-
this.cookies[host] =
|
|
1068
|
+
if (host) {
|
|
1069
|
+
this.cookies[host] = responseCookies
|
|
1001
1070
|
}
|
|
1002
1071
|
}
|
|
1003
1072
|
}
|
package/src/scripting/Convo.js
CHANGED
|
@@ -597,7 +597,7 @@ class Convo {
|
|
|
597
597
|
}
|
|
598
598
|
Object.assign(scriptingMemory, scriptingMemoryUpdate)
|
|
599
599
|
try {
|
|
600
|
-
await this.scriptingEvents.assertConvoStep({ convo: this, convoStep, container, scriptingMemory, botMsg, transcript, transcriptStep })
|
|
600
|
+
await this.scriptingEvents.assertConvoStep({ convo: this, convoStep, container, scriptingMemory, botMsg, transcript, transcriptStep, transcriptSteps })
|
|
601
601
|
await this.scriptingEvents.onBotEnd({ convo: this, convoStep, container, scriptingMemory, botMsg, transcript, transcriptStep })
|
|
602
602
|
optionalStepAssertionError = false
|
|
603
603
|
} catch (err) {
|
|
@@ -825,7 +825,7 @@ class Convo {
|
|
|
825
825
|
}
|
|
826
826
|
|
|
827
827
|
_checkNormalizeText (container, str) {
|
|
828
|
-
return normalizeText(str,
|
|
828
|
+
return normalizeText(str, container.caps)
|
|
829
829
|
}
|
|
830
830
|
|
|
831
831
|
expandPartialConvos () {
|