@tiledesk/tiledesk-voice-twilio-connector 0.1.27 → 0.2.0-rc3
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/LICENSE +179 -0
- package/README.md +44 -0
- package/index.js +7 -1529
- package/package.json +23 -22
- package/src/app.js +146 -0
- package/src/config/index.js +32 -0
- package/src/controllers/VoiceController.js +488 -0
- package/src/controllers/VoiceController.original.js +811 -0
- package/src/middlewares/httpLogger.js +31 -0
- package/src/models/KeyValueStore.js +78 -0
- package/src/routes/manageApp.js +298 -0
- package/src/routes/voice.js +22 -0
- package/src/services/AiService.js +219 -0
- package/src/services/AiService.sdk.js +367 -0
- package/src/services/IntegrationService.js +74 -0
- package/src/services/MessageService.js +133 -0
- package/src/services/README_SDK.md +107 -0
- package/src/services/SessionService.js +143 -0
- package/src/services/SpeechService.js +134 -0
- package/src/services/TiledeskMessageBuilder.js +135 -0
- package/src/services/TwilioService.js +122 -0
- package/src/services/UploadService.js +78 -0
- package/src/services/channels/TiledeskChannel.js +269 -0
- package/{tiledesk → src/services/channels}/VoiceChannel.js +17 -56
- package/src/services/clients/TiledeskSubscriptionClient.js +78 -0
- package/src/services/index.js +45 -0
- package/src/services/translators/TiledeskTwilioTranslator.js +509 -0
- package/{tiledesk/TiledeskTwilioTranslator.js → src/services/translators/TiledeskTwilioTranslator.original.js} +119 -202
- package/src/utils/fileUtils.js +24 -0
- package/src/utils/logger.js +32 -0
- package/{tiledesk → src/utils}/utils-message.js +6 -21
- package/logs/app.log +0 -3082
- package/routes/manageApp.js +0 -419
- package/tiledesk/KVBaseMongo.js +0 -101
- package/tiledesk/TiledeskChannel.js +0 -363
- package/tiledesk/TiledeskSubscriptionClient.js +0 -135
- package/tiledesk/fileUtils.js +0 -55
- package/tiledesk/services/AiService.js +0 -230
- package/tiledesk/services/IntegrationService.js +0 -81
- package/tiledesk/services/UploadService.js +0 -88
- /package/{winston.js → src/config/logger.js} +0 -0
- /package/{tiledesk → src}/services/voiceEventEmitter.js +0 -0
- /package/{template → src/template}/configure.html +0 -0
- /package/{template → src/template}/css/configure.css +0 -0
- /package/{template → src/template}/css/error.css +0 -0
- /package/{template → src/template}/css/style.css +0 -0
- /package/{template → src/template}/error.html +0 -0
- /package/{tiledesk → src/utils}/constants.js +0 -0
- /package/{tiledesk → src/utils}/errors.js +0 -0
- /package/{tiledesk → src/utils}/utils.js +0 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
const axios = require("axios").default;
|
|
2
|
+
const jwt = require("jsonwebtoken");
|
|
3
|
+
|
|
4
|
+
const utils = require('../../utils/utils-message.js');
|
|
5
|
+
const { TYPE_MESSAGE, CHANNEL_NAME } = require('../../utils/constants');
|
|
6
|
+
|
|
7
|
+
const winston = require("../../utils/logger");
|
|
8
|
+
const voiceEventEmitter = require('../voiceEventEmitter');
|
|
9
|
+
|
|
10
|
+
class TiledeskChannel {
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
constructor(config) {
|
|
14
|
+
|
|
15
|
+
if (!config) {
|
|
16
|
+
throw new Error("[TiledeskChannel] config is mandatory");
|
|
17
|
+
}
|
|
18
|
+
if (!config.API_URL) {
|
|
19
|
+
throw new Error("[TiledeskChannel] config.API_URL is mandatory");
|
|
20
|
+
}
|
|
21
|
+
if (!config.redis_client) {
|
|
22
|
+
throw new Error("[TiledeskChannel] config.redis_client is mandatory");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
this.log = config.log || false;
|
|
26
|
+
this.API_URL = config.API_URL;
|
|
27
|
+
this.redis_client = config.redis_client;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
async signIn(user_id, settings) {
|
|
32
|
+
// ani = calling phone number
|
|
33
|
+
|
|
34
|
+
winston.debug('[TiledeskChannel] sigIn settings', settings)
|
|
35
|
+
|
|
36
|
+
let payload = {
|
|
37
|
+
_id: CHANNEL_NAME + '-' + user_id,
|
|
38
|
+
firstname: user_id,
|
|
39
|
+
lastname: "",
|
|
40
|
+
phone: user_id,
|
|
41
|
+
sub: "userexternal",
|
|
42
|
+
aud: "https://tiledesk.com/subscriptions/" + settings.subscriptionId,
|
|
43
|
+
};
|
|
44
|
+
let customToken = jwt.sign(payload, settings.secret);
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const response = await axios({
|
|
48
|
+
url: this.API_URL + "/auth/signInWithCustomToken",
|
|
49
|
+
headers: {
|
|
50
|
+
"Content-Type": "application/json",
|
|
51
|
+
Authorization: "JWT " + customToken,
|
|
52
|
+
},
|
|
53
|
+
data: {},
|
|
54
|
+
method: "POST",
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
if (!response.data) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
//response.data.token = await this.fixToken(response.data.token);
|
|
61
|
+
let token = await this.fixToken(response.data.token);
|
|
62
|
+
|
|
63
|
+
let data = {
|
|
64
|
+
token: token,
|
|
65
|
+
_id: response.data.user._id
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
return data;
|
|
69
|
+
} catch (err) {
|
|
70
|
+
winston.error("[TiledeskChannel] sign in error: ", err.response);
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async generateConversation(ani, callId, project_id){
|
|
76
|
+
return "support-group-" + project_id + "-" + ani + "-" + CHANNEL_NAME + "-" + callId;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async getConversation(ani, callId, token, project_id) {
|
|
80
|
+
let new_request_id = await this.generateConversation(ani, callId, project_id)
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
const response = await axios({
|
|
84
|
+
url: this.API_URL + "/" + project_id + "/requests/me?channel=" + CHANNEL_NAME,
|
|
85
|
+
//url: this.API_URL + "/" + project_id + "/requests/me",
|
|
86
|
+
headers: {
|
|
87
|
+
"Content-Type": "application/json",
|
|
88
|
+
Authorization: token,
|
|
89
|
+
},
|
|
90
|
+
method: "GET",
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
let request_id;
|
|
94
|
+
if (response.data.requests[0]) {
|
|
95
|
+
request_id = response.data.requests[0].request_id;
|
|
96
|
+
winston.debug("[TiledeskChannel] use already opened conversation: ", request_id);
|
|
97
|
+
} else {
|
|
98
|
+
request_id = new_request_id;
|
|
99
|
+
winston.debug("[TiledeskChannel] use new conversation: ", request_id);
|
|
100
|
+
}
|
|
101
|
+
return request_id;
|
|
102
|
+
} catch (err) {
|
|
103
|
+
winston.error("[TiledeskChannel] get requests error: ", err);
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async getDepartments(token, project_id) {
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
const response = await axios({
|
|
112
|
+
url: this.API_URL + "/" + project_id + "/departments/allstatus",
|
|
113
|
+
headers: {
|
|
114
|
+
'Content-Type': 'application/json',
|
|
115
|
+
'Authorization': token
|
|
116
|
+
},
|
|
117
|
+
method: 'GET'
|
|
118
|
+
});
|
|
119
|
+
winston.debug("[TiledeskChannel] get departments response.data: ", response.data);
|
|
120
|
+
return response.data;
|
|
121
|
+
} catch (err) {
|
|
122
|
+
winston.error("[TiledeskChannel] get departments error");
|
|
123
|
+
throw err;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async send(tiledeskMessage, token, conversation_id, project_id) {
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
|
+
const response = await axios({
|
|
131
|
+
url: this.API_URL + `/${project_id}/requests/${conversation_id}/messages`,
|
|
132
|
+
headers: {
|
|
133
|
+
'Content-Type': 'application/json',
|
|
134
|
+
'Authorization': token
|
|
135
|
+
},
|
|
136
|
+
data: tiledeskMessage,
|
|
137
|
+
method: 'POST'
|
|
138
|
+
});
|
|
139
|
+
winston.debug("[TiledeskChannel] send message response: ", response.data);
|
|
140
|
+
return response.data;
|
|
141
|
+
} catch (err) {
|
|
142
|
+
winston.error("[TiledeskChannel] send message: ", err.response?.data);
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
/** ADD MESSAGE TO REDIS QUEUE **/
|
|
150
|
+
async addMessageToQueue(message){
|
|
151
|
+
|
|
152
|
+
/*SKIP INFO MESSAGES*/
|
|
153
|
+
if(utils.messageType(TYPE_MESSAGE.INFO, message)){
|
|
154
|
+
winston.debug("> SKIPPING INFO message: " + JSON.stringify(message) );
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/*SKIP CURRENT USER MESSAGES*/
|
|
159
|
+
if (message.sender.indexOf(CHANNEL_NAME) > -1) {
|
|
160
|
+
winston.debug("> SKIPPING ECHO message: " + JSON.stringify(message) );
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
winston.debug("> SAVE message TO QUEUE: " + JSON.stringify(message) );
|
|
165
|
+
const conversation_id = message.recipient;
|
|
166
|
+
const queueKey = `tiledesk:queue:${conversation_id}`;
|
|
167
|
+
|
|
168
|
+
// Use pipeline for atomic push + expire (single round-trip)
|
|
169
|
+
await this.redis_client
|
|
170
|
+
.multi()
|
|
171
|
+
.rPush(queueKey, JSON.stringify(message))
|
|
172
|
+
.expire(queueKey, 86400)
|
|
173
|
+
.exec();
|
|
174
|
+
|
|
175
|
+
// Emit event for real-time subscribers
|
|
176
|
+
voiceEventEmitter.emit(`tiledesk:conversation:${conversation_id}`, message);
|
|
177
|
+
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
/** GET MESSAGES FROM REDIS QUEUE LIST **/
|
|
183
|
+
async getMessagesFromQueue(conversation_id){
|
|
184
|
+
const queueKey = `tiledesk:queue:${conversation_id}`;
|
|
185
|
+
const queue = await this.redis_client.lRange(queueKey, 0, -1);
|
|
186
|
+
|
|
187
|
+
if (!queue || queue.length === 0) {
|
|
188
|
+
return [];
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return queue.map(item => JSON.parse(item));
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** PUBLISH MESSAGE TO REDIS TOPIC **/
|
|
195
|
+
async publishMessageToTopic(message){
|
|
196
|
+
|
|
197
|
+
/*SKIP INFO MESSAGES*/
|
|
198
|
+
if(utils.messageType(TYPE_MESSAGE.INFO, message)){
|
|
199
|
+
winston.debug("> SKIPPING INFO message");
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/*SKIP CURRENT USER MESSAGES*/
|
|
204
|
+
if (message.sender.indexOf("vxml") > -1) {
|
|
205
|
+
winston.debug("> SKIPPING ECHO message");
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
voiceEventEmitter.emit(`tiledesk:conversation:${message.recipient}`, message);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** SUBSCRIBE TO REDIS TOPIC */
|
|
213
|
+
async subscribeToTopic(conversation_id){
|
|
214
|
+
const topic = `tiledesk:conversation:${conversation_id}`;
|
|
215
|
+
// console.log("subscribeToTopic: " + topic);
|
|
216
|
+
|
|
217
|
+
return new Promise((resolve, reject) => {
|
|
218
|
+
voiceEventEmitter.once(topic, (message) => {
|
|
219
|
+
resolve(message);
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** REMOVE MESSAGE FROM REDIS QUEUE LIST (removes first message - FIFO) **/
|
|
225
|
+
async removeMessageFromQueue(conversation_id, message_id){
|
|
226
|
+
const queueKey = `tiledesk:queue:${conversation_id}`;
|
|
227
|
+
// Use lPop for FIFO queue - removes and returns first element
|
|
228
|
+
await this.redis_client.lPop(queueKey);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** CLEAR QUEUE FROM REDIS **/
|
|
232
|
+
async clearQueue(conversation_id){
|
|
233
|
+
if(conversation_id){
|
|
234
|
+
await this.redis_client.del(`tiledesk:queue:${conversation_id}`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
async generateWaitTdMessage(ani, delayTime){
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
return {
|
|
245
|
+
text: '',
|
|
246
|
+
senderFullname: ani,
|
|
247
|
+
attributes: {
|
|
248
|
+
commands:[
|
|
249
|
+
{ type: 'wait', time: delayTime}
|
|
250
|
+
]
|
|
251
|
+
},
|
|
252
|
+
channel: { name: CHANNEL_NAME }
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
async fixToken(token) {
|
|
258
|
+
let index = token.lastIndexOf("JWT ");
|
|
259
|
+
if (index != -1) {
|
|
260
|
+
let new_token = token.substring(index + 4);
|
|
261
|
+
return "JWT " + new_token;
|
|
262
|
+
} else {
|
|
263
|
+
return "JWT " + token;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
module.exports = { TiledeskChannel };
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
require('dotenv').config();
|
|
2
|
-
const
|
|
3
|
-
const jwt = require("jsonwebtoken");
|
|
4
|
-
const { v4: uuidv4 } = require("uuid");
|
|
5
|
-
const { promisify } = require('util');
|
|
2
|
+
const winston = require("../../utils/logger");
|
|
6
3
|
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
const voiceEventEmitter = require('./services/voiceEventEmitter');
|
|
4
|
+
const voiceEventEmitter = require('../voiceEventEmitter');
|
|
10
5
|
|
|
11
6
|
class VoiceChannel {
|
|
12
7
|
|
|
@@ -68,50 +63,23 @@ class VoiceChannel {
|
|
|
68
63
|
|
|
69
64
|
/** ADD POOLING DELAY INDEX TO REDIS **/
|
|
70
65
|
async saveDelayIndexForCallId(callId){
|
|
71
|
-
|
|
72
|
-
//
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
//increment
|
|
76
|
-
const delayIndex = (+index) +1
|
|
77
|
-
//save new index to redis
|
|
78
|
-
await this.redis_client.set('tiledesk:voice:'+callId + ':delayIndex', delayIndex, {'EX': 86400});
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
//if index is not present: set to default (0)
|
|
82
|
-
await this.redis_client.set('tiledesk:voice:'+callId + ':delayIndex', 0, {'EX': 86400});
|
|
66
|
+
const key = `tiledesk:voice:${callId}:delayIndex`;
|
|
67
|
+
// Use INCR for atomic increment, initializes to 1 if key doesn't exist
|
|
68
|
+
await this.redis_client.incr(key);
|
|
69
|
+
await this.redis_client.expire(key, 86400);
|
|
83
70
|
}
|
|
84
71
|
|
|
85
72
|
/** RESET INDEX INTO REDIS DATA FOR CURRENT CALLID **/
|
|
86
73
|
async clearDelayTimeForCallId(callId){
|
|
87
|
-
|
|
88
|
-
//get value for current callId
|
|
89
|
-
const index = await this.redis_client.get('tiledesk:voice:'+callId + ':delayIndex');
|
|
90
|
-
winston.debug('clearDelayTimeForCallId: index -->'+index)
|
|
91
|
-
if(index){
|
|
92
|
-
//set index to default (0)
|
|
93
|
-
await this.redis_client.set('tiledesk:voice:'+callId + ':delayIndex', 0, {'EX': 86400});
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
//if index is not present: set to default (0)
|
|
74
|
+
// Always reset to default (0) regardless of current state
|
|
97
75
|
await this.redis_client.set('tiledesk:voice:'+callId + ':delayIndex', 0, {'EX': 86400});
|
|
98
76
|
}
|
|
99
77
|
|
|
100
78
|
|
|
101
79
|
async saveSettingsForCallId(attributes, callId){
|
|
102
|
-
|
|
103
80
|
winston.debug('[VoiceChannel] saveSettingsForCallId: attributes -->', attributes)
|
|
104
|
-
|
|
105
|
-
const index = await this.redis_client.get('tiledesk:voice:'+callId + ':attributes');
|
|
106
|
-
winston.debug('[VoiceChannel] saveSettingsForCallId: attributes found -->'+index)
|
|
107
|
-
if(index){
|
|
108
|
-
//set index to default (0)
|
|
109
|
-
await this.redis_client.set('tiledesk:voice:'+callId + ':attributes', JSON.stringify(attributes), {'EX': 86400});
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
//if index is not present: set to default (0)
|
|
81
|
+
// Always save/overwrite settings
|
|
113
82
|
await this.redis_client.set('tiledesk:voice:'+callId + ':attributes', JSON.stringify(attributes), {'EX': 86400});
|
|
114
|
-
|
|
115
83
|
}
|
|
116
84
|
|
|
117
85
|
|
|
@@ -145,22 +113,15 @@ class VoiceChannel {
|
|
|
145
113
|
|
|
146
114
|
|
|
147
115
|
async deleteCallKeys(callSid) {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
cursor = reply.cursor;
|
|
158
|
-
const keys = reply.keys;
|
|
159
|
-
|
|
160
|
-
if (keys.length > 0) {
|
|
161
|
-
await this.redis_client.del(keys);
|
|
162
|
-
}
|
|
163
|
-
} while (cursor !== 0);
|
|
116
|
+
// Use known key patterns instead of SCAN for better performance
|
|
117
|
+
const keys = [
|
|
118
|
+
`tiledesk:voice:${callSid}:session`,
|
|
119
|
+
`tiledesk:voice:${callSid}:attributes`,
|
|
120
|
+
`tiledesk:voice:${callSid}:delayIndex`
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
// Use unlink for non-blocking delete
|
|
124
|
+
await this.redis_client.unlink(keys);
|
|
164
125
|
}
|
|
165
126
|
|
|
166
127
|
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
const axios = require("axios").default;
|
|
2
|
+
const winston = require('../../utils/logger')
|
|
3
|
+
|
|
4
|
+
class TiledeskSubscriptionClient {
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Constructor for TiledeskSubscriptionClient
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* const { TiledeskSubscriptionClient } = require('tiledesk-subscription-client');
|
|
11
|
+
* const tdClient = new TiledeskSubscriptionClient({API_URL: tiledeskApiUrl, token: jwt_token, log: log});
|
|
12
|
+
* @param {Object} config JSON configuration.
|
|
13
|
+
* @param {string} config.API_URL Mandatory. The Tiledesk api url.
|
|
14
|
+
* @param {string} config.token Optional. Token required for authentication.
|
|
15
|
+
* @param {boolean} config.log Optional. If true HTTP requests are logged.
|
|
16
|
+
*/
|
|
17
|
+
constructor(config) {
|
|
18
|
+
if (!config) {
|
|
19
|
+
throw new Error('[TiledeskSubscriptionClient] config is mandatory');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (!config.API_URL) {
|
|
23
|
+
throw new Error('[TiledeskSubscriptionClient] config.API_URL is mandatory');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
this.project_id = config.project_id
|
|
27
|
+
this.API_URL = config.API_URL;
|
|
28
|
+
this.token = config.token;
|
|
29
|
+
this.config = config;
|
|
30
|
+
this.log = false;
|
|
31
|
+
if (config.log) {
|
|
32
|
+
this.log = config.log;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async subscribe(subscription_info) {
|
|
38
|
+
const URL = this.API_URL + `/${this.project_id}/subscriptions`;
|
|
39
|
+
try {
|
|
40
|
+
const response = await axios({
|
|
41
|
+
url: URL,
|
|
42
|
+
headers: {
|
|
43
|
+
'Content-Type': 'application/json',
|
|
44
|
+
'Authorization': this.token
|
|
45
|
+
},
|
|
46
|
+
data: subscription_info,
|
|
47
|
+
method: 'POST'
|
|
48
|
+
});
|
|
49
|
+
winston.debug("[TiledeskSubscriptionClient] Subscribed");
|
|
50
|
+
return response.data;
|
|
51
|
+
} catch (err) {
|
|
52
|
+
throw err;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async unsubscribe(subscriptionId) {
|
|
57
|
+
const URL = this.API_URL + `/${this.project_id}/subscriptions/${subscriptionId}`;
|
|
58
|
+
try {
|
|
59
|
+
const response = await axios({
|
|
60
|
+
url: URL,
|
|
61
|
+
headers: {
|
|
62
|
+
'Content-Type': 'application/json',
|
|
63
|
+
'Authorization': this.token
|
|
64
|
+
},
|
|
65
|
+
method: 'DELETE'
|
|
66
|
+
});
|
|
67
|
+
winston.debug("[TiledeskSubscriptionClient] Unsubscribed");
|
|
68
|
+
return response.data;
|
|
69
|
+
} catch (err) {
|
|
70
|
+
throw err;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
module.exports = { TiledeskSubscriptionClient }
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Services Index
|
|
3
|
+
*
|
|
4
|
+
* Central export point for all business logic services.
|
|
5
|
+
* Import from this file to access all services in one place.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { SessionService } = require('./SessionService');
|
|
9
|
+
const { MessageService } = require('./MessageService');
|
|
10
|
+
const { SpeechService } = require('./SpeechService');
|
|
11
|
+
const { TwilioService } = require('./TwilioService');
|
|
12
|
+
const { TiledeskMessageBuilder } = require('./TiledeskMessageBuilder');
|
|
13
|
+
|
|
14
|
+
// Channel services
|
|
15
|
+
const { TiledeskChannel } = require('./channels/TiledeskChannel');
|
|
16
|
+
const { VoiceChannel } = require('./channels/VoiceChannel');
|
|
17
|
+
|
|
18
|
+
// Translator services
|
|
19
|
+
const { TiledeskTwilioTranslator } = require('./translators/TiledeskTwilioTranslator');
|
|
20
|
+
|
|
21
|
+
// Integration services
|
|
22
|
+
const { IntegrationService } = require('./IntegrationService');
|
|
23
|
+
const { UploadService } = require('./UploadService');
|
|
24
|
+
const { AiService } = require('./AiService');
|
|
25
|
+
|
|
26
|
+
module.exports = {
|
|
27
|
+
// Core business services
|
|
28
|
+
SessionService,
|
|
29
|
+
MessageService,
|
|
30
|
+
SpeechService,
|
|
31
|
+
TwilioService,
|
|
32
|
+
TiledeskMessageBuilder,
|
|
33
|
+
|
|
34
|
+
// Channel services
|
|
35
|
+
TiledeskChannel,
|
|
36
|
+
VoiceChannel,
|
|
37
|
+
|
|
38
|
+
// Translator services
|
|
39
|
+
TiledeskTwilioTranslator,
|
|
40
|
+
|
|
41
|
+
// Integration services
|
|
42
|
+
IntegrationService,
|
|
43
|
+
UploadService,
|
|
44
|
+
AiService
|
|
45
|
+
};
|