@open-wa/wa-automate 4.44.11 → 4.45.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/dist/cli/cli-options.js
CHANGED
@@ -29,6 +29,11 @@ exports.optionList = [{
|
|
29
29
|
type: String,
|
30
30
|
typeLabel: '{blue {underline mEEwUGEEML2ZThMm252rLg1M}}',
|
31
31
|
description: "The access token of the specific Chatwoot inbox you set up for this session"
|
32
|
+
}, {
|
33
|
+
name: 'force-update-cw-webhook',
|
34
|
+
type: Boolean,
|
35
|
+
default: false,
|
36
|
+
description: "Updates the chatwoot inbox webhook with the --api-host value on every launch"
|
32
37
|
},
|
33
38
|
{
|
34
39
|
name: 'port',
|
package/dist/cli/index.js
CHANGED
@@ -21,6 +21,7 @@ const setup_1 = require("./setup");
|
|
21
21
|
const collections_1 = require("./collections");
|
22
22
|
const server_1 = require("./server");
|
23
23
|
const localtunnel_1 = __importDefault(require("localtunnel"));
|
24
|
+
const chatwoot_1 = require("./integrations/chatwoot");
|
24
25
|
let checkUrl = (s) => (typeof s === "string") && (0, is_url_superb_1.default)(s);
|
25
26
|
const ready = (config) => __awaiter(void 0, void 0, void 0, function* () {
|
26
27
|
(0, index_1.processSend)('ready');
|
@@ -199,7 +200,7 @@ function start() {
|
|
199
200
|
if (cliConfig.tunnel) {
|
200
201
|
spinner.info(`\n• Setting up external tunnel`);
|
201
202
|
const tunnel = yield (0, localtunnel_1.default)({ port: PORT });
|
202
|
-
cliConfig.tunnel = tunnel.url;
|
203
|
+
cliConfig.apiHost = cliConfig.tunnel = tunnel.url;
|
203
204
|
spinner.succeed(`\n\t${(0, terminal_link_1.default)('External address', tunnel.url)}`);
|
204
205
|
}
|
205
206
|
const apiDocsUrl = cliConfig.apiHost ? `${cliConfig.apiHost}/api-docs/ ` : `${cliConfig.host.includes('http') ? '' : 'http://'}${cliConfig.host}:${PORT}/api-docs/ `;
|
@@ -211,6 +212,7 @@ function start() {
|
|
211
212
|
const statsLink = (0, terminal_link_1.default)('API Stats', swaggerStatsUrl);
|
212
213
|
spinner.succeed(`\n\t${statsLink}`);
|
213
214
|
}
|
215
|
+
yield (0, chatwoot_1.setupChatwootOutgoingMessageHandler)(cliConfig, client);
|
214
216
|
}
|
215
217
|
yield ready(Object.assign(Object.assign(Object.assign(Object.assign({}, createConfig), cliConfig), client.getSessionInfo()), { hostAccountNumber: yield client.getHostNumber() }));
|
216
218
|
if (cliConfig.emitUnread) {
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import { Client } from '../..';
|
2
2
|
import { cliFlags } from '../server';
|
3
3
|
import { Request, Response } from "express";
|
4
|
+
export declare const chatwoot_webhook_check_event_name = "cli.integrations.chatwoot.check";
|
4
5
|
export declare type expressMiddleware = (req: Request, res: Response) => Promise<Response<any, Record<string, any>>>;
|
5
6
|
export declare const chatwootMiddleware: (cliConfig: cliFlags, client: Client) => expressMiddleware;
|
6
7
|
export declare const setupChatwootOutgoingMessageHandler: (cliConfig: cliFlags, client: Client) => Promise<void>;
|
@@ -12,7 +12,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
13
13
|
};
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
15
|
-
exports.setupChatwootOutgoingMessageHandler = exports.chatwootMiddleware = void 0;
|
15
|
+
exports.setupChatwootOutgoingMessageHandler = exports.chatwootMiddleware = exports.chatwoot_webhook_check_event_name = void 0;
|
16
|
+
const uuid_apikey_1 = __importDefault(require("uuid-apikey"));
|
17
|
+
const __1 = require("../..");
|
16
18
|
const axios_1 = __importDefault(require("axios"));
|
17
19
|
const form_data_1 = __importDefault(require("form-data"));
|
18
20
|
const mime_types_1 = __importDefault(require("mime-types"));
|
@@ -24,6 +26,7 @@ const convoReg = {
|
|
24
26
|
//WID : chatwoot conversation ID
|
25
27
|
"example@c.us": "1"
|
26
28
|
};
|
29
|
+
exports.chatwoot_webhook_check_event_name = "cli.integrations.chatwoot.check";
|
27
30
|
const chatwootMiddleware = (cliConfig, client) => {
|
28
31
|
return (req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
29
32
|
const processMesssage = () => __awaiter(void 0, void 0, void 0, function* () {
|
@@ -48,10 +51,10 @@ const chatwootMiddleware = (cliConfig, client) => {
|
|
48
51
|
if ((attachments === null || attachments === void 0 ? void 0 : attachments.length) > 0) {
|
49
52
|
//has attachments
|
50
53
|
const [firstAttachment, ...restAttachments] = attachments;
|
51
|
-
const sendAttachment = (attachment, c) => __awaiter(void 0, void 0, void 0, function* () { return client.sendImage(to, attachment.data_url, attachment.data_url.substring(attachment.data_url.lastIndexOf('/') + 1), c || '', null, true); });
|
54
|
+
const sendAttachment = (attachment, c) => __awaiter(void 0, void 0, void 0, function* () { return attachment && client.sendImage(to, attachment.data_url, attachment.data_url.substring(attachment.data_url.lastIndexOf('/') + 1), c || '', null, true); });
|
52
55
|
//send the text as the caption with the first message only
|
53
56
|
promises.push(sendAttachment(firstAttachment, content));
|
54
|
-
(restAttachments || []).map(sendAttachment).map(promises.push);
|
57
|
+
((restAttachments || []).map(attachment => sendAttachment(attachment)) || []).map(p => promises.push(p));
|
55
58
|
}
|
56
59
|
else {
|
57
60
|
//no attachments
|
@@ -71,7 +74,15 @@ const chatwootMiddleware = (cliConfig, client) => {
|
|
71
74
|
}
|
72
75
|
else {
|
73
76
|
//not a location message
|
74
|
-
|
77
|
+
/**
|
78
|
+
* Check for url
|
79
|
+
*/
|
80
|
+
const urlregex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/g;
|
81
|
+
if (content.match(urlregex) && content.match(urlregex)[0]) {
|
82
|
+
promises.push(client.sendLinkWithAutoPreview(to, content.match(urlregex)[0], content));
|
83
|
+
}
|
84
|
+
else
|
85
|
+
promises.push(client.sendText(to, content));
|
75
86
|
}
|
76
87
|
}
|
77
88
|
return yield Promise.all(promises);
|
@@ -89,15 +100,66 @@ const chatwootMiddleware = (cliConfig, client) => {
|
|
89
100
|
};
|
90
101
|
exports.chatwootMiddleware = chatwootMiddleware;
|
91
102
|
const setupChatwootOutgoingMessageHandler = (cliConfig, client) => __awaiter(void 0, void 0, void 0, function* () {
|
103
|
+
__1.log.info(`Setting up chatwoot integration: ${cliConfig.chatwootUrl}`);
|
92
104
|
const u = cliConfig.chatwootUrl; //e.g `"localhost:3000/api/v1/accounts/3"
|
93
105
|
const api_access_token = cliConfig.chatwootApiAccessToken;
|
94
106
|
const _u = new URL(u);
|
95
107
|
const origin = _u.origin;
|
96
108
|
const port = _u.port || 80;
|
97
|
-
const
|
109
|
+
const accountNumber = yield client.getHostNumber();
|
110
|
+
const proms = [];
|
111
|
+
let expectedSelfWebhookUrl = cliConfig.apiHost ? `${cliConfig.apiHost}/chatwoot ` : `${cliConfig.host.includes('http') ? '' : 'http://'}${cliConfig.host}:${cliConfig.port}/chatwoot `;
|
112
|
+
expectedSelfWebhookUrl = expectedSelfWebhookUrl.trim();
|
113
|
+
if (cliConfig.key)
|
114
|
+
expectedSelfWebhookUrl = `${expectedSelfWebhookUrl}?api_key=${cliConfig.key}`;
|
115
|
+
let [accountId, inboxId] = (u.match(/\/(app|(api\/v1))\/accounts\/\d*\/(inbox|inboxes)\/\d*/g) || [''])[0].split('/').filter(Number);
|
116
|
+
inboxId = inboxId || u.match(/inboxes\/\d*/g) && u.match(/inboxes\/\d*/g)[0].replace('inboxes/', '');
|
98
117
|
// const accountId = u.match(/accounts\/\d*/g) && u.match(/accounts\/\d*/g)[0].replace('accounts/', '')
|
99
|
-
|
100
|
-
|
118
|
+
/**
|
119
|
+
* Is the inbox and or account id undefined??
|
120
|
+
*/
|
121
|
+
if (!accountId) {
|
122
|
+
__1.log.info(`CHATWOOT INTEGRATION: account ID missing. Attempting to infer from access token....`);
|
123
|
+
/**
|
124
|
+
* If the account ID is undefined then get the account ID from the access_token
|
125
|
+
*/
|
126
|
+
accountId = (yield axios_1.default.get(`${origin}/api/v1/profile`, { headers: { api_access_token } })).data.account_id;
|
127
|
+
__1.log.info(`CHATWOOT INTEGRATION: Got account ID: ${accountId}`);
|
128
|
+
}
|
129
|
+
if (!inboxId) {
|
130
|
+
__1.log.info(`CHATWOOT INTEGRATION: inbox ID missing. Attempting to find correct inbox....`);
|
131
|
+
/**
|
132
|
+
* Find the inbox with the correct setup.
|
133
|
+
*/
|
134
|
+
const inboxArray = (yield axios_1.default.get(`${origin}/api/v1/accounts/${accountId}/inboxes`, { headers: { api_access_token } })).data.payload;
|
135
|
+
const possibleInbox = inboxArray.find(inbox => { var _a; return ((_a = inbox === null || inbox === void 0 ? void 0 : inbox.additional_attributes) === null || _a === void 0 ? void 0 : _a.hostAccountNumber) === accountNumber; });
|
136
|
+
if (possibleInbox) {
|
137
|
+
__1.log.info(`CHATWOOT INTEGRATION: found inbox: ${JSON.stringify(possibleInbox)}`);
|
138
|
+
__1.log.info(`CHATWOOT INTEGRATION: found inbox id: ${possibleInbox.channel_id}`);
|
139
|
+
inboxId = possibleInbox.channel_id;
|
140
|
+
}
|
141
|
+
else {
|
142
|
+
__1.log.info(`CHATWOOT INTEGRATION: inbox not found. Attempting to create inbox....`);
|
143
|
+
/**
|
144
|
+
* Create inbox
|
145
|
+
*/
|
146
|
+
const { data: new_inbox } = (yield axios_1.default.post(`${origin}/api/v1/accounts/${accountId}/inboxes`, {
|
147
|
+
"name": `open-wa-${accountNumber}`,
|
148
|
+
"channel": {
|
149
|
+
"phone_number": `${accountNumber}`,
|
150
|
+
"type": "api",
|
151
|
+
"webhook_url": expectedSelfWebhookUrl,
|
152
|
+
"additional_attributes": {
|
153
|
+
"sessionId": client.getSessionId(),
|
154
|
+
"hostAccountNumber": `${accountNumber}`
|
155
|
+
}
|
156
|
+
}
|
157
|
+
}, { headers: { api_access_token } }));
|
158
|
+
inboxId = new_inbox.id;
|
159
|
+
__1.log.info(`CHATWOOT INTEGRATION: inbox created. id: ${inboxId}`);
|
160
|
+
}
|
161
|
+
}
|
162
|
+
const cwReq = (method, path, data, _headers) => {
|
101
163
|
const url = `${origin}/api/v1/accounts/${accountId}/${path}`.replace('app.bentonow.com', 'chat.bentonow.com');
|
102
164
|
// console.log(url,method,data)
|
103
165
|
return (0, axios_1.default)({
|
@@ -107,20 +169,74 @@ const setupChatwootOutgoingMessageHandler = (cliConfig, client) => __awaiter(voi
|
|
107
169
|
headers: Object.assign({ api_access_token }, _headers)
|
108
170
|
});
|
109
171
|
};
|
110
|
-
|
111
|
-
|
172
|
+
let { data: get_inbox } = yield cwReq('get', `inboxes/${inboxId}`);
|
173
|
+
/**
|
174
|
+
* Update the webhook
|
175
|
+
*/
|
176
|
+
const updatePayload = {
|
177
|
+
"channel": {
|
178
|
+
"additional_attributes": {
|
179
|
+
"sessionId": client.getSessionId(),
|
180
|
+
"hostAccountNumber": `${accountNumber}`,
|
181
|
+
"instanceId": `${client.getInstanceId()}`
|
182
|
+
}
|
183
|
+
}
|
184
|
+
};
|
185
|
+
if (cliConfig.forceUpdateCwWebhook)
|
186
|
+
updatePayload.channel['webhook_url'] = expectedSelfWebhookUrl;
|
187
|
+
const updateInboxPromise = cwReq('patch', `inboxes/${inboxId}`, updatePayload);
|
188
|
+
if (cliConfig.forceUpdateCwWebhook)
|
189
|
+
get_inbox = (yield updateInboxPromise).data;
|
190
|
+
else
|
191
|
+
proms.push(updateInboxPromise);
|
112
192
|
/**
|
113
193
|
* Get the inbox and test it.
|
114
194
|
*/
|
115
195
|
if (!((get_inbox === null || get_inbox === void 0 ? void 0 : get_inbox.webhook_url) || "").includes("/chatwoot"))
|
116
196
|
console.log("Please set the chatwoot inbox webhook to this sessions URL with path /chatwoot");
|
197
|
+
/**
|
198
|
+
* Check the webhook URL
|
199
|
+
*/
|
200
|
+
const chatwootWebhookCheck = () => __awaiter(void 0, void 0, void 0, function* () {
|
201
|
+
let checkCodePromise;
|
202
|
+
const cancelCheckProm = () => (checkCodePromise.cancel && typeof checkCodePromise.cancel === "function") && checkCodePromise.cancel();
|
203
|
+
try {
|
204
|
+
const wUrl = get_inbox.webhook_url.split('?')[0].replace(/\/+$/, "").trim();
|
205
|
+
const checkWhURL = `${wUrl}${wUrl.endsWith("/") ? '' : `/`}checkWebhook${cliConfig.key ? `?api_key=${cliConfig.key}` : ''}`;
|
206
|
+
__1.log.info(`Verifying webhook url: ${checkWhURL}`);
|
207
|
+
const checkCode = uuid_apikey_1.default.create().apiKey; //random generated string
|
208
|
+
yield new Promise((resolve, reject) => __awaiter(void 0, void 0, void 0, function* () {
|
209
|
+
var _a;
|
210
|
+
checkCodePromise = __1.ev.waitFor(exports.chatwoot_webhook_check_event_name, 5000).catch(reject);
|
211
|
+
yield axios_1.default.post(checkWhURL, {
|
212
|
+
checkCode
|
213
|
+
}, { headers: { api_key: cliConfig.key || '' } }).catch(reject);
|
214
|
+
const checkCodeResponse = yield checkCodePromise;
|
215
|
+
if (checkCodeResponse && ((_a = checkCodeResponse[0]) === null || _a === void 0 ? void 0 : _a.checkCode) == checkCode)
|
216
|
+
resolve(true);
|
217
|
+
else
|
218
|
+
reject(`Webhook check code is incorrect. Expected ${checkCode} - incoming ${((checkCodeResponse || [])[0] || {}).checkCode}`);
|
219
|
+
}));
|
220
|
+
__1.log.info('Chatwoot webhook verification successful');
|
221
|
+
}
|
222
|
+
catch (error) {
|
223
|
+
cancelCheckProm();
|
224
|
+
const e = `Unable to verify the chatwoot webhook URL on this inbox: ${error.message}`;
|
225
|
+
console.error(e);
|
226
|
+
__1.log.error(e);
|
227
|
+
}
|
228
|
+
finally {
|
229
|
+
cancelCheckProm();
|
230
|
+
}
|
231
|
+
});
|
232
|
+
proms.push(chatwootWebhookCheck());
|
117
233
|
/**
|
118
234
|
* Get Contacts and conversations
|
119
235
|
*/
|
120
236
|
const searchContact = (number) => __awaiter(void 0, void 0, void 0, function* () {
|
121
237
|
try {
|
122
238
|
const n = number.replace('@c.us', '');
|
123
|
-
const { data } = yield cwReq(`contacts/search?q=${n}&sort=phone_number
|
239
|
+
const { data } = yield cwReq('get', `contacts/search?q=${n}&sort=phone_number`);
|
124
240
|
if (data.payload.length) {
|
125
241
|
return data.payload.find(x => (x.phone_number || "").includes(n)) || false;
|
126
242
|
}
|
@@ -133,8 +249,8 @@ const setupChatwootOutgoingMessageHandler = (cliConfig, client) => __awaiter(voi
|
|
133
249
|
});
|
134
250
|
const getContactConversation = (number) => __awaiter(void 0, void 0, void 0, function* () {
|
135
251
|
try {
|
136
|
-
const { data } = yield cwReq(`contacts/${contactReg[number]}/conversations
|
137
|
-
const allContactConversations = data.payload.filter(c => c.inbox_id ===
|
252
|
+
const { data } = yield cwReq('get', `contacts/${contactReg[number]}/conversations`);
|
253
|
+
const allContactConversations = data.payload.filter(c => c.inbox_id === inboxId).sort((a, b) => a.id - b.id);
|
138
254
|
const [opened, notOpen] = [allContactConversations.filter(c => c.status === 'open'), allContactConversations.filter(c => c.status != 'open')];
|
139
255
|
return opened[0] || notOpen[0];
|
140
256
|
}
|
@@ -144,9 +260,9 @@ const setupChatwootOutgoingMessageHandler = (cliConfig, client) => __awaiter(voi
|
|
144
260
|
});
|
145
261
|
const createConversation = (contact_id) => __awaiter(void 0, void 0, void 0, function* () {
|
146
262
|
try {
|
147
|
-
const { data } = yield cwReq(
|
263
|
+
const { data } = yield cwReq('post', `conversations`, {
|
148
264
|
contact_id,
|
149
|
-
"inbox_id":
|
265
|
+
"inbox_id": inboxId
|
150
266
|
});
|
151
267
|
return data;
|
152
268
|
}
|
@@ -156,7 +272,7 @@ const setupChatwootOutgoingMessageHandler = (cliConfig, client) => __awaiter(voi
|
|
156
272
|
});
|
157
273
|
const createContact = (contact) => __awaiter(void 0, void 0, void 0, function* () {
|
158
274
|
try {
|
159
|
-
const { data } = yield cwReq(
|
275
|
+
const { data } = yield cwReq('post', `contacts`, {
|
160
276
|
"identifier": contact.id,
|
161
277
|
"name": contact.formattedName || contact.id,
|
162
278
|
"phone_number": `+${contact.id.replace('@c.us', '')}`,
|
@@ -170,7 +286,7 @@ const setupChatwootOutgoingMessageHandler = (cliConfig, client) => __awaiter(voi
|
|
170
286
|
});
|
171
287
|
const sendConversationMessage = (content, contactId, message) => __awaiter(void 0, void 0, void 0, function* () {
|
172
288
|
try {
|
173
|
-
const { data } = yield cwReq(`conversations/${convoReg[contactId]}/messages`,
|
289
|
+
const { data } = yield cwReq('post', `conversations/${convoReg[contactId]}/messages`, {
|
174
290
|
content,
|
175
291
|
"message_type": 0,
|
176
292
|
"private": false
|
@@ -193,7 +309,7 @@ const setupChatwootOutgoingMessageHandler = (cliConfig, client) => __awaiter(voi
|
|
193
309
|
formData.append('content', content);
|
194
310
|
formData.append('message_type', 'incoming');
|
195
311
|
try {
|
196
|
-
const { data } = yield cwReq(`conversations/${convoReg[contactId]}/messages`,
|
312
|
+
const { data } = yield cwReq('post', `conversations/${convoReg[contactId]}/messages`, formData, formData.getHeaders());
|
197
313
|
return data;
|
198
314
|
}
|
199
315
|
catch (error) {
|
@@ -204,7 +320,7 @@ const setupChatwootOutgoingMessageHandler = (cliConfig, client) => __awaiter(voi
|
|
204
320
|
/**
|
205
321
|
* Update the chatwoot contact and conversation registries
|
206
322
|
*/
|
207
|
-
client.onMessage((message) => __awaiter(void 0, void 0, void 0, function* () {
|
323
|
+
const setOnMessageProm = client.onMessage((message) => __awaiter(void 0, void 0, void 0, function* () {
|
208
324
|
if (message.from.includes('g')) {
|
209
325
|
//chatwoot integration does not support group chats
|
210
326
|
return;
|
@@ -266,5 +382,8 @@ const setupChatwootOutgoingMessageHandler = (cliConfig, client) => __awaiter(voi
|
|
266
382
|
else
|
267
383
|
yield sendConversationMessage(text, message.from, message);
|
268
384
|
}));
|
385
|
+
proms.push(setOnMessageProm);
|
386
|
+
yield Promise.all(proms);
|
387
|
+
return;
|
269
388
|
});
|
270
389
|
exports.setupChatwootOutgoingMessageHandler = setupChatwootOutgoingMessageHandler;
|
package/dist/cli/server.js
CHANGED
@@ -298,7 +298,13 @@ const setupTwilioCompatibleWebhook = (cliConfig, client) => {
|
|
298
298
|
exports.setupTwilioCompatibleWebhook = setupTwilioCompatibleWebhook;
|
299
299
|
const setupChatwoot = (cliConfig, client) => __awaiter(void 0, void 0, void 0, function* () {
|
300
300
|
exports.app.post('/chatwoot', (0, chatwoot_1.chatwootMiddleware)(cliConfig, client));
|
301
|
-
|
301
|
+
exports.app.post(`/chatwoot/checkWebhook`, (req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
302
|
+
const { body } = req;
|
303
|
+
__1.log.info(`chatwoot webhook check request received: ${body.checkCode}`);
|
304
|
+
yield __1.ev.emitAsync(chatwoot_1.chatwoot_webhook_check_event_name, body);
|
305
|
+
return res.send({});
|
306
|
+
}));
|
307
|
+
// await setupChatwootOutgoingMessageHandler(cliConfig, client);
|
302
308
|
});
|
303
309
|
exports.setupChatwoot = setupChatwoot;
|
304
310
|
const setupBotPressHandler = (cliConfig, client) => {
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@open-wa/wa-automate",
|
3
|
-
"version": "4.
|
3
|
+
"version": "4.45.0",
|
4
4
|
"licenseCheckUrl": "https://funcs.openwa.dev/license-check",
|
5
5
|
"brokenMethodReportUrl": "https://funcs.openwa.dev/report-bm",
|
6
6
|
"patches": "https://cdn.openwa.dev/patches.json",
|
@@ -123,7 +123,7 @@
|
|
123
123
|
"cross-spawn": "^7.0.3",
|
124
124
|
"datauri": "^4.0.1",
|
125
125
|
"death": "^1.1.0",
|
126
|
-
"eventemitter2": "^6.4.
|
126
|
+
"eventemitter2": "^6.4.7",
|
127
127
|
"express": "^4.17.1",
|
128
128
|
"express-ipfilter": "^1.3.1",
|
129
129
|
"express-robots-txt": "^1.0.0",
|