wingbot 3.67.30 → 3.68.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/Responder.js +34 -4
- package/src/ReturnSender.js +91 -26
- package/src/graphApi/conversationsApi.js +2 -2
- package/src/templates/ButtonTemplate.js +34 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wingbot",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.68.0-alpha.1",
|
|
4
4
|
"description": "Enterprise Messaging Bot Conversation Engine",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|
|
19
|
-
"url": "git+ssh://git@github.com/wingbotai/
|
|
19
|
+
"url": "git+ssh://git@github.com/wingbotai/wingnpbot.git"
|
|
20
20
|
},
|
|
21
21
|
"keywords": [
|
|
22
22
|
"Enterprise",
|
package/src/Responder.js
CHANGED
|
@@ -25,6 +25,8 @@ const EXCEPTION_HOPCOUNT_THRESHOLD = 5;
|
|
|
25
25
|
|
|
26
26
|
/** @typedef {import('./Request')} Request */
|
|
27
27
|
/** @typedef {import('./ReturnSender').UploadResult} UploadResult */
|
|
28
|
+
/** @typedef {import('./ReturnSender').SendOptions} SendOptions */
|
|
29
|
+
/** @typedef {import('./ReturnSender').TextFilter} TextFilter */
|
|
28
30
|
/** @typedef {import('./analytics/consts').TrackingCategory} TrackingCategory */
|
|
29
31
|
/** @typedef {import('./analytics/consts').TrackingType} TrackingType */
|
|
30
32
|
/** @typedef {import('./transcript/transcriptFromHistory').Transcript} Transcript */
|
|
@@ -36,11 +38,19 @@ const EXCEPTION_HOPCOUNT_THRESHOLD = 5;
|
|
|
36
38
|
const ExpectedInput = {
|
|
37
39
|
TYPE_PASSWORD: 'password',
|
|
38
40
|
TYPE_NONE: 'none',
|
|
39
|
-
TYPE_UPLOAD: 'upload'
|
|
41
|
+
TYPE_UPLOAD: 'upload',
|
|
42
|
+
TYPE_WEBVIEW: 'webview'
|
|
40
43
|
};
|
|
41
44
|
|
|
42
45
|
Object.freeze(ExpectedInput);
|
|
43
46
|
|
|
47
|
+
/**
|
|
48
|
+
* @typedef {object} ExpectedInputOptions
|
|
49
|
+
* @prop {string} [url]
|
|
50
|
+
* @prop {string} [webview_height_ratio]
|
|
51
|
+
* @prop {string} [on_close_payload]
|
|
52
|
+
*/
|
|
53
|
+
|
|
44
54
|
/**
|
|
45
55
|
* @typedef {object} QuickReply
|
|
46
56
|
* @prop {string} title
|
|
@@ -200,6 +210,9 @@ class Responder {
|
|
|
200
210
|
this._textResponses = [];
|
|
201
211
|
|
|
202
212
|
this._typingSent = false;
|
|
213
|
+
|
|
214
|
+
/** @type {SendOptions} */
|
|
215
|
+
this._nextMessageSendOptions = null;
|
|
203
216
|
}
|
|
204
217
|
|
|
205
218
|
_findPersonaConfiguration (name) {
|
|
@@ -369,7 +382,12 @@ class Responder {
|
|
|
369
382
|
}
|
|
370
383
|
this.startedOutput = true;
|
|
371
384
|
this._typingSent = data.sender_action === 'typing_on';
|
|
372
|
-
|
|
385
|
+
let opts;
|
|
386
|
+
if (!data.sender_action && this._nextMessageSendOptions) {
|
|
387
|
+
opts = this._nextMessageSendOptions;
|
|
388
|
+
this._nextMessageSendOptions = null;
|
|
389
|
+
}
|
|
390
|
+
this._messageSender.send(data, opts);
|
|
373
391
|
return this;
|
|
374
392
|
}
|
|
375
393
|
|
|
@@ -881,15 +899,16 @@ class Responder {
|
|
|
881
899
|
/**
|
|
882
900
|
*
|
|
883
901
|
* @param {ExpectedInput} type
|
|
902
|
+
* @param {ExpectedInputOptions} [options]
|
|
884
903
|
* @returns {this}
|
|
885
904
|
* @example
|
|
886
905
|
* bot.use((req, res) => {
|
|
887
906
|
* res.expectedInput(res.ExpectedInputTypes.TYPE_PASSWORD)
|
|
888
907
|
* });
|
|
889
908
|
*/
|
|
890
|
-
expectedInput (type) {
|
|
909
|
+
expectedInput (type, options = {}) {
|
|
891
910
|
this._messageSender.send({
|
|
892
|
-
expectedIntentsAndEntities: [{ type }]
|
|
911
|
+
expectedIntentsAndEntities: [{ type, ...options }]
|
|
893
912
|
});
|
|
894
913
|
return this;
|
|
895
914
|
}
|
|
@@ -1311,6 +1330,17 @@ class Responder {
|
|
|
1311
1330
|
);
|
|
1312
1331
|
}
|
|
1313
1332
|
|
|
1333
|
+
/**
|
|
1334
|
+
* Set next message as confident
|
|
1335
|
+
*
|
|
1336
|
+
* @param {TextFilter} anonymizer
|
|
1337
|
+
*/
|
|
1338
|
+
nextOutputConfident (anonymizer) {
|
|
1339
|
+
this._nextMessageSendOptions = {
|
|
1340
|
+
anonymizer
|
|
1341
|
+
};
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1314
1344
|
/**
|
|
1315
1345
|
* Override action tracking
|
|
1316
1346
|
*
|
package/src/ReturnSender.js
CHANGED
|
@@ -32,9 +32,9 @@ const extractText = require('./transcript/extractText');
|
|
|
32
32
|
/**
|
|
33
33
|
* @typedef {object} ReturnSenderOptions
|
|
34
34
|
* @prop {boolean} [dontWaitForDeferredOps]
|
|
35
|
-
* @prop {
|
|
35
|
+
* @prop {TextFilter} [textFilter] - filter for saving the texts
|
|
36
36
|
* @prop {boolean} [logStandbyEvents] - log the standby events
|
|
37
|
-
* @prop {
|
|
37
|
+
* @prop {TextFilter} [confidentInputFilter] - filter for confident input (@CONFIDENT)
|
|
38
38
|
*/
|
|
39
39
|
|
|
40
40
|
/**
|
|
@@ -53,11 +53,17 @@ const extractText = require('./transcript/extractText');
|
|
|
53
53
|
* @prop {Function} error
|
|
54
54
|
*/
|
|
55
55
|
|
|
56
|
+
/**
|
|
57
|
+
* @typedef {object} SendOptions
|
|
58
|
+
* @prop {TextFilter} [anonymizer]
|
|
59
|
+
*/
|
|
60
|
+
|
|
56
61
|
/**
|
|
57
62
|
* Text filter function
|
|
58
63
|
*
|
|
59
|
-
* @callback
|
|
64
|
+
* @callback TextFilter
|
|
60
65
|
* @param {string} text - input text
|
|
66
|
+
* @param {'text'|'title'|'url'|'content'} key
|
|
61
67
|
* @returns {string} - filtered text
|
|
62
68
|
*/
|
|
63
69
|
|
|
@@ -73,10 +79,11 @@ class ReturnSender {
|
|
|
73
79
|
constructor (options, senderId, incommingMessage, logger = null) {
|
|
74
80
|
this._queue = [];
|
|
75
81
|
|
|
76
|
-
/**
|
|
77
|
-
* @type {object[]}
|
|
78
|
-
*/
|
|
82
|
+
/** @type {object[]} */
|
|
79
83
|
this.responses = [];
|
|
84
|
+
|
|
85
|
+
/** @type {SendOptions[]} */
|
|
86
|
+
this._responseOptions = [];
|
|
80
87
|
this._results = [];
|
|
81
88
|
|
|
82
89
|
this._promise = null;
|
|
@@ -131,7 +138,7 @@ class ReturnSender {
|
|
|
131
138
|
* For example to remove any confidential data
|
|
132
139
|
*
|
|
133
140
|
* @param {string} text
|
|
134
|
-
* @type {
|
|
141
|
+
* @type {TextFilter}
|
|
135
142
|
*/
|
|
136
143
|
this.textFilter = options.textFilter || ((text) => text);
|
|
137
144
|
|
|
@@ -227,7 +234,7 @@ class ReturnSender {
|
|
|
227
234
|
: this.textFilter;
|
|
228
235
|
|
|
229
236
|
return [
|
|
230
|
-
filter(text).trim()
|
|
237
|
+
filter(text, null).trim()
|
|
231
238
|
];
|
|
232
239
|
}
|
|
233
240
|
|
|
@@ -240,7 +247,7 @@ class ReturnSender {
|
|
|
240
247
|
: this.textFilter;
|
|
241
248
|
|
|
242
249
|
return this._responseTexts
|
|
243
|
-
.map((t) => filter(t))
|
|
250
|
+
.map((t) => filter(t, null))
|
|
244
251
|
.filter((t) => t && `${t}`.trim());
|
|
245
252
|
}
|
|
246
253
|
|
|
@@ -300,11 +307,18 @@ class ReturnSender {
|
|
|
300
307
|
return new Promise((r) => setTimeout(r, nextWait));
|
|
301
308
|
}
|
|
302
309
|
|
|
303
|
-
_filterMessage (payload, confidentInput =
|
|
310
|
+
_filterMessage (payload, confidentInput = null, req = null) {
|
|
304
311
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
312
|
+
let filter;
|
|
313
|
+
const processButtons = typeof confidentInput === 'function';
|
|
314
|
+
|
|
315
|
+
if (processButtons) {
|
|
316
|
+
filter = confidentInput;
|
|
317
|
+
} else if (confidentInput) {
|
|
318
|
+
filter = this.confidentInputFilter;
|
|
319
|
+
} else {
|
|
320
|
+
filter = this.textFilter;
|
|
321
|
+
}
|
|
308
322
|
|
|
309
323
|
let { message } = payload;
|
|
310
324
|
|
|
@@ -314,7 +328,7 @@ class ReturnSender {
|
|
|
314
328
|
text: message.text ? message.text : message.voice.ssml,
|
|
315
329
|
voice: {
|
|
316
330
|
...message.voice,
|
|
317
|
-
ssml: filter(message.voice.ssml)
|
|
331
|
+
ssml: filter(message.voice.ssml, 'ssml')
|
|
318
332
|
}
|
|
319
333
|
};
|
|
320
334
|
}
|
|
@@ -331,7 +345,7 @@ class ReturnSender {
|
|
|
331
345
|
...payload,
|
|
332
346
|
message: {
|
|
333
347
|
...message,
|
|
334
|
-
text: filter(text)
|
|
348
|
+
text: filter(text, 'text')
|
|
335
349
|
}
|
|
336
350
|
};
|
|
337
351
|
}
|
|
@@ -342,6 +356,8 @@ class ReturnSender {
|
|
|
342
356
|
&& message.attachment.payload
|
|
343
357
|
&& message.attachment.payload.text) {
|
|
344
358
|
|
|
359
|
+
const { payload: p } = message.attachment;
|
|
360
|
+
|
|
345
361
|
return {
|
|
346
362
|
...payload,
|
|
347
363
|
message: {
|
|
@@ -349,8 +365,46 @@ class ReturnSender {
|
|
|
349
365
|
attachment: {
|
|
350
366
|
...message.attachment,
|
|
351
367
|
payload: {
|
|
352
|
-
...
|
|
353
|
-
text: filter(
|
|
368
|
+
...p,
|
|
369
|
+
text: filter(p.text, 'text'),
|
|
370
|
+
...(processButtons && Array.isArray(p.buttons)
|
|
371
|
+
? {
|
|
372
|
+
buttons: p.buttons.map((btn) => {
|
|
373
|
+
switch (btn.type) {
|
|
374
|
+
case 'attachment':
|
|
375
|
+
return {
|
|
376
|
+
...btn,
|
|
377
|
+
title: filter(btn.title, 'title'),
|
|
378
|
+
...(btn.payload && btn.payload.content
|
|
379
|
+
? {
|
|
380
|
+
payload: {
|
|
381
|
+
...btn.payload,
|
|
382
|
+
content: filter(btn.payload.content, 'content')
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
: {}
|
|
386
|
+
)
|
|
387
|
+
};
|
|
388
|
+
case 'web_url':
|
|
389
|
+
return {
|
|
390
|
+
...btn,
|
|
391
|
+
url: filter(btn.url, 'url'),
|
|
392
|
+
title: filter(btn.title, 'title')
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
case 'postback':
|
|
396
|
+
return {
|
|
397
|
+
...btn,
|
|
398
|
+
title: filter(btn.title, 'title')
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
default:
|
|
402
|
+
return btn;
|
|
403
|
+
}
|
|
404
|
+
})
|
|
405
|
+
}
|
|
406
|
+
: {}
|
|
407
|
+
)
|
|
354
408
|
}
|
|
355
409
|
}
|
|
356
410
|
}
|
|
@@ -363,10 +417,11 @@ class ReturnSender {
|
|
|
363
417
|
async _work () {
|
|
364
418
|
this._isWorking = true;
|
|
365
419
|
let payload;
|
|
420
|
+
let options;
|
|
366
421
|
let req;
|
|
367
422
|
let previousResponse = null;
|
|
368
423
|
while (this._queue.length > 0) {
|
|
369
|
-
payload = this._queue.shift();
|
|
424
|
+
({ payload, options } = this._queue.shift());
|
|
370
425
|
|
|
371
426
|
let lastInQueueForNow = this._queue.length === 0;
|
|
372
427
|
if (this._queue.length === 0 && this._sendLastMessageWithFinish) {
|
|
@@ -392,6 +447,7 @@ class ReturnSender {
|
|
|
392
447
|
} else {
|
|
393
448
|
await this._enrichPayload(payload, req, lastInQueueForNow);
|
|
394
449
|
this.responses.push(payload);
|
|
450
|
+
this._responseOptions.push(options);
|
|
395
451
|
previousResponse = await this._send(payload);
|
|
396
452
|
this._results.push(previousResponse);
|
|
397
453
|
}
|
|
@@ -487,7 +543,13 @@ class ReturnSender {
|
|
|
487
543
|
return false;
|
|
488
544
|
}
|
|
489
545
|
|
|
490
|
-
|
|
546
|
+
/**
|
|
547
|
+
*
|
|
548
|
+
* @param {object} payload
|
|
549
|
+
* @param {SendOptions} options
|
|
550
|
+
* @returns {void}
|
|
551
|
+
*/
|
|
552
|
+
send (payload, options = {}) {
|
|
491
553
|
if (this._finished) {
|
|
492
554
|
throw new Error('Cannot send message after sender is finished');
|
|
493
555
|
}
|
|
@@ -510,17 +572,17 @@ class ReturnSender {
|
|
|
510
572
|
if (payload.set_context
|
|
511
573
|
&& !this._isVisibleMessage(payload, false)
|
|
512
574
|
&& lastInQueue
|
|
513
|
-
&& this._isVisibleMessage(lastInQueue)) {
|
|
575
|
+
&& this._isVisibleMessage(lastInQueue.payload)) {
|
|
514
576
|
|
|
515
577
|
const { set_context: setContext, ...rest } = payload;
|
|
516
578
|
|
|
517
579
|
Object.assign(
|
|
518
|
-
lastInQueue,
|
|
580
|
+
lastInQueue.payload,
|
|
519
581
|
rest,
|
|
520
|
-
lastInQueue,
|
|
582
|
+
lastInQueue.payload,
|
|
521
583
|
{
|
|
522
584
|
set_context: {
|
|
523
|
-
...lastInQueue.set_context,
|
|
585
|
+
...lastInQueue.payload.set_context,
|
|
524
586
|
...setContext
|
|
525
587
|
}
|
|
526
588
|
}
|
|
@@ -532,7 +594,7 @@ class ReturnSender {
|
|
|
532
594
|
if (text) {
|
|
533
595
|
this._responseTexts.push(text);
|
|
534
596
|
}
|
|
535
|
-
this._queue.push(payload);
|
|
597
|
+
this._queue.push({ payload, options });
|
|
536
598
|
this._gotAnotherEvent();
|
|
537
599
|
|
|
538
600
|
if (this._catchedBeforeFinish) {
|
|
@@ -620,7 +682,7 @@ class ReturnSender {
|
|
|
620
682
|
let text = req.text();
|
|
621
683
|
|
|
622
684
|
if (text) {
|
|
623
|
-
text = this.textFilter(text);
|
|
685
|
+
text = this.textFilter(text, null);
|
|
624
686
|
}
|
|
625
687
|
|
|
626
688
|
const expected = req.expected();
|
|
@@ -675,7 +737,10 @@ class ReturnSender {
|
|
|
675
737
|
}
|
|
676
738
|
|
|
677
739
|
try {
|
|
678
|
-
const sent = this.responses.map((s) =>
|
|
740
|
+
const sent = this.responses.map((s, i) => {
|
|
741
|
+
const opts = this._responseOptions[i];
|
|
742
|
+
return this._filterMessage(s, opts.anonymizer);
|
|
743
|
+
});
|
|
679
744
|
const processedEvent = req
|
|
680
745
|
? req.event
|
|
681
746
|
: this._incommingMessage;
|
|
@@ -33,7 +33,7 @@ const { apiTextOutputFilter, mapObject, defaultMapperFactory } = require('../uti
|
|
|
33
33
|
/**
|
|
34
34
|
* Function for filtration of string output
|
|
35
35
|
*
|
|
36
|
-
* @callback
|
|
36
|
+
* @callback TextFilter
|
|
37
37
|
* @param {string} value
|
|
38
38
|
* @param {string} key
|
|
39
39
|
* @returns {any}
|
|
@@ -48,7 +48,7 @@ const { apiTextOutputFilter, mapObject, defaultMapperFactory } = require('../uti
|
|
|
48
48
|
* @param {Notifications} notifications
|
|
49
49
|
* @param {string[]|Function} [acl] - limit api to array of groups or use auth function
|
|
50
50
|
* @param {object} options
|
|
51
|
-
* @param {
|
|
51
|
+
* @param {TextFilter} [options.stateTextFilter] - optional funcion for filtering data in states
|
|
52
52
|
* @param {Mapper} [options.mapper] - mapper for state values
|
|
53
53
|
* @returns {ConversationsAPI}
|
|
54
54
|
* @example
|
|
@@ -83,18 +83,35 @@ class ButtonTemplate extends BaseTemplate {
|
|
|
83
83
|
* @param {string} linkUrl - button url
|
|
84
84
|
* @param {boolean} hasExtension - includes token in url
|
|
85
85
|
* @param {string} [webviewHeight=null] - compact|tall|full
|
|
86
|
+
* @param {string} [onCloseAction] - close action for webview
|
|
87
|
+
* @param {object} [onCloseData] - data
|
|
86
88
|
* @returns {this}
|
|
87
89
|
*
|
|
88
90
|
* @memberOf ButtonTemplate
|
|
89
91
|
*/
|
|
90
|
-
urlButton (
|
|
91
|
-
|
|
92
|
+
urlButton (
|
|
93
|
+
title,
|
|
94
|
+
linkUrl,
|
|
95
|
+
hasExtension = false,
|
|
96
|
+
webviewHeight = null,
|
|
97
|
+
onCloseAction = null,
|
|
98
|
+
onCloseData = {}
|
|
99
|
+
) {
|
|
100
|
+
const btn = {
|
|
92
101
|
type: 'web_url',
|
|
93
102
|
title: this._t(title),
|
|
94
103
|
url: this._makeExtensionUrl(linkUrl, hasExtension),
|
|
95
104
|
webview_height_ratio: webviewHeight || (hasExtension ? 'tall' : 'full'),
|
|
96
105
|
messenger_extensions: hasExtension
|
|
97
|
-
}
|
|
106
|
+
};
|
|
107
|
+
// on_close_payload
|
|
108
|
+
if (onCloseAction) {
|
|
109
|
+
Object.assign(btn, {
|
|
110
|
+
on_close_payload: this._createPayload(onCloseAction, onCloseData)
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
this.buttons.push(btn);
|
|
98
115
|
return this;
|
|
99
116
|
}
|
|
100
117
|
|
|
@@ -110,23 +127,27 @@ class ButtonTemplate extends BaseTemplate {
|
|
|
110
127
|
* @memberOf ButtonTemplate
|
|
111
128
|
*/
|
|
112
129
|
postBackButton (title, action, data = {}, setState = null) {
|
|
113
|
-
const hasSetState = setState && Object.keys(setState).length !== 0;
|
|
114
|
-
|
|
115
130
|
this.buttons.push({
|
|
116
131
|
type: 'postback',
|
|
117
132
|
title: this._t(title),
|
|
118
|
-
payload:
|
|
119
|
-
action: makeAbsolute(action, this.context.path),
|
|
120
|
-
data: {
|
|
121
|
-
_ca: this.context.currentAction,
|
|
122
|
-
...data
|
|
123
|
-
},
|
|
124
|
-
...(hasSetState ? { setState } : {})
|
|
125
|
-
})
|
|
133
|
+
payload: this._createPayload(action, data, setState)
|
|
126
134
|
});
|
|
127
135
|
return this;
|
|
128
136
|
}
|
|
129
137
|
|
|
138
|
+
_createPayload (action, data, setState = null) {
|
|
139
|
+
const hasSetState = setState && Object.keys(setState).length !== 0;
|
|
140
|
+
|
|
141
|
+
return JSON.stringify({
|
|
142
|
+
action: makeAbsolute(action, this.context.path),
|
|
143
|
+
data: {
|
|
144
|
+
_ca: this.context.currentAction,
|
|
145
|
+
...data
|
|
146
|
+
},
|
|
147
|
+
...(hasSetState ? { setState } : {})
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
130
151
|
/**
|
|
131
152
|
* Adds button, which opens a popup with content on click.
|
|
132
153
|
*
|