@wabot-dev/framework 0.5.7 → 0.5.9
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/src/addon/chat-controller/cmd/CmdChannel.js +6 -2
- package/dist/src/addon/chat-controller/cmd/cmdChannelName.js +3 -0
- package/dist/src/addon/chat-controller/socket/SocketChannel.js +6 -2
- package/dist/src/addon/chat-controller/socket/socketChannelName.js +3 -0
- package/dist/src/addon/chat-controller/telegram/TelegramChannel.js +6 -2
- package/dist/src/addon/chat-controller/telegram/telegramChannelName.js +3 -0
- package/dist/src/addon/chat-controller/wasender/@whatsAppByWasender.js +20 -0
- package/dist/src/addon/chat-controller/wasender/WasenderWebhookController.js +82 -0
- package/dist/src/addon/chat-controller/wasender/WhatsAppByWasenderChannel.js +67 -0
- package/dist/src/addon/chat-controller/wasender/WhatsAppByWasenderChannelConfig.js +16 -0
- package/dist/src/addon/chat-controller/wasender/WhatsAppReceiverByWasender.js +39 -0
- package/dist/src/addon/chat-controller/wasender/WhatsAppSenderByWasender.js +33 -0
- package/dist/src/addon/chat-controller/wasender/extractNumberFromWasenderKey.js +5 -0
- package/dist/src/addon/chat-controller/wasender/whatsAppByWasenderChannelName.js +3 -0
- package/dist/src/addon/chat-controller/whatsapp/WhatsAppChannel.js +3 -0
- package/dist/src/addon/chat-controller/whatsapp/cloud-api/WhatsAppReceiverByCloudApi.js +2 -2
- package/dist/src/addon/chat-controller/whatsapp/proxy/WhatsAppReceiverByWabotProxy.js +2 -1
- package/dist/src/addon/chat-controller/whatsapp/whatsAppChannelName.js +3 -0
- package/dist/src/addon/chat-controller/whatsapp-by-wasender/@whatsAppByWasender.js +20 -0
- package/dist/src/addon/chat-controller/whatsapp-by-wasender/WhatsAppByWasenderChannel.js +52 -0
- package/dist/src/addon/chat-controller/whatsapp-by-wasender/WhatsAppByWasenderChannelConfig.js +16 -0
- package/dist/src/addon/chat-controller/whatsapp-by-wasender/WhatsAppReceiverByWasender.js +106 -0
- package/dist/src/addon/chat-controller/whatsapp-by-wasender/WhatsAppSenderByWasender.js +40 -0
- package/dist/src/addon/chat-controller/whatsapp-by-wasender/extractNumberFromWasenderKey.js +5 -0
- package/dist/src/feature/rest-controller/metadata/RestControllerMetadataStore.js +35 -8
- package/dist/src/index.d.ts +203 -7
- package/dist/src/index.js +12 -0
- package/dist/src/node_modules/wasenderapi/dist/index.js +553 -0
- package/package.json +3 -2
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { __decorate, __metadata } from 'tslib';
|
|
2
2
|
import { injectable } from '../../../core/injection/index.js';
|
|
3
3
|
import { Logger } from '../../../core/logger/Logger.js';
|
|
4
|
+
import { cmdChannelName } from './cmdChannelName.js';
|
|
4
5
|
import * as readline from 'readline';
|
|
5
6
|
import * as fs from 'fs';
|
|
6
7
|
import * as path from 'path';
|
|
@@ -10,13 +11,15 @@ import { Auth } from '../../../core/auth/Auth.js';
|
|
|
10
11
|
var CmdChannel_1;
|
|
11
12
|
const chatIdPath = '.cmd-channel/id.json';
|
|
12
13
|
const authInfoPath = '.cmd-channel/auth-info.json';
|
|
13
|
-
let CmdChannel =
|
|
14
|
+
let CmdChannel = class CmdChannel {
|
|
15
|
+
static { CmdChannel_1 = this; }
|
|
14
16
|
auth;
|
|
15
17
|
chatId = undefined;
|
|
16
18
|
rl = readline.createInterface({
|
|
17
19
|
input: process.stdin,
|
|
18
20
|
output: process.stdout,
|
|
19
21
|
});
|
|
22
|
+
static channelName = cmdChannelName;
|
|
20
23
|
callBack = null;
|
|
21
24
|
constructor(auth) {
|
|
22
25
|
this.auth = auth;
|
|
@@ -50,7 +53,7 @@ let CmdChannel = CmdChannel_1 = class CmdChannel {
|
|
|
50
53
|
const chatConnection = {
|
|
51
54
|
id: this.chatId,
|
|
52
55
|
chatType: 'PRIVATE',
|
|
53
|
-
channelName: CmdChannel_1.
|
|
56
|
+
channelName: CmdChannel_1.channelName,
|
|
54
57
|
};
|
|
55
58
|
if (!this.callBack)
|
|
56
59
|
return;
|
|
@@ -61,6 +64,7 @@ let CmdChannel = CmdChannel_1 = class CmdChannel {
|
|
|
61
64
|
}
|
|
62
65
|
}
|
|
63
66
|
await this.callBack({
|
|
67
|
+
channel: cmdChannelName,
|
|
64
68
|
chatConnection,
|
|
65
69
|
message: {
|
|
66
70
|
text: trimmedInput,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { __decorate, __metadata } from 'tslib';
|
|
2
2
|
import { injectable } from '../../../core/injection/index.js';
|
|
3
|
+
import { socketChannelName } from './socketChannelName.js';
|
|
3
4
|
import { handshakeMiddlewares } from '../../../feature/socket-controller/metadata/@handshakeMiddlewares.js';
|
|
4
5
|
import { socketController } from '../../../feature/socket-controller/metadata/@socketController.js';
|
|
5
6
|
import { onSocketEvent } from '../../../feature/socket-controller/metadata/@onSocketEvent.js';
|
|
@@ -33,8 +34,10 @@ __decorate([
|
|
|
33
34
|
isNotEmpty(),
|
|
34
35
|
__metadata("design:type", String)
|
|
35
36
|
], SocketChannelReceivedMessage.prototype, "text", void 0);
|
|
36
|
-
let SocketChannel =
|
|
37
|
+
let SocketChannel = class SocketChannel {
|
|
38
|
+
static { SocketChannel_1 = this; }
|
|
37
39
|
config;
|
|
40
|
+
static channelName = socketChannelName;
|
|
38
41
|
callBack = null;
|
|
39
42
|
controller = null;
|
|
40
43
|
constructor(config) {
|
|
@@ -58,9 +61,10 @@ let SocketChannel = SocketChannel_1 = class SocketChannel {
|
|
|
58
61
|
const chatConnection = {
|
|
59
62
|
id: message.chatId,
|
|
60
63
|
chatType: 'PRIVATE',
|
|
61
|
-
channelName: SocketChannel_1.
|
|
64
|
+
channelName: SocketChannel_1.channelName,
|
|
62
65
|
};
|
|
63
66
|
await channel.callBack({
|
|
67
|
+
channel: socketChannelName,
|
|
64
68
|
chatConnection,
|
|
65
69
|
message: {
|
|
66
70
|
text: message.text,
|
|
@@ -2,10 +2,13 @@ import { __decorate, __metadata } from 'tslib';
|
|
|
2
2
|
import { Bot } from 'grammy';
|
|
3
3
|
import { TelegramChannelConfig } from './TelegramChannelConfig.js';
|
|
4
4
|
import { injectable } from '../../../core/injection/index.js';
|
|
5
|
+
import { telegramChannelName } from './telegramChannelName.js';
|
|
5
6
|
|
|
6
7
|
var TelegramChannel_1;
|
|
7
|
-
let TelegramChannel =
|
|
8
|
+
let TelegramChannel = class TelegramChannel {
|
|
9
|
+
static { TelegramChannel_1 = this; }
|
|
8
10
|
config;
|
|
11
|
+
static channelName = telegramChannelName;
|
|
9
12
|
bot;
|
|
10
13
|
constructor(config) {
|
|
11
14
|
this.config = config;
|
|
@@ -19,9 +22,10 @@ let TelegramChannel = TelegramChannel_1 = class TelegramChannel {
|
|
|
19
22
|
const chatConnection = {
|
|
20
23
|
id: ctx.message.chat.id.toString(),
|
|
21
24
|
chatType: ctx.message.chat.type === 'private' ? 'PRIVATE' : 'GROUP',
|
|
22
|
-
channelName: TelegramChannel_1.
|
|
25
|
+
channelName: TelegramChannel_1.channelName,
|
|
23
26
|
};
|
|
24
27
|
await callback({
|
|
28
|
+
channel: telegramChannelName,
|
|
25
29
|
chatConnection,
|
|
26
30
|
message: {
|
|
27
31
|
senderName: ctx.from.first_name,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { container } from '../../../core/injection/index.js';
|
|
2
|
+
import { WhatsAppByWasenderChannelConfig } from './WhatsAppByWasenderChannelConfig.js';
|
|
3
|
+
import { ControllerMetadataStore } from '../../../feature/chat-controller/metadata/ControllerMetadataStore.js';
|
|
4
|
+
import '../../../feature/chat-controller/ChatResolver.js';
|
|
5
|
+
import '../../../feature/chat-controller/runChatControllers.js';
|
|
6
|
+
import { WhatsAppByWasenderChannel } from './WhatsAppByWasenderChannel.js';
|
|
7
|
+
|
|
8
|
+
function whatsAppByWasender(config) {
|
|
9
|
+
return function (target, propertyKey) {
|
|
10
|
+
const store = container.resolve(ControllerMetadataStore);
|
|
11
|
+
store.saveChannelMetadata({
|
|
12
|
+
channelConstructor: WhatsAppByWasenderChannel,
|
|
13
|
+
functionName: propertyKey.toString(),
|
|
14
|
+
controllerConstructor: target.constructor,
|
|
15
|
+
channelConfig: new WhatsAppByWasenderChannelConfig(config ?? {}),
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export { whatsAppByWasender };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { __decorate, __metadata } from 'tslib';
|
|
2
|
+
import { Logger } from '../../../core/logger/Logger.js';
|
|
3
|
+
import '../../../core/injection/index.js';
|
|
4
|
+
import '../../../feature/rest-controller/metadata/RestControllerMetadataStore.js';
|
|
5
|
+
import { onPost } from '../../../feature/rest-controller/metadata/@onPost.js';
|
|
6
|
+
import { extractNumberFromWasenderMessageKey } from './extractNumberFromWasenderKey.js';
|
|
7
|
+
import { IncomingMessage } from 'http';
|
|
8
|
+
|
|
9
|
+
class WasenderWebhookController {
|
|
10
|
+
wasender;
|
|
11
|
+
listener;
|
|
12
|
+
logger = new Logger('wabot:wasender-webhook');
|
|
13
|
+
constructor(wasender, listener) {
|
|
14
|
+
this.wasender = wasender;
|
|
15
|
+
this.listener = listener;
|
|
16
|
+
}
|
|
17
|
+
async handleWebhook(req) {
|
|
18
|
+
const rawBody = await this.getRawBody(req);
|
|
19
|
+
const event = await this.parseEvent(req, rawBody);
|
|
20
|
+
this.logger.trace(`received event ${event.event}`);
|
|
21
|
+
switch (event.event) {
|
|
22
|
+
case 'messages.received':
|
|
23
|
+
const messages = Array.isArray(event.data.messages)
|
|
24
|
+
? event.data.messages
|
|
25
|
+
: [event.data.messages];
|
|
26
|
+
await this.handleMessages(messages);
|
|
27
|
+
break;
|
|
28
|
+
default:
|
|
29
|
+
this.logger.warn(`unhandled event type ${event.event}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async handleMessages(messages) {
|
|
33
|
+
for (const message of messages) {
|
|
34
|
+
const rawNumber = extractNumberFromWasenderMessageKey(message.key);
|
|
35
|
+
const from = rawNumber.startsWith('+') ? rawNumber : `+${rawNumber}`;
|
|
36
|
+
this.logger.trace(`new message from '${from}'`);
|
|
37
|
+
if (message.message.conversation) {
|
|
38
|
+
await this.listener({
|
|
39
|
+
text: message.message.conversation,
|
|
40
|
+
senderName: message.pushName,
|
|
41
|
+
senderId: from,
|
|
42
|
+
metadata: {
|
|
43
|
+
whatsAppNumber: from,
|
|
44
|
+
},
|
|
45
|
+
}, from);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async parseEvent(req, rawBody) {
|
|
50
|
+
const adapter = {
|
|
51
|
+
getHeader: (name) => {
|
|
52
|
+
const value = req.headers[name.toLowerCase()];
|
|
53
|
+
return Array.isArray(value) ? value[0] : value;
|
|
54
|
+
},
|
|
55
|
+
getRawBody: () => rawBody,
|
|
56
|
+
};
|
|
57
|
+
const event = await this.wasender.handleWebhookEvent(adapter);
|
|
58
|
+
return event;
|
|
59
|
+
}
|
|
60
|
+
getRawBody(req) {
|
|
61
|
+
return new Promise((resolve, reject) => {
|
|
62
|
+
let data = '';
|
|
63
|
+
req.on('data', (chunk) => {
|
|
64
|
+
data += chunk;
|
|
65
|
+
});
|
|
66
|
+
req.on('end', () => {
|
|
67
|
+
resolve(data);
|
|
68
|
+
});
|
|
69
|
+
req.on('error', (err) => {
|
|
70
|
+
reject(err);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
__decorate([
|
|
76
|
+
onPost({ disableJsonParser: true, disableUrlEncodedParser: true }),
|
|
77
|
+
__metadata("design:type", Function),
|
|
78
|
+
__metadata("design:paramtypes", [IncomingMessage]),
|
|
79
|
+
__metadata("design:returntype", Promise)
|
|
80
|
+
], WasenderWebhookController.prototype, "handleWebhook", null);
|
|
81
|
+
|
|
82
|
+
export { WasenderWebhookController };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { __decorate, __metadata } from 'tslib';
|
|
2
|
+
import { injectable } from '../../../core/injection/index.js';
|
|
3
|
+
import { Env } from '../../../core/env/Env.js';
|
|
4
|
+
import { Logger } from '../../../core/logger/Logger.js';
|
|
5
|
+
import { WhatsAppByWasenderChannelConfig } from './WhatsAppByWasenderChannelConfig.js';
|
|
6
|
+
import { WhatsAppReceiverByWasender } from './WhatsAppReceiverByWasender.js';
|
|
7
|
+
import { WhatsAppSenderByWasender } from './WhatsAppSenderByWasender.js';
|
|
8
|
+
import { whatsAppByWasenderChannelName } from './whatsAppByWasenderChannelName.js';
|
|
9
|
+
|
|
10
|
+
var WhatsAppByWasenderChannel_1;
|
|
11
|
+
let WhatsAppByWasenderChannel = class WhatsAppByWasenderChannel {
|
|
12
|
+
static { WhatsAppByWasenderChannel_1 = this; }
|
|
13
|
+
logger = new Logger('wabot:whatsapp-by-wasender-channel');
|
|
14
|
+
sender;
|
|
15
|
+
receiver;
|
|
16
|
+
phoneNumber;
|
|
17
|
+
static channelName = whatsAppByWasenderChannelName;
|
|
18
|
+
constructor(config, env) {
|
|
19
|
+
const apiKey = config.apiKey ?? env.requireString('WASENDER_API_KEY');
|
|
20
|
+
const webhookSecret = config.webhookSecret ?? env.requireString('WASENDER_WEBHOOK_SECRET');
|
|
21
|
+
this.phoneNumber = config.phoneNumber ?? env.requireString('WASENDER_PHONE_NUMBER');
|
|
22
|
+
this.sender = new WhatsAppSenderByWasender(apiKey, config.retryOptions);
|
|
23
|
+
this.receiver = new WhatsAppReceiverByWasender({
|
|
24
|
+
apiKey,
|
|
25
|
+
webhookSecret,
|
|
26
|
+
webhookPath: config.webhookPath,
|
|
27
|
+
retryOptions: config.retryOptions,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
listen(callback) {
|
|
31
|
+
this.receiver.listenMessage(async (message, from) => {
|
|
32
|
+
try {
|
|
33
|
+
await callback({
|
|
34
|
+
channel: whatsAppByWasenderChannelName,
|
|
35
|
+
chatConnection: {
|
|
36
|
+
chatType: 'PRIVATE',
|
|
37
|
+
channelName: WhatsAppByWasenderChannel_1.channelName,
|
|
38
|
+
id: from,
|
|
39
|
+
},
|
|
40
|
+
message,
|
|
41
|
+
reply: async (replyMessage) => {
|
|
42
|
+
await this.sender.send({
|
|
43
|
+
from: this.phoneNumber,
|
|
44
|
+
to: from,
|
|
45
|
+
message: replyMessage,
|
|
46
|
+
});
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
this.logger.error('Failed to handle WhatsApp message', err);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
connect() {
|
|
56
|
+
this.receiver.connect();
|
|
57
|
+
}
|
|
58
|
+
disconnect() {
|
|
59
|
+
this.receiver.disconnect();
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
WhatsAppByWasenderChannel = WhatsAppByWasenderChannel_1 = __decorate([
|
|
63
|
+
injectable(),
|
|
64
|
+
__metadata("design:paramtypes", [WhatsAppByWasenderChannelConfig, Env])
|
|
65
|
+
], WhatsAppByWasenderChannel);
|
|
66
|
+
|
|
67
|
+
export { WhatsAppByWasenderChannel };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class WhatsAppByWasenderChannelConfig {
|
|
2
|
+
apiKey;
|
|
3
|
+
webhookSecret;
|
|
4
|
+
phoneNumber;
|
|
5
|
+
webhookPath;
|
|
6
|
+
retryOptions;
|
|
7
|
+
constructor(config) {
|
|
8
|
+
this.apiKey = config.apiKey;
|
|
9
|
+
this.webhookSecret = config.webhookSecret;
|
|
10
|
+
this.phoneNumber = config.phoneNumber;
|
|
11
|
+
this.webhookPath = config.webhookPath ?? '/wasender/hook';
|
|
12
|
+
this.retryOptions = config.retryOptions ?? { enabled: true, maxRetries: 3 };
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { WhatsAppByWasenderChannelConfig };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { __decorate, __metadata } from 'tslib';
|
|
2
|
+
import '../../../core/injection/index.js';
|
|
3
|
+
import '../../../feature/rest-controller/metadata/RestControllerMetadataStore.js';
|
|
4
|
+
import { restController } from '../../../feature/rest-controller/metadata/@restController.js';
|
|
5
|
+
import { runRestControllers } from '../../../feature/rest-controller/runRestControllers.js';
|
|
6
|
+
import { createWasender } from '../../../node_modules/wasenderapi/dist/index.js';
|
|
7
|
+
import { WasenderWebhookController } from './WasenderWebhookController.js';
|
|
8
|
+
|
|
9
|
+
class WhatsAppReceiverByWasender {
|
|
10
|
+
config;
|
|
11
|
+
wasender;
|
|
12
|
+
listener = null;
|
|
13
|
+
constructor(config) {
|
|
14
|
+
this.config = config;
|
|
15
|
+
this.wasender = createWasender(config.apiKey, undefined, undefined, undefined, config.retryOptions, config.webhookSecret);
|
|
16
|
+
}
|
|
17
|
+
listenMessage(listener) {
|
|
18
|
+
this.listener = listener;
|
|
19
|
+
}
|
|
20
|
+
connect() {
|
|
21
|
+
const wasender = this.wasender;
|
|
22
|
+
const listener = this.listener;
|
|
23
|
+
let UniqueController = class UniqueController extends WasenderWebhookController {
|
|
24
|
+
constructor() {
|
|
25
|
+
super(wasender, listener);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
UniqueController = __decorate([
|
|
29
|
+
restController(this.config.webhookPath),
|
|
30
|
+
__metadata("design:paramtypes", [])
|
|
31
|
+
], UniqueController);
|
|
32
|
+
runRestControllers([UniqueController]);
|
|
33
|
+
}
|
|
34
|
+
disconnect() {
|
|
35
|
+
// Nothing to disconnect
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export { WhatsAppReceiverByWasender };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Logger } from '../../../core/logger/Logger.js';
|
|
2
|
+
import { createWasender } from '../../../node_modules/wasenderapi/dist/index.js';
|
|
3
|
+
|
|
4
|
+
class WhatsAppSenderByWasender {
|
|
5
|
+
wasender;
|
|
6
|
+
logger = new Logger('wabot:whatsapp-sender-by-wasender');
|
|
7
|
+
constructor(apiKey, retryOptions) {
|
|
8
|
+
this.wasender = createWasender(apiKey, undefined, undefined, undefined, retryOptions, undefined);
|
|
9
|
+
}
|
|
10
|
+
async send(request) {
|
|
11
|
+
try {
|
|
12
|
+
const textPayload = {
|
|
13
|
+
messageType: 'text',
|
|
14
|
+
to: `+${request.to.replace(/\D+/g, '')}`,
|
|
15
|
+
text: request.message.text ?? 'No Text',
|
|
16
|
+
};
|
|
17
|
+
const result = await this.wasender.send(textPayload);
|
|
18
|
+
this.logger.trace(`message sent from '${request.from}' to '${request.to}'`);
|
|
19
|
+
this.logger.trace(`rate limit remaining: ${result.rateLimit?.remaining}`);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
this.logger.error(`Failed to send message from '${request.from}' to '${request.to}'`, error);
|
|
23
|
+
if (error instanceof Error) {
|
|
24
|
+
throw new Error(error.message, { cause: error });
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
throw new Error('error sending message');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export { WhatsAppSenderByWasender };
|
|
@@ -4,11 +4,13 @@ import { Logger } from '../../../core/logger/Logger.js';
|
|
|
4
4
|
import { WhatsappChannelConfig } from './WhatsAppChannelConfig.js';
|
|
5
5
|
import { WhatsAppReceiver } from './WhatsAppReceiver.js';
|
|
6
6
|
import { WhatsAppSender } from './WhatsAppSender.js';
|
|
7
|
+
import { whatsAppChannelName } from './whatsAppChannelName.js';
|
|
7
8
|
|
|
8
9
|
let WhatsAppChannel = class WhatsAppChannel {
|
|
9
10
|
config;
|
|
10
11
|
sender;
|
|
11
12
|
receiver;
|
|
13
|
+
static channelName = whatsAppChannelName;
|
|
12
14
|
logger = new Logger('wabot:whatsapp-channel');
|
|
13
15
|
constructor(config, sender, receiver) {
|
|
14
16
|
this.config = config;
|
|
@@ -21,6 +23,7 @@ let WhatsAppChannel = class WhatsAppChannel {
|
|
|
21
23
|
listener: async (message) => {
|
|
22
24
|
try {
|
|
23
25
|
await callback({
|
|
26
|
+
channel: whatsAppChannelName,
|
|
24
27
|
chatConnection: message.chatConnection,
|
|
25
28
|
message: message.message,
|
|
26
29
|
reply: async (replyMessage) => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Logger } from '../../../../core/logger/Logger.js';
|
|
2
|
+
import { whatsAppChannelName } from '../whatsAppChannelName.js';
|
|
2
3
|
import { json } from 'express';
|
|
3
4
|
import { WhatsAppReceiver } from '../WhatsAppReceiver.js';
|
|
4
5
|
|
|
@@ -78,11 +79,10 @@ class WhatsAppReceiverByCloudApi extends WhatsAppReceiver {
|
|
|
78
79
|
this.logger.warn(`Message type '${message.type}' is not supported yet`);
|
|
79
80
|
return;
|
|
80
81
|
}
|
|
81
|
-
const channelName = 'WhatsAppChannel';
|
|
82
82
|
const chatConnection = {
|
|
83
83
|
id: contact.wa_id,
|
|
84
84
|
chatType: 'PRIVATE',
|
|
85
|
-
channelName,
|
|
85
|
+
channelName: whatsAppChannelName,
|
|
86
86
|
};
|
|
87
87
|
await listener({
|
|
88
88
|
chatConnection,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { __decorate, __metadata } from 'tslib';
|
|
2
2
|
import { WhatsAppReceiver } from '../WhatsAppReceiver.js';
|
|
3
|
+
import { whatsAppChannelName } from '../whatsAppChannelName.js';
|
|
3
4
|
import { injectable } from '../../../../core/injection/index.js';
|
|
4
5
|
import { Logger } from '../../../../core/logger/Logger.js';
|
|
5
6
|
import { WHATSAPP_MESSAGE_EVENT } from './WhatsAppProxyContracts.js';
|
|
@@ -45,7 +46,7 @@ let WhatsAppReceiverByWabotProxy = class WhatsAppReceiverByWabotProxy extends Wh
|
|
|
45
46
|
request.listener({
|
|
46
47
|
chatConnection: {
|
|
47
48
|
chatType: 'PRIVATE',
|
|
48
|
-
channelName:
|
|
49
|
+
channelName: whatsAppChannelName,
|
|
49
50
|
id: data.from,
|
|
50
51
|
},
|
|
51
52
|
message: {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { container } from '../../../core/injection/index.js';
|
|
2
|
+
import { WhatsAppByWasenderChannelConfig } from './WhatsAppByWasenderChannelConfig.js';
|
|
3
|
+
import { ControllerMetadataStore } from '../../../feature/chat-controller/metadata/ControllerMetadataStore.js';
|
|
4
|
+
import '../../../feature/chat-controller/ChatResolver.js';
|
|
5
|
+
import '../../../feature/chat-controller/runChatControllers.js';
|
|
6
|
+
import { WhatsAppByWasenderChannel } from './WhatsAppByWasenderChannel.js';
|
|
7
|
+
|
|
8
|
+
function whatsAppByWasender(config) {
|
|
9
|
+
return function (target, propertyKey) {
|
|
10
|
+
const store = container.resolve(ControllerMetadataStore);
|
|
11
|
+
store.saveChannelMetadata({
|
|
12
|
+
channelConstructor: WhatsAppByWasenderChannel,
|
|
13
|
+
functionName: propertyKey.toString(),
|
|
14
|
+
controllerConstructor: target.constructor,
|
|
15
|
+
channelConfig: new WhatsAppByWasenderChannelConfig(config),
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export { whatsAppByWasender };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { __decorate, __metadata } from 'tslib';
|
|
2
|
+
import { injectable } from '../../../core/injection/index.js';
|
|
3
|
+
import { Logger } from '../../../core/logger/Logger.js';
|
|
4
|
+
import { WhatsAppByWasenderChannelConfig } from './WhatsAppByWasenderChannelConfig.js';
|
|
5
|
+
import { WhatsAppReceiverByWasender } from './WhatsAppReceiverByWasender.js';
|
|
6
|
+
import { WhatsAppSenderByWasender } from './WhatsAppSenderByWasender.js';
|
|
7
|
+
|
|
8
|
+
let WhatsAppByWasenderChannel = class WhatsAppByWasenderChannel {
|
|
9
|
+
config;
|
|
10
|
+
sender;
|
|
11
|
+
receiver;
|
|
12
|
+
logger = new Logger('wabot:whatsapp-by-wasender-channel');
|
|
13
|
+
constructor(config, sender, receiver) {
|
|
14
|
+
this.config = config;
|
|
15
|
+
this.sender = sender;
|
|
16
|
+
this.receiver = receiver;
|
|
17
|
+
}
|
|
18
|
+
listen(callback) {
|
|
19
|
+
this.receiver.listenMessage(async (message) => {
|
|
20
|
+
try {
|
|
21
|
+
await callback({
|
|
22
|
+
chatConnection: message.chatConnection,
|
|
23
|
+
message: message.message,
|
|
24
|
+
reply: async (replyMessage) => {
|
|
25
|
+
await this.sender.send({
|
|
26
|
+
from: this.config.phoneNumber,
|
|
27
|
+
to: message.chatConnection.id,
|
|
28
|
+
message: replyMessage,
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
this.logger.error('Failed to handle WhatsApp message', err);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
connect() {
|
|
39
|
+
this.receiver.connect();
|
|
40
|
+
}
|
|
41
|
+
disconnect() {
|
|
42
|
+
this.receiver.disconnect();
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
WhatsAppByWasenderChannel = __decorate([
|
|
46
|
+
injectable(),
|
|
47
|
+
__metadata("design:paramtypes", [WhatsAppByWasenderChannelConfig,
|
|
48
|
+
WhatsAppSenderByWasender,
|
|
49
|
+
WhatsAppReceiverByWasender])
|
|
50
|
+
], WhatsAppByWasenderChannel);
|
|
51
|
+
|
|
52
|
+
export { WhatsAppByWasenderChannel };
|
package/dist/src/addon/chat-controller/whatsapp-by-wasender/WhatsAppByWasenderChannelConfig.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class WhatsAppByWasenderChannelConfig {
|
|
2
|
+
apiKey;
|
|
3
|
+
webhookSecret;
|
|
4
|
+
phoneNumber;
|
|
5
|
+
webhookPath;
|
|
6
|
+
retryOptions;
|
|
7
|
+
constructor(config) {
|
|
8
|
+
this.apiKey = config.apiKey;
|
|
9
|
+
this.webhookSecret = config.webhookSecret;
|
|
10
|
+
this.phoneNumber = config.phoneNumber;
|
|
11
|
+
this.webhookPath = config.webhookPath ?? '/wasender/hook';
|
|
12
|
+
this.retryOptions = config.retryOptions ?? { enabled: true, maxRetries: 3 };
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { WhatsAppByWasenderChannelConfig };
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { __decorate, __metadata } from 'tslib';
|
|
2
|
+
import { Logger } from '../../../core/logger/Logger.js';
|
|
3
|
+
import { injectable } from '../../../core/injection/index.js';
|
|
4
|
+
import { ExpressProvider } from '../../../feature/express/ExpressProvider.js';
|
|
5
|
+
import { createWasender } from '../../../node_modules/wasenderapi/dist/index.js';
|
|
6
|
+
import { WhatsAppByWasenderChannelConfig } from './WhatsAppByWasenderChannelConfig.js';
|
|
7
|
+
import { extractNumberFromWasenderMessageKey } from './extractNumberFromWasenderKey.js';
|
|
8
|
+
|
|
9
|
+
let WhatsAppReceiverByWasender = class WhatsAppReceiverByWasender {
|
|
10
|
+
expressProvider;
|
|
11
|
+
config;
|
|
12
|
+
wasender;
|
|
13
|
+
listener = null;
|
|
14
|
+
logger = new Logger('wabot:whatsapp-receiver-by-wasender');
|
|
15
|
+
constructor(expressProvider, config) {
|
|
16
|
+
this.expressProvider = expressProvider;
|
|
17
|
+
this.config = config;
|
|
18
|
+
this.wasender = createWasender(config.apiKey, undefined, undefined, undefined, config.retryOptions, config.webhookSecret);
|
|
19
|
+
}
|
|
20
|
+
listenMessage(listener) {
|
|
21
|
+
this.listener = listener;
|
|
22
|
+
}
|
|
23
|
+
connect() {
|
|
24
|
+
const expressApp = this.expressProvider.getExpress();
|
|
25
|
+
expressApp.post(this.config.webhookPath, async (req, res) => {
|
|
26
|
+
try {
|
|
27
|
+
const rawBody = await this.getRawBody(req);
|
|
28
|
+
const event = await this.parseEvent(req, rawBody);
|
|
29
|
+
this.logger.trace(`received event ${event.event}`);
|
|
30
|
+
switch (event.event) {
|
|
31
|
+
case 'messages.received':
|
|
32
|
+
const messages = Array.isArray(event.data.messages)
|
|
33
|
+
? event.data.messages
|
|
34
|
+
: [event.data.messages];
|
|
35
|
+
await this.handleMessages(messages);
|
|
36
|
+
break;
|
|
37
|
+
default:
|
|
38
|
+
this.logger.warn(`unhandled event type ${event.event}`);
|
|
39
|
+
}
|
|
40
|
+
res.sendStatus(200);
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
this.logger.error('Failed to handle Wasender webhook', err);
|
|
44
|
+
res.sendStatus(500);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
this.expressProvider.listen();
|
|
48
|
+
}
|
|
49
|
+
disconnect() {
|
|
50
|
+
// Nothing to disconnect
|
|
51
|
+
}
|
|
52
|
+
async handleMessages(messages) {
|
|
53
|
+
if (!this.listener) {
|
|
54
|
+
this.logger.warn('No listener registered, ignoring messages');
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
for (const message of messages) {
|
|
58
|
+
const from = extractNumberFromWasenderMessageKey(message.key);
|
|
59
|
+
this.logger.trace(`new message from '${from}' to '${this.config.phoneNumber}'`);
|
|
60
|
+
if (message.message.conversation) {
|
|
61
|
+
const chatConnection = {
|
|
62
|
+
chatType: 'PRIVATE',
|
|
63
|
+
channelName: 'WhatsAppByWasenderChannel',
|
|
64
|
+
id: from,
|
|
65
|
+
};
|
|
66
|
+
await this.listener({
|
|
67
|
+
chatConnection,
|
|
68
|
+
message: {
|
|
69
|
+
text: message.message.conversation,
|
|
70
|
+
senderName: message.pushName,
|
|
71
|
+
senderId: from,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
async parseEvent(req, rawBody) {
|
|
78
|
+
const adapter = {
|
|
79
|
+
getHeader: (name) => req.header(name),
|
|
80
|
+
getRawBody: () => rawBody,
|
|
81
|
+
};
|
|
82
|
+
const event = await this.wasender.handleWebhookEvent(adapter);
|
|
83
|
+
return event;
|
|
84
|
+
}
|
|
85
|
+
getRawBody(req) {
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
let data = '';
|
|
88
|
+
req.on('data', (chunk) => {
|
|
89
|
+
data += chunk;
|
|
90
|
+
});
|
|
91
|
+
req.on('end', () => {
|
|
92
|
+
resolve(data);
|
|
93
|
+
});
|
|
94
|
+
req.on('error', (err) => {
|
|
95
|
+
reject(err);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
WhatsAppReceiverByWasender = __decorate([
|
|
101
|
+
injectable(),
|
|
102
|
+
__metadata("design:paramtypes", [ExpressProvider,
|
|
103
|
+
WhatsAppByWasenderChannelConfig])
|
|
104
|
+
], WhatsAppReceiverByWasender);
|
|
105
|
+
|
|
106
|
+
export { WhatsAppReceiverByWasender };
|