wingbot 3.32.0-alpha.1 → 3.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -6
- package/src/BotApp.js +21 -6
- package/src/BuildRouter.js +28 -11
- package/src/ConversationTester.js +2 -2
- package/src/Request.js +14 -1
- package/src/Responder.js +5 -1
- package/src/ReturnSender.js +66 -20
- package/src/Router.js +1 -1
- package/src/Tester.js +42 -5
- package/src/features.js +6 -0
- package/src/resolvers/expected.js +10 -1
- package/src/utils/customFn.js +0 -8
- package/src/utils/getUpdate.js +2 -2
- package/src/utils/quickReplies.js +3 -2
- package/src/utils/wrapPluginFunction.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wingbot",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.33.0",
|
|
4
4
|
"description": "Enterprise Messaging Bot Conversation Engine",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"doc": "npm run doc:gql && node ./bin/makeApiDoc.js && cpy ./CHANGELOG.md ./doc && gitbook install ./doc && gitbook build ./doc && rimraf -rf ./docs && rimraf --rf ./doc/CHANGELOG.md && move-cli ./doc/_book ./docs",
|
|
10
10
|
"test": "npm run test:lint && npm run test:coverage && npm run test:coverage:threshold",
|
|
11
11
|
"test:coverage": "nyc --reporter=html mocha ./test && nyc report",
|
|
12
|
-
"test:coverage:threshold": "nyc check-coverage --lines
|
|
12
|
+
"test:coverage:threshold": "nyc check-coverage --lines 91 --functions 90 --branches 82",
|
|
13
13
|
"test:backend": "mocha ./test",
|
|
14
14
|
"test:lint": "eslint --ext .js src test *.js plugins"
|
|
15
15
|
},
|
|
@@ -57,14 +57,12 @@
|
|
|
57
57
|
"graphql": "^15.8.0",
|
|
58
58
|
"jsonwebtoken": "^8.5.1",
|
|
59
59
|
"node-fetch": "^2.6.7",
|
|
60
|
-
"path-to-regexp": "^6.2.
|
|
60
|
+
"path-to-regexp": "^6.2.1",
|
|
61
61
|
"uuid": "^8.3.2",
|
|
62
62
|
"webalize": "^0.1.0"
|
|
63
63
|
},
|
|
64
64
|
"optionalDependencies": {
|
|
65
65
|
"axios": "^0.21.1",
|
|
66
|
-
"handlebars": "^4.0.0"
|
|
67
|
-
"request": "^2.88.0",
|
|
68
|
-
"request-promise-native": "^1.0.7"
|
|
66
|
+
"handlebars": "^4.0.0"
|
|
69
67
|
}
|
|
70
68
|
}
|
package/src/BotApp.js
CHANGED
|
@@ -23,6 +23,7 @@ const DEFAULT_API_URL = 'https://orchestrator-api.wingbot.ai';
|
|
|
23
23
|
|
|
24
24
|
/** @typedef {import('./CallbackAuditLog')} AuditLog */
|
|
25
25
|
/** @typedef {import('./BotAppSender').TlsOptions} TlsOptions */
|
|
26
|
+
/** @typedef {import('./ReturnSender').ReturnSenderOptions} ReturnSenderOptions */
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
29
|
* @typedef {object} BotAppOptions
|
|
@@ -35,7 +36,7 @@ const DEFAULT_API_URL = 'https://orchestrator-api.wingbot.ai';
|
|
|
35
36
|
* @prop {AuditLog} [auditLog]
|
|
36
37
|
* @prop {TlsOptions} [tls]
|
|
37
38
|
*
|
|
38
|
-
* @typedef {ProcessorOptions & BotAppOptions} Options
|
|
39
|
+
* @typedef {ProcessorOptions & BotAppOptions & ReturnSenderOptions} Options
|
|
39
40
|
*/
|
|
40
41
|
|
|
41
42
|
/**
|
|
@@ -66,9 +67,20 @@ class BotApp {
|
|
|
66
67
|
preferSynchronousResponse = false,
|
|
67
68
|
auditLog = null,
|
|
68
69
|
tls = null,
|
|
70
|
+
|
|
71
|
+
textFilter,
|
|
72
|
+
logStandbyEvents,
|
|
73
|
+
confidentInputFilter,
|
|
74
|
+
|
|
69
75
|
...processorOptions
|
|
70
76
|
} = options;
|
|
71
77
|
|
|
78
|
+
this._returnSenderOptions = {
|
|
79
|
+
textFilter,
|
|
80
|
+
logStandbyEvents,
|
|
81
|
+
confidentInputFilter
|
|
82
|
+
};
|
|
83
|
+
|
|
72
84
|
this._secret = Promise.resolve(secret);
|
|
73
85
|
this._fetch = fetch; // mock
|
|
74
86
|
this._appId = appId;
|
|
@@ -197,16 +209,18 @@ class BotApp {
|
|
|
197
209
|
sync = false,
|
|
198
210
|
headers = {}
|
|
199
211
|
) {
|
|
200
|
-
const
|
|
212
|
+
const setResponseToMid = message.response_to_mid || message.mid;
|
|
201
213
|
|
|
202
214
|
if (sync || this._preferSynchronousResponse) {
|
|
203
|
-
const
|
|
215
|
+
const options = this._returnSenderOptions;
|
|
216
|
+
const sender = new ReturnSender(options, senderId, message, this._senderLogger);
|
|
204
217
|
sender.propagatesWaitEvent = true;
|
|
205
218
|
const res = await this._processor.processMessage(message, pageId, sender, { appId });
|
|
206
219
|
await this._processSenderResponses(sender, senderId, pageId, headers);
|
|
207
220
|
|
|
208
221
|
return {
|
|
209
222
|
status: res.status,
|
|
223
|
+
// yes, it should be just mid
|
|
210
224
|
response_to_mid: message.mid,
|
|
211
225
|
messaging: sender.responses
|
|
212
226
|
.map((response) => {
|
|
@@ -216,8 +230,8 @@ class BotApp {
|
|
|
216
230
|
}
|
|
217
231
|
|
|
218
232
|
// attach response_to_mid
|
|
219
|
-
if (typeof response.response_to_mid === 'undefined' &&
|
|
220
|
-
Object.assign(response, { response_to_mid:
|
|
233
|
+
if (typeof response.response_to_mid === 'undefined' && setResponseToMid) {
|
|
234
|
+
Object.assign(response, { response_to_mid: setResponseToMid });
|
|
221
235
|
}
|
|
222
236
|
|
|
223
237
|
return response;
|
|
@@ -226,11 +240,12 @@ class BotApp {
|
|
|
226
240
|
}
|
|
227
241
|
|
|
228
242
|
const options = {
|
|
243
|
+
...this._returnSenderOptions,
|
|
229
244
|
apiUrl: this._apiUrl,
|
|
230
245
|
pageId,
|
|
231
246
|
appId,
|
|
232
247
|
secret,
|
|
233
|
-
mid,
|
|
248
|
+
mid: setResponseToMid,
|
|
234
249
|
fetch: this._fetch,
|
|
235
250
|
tls: this._tls
|
|
236
251
|
};
|
package/src/BuildRouter.js
CHANGED
|
@@ -159,7 +159,6 @@ class BuildRouter extends Router {
|
|
|
159
159
|
* @param {ConfigStorage} [context.configStorage] - function, that translates links globally
|
|
160
160
|
* @param {boolean} [context.allowForbiddenSnippetWords] - disable security rule
|
|
161
161
|
* @param {RouteConfig[]} [context.routeConfigs] - list of disabled routes
|
|
162
|
-
* @param {object} [context.config] - context data
|
|
163
162
|
* @param {object} [context.configuration]
|
|
164
163
|
* @param {fetch} [fetchFn] - override a request function
|
|
165
164
|
* @example
|
|
@@ -427,7 +426,8 @@ class BuildRouter extends Router {
|
|
|
427
426
|
this._configTs = 0;
|
|
428
427
|
}
|
|
429
428
|
if (this._prebuiltGlobalIntents !== null) {
|
|
430
|
-
this.globalIntents
|
|
429
|
+
this.globalIntents.clear();
|
|
430
|
+
this._prebuiltGlobalIntents.forEach(([k, v]) => this.globalIntents.set(k, v));
|
|
431
431
|
}
|
|
432
432
|
}
|
|
433
433
|
|
|
@@ -449,7 +449,8 @@ class BuildRouter extends Router {
|
|
|
449
449
|
if (this._prebuiltGlobalIntents === null) {
|
|
450
450
|
this._prebuiltGlobalIntents = Array.from(this.globalIntents.entries());
|
|
451
451
|
} else {
|
|
452
|
-
this.globalIntents
|
|
452
|
+
this.globalIntents.clear();
|
|
453
|
+
this._prebuiltGlobalIntents.forEach(([k, v]) => this.globalIntents.set(k, v));
|
|
453
454
|
}
|
|
454
455
|
|
|
455
456
|
if (this._prebuiltRoutesCount === null) {
|
|
@@ -754,15 +755,21 @@ class BuildRouter extends Router {
|
|
|
754
755
|
nextRouteIsSameResponder = nextRoute.respondsToRouteId === route.respondsToRouteId;
|
|
755
756
|
}
|
|
756
757
|
|
|
758
|
+
const buildInfo = {
|
|
759
|
+
expectedToAddResolver: !!route.expectedPath,
|
|
760
|
+
attachedRouter: false
|
|
761
|
+
};
|
|
762
|
+
|
|
757
763
|
const resolvers = [
|
|
758
764
|
...this._buildRouteHead(route, nextRouteIsSameResponder),
|
|
759
|
-
...this.buildResolvers(route.resolvers, route,
|
|
765
|
+
...this.buildResolvers(route.resolvers, route, buildInfo)
|
|
760
766
|
];
|
|
761
767
|
|
|
762
768
|
if (route.expectedPath) {
|
|
763
769
|
// attach expected before last message, if there is
|
|
764
770
|
resolvers.push(expected({
|
|
765
|
-
path: route.expectedPath
|
|
771
|
+
path: route.expectedPath,
|
|
772
|
+
attachedRouter: buildInfo.attachedRouter
|
|
766
773
|
}, {
|
|
767
774
|
isLastIndex: true
|
|
768
775
|
}));
|
|
@@ -790,10 +797,10 @@ class BuildRouter extends Router {
|
|
|
790
797
|
*
|
|
791
798
|
* @param {Resolver[]} resolvers
|
|
792
799
|
* @param {TransformedRoute} route
|
|
793
|
-
* @param {*}
|
|
800
|
+
* @param {*} buildInfo
|
|
794
801
|
* @returns {Middleware[]}
|
|
795
802
|
*/
|
|
796
|
-
buildResolvers (resolvers, route = DUMMY_ROUTE,
|
|
803
|
+
buildResolvers (resolvers, route = DUMMY_ROUTE, buildInfo = {}) {
|
|
797
804
|
const {
|
|
798
805
|
path: ctxPath, isFallback, isResponder, expectedPath, id
|
|
799
806
|
} = route;
|
|
@@ -812,7 +819,7 @@ class BuildRouter extends Router {
|
|
|
812
819
|
|
|
813
820
|
const context = {
|
|
814
821
|
...this._context,
|
|
815
|
-
isLastIndex: lastIndex === i && !expectedToAddResolver,
|
|
822
|
+
isLastIndex: lastIndex === i && !buildInfo.expectedToAddResolver,
|
|
816
823
|
isLastMessage: lastMessageIndex === i,
|
|
817
824
|
router: this,
|
|
818
825
|
linksMap: this._linksMap,
|
|
@@ -824,7 +831,8 @@ class BuildRouter extends Router {
|
|
|
824
831
|
configuration
|
|
825
832
|
};
|
|
826
833
|
|
|
827
|
-
const resFn = this._resolverFactory(resolver, context);
|
|
834
|
+
const resFn = this._resolverFactory(resolver, context, buildInfo);
|
|
835
|
+
|
|
828
836
|
// @ts-ignore
|
|
829
837
|
resFn.configuration = configuration;
|
|
830
838
|
return resFn;
|
|
@@ -835,9 +843,10 @@ class BuildRouter extends Router {
|
|
|
835
843
|
*
|
|
836
844
|
* @param {Resolver} resolver
|
|
837
845
|
* @param {BotContext} context
|
|
846
|
+
* @param {*} buildInfo
|
|
838
847
|
* @returns {Middleware}
|
|
839
848
|
*/
|
|
840
|
-
_resolverFactory (resolver, context) {
|
|
849
|
+
_resolverFactory (resolver, context, buildInfo) {
|
|
841
850
|
const { type } = resolver;
|
|
842
851
|
|
|
843
852
|
if (!this.resources.has(type)) {
|
|
@@ -848,9 +857,17 @@ class BuildRouter extends Router {
|
|
|
848
857
|
|
|
849
858
|
const fn = factoryFn(resolver.params, context, this._plugins);
|
|
850
859
|
|
|
860
|
+
if (fn.reduce) {
|
|
861
|
+
Object.assign(buildInfo, { attachedRouter: true });
|
|
862
|
+
}
|
|
863
|
+
|
|
851
864
|
if ([
|
|
852
865
|
'botbuild.include',
|
|
853
|
-
'botbuild.path'
|
|
866
|
+
'botbuild.path',
|
|
867
|
+
'botbuild.customCode',
|
|
868
|
+
'botbuild.inlineCode',
|
|
869
|
+
'botbuild.plugin',
|
|
870
|
+
'botbuild.postback'
|
|
854
871
|
].includes(type)) {
|
|
855
872
|
return fn;
|
|
856
873
|
}
|
|
@@ -524,7 +524,7 @@ class ConversationTester {
|
|
|
524
524
|
await tester.text(textCase.text);
|
|
525
525
|
|
|
526
526
|
if (textCase.action) {
|
|
527
|
-
tester.passedAction(textCase.action);
|
|
527
|
+
tester.passedAction(textCase.action, true);
|
|
528
528
|
}
|
|
529
529
|
|
|
530
530
|
if (textCase.appId) {
|
|
@@ -623,7 +623,7 @@ class ConversationTester {
|
|
|
623
623
|
if (!this._options.disableAssertActions) {
|
|
624
624
|
passedAction.split('\n')
|
|
625
625
|
.map((a) => (a.trim().match(/^[a-z\-0-9/_]+$/) ? a : tokenize(a)))
|
|
626
|
-
.forEach((a) => a && t.passedAction(a));
|
|
626
|
+
.forEach((a) => a && t.passedAction(a, true));
|
|
627
627
|
}
|
|
628
628
|
|
|
629
629
|
const any = t.any();
|
package/src/Request.js
CHANGED
|
@@ -16,6 +16,7 @@ const {
|
|
|
16
16
|
FEATURE_SSML,
|
|
17
17
|
FEATURE_PHRASES,
|
|
18
18
|
FEATURE_TEXT,
|
|
19
|
+
FEATURE_TRACKING,
|
|
19
20
|
getDefaultFeatureList
|
|
20
21
|
} = require('./features');
|
|
21
22
|
|
|
@@ -259,6 +260,11 @@ class Request {
|
|
|
259
260
|
*/
|
|
260
261
|
this.FEATURE_TEXT = FEATURE_TEXT;
|
|
261
262
|
|
|
263
|
+
/**
|
|
264
|
+
* @constant {string} FEATURE_TRACKING channel supports tracking protocol
|
|
265
|
+
*/
|
|
266
|
+
this.FEATURE_TRACKING = FEATURE_TRACKING;
|
|
267
|
+
|
|
262
268
|
/** @type {object} */
|
|
263
269
|
this.configuration = Object.freeze({});
|
|
264
270
|
}
|
|
@@ -837,7 +843,9 @@ class Request {
|
|
|
837
843
|
* });
|
|
838
844
|
*/
|
|
839
845
|
expectedContext (justOnce = false, includeKeywords = false) {
|
|
840
|
-
const
|
|
846
|
+
const ad = this.actionData();
|
|
847
|
+
const expected = ad._useExpected || this.state._expected;
|
|
848
|
+
const confident = this.state._expectedConfidentInput;
|
|
841
849
|
|
|
842
850
|
const ret = {};
|
|
843
851
|
|
|
@@ -1770,4 +1778,9 @@ Request.FEATURE_PHRASES = FEATURE_PHRASES;
|
|
|
1770
1778
|
*/
|
|
1771
1779
|
Request.FEATURE_TEXT = FEATURE_TEXT;
|
|
1772
1780
|
|
|
1781
|
+
/**
|
|
1782
|
+
* @constant {string} FEATURE_TRACKING channel supports tracking protocol
|
|
1783
|
+
*/
|
|
1784
|
+
Request.FEATURE_TRACKING = FEATURE_TRACKING;
|
|
1785
|
+
|
|
1773
1786
|
module.exports = Request;
|
package/src/Responder.js
CHANGED
|
@@ -528,6 +528,8 @@ class Responder {
|
|
|
528
528
|
if (prepend) Object.assign(prep, { _prepend: true });
|
|
529
529
|
if (justToExisting) Object.assign(prep, { _justToExisting: true });
|
|
530
530
|
|
|
531
|
+
const useCa = this.currentAction();
|
|
532
|
+
|
|
531
533
|
if (actionIsObject) {
|
|
532
534
|
this._quickReplyCollector.push({
|
|
533
535
|
...prep,
|
|
@@ -535,7 +537,8 @@ class Responder {
|
|
|
535
537
|
data: {
|
|
536
538
|
...prep.data,
|
|
537
539
|
...data
|
|
538
|
-
}
|
|
540
|
+
},
|
|
541
|
+
useCa
|
|
539
542
|
});
|
|
540
543
|
} else {
|
|
541
544
|
this._quickReplyCollector.push({
|
|
@@ -543,6 +546,7 @@ class Responder {
|
|
|
543
546
|
action: this.toAbsoluteAction(action),
|
|
544
547
|
title,
|
|
545
548
|
data,
|
|
549
|
+
useCa,
|
|
546
550
|
...prep
|
|
547
551
|
});
|
|
548
552
|
}
|
package/src/ReturnSender.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
'use strict';
|
|
5
5
|
|
|
6
6
|
const ai = require('./Ai');
|
|
7
|
-
const { FEATURE_PHRASES } = require('./features');
|
|
7
|
+
const { FEATURE_PHRASES, FEATURE_TRACKING } = require('./features');
|
|
8
8
|
const { FLAG_DO_NOT_LOG } = require('./flags');
|
|
9
9
|
|
|
10
10
|
/** @typedef {import('./Request')} Request */
|
|
@@ -70,8 +70,10 @@ class ReturnSender {
|
|
|
70
70
|
|
|
71
71
|
this._sequence = 0;
|
|
72
72
|
|
|
73
|
-
this.
|
|
74
|
-
|
|
73
|
+
this._features = Array.isArray(incommingMessage.features) ? incommingMessage.features : ['text'];
|
|
74
|
+
|
|
75
|
+
this._sendLastMessageWithFinish = this._features.includes(FEATURE_PHRASES)
|
|
76
|
+
|| this._features.includes(FEATURE_TRACKING);
|
|
75
77
|
|
|
76
78
|
/**
|
|
77
79
|
* @type {Function}
|
|
@@ -196,9 +198,22 @@ class ReturnSender {
|
|
|
196
198
|
? this.confidentInputFilter
|
|
197
199
|
: this.textFilter;
|
|
198
200
|
|
|
201
|
+
let { message } = payload;
|
|
202
|
+
|
|
203
|
+
if (message && message.voice && message.voice.ssml) {
|
|
204
|
+
message = {
|
|
205
|
+
...message,
|
|
206
|
+
text: message.text ? message.text : message.voice.ssml,
|
|
207
|
+
voice: {
|
|
208
|
+
...message.voice,
|
|
209
|
+
ssml: filter(message.voice.ssml)
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
199
214
|
// text message
|
|
200
|
-
if (
|
|
201
|
-
let { text } =
|
|
215
|
+
if (message && message.text) {
|
|
216
|
+
let { text } = message;
|
|
202
217
|
|
|
203
218
|
if (req && req._anonymizedText) {
|
|
204
219
|
text = req._anonymizedText;
|
|
@@ -207,27 +222,27 @@ class ReturnSender {
|
|
|
207
222
|
return {
|
|
208
223
|
...payload,
|
|
209
224
|
message: {
|
|
210
|
-
...
|
|
225
|
+
...message,
|
|
211
226
|
text: filter(text)
|
|
212
227
|
}
|
|
213
228
|
};
|
|
214
229
|
}
|
|
215
230
|
|
|
216
231
|
// button message
|
|
217
|
-
if (
|
|
218
|
-
&&
|
|
219
|
-
&&
|
|
220
|
-
&&
|
|
232
|
+
if (message && message.attachment
|
|
233
|
+
&& message.attachment.type === 'template'
|
|
234
|
+
&& message.attachment.payload
|
|
235
|
+
&& message.attachment.payload.text) {
|
|
221
236
|
|
|
222
237
|
return {
|
|
223
238
|
...payload,
|
|
224
239
|
message: {
|
|
225
|
-
...
|
|
240
|
+
...message,
|
|
226
241
|
attachment: {
|
|
227
|
-
...
|
|
242
|
+
...message.attachment,
|
|
228
243
|
payload: {
|
|
229
|
-
...
|
|
230
|
-
text: filter(
|
|
244
|
+
...message.attachment.payload,
|
|
245
|
+
text: filter(message.attachment.payload.text)
|
|
231
246
|
}
|
|
232
247
|
}
|
|
233
248
|
}
|
|
@@ -246,9 +261,7 @@ class ReturnSender {
|
|
|
246
261
|
payload = this._queue.shift();
|
|
247
262
|
|
|
248
263
|
let lastInQueueForNow = this._queue.length === 0;
|
|
249
|
-
if (this._queue.length === 0
|
|
250
|
-
&& (this._sendLastMessageWithFinish
|
|
251
|
-
|| this._intentsAndEntities.some((e) => e && e.type))) {
|
|
264
|
+
if (this._queue.length === 0 && this._sendLastMessageWithFinish) {
|
|
252
265
|
await Promise.race([
|
|
253
266
|
this._anotherEventPromise,
|
|
254
267
|
this._finishedPromise
|
|
@@ -279,8 +292,16 @@ class ReturnSender {
|
|
|
279
292
|
}
|
|
280
293
|
|
|
281
294
|
async _enrichPayload (payload, req, lastInQueueForNow) {
|
|
282
|
-
if (lastInQueueForNow
|
|
283
|
-
|
|
295
|
+
if (!lastInQueueForNow) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
if (this._features.includes(FEATURE_TRACKING)) {
|
|
299
|
+
const tracking = this._createTracking(req);
|
|
300
|
+
Object.assign(payload, { tracking });
|
|
301
|
+
}
|
|
302
|
+
if (req && this._intentsAndEntities.length !== 0) {
|
|
303
|
+
const supportsPhrases = this._features.includes(FEATURE_PHRASES);
|
|
304
|
+
const { phrases } = supportsPhrases
|
|
284
305
|
? await ai.ai.getPhrases(req)
|
|
285
306
|
: { phrases: new Map() };
|
|
286
307
|
|
|
@@ -295,7 +316,7 @@ class ReturnSender {
|
|
|
295
316
|
input = aiObj;
|
|
296
317
|
return;
|
|
297
318
|
}
|
|
298
|
-
if (!
|
|
319
|
+
if (!supportsPhrases) {
|
|
299
320
|
return;
|
|
300
321
|
}
|
|
301
322
|
if (aiObj.startsWith('@')) {
|
|
@@ -349,6 +370,8 @@ class ReturnSender {
|
|
|
349
370
|
}
|
|
350
371
|
if (Array.isArray(payload.expectedIntentsAndEntities)) {
|
|
351
372
|
this._intentsAndEntities.push(...payload.expectedIntentsAndEntities);
|
|
373
|
+
this._sendLastMessageWithFinish = this._sendLastMessageWithFinish
|
|
374
|
+
|| this._intentsAndEntities.some((e) => e && e.type);
|
|
352
375
|
return;
|
|
353
376
|
}
|
|
354
377
|
|
|
@@ -403,6 +426,29 @@ class ReturnSender {
|
|
|
403
426
|
};
|
|
404
427
|
}
|
|
405
428
|
|
|
429
|
+
_createTracking (req = null, res = null) {
|
|
430
|
+
const payload = {};
|
|
431
|
+
const meta = {
|
|
432
|
+
actions: this._visitedInteractions.slice()
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
if (req) {
|
|
436
|
+
Object.assign(meta, {
|
|
437
|
+
intent: req.intent(ai.ai.confidence),
|
|
438
|
+
confidence: ai.ai.confidence,
|
|
439
|
+
intents: (req.intents || [])
|
|
440
|
+
.map((i) => this._cleanupIntent(i)),
|
|
441
|
+
entities: this._cleanupEntities((req.entities || [])
|
|
442
|
+
.filter((e) => e.score >= ai.ai.confidence))
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
if (res) {
|
|
446
|
+
Object.assign(payload, res.senderMeta);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
return Object.assign(this._tracking, { payload, meta });
|
|
450
|
+
}
|
|
451
|
+
|
|
406
452
|
/**
|
|
407
453
|
* @private
|
|
408
454
|
* @param {Request} req
|
package/src/Router.js
CHANGED
|
@@ -271,7 +271,7 @@ class Router extends ReducerWrapper {
|
|
|
271
271
|
}
|
|
272
272
|
|
|
273
273
|
// used as protected method
|
|
274
|
-
async processReducers (reducers, req, res, postBack,
|
|
274
|
+
async processReducers (reducers, req, res, postBack, action, doNotTrack = false) {
|
|
275
275
|
const routeToReduce = {
|
|
276
276
|
reducers,
|
|
277
277
|
path: res.routePath
|
package/src/Tester.js
CHANGED
|
@@ -69,9 +69,21 @@ class Tester {
|
|
|
69
69
|
info: e => console.info(e) // eslint-disable-line
|
|
70
70
|
};
|
|
71
71
|
|
|
72
|
+
this._cachedGiMap = null;
|
|
73
|
+
|
|
72
74
|
this._listener = (senderIdentifier, action, text, req, prevAction, doNotTrack) => {
|
|
75
|
+
const reqAction = req.action();
|
|
76
|
+
if (reqAction
|
|
77
|
+
&& !this._actionMatches(action, reqAction)
|
|
78
|
+
&& this._actionHasGlobalIntent(reqAction)) {
|
|
79
|
+
|
|
80
|
+
this._actionsCollector.push({
|
|
81
|
+
action: reqAction, text, prevAction, doNotTrack, isReqAction: true
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
73
85
|
this._actionsCollector.push({
|
|
74
|
-
action, text, prevAction, doNotTrack
|
|
86
|
+
action, text, prevAction, doNotTrack, isReqAction: false
|
|
75
87
|
});
|
|
76
88
|
};
|
|
77
89
|
|
|
@@ -127,10 +139,27 @@ class Tester {
|
|
|
127
139
|
this.features = null;
|
|
128
140
|
}
|
|
129
141
|
|
|
142
|
+
_actionHasGlobalIntent (action) {
|
|
143
|
+
if (!this.processor.reducer
|
|
144
|
+
|| !('globalIntents' in this.processor.reducer)) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
if (this._cachedGiMap === null) {
|
|
148
|
+
this._cachedGiMap = new Set();
|
|
149
|
+
|
|
150
|
+
for (const value of this.processor.reducer.globalIntents.values()) {
|
|
151
|
+
this._cachedGiMap.add(value.action);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return this._cachedGiMap.has(action.replace(/^\/?/, '/'));
|
|
156
|
+
}
|
|
157
|
+
|
|
130
158
|
dealloc () {
|
|
131
159
|
this.processor.reducer
|
|
132
160
|
.removeListener('_action', this._listener);
|
|
133
161
|
this.processor.reducer = null;
|
|
162
|
+
this._cachedGiMap = null;
|
|
134
163
|
}
|
|
135
164
|
|
|
136
165
|
/**
|
|
@@ -255,22 +284,30 @@ class Tester {
|
|
|
255
284
|
return new ResponseAssert(this.responses[this.responses.length - 1]);
|
|
256
285
|
}
|
|
257
286
|
|
|
287
|
+
_actionMatches (botAction, path) {
|
|
288
|
+
return botAction === path
|
|
289
|
+
|| (path === '*' && botAction === '/*')
|
|
290
|
+
|| (!botAction.match(/\*/) && actionMatches(botAction, path));
|
|
291
|
+
}
|
|
292
|
+
|
|
258
293
|
/**
|
|
259
|
-
* Checks, that
|
|
294
|
+
* Checks, that request passed an interaction
|
|
260
295
|
*
|
|
261
296
|
* @param {string} path
|
|
297
|
+
* @param {boolean} [matchRequestActions]
|
|
262
298
|
* @returns {this}
|
|
263
299
|
*
|
|
264
300
|
* @memberOf Tester
|
|
265
301
|
*/
|
|
266
|
-
passedAction (path) {
|
|
302
|
+
passedAction (path, matchRequestActions = false) {
|
|
267
303
|
const ok = this.actions
|
|
268
|
-
.some((action) => (action.
|
|
269
|
-
|
|
304
|
+
.some((action) => (!action.isReqAction || matchRequestActions)
|
|
305
|
+
&& this._actionMatches(action.action, path));
|
|
270
306
|
let actual;
|
|
271
307
|
if (!ok) {
|
|
272
308
|
const set = new Set();
|
|
273
309
|
actual = this.actions
|
|
310
|
+
.filter((a) => !a.isReqAction || matchRequestActions)
|
|
274
311
|
.map((a) => (a.doNotTrack ? `(system interaction) ${a.action}` : a.action))
|
|
275
312
|
.filter((a) => !set.has(a) && set.add(a));
|
|
276
313
|
assert.fail(asserts.ex('Interaction was not passed', path, actual));
|
package/src/features.js
CHANGED
|
@@ -23,6 +23,11 @@ const FEATURE_SSML = 'ssml';
|
|
|
23
23
|
*/
|
|
24
24
|
const FEATURE_PHRASES = 'phrases';
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* @constant {string} FEATURE_TRACKING channel supports tracking protocol
|
|
28
|
+
*/
|
|
29
|
+
const FEATURE_TRACKING = 'tracking';
|
|
30
|
+
|
|
26
31
|
function getDefaultFeatureList () {
|
|
27
32
|
return [FEATURE_TEXT];
|
|
28
33
|
}
|
|
@@ -32,5 +37,6 @@ module.exports = {
|
|
|
32
37
|
FEATURE_VOICE,
|
|
33
38
|
FEATURE_SSML,
|
|
34
39
|
FEATURE_PHRASES,
|
|
40
|
+
FEATURE_TRACKING,
|
|
35
41
|
getDefaultFeatureList
|
|
36
42
|
};
|
|
@@ -5,7 +5,16 @@
|
|
|
5
5
|
|
|
6
6
|
const Router = require('../Router');
|
|
7
7
|
|
|
8
|
-
function expected ({ path }, { isLastIndex }) {
|
|
8
|
+
function expected ({ path, attachedRouter }, { isLastIndex }) {
|
|
9
|
+
|
|
10
|
+
if (attachedRouter) {
|
|
11
|
+
return (req, res, postBack) => postBack(path, {
|
|
12
|
+
_useExpected: {
|
|
13
|
+
action: res.toAbsoluteAction(path),
|
|
14
|
+
data: {}
|
|
15
|
+
}
|
|
16
|
+
}, true);
|
|
17
|
+
}
|
|
9
18
|
|
|
10
19
|
return (req, res) => {
|
|
11
20
|
res.expected(path);
|
package/src/utils/customFn.js
CHANGED
|
@@ -6,14 +6,6 @@
|
|
|
6
6
|
const Router = require('../Router'); // eslint-disable-line
|
|
7
7
|
const ai = require('../Ai'); // eslint-disable-line
|
|
8
8
|
const fetch = require('node-fetch'); // eslint-disable-line
|
|
9
|
-
let request;
|
|
10
|
-
try {
|
|
11
|
-
// @ts-ignore
|
|
12
|
-
request = module.require('request-promise-native');
|
|
13
|
-
} catch (e) {
|
|
14
|
-
// eslint-disable-next-line no-unused-vars
|
|
15
|
-
request = () => { throw new Error('To use request, you have to manually install request-promise-native into your bot.'); };
|
|
16
|
-
}
|
|
17
9
|
let axios;
|
|
18
10
|
try {
|
|
19
11
|
// @ts-ignore
|
package/src/utils/getUpdate.js
CHANGED
|
@@ -20,7 +20,7 @@ const UNSUBSCRIBE = '_$unsubscribe';
|
|
|
20
20
|
|
|
21
21
|
function getUpdate (attr, value, currentState = {}) {
|
|
22
22
|
let param;
|
|
23
|
-
let rest = attr;
|
|
23
|
+
let rest = attr && attr.replace(/\u2219/g, '.');
|
|
24
24
|
let state = currentState;
|
|
25
25
|
const ret = {};
|
|
26
26
|
let up = ret;
|
|
@@ -53,7 +53,7 @@ function getUpdate (attr, value, currentState = {}) {
|
|
|
53
53
|
|
|
54
54
|
function getValue (attr, currentState = {}) {
|
|
55
55
|
let param;
|
|
56
|
-
let rest = attr;
|
|
56
|
+
let rest = attr && attr.replace(/\u2219/g, '.');
|
|
57
57
|
let state = currentState;
|
|
58
58
|
|
|
59
59
|
do {
|
|
@@ -133,7 +133,8 @@ function makeQuickReplies (replies, path = '', translate = (w) => w, quickReplyC
|
|
|
133
133
|
data = {},
|
|
134
134
|
isLocation = false,
|
|
135
135
|
isEmail = false,
|
|
136
|
-
isPhone = false
|
|
136
|
+
isPhone = false,
|
|
137
|
+
useCa = currentAction
|
|
137
138
|
} = reply;
|
|
138
139
|
let {
|
|
139
140
|
setState = null
|
|
@@ -219,7 +220,7 @@ function makeQuickReplies (replies, path = '', translate = (w) => w, quickReplyC
|
|
|
219
220
|
payload = {
|
|
220
221
|
action: absoluteAction,
|
|
221
222
|
data: {
|
|
222
|
-
_ca:
|
|
223
|
+
_ca: useCa,
|
|
223
224
|
...data
|
|
224
225
|
}
|
|
225
226
|
};
|
|
@@ -41,7 +41,7 @@ function wrapPluginFunction (
|
|
|
41
41
|
return true;
|
|
42
42
|
}
|
|
43
43
|
const reducers = preprocessedItems.get(codeBlockName);
|
|
44
|
-
return router.processReducers(reducers, req, res, postBack,
|
|
44
|
+
return router.processReducers(reducers, req, res, postBack, action, true);
|
|
45
45
|
}
|
|
46
46
|
});
|
|
47
47
|
|