botforje 0.0.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.
Files changed (84) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +381 -0
  3. package/dist/action/action.js +44 -0
  4. package/dist/action/catalog.js +40 -0
  5. package/dist/action/cooldown.js +60 -0
  6. package/dist/action/executor.js +23 -0
  7. package/dist/action/template.js +13 -0
  8. package/dist/action/types.js +2 -0
  9. package/dist/action/webhook.js +36 -0
  10. package/dist/actions/action.js +26 -0
  11. package/dist/actions/cooldown.js +66 -0
  12. package/dist/actions/request.js +40 -0
  13. package/dist/api/routes/auth.js +56 -0
  14. package/dist/api/routes/bots.js +51 -0
  15. package/dist/api/routes/config.js +24 -0
  16. package/dist/api/routes/health.js +15 -0
  17. package/dist/api/routes/index.js +14 -0
  18. package/dist/api/routes/messages.js +69 -0
  19. package/dist/api/routes/sessions.js +97 -0
  20. package/dist/api/routes/status.js +38 -0
  21. package/dist/api/server.js +153 -0
  22. package/dist/auth/service.js +102 -0
  23. package/dist/boot/fleet.js +207 -0
  24. package/dist/bot/bot.js +30 -0
  25. package/dist/bot/fleet.js +211 -0
  26. package/dist/bot/fuzzy.js +20 -0
  27. package/dist/bot/mapper.js +47 -0
  28. package/dist/bot/types.js +2 -0
  29. package/dist/bot/validation.js +38 -0
  30. package/dist/bot.js +31 -0
  31. package/dist/cli/create-bot.js +84 -0
  32. package/dist/cli.js +138 -0
  33. package/dist/commands/auth.js +200 -0
  34. package/dist/commands/create-bot.js +64 -0
  35. package/dist/commands/guide.js +563 -0
  36. package/dist/commands/lock.js +73 -0
  37. package/dist/commands/status.js +145 -0
  38. package/dist/commands/unlock.js +88 -0
  39. package/dist/commands/validate.js +19 -0
  40. package/dist/config/mapper.js +152 -0
  41. package/dist/config/schema.js +2 -0
  42. package/dist/config/validation.js +705 -0
  43. package/dist/config/watcher.js +145 -0
  44. package/dist/config/yaml.js +197 -0
  45. package/dist/fleet.js +247 -0
  46. package/dist/flow/executor.js +286 -0
  47. package/dist/flow/flow.js +2 -0
  48. package/dist/flow/mapper.js +72 -0
  49. package/dist/flow/state.js +115 -0
  50. package/dist/flow/types.js +2 -0
  51. package/dist/graph/executor.js +294 -0
  52. package/dist/graph/graph.js +2 -0
  53. package/dist/graph/state.js +118 -0
  54. package/dist/helpers/data.js +42 -0
  55. package/dist/helpers/fuzzy.js +30 -0
  56. package/dist/helpers/logger.js +89 -0
  57. package/dist/helpers/validation.js +38 -0
  58. package/dist/index.js +92 -0
  59. package/dist/messages/contracts.js +2 -0
  60. package/dist/messages/inbox.js +58 -0
  61. package/dist/messages/outbox.js +136 -0
  62. package/dist/services/auto-response.js +62 -0
  63. package/dist/services/cooldown.js +60 -0
  64. package/dist/services/fleet.js +207 -0
  65. package/dist/services/flow-executor.js +195 -0
  66. package/dist/services/flow-state.js +118 -0
  67. package/dist/services/inbox.js +50 -0
  68. package/dist/services/message-handler.js +78 -0
  69. package/dist/services/message-queue.js +138 -0
  70. package/dist/services/outbox.js +138 -0
  71. package/dist/services/session.js +118 -0
  72. package/dist/services/webhook.js +87 -0
  73. package/dist/utils/logger.js +89 -0
  74. package/dist/utils/webhook.js +36 -0
  75. package/dist/validation/validate.js +592 -0
  76. package/dist/whatsapp/client.js +293 -0
  77. package/dist/whatsapp/session.js +158 -0
  78. package/dist/whatsapp/types.js +109 -0
  79. package/dist/whatsapp/whatsapp.js +109 -0
  80. package/package.json +97 -0
  81. package/scripts/postinstall.js +45 -0
  82. package/scripts/preuninstall.js +48 -0
  83. package/scripts/setup-systemd.js +91 -0
  84. package/service/botforje.service.template +25 -0
@@ -0,0 +1,293 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.WhatsAppInitializer = exports.WhatsAppChannel = void 0;
37
+ exports.getWwebCacheDir = getWwebCacheDir;
38
+ exports.setGlobalConfig = setGlobalConfig;
39
+ exports.getPuppeteerOptions = getPuppeteerOptions;
40
+ exports.getClientOptions = getClientOptions;
41
+ const whatsapp_web_js_1 = require("whatsapp-web.js");
42
+ const path = __importStar(require("path"));
43
+ const os = __importStar(require("os"));
44
+ const whatsapp_1 = require("./whatsapp");
45
+ const logger_1 = require("../helpers/logger");
46
+ function getWwebCacheDir() {
47
+ const cacheHome = process.env.XDG_CACHE_HOME || path.join(os.homedir(), '.cache');
48
+ return path.join(cacheHome, 'botforje');
49
+ }
50
+ let globalConfig;
51
+ function setGlobalConfig(config) {
52
+ globalConfig = config;
53
+ }
54
+ function getPuppeteerOptions() {
55
+ const chromiumPath = globalConfig?.chromium_path || '/usr/bin/chromium';
56
+ return {
57
+ executablePath: chromiumPath,
58
+ headless: true,
59
+ args: [
60
+ '--no-sandbox',
61
+ '--disable-setuid-sandbox',
62
+ '--disable-dev-shm-usage',
63
+ '--disable-accelerated-2d-canvas',
64
+ '--no-first-run',
65
+ '--no-zygote',
66
+ '--disable-gpu',
67
+ '--disable-software-rasterizer',
68
+ '--disable-extensions',
69
+ '--disable-background-networking',
70
+ '--disable-default-apps',
71
+ '--disable-sync',
72
+ '--metrics-recording-only',
73
+ '--mute-audio',
74
+ ],
75
+ };
76
+ }
77
+ function getClientOptions(clientId) {
78
+ return {
79
+ authStrategy: new whatsapp_web_js_1.LocalAuth({
80
+ clientId: clientId,
81
+ dataPath: path.join(getWwebCacheDir(), '.wwebjs_auth'),
82
+ }),
83
+ puppeteer: getPuppeteerOptions(),
84
+ webVersionCache: {
85
+ type: 'local',
86
+ path: path.join(getWwebCacheDir(), '.wwebjs_cache'),
87
+ },
88
+ };
89
+ }
90
+ class WhatsAppChannel {
91
+ constructor(clientId) {
92
+ this.messageHandlers = [];
93
+ this.readyHandlers = [];
94
+ this.disconnectedHandlers = [];
95
+ this.authFailureHandlers = [];
96
+ this.connectionErrorHandlers = [];
97
+ this.stateChangeHandlers = [];
98
+ this.authRequiredHandlers = [];
99
+ this.isConnected = false;
100
+ this.channelId = clientId;
101
+ this.client = new whatsapp_web_js_1.Client(getClientOptions(clientId));
102
+ this.setupEventListeners();
103
+ }
104
+ get logger() {
105
+ return (0, logger_1.getLogger)();
106
+ }
107
+ setupEventListeners() {
108
+ this.client.on('ready', () => {
109
+ this.isConnected = true;
110
+ if (this.client.info?.wid) {
111
+ this.phoneNumber = (0, whatsapp_1.widToPhoneNumber)(this.client.info.wid._serialized);
112
+ }
113
+ this.readyHandlers.forEach(handler => handler());
114
+ });
115
+ this.client.on('message', async (msg) => {
116
+ const domainMessage = (0, whatsapp_1.toDomainMessage)(msg);
117
+ if (msg.from.includes('@lid')) {
118
+ try {
119
+ const contact = await msg.getContact();
120
+ const result = await this.client.getContactLidAndPhone([contact.id._serialized]);
121
+ if (result && result[0]?.pn) {
122
+ domainMessage.from = (0, whatsapp_1.normalizePhoneNumber)(result[0].pn);
123
+ }
124
+ domainMessage.senderName = contact.pushname || contact.name || contact.shortName;
125
+ }
126
+ catch (err) {
127
+ this.logger.debug(`LID resolution failed: ${err.message}`);
128
+ }
129
+ }
130
+ else {
131
+ try {
132
+ const contact = await msg.getContact();
133
+ domainMessage.senderName = contact.pushname || contact.name || contact.shortName;
134
+ }
135
+ catch (err) {
136
+ this.logger.debug(`Contact resolution failed: ${err.message}`);
137
+ }
138
+ }
139
+ this.messageHandlers.forEach(handler => handler(domainMessage));
140
+ });
141
+ this.client.on('disconnected', reason => {
142
+ this.isConnected = false;
143
+ this.disconnectedHandlers.forEach(handler => handler(reason));
144
+ });
145
+ this.client.on('qr', (qr) => {
146
+ this.logger.info(`qr auth required for channel ${this.channelId}`);
147
+ const info = {
148
+ channelId: this.channelId,
149
+ method: 'qr',
150
+ data: qr,
151
+ };
152
+ this.authRequiredHandlers.forEach(handler => handler(info));
153
+ });
154
+ this.client.on('auth_failure', (msg) => {
155
+ const error = new Error(typeof msg === 'string' ? msg : 'Authentication failed');
156
+ this.authFailureHandlers.forEach(handler => handler(error));
157
+ });
158
+ this.client.on('connection_error', (error) => {
159
+ this.connectionErrorHandlers.forEach(handler => handler(error));
160
+ });
161
+ this.client.on('change_state', state => {
162
+ const domainState = this.mapWhatsAppState(state);
163
+ this.stateChangeHandlers.forEach(handler => handler(domainState));
164
+ });
165
+ }
166
+ mapWhatsAppState(state) {
167
+ switch (state) {
168
+ case whatsapp_1.WhatsAppConnectionState.CONNECTED:
169
+ return 'connected';
170
+ case whatsapp_1.WhatsAppConnectionState.CONNECTING:
171
+ return 'connecting';
172
+ case whatsapp_1.WhatsAppConnectionState.DISCONNECTED:
173
+ return 'disconnected';
174
+ case whatsapp_1.WhatsAppConnectionState.AUTHENTICATING:
175
+ return 'authenticating';
176
+ default:
177
+ return 'unknown';
178
+ }
179
+ }
180
+ async connect() {
181
+ if (this.isConnected) {
182
+ throw new Error('Channel is already connected');
183
+ }
184
+ await this.client.initialize();
185
+ }
186
+ async disconnect() {
187
+ if (this.client) {
188
+ await this.client.destroy();
189
+ this.isConnected = false;
190
+ }
191
+ }
192
+ async send(message) {
193
+ if (!this.isConnected) {
194
+ throw new Error('Channel is not connected');
195
+ }
196
+ const whatsappMsg = (0, whatsapp_1.toWhatsAppFormat)(message);
197
+ this.logger.debug(`WhatsApp send options: ${JSON.stringify(whatsappMsg.options, null, 2)}`);
198
+ if (whatsappMsg.options?.type === 'location') {
199
+ const { latitude, longitude, name, address, url, description } = whatsappMsg.options;
200
+ const locationInstance = new whatsapp_web_js_1.Location(latitude, longitude, { name, address, url, description });
201
+ const { type: _t, latitude: _la, longitude: _lo, name: _n, address: _a, url: _u, description: _d, ...rest } = whatsappMsg.options;
202
+ const result = await this.client.sendMessage(whatsappMsg.to, locationInstance, rest);
203
+ return result.id._serialized;
204
+ }
205
+ const result = await this.client.sendMessage(whatsappMsg.to, whatsappMsg.content, whatsappMsg.options);
206
+ return result.id._serialized;
207
+ }
208
+ onMessage(handler) {
209
+ this.messageHandlers.push(handler);
210
+ }
211
+ onReady(handler) {
212
+ if (this.isConnected) {
213
+ handler();
214
+ }
215
+ else {
216
+ this.readyHandlers.push(handler);
217
+ }
218
+ }
219
+ onDisconnected(handler) {
220
+ this.disconnectedHandlers.push(handler);
221
+ }
222
+ onAuthFailure(handler) {
223
+ this.authFailureHandlers.push(handler);
224
+ }
225
+ onConnectionError(handler) {
226
+ this.connectionErrorHandlers.push(handler);
227
+ }
228
+ onStateChange(handler) {
229
+ this.stateChangeHandlers.push(handler);
230
+ }
231
+ onAuthRequired(handler) {
232
+ this.authRequiredHandlers.push(handler);
233
+ }
234
+ getPhone() {
235
+ return this.phoneNumber;
236
+ }
237
+ }
238
+ exports.WhatsAppChannel = WhatsAppChannel;
239
+ class WhatsAppInitializer {
240
+ constructor(clientId) {
241
+ this.authSuccessFired = false;
242
+ this.client = new whatsapp_web_js_1.Client(getClientOptions(clientId));
243
+ this.setupEventListeners();
244
+ }
245
+ setupEventListeners() {
246
+ this.client.on('qr', (qr) => {
247
+ if (this.qrHandler) {
248
+ this.qrHandler(qr);
249
+ }
250
+ });
251
+ this.client.on('ready', async () => {
252
+ if (this.authSuccessFired)
253
+ return;
254
+ this.authSuccessFired = true;
255
+ try {
256
+ const info = this.client.info;
257
+ const phoneNumber = (0, whatsapp_1.widToPhoneNumber)(info.wid._serialized);
258
+ if (this.successHandler) {
259
+ this.successHandler(phoneNumber);
260
+ }
261
+ }
262
+ catch (error) {
263
+ if (this.failureHandler) {
264
+ this.failureHandler(new Error('Failed to get phone number after authentication'));
265
+ }
266
+ }
267
+ });
268
+ this.client.on('auth_failure', (error) => {
269
+ if (this.failureHandler) {
270
+ const errorObj = error instanceof Error ? error : new Error(String(error));
271
+ this.failureHandler(errorObj);
272
+ }
273
+ });
274
+ }
275
+ async initialize() {
276
+ await this.client.initialize();
277
+ }
278
+ async destroy() {
279
+ if (this.client) {
280
+ await this.client.destroy();
281
+ }
282
+ }
283
+ onQRCode(handler) {
284
+ this.qrHandler = handler;
285
+ }
286
+ onAuthSuccess(handler) {
287
+ this.successHandler = handler;
288
+ }
289
+ onAuthFailure(handler) {
290
+ this.failureHandler = handler;
291
+ }
292
+ }
293
+ exports.WhatsAppInitializer = WhatsAppInitializer;
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SessionManager = void 0;
4
+ const client_1 = require("./client");
5
+ const logger_1 = require("../helpers/logger");
6
+ class SessionManager {
7
+ constructor() {
8
+ this.channels = new Map();
9
+ this.states = new Map();
10
+ this.qrData = new Map();
11
+ this.phoneNumbers = new Map();
12
+ this.errors = new Map();
13
+ this.eventListeners = new Map();
14
+ this.readyCallbacks = new Map();
15
+ }
16
+ get logger() {
17
+ return (0, logger_1.getLogger)();
18
+ }
19
+ static getInstance() {
20
+ if (!this.instance) {
21
+ this.instance = new SessionManager();
22
+ }
23
+ return this.instance;
24
+ }
25
+ createChannel(id) {
26
+ if (this.channels.has(id)) {
27
+ throw new Error(`Channel already exists for ID ${id}`);
28
+ }
29
+ const channel = new client_1.WhatsAppChannel(id);
30
+ this.channels.set(id, channel);
31
+ this.states.set(id, 'pending');
32
+ return channel;
33
+ }
34
+ getChannel(id) {
35
+ return this.channels.get(id);
36
+ }
37
+ getAllChannels() {
38
+ return new Map(this.channels);
39
+ }
40
+ async removeChannel(id) {
41
+ const channel = this.channels.get(id);
42
+ if (channel) {
43
+ await channel.disconnect();
44
+ this.channels.delete(id);
45
+ this.states.delete(id);
46
+ this.qrData.delete(id);
47
+ this.phoneNumbers.delete(id);
48
+ this.errors.delete(id);
49
+ this.eventListeners.delete(id);
50
+ this.readyCallbacks.delete(id);
51
+ }
52
+ }
53
+ async removeAllChannels() {
54
+ const ids = Array.from(this.channels.keys());
55
+ await Promise.all(ids.map(id => this.removeChannel(id)));
56
+ }
57
+ getChannelCount() {
58
+ return this.channels.size;
59
+ }
60
+ hasChannel(id) {
61
+ return this.channels.has(id);
62
+ }
63
+ getSessionInfo(id) {
64
+ if (!this.channels.has(id))
65
+ return undefined;
66
+ return {
67
+ state: this.states.get(id) || 'pending',
68
+ phone: this.phoneNumbers.get(id),
69
+ lastQR: this.qrData.get(id),
70
+ error: this.errors.get(id),
71
+ };
72
+ }
73
+ getAllSessions() {
74
+ const result = new Map();
75
+ for (const id of this.channels.keys()) {
76
+ const info = this.getSessionInfo(id);
77
+ if (info)
78
+ result.set(id, info);
79
+ }
80
+ return result;
81
+ }
82
+ async registerSession(id) {
83
+ if (this.channels.has(id)) {
84
+ const state = this.states.get(id);
85
+ if (state === 'connected') {
86
+ throw new Error(`Session "${id}" is already authenticated`);
87
+ }
88
+ await this.removeChannel(id);
89
+ }
90
+ this.logger.info(`Registering session: ${id}`);
91
+ const channel = new client_1.WhatsAppChannel(id);
92
+ this.channels.set(id, channel);
93
+ this.states.set(id, 'pending');
94
+ channel.onAuthRequired((info) => {
95
+ this.states.set(id, 'qr_received');
96
+ if (info.data)
97
+ this.qrData.set(id, info.data);
98
+ this.logger.info(`qr auth required for session ${id}`);
99
+ this.emitEvent(id, { type: 'qr', data: info.data });
100
+ });
101
+ channel.onReady(() => {
102
+ this.states.set(id, 'connected');
103
+ const phone = channel.getPhone();
104
+ if (phone)
105
+ this.phoneNumbers.set(id, phone);
106
+ this.logger.info(`Session "${id}" connected`);
107
+ this.emitEvent(id, { type: 'ready' });
108
+ this.readyCallbacks.get(id)?.forEach(cb => cb(channel));
109
+ });
110
+ channel.onDisconnected((reason) => {
111
+ this.states.set(id, 'disconnected');
112
+ this.errors.set(id, reason);
113
+ this.emitEvent(id, { type: 'disconnected', data: reason });
114
+ });
115
+ channel.onAuthFailure((error) => {
116
+ this.states.set(id, 'auth_failure');
117
+ this.errors.set(id, error.message);
118
+ this.emitEvent(id, { type: 'auth_failure', data: error.message });
119
+ });
120
+ await channel.connect();
121
+ }
122
+ onSessionEvent(id, handler) {
123
+ if (!this.eventListeners.has(id)) {
124
+ this.eventListeners.set(id, new Set());
125
+ }
126
+ this.eventListeners.get(id).add(handler);
127
+ }
128
+ removeSessionEventListener(id, handler) {
129
+ this.eventListeners.get(id)?.delete(handler);
130
+ }
131
+ onSessionReady(id, callback) {
132
+ if (!this.readyCallbacks.has(id)) {
133
+ this.readyCallbacks.set(id, new Set());
134
+ }
135
+ this.readyCallbacks.get(id).add(callback);
136
+ const state = this.states.get(id);
137
+ if (state === 'connected') {
138
+ const channel = this.channels.get(id);
139
+ if (channel)
140
+ callback(channel);
141
+ }
142
+ }
143
+ removeSessionReadyCallback(id, callback) {
144
+ this.readyCallbacks.get(id)?.delete(callback);
145
+ }
146
+ emitEvent(id, event) {
147
+ this.eventListeners.get(id)?.forEach(handler => {
148
+ try {
149
+ handler(event);
150
+ }
151
+ catch (err) {
152
+ const msg = err instanceof Error ? err.message : String(err);
153
+ this.logger.error(`Session event handler error for ${id}: ${msg}`);
154
+ }
155
+ });
156
+ }
157
+ }
158
+ exports.SessionManager = SessionManager;
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WhatsAppConnectionState = exports.WhatsAppMessageType = void 0;
4
+ exports.normalizePhoneNumber = normalizePhoneNumber;
5
+ exports.extractPhoneNumberFromWid = extractPhoneNumberFromWid;
6
+ exports.widToPhoneNumber = widToPhoneNumber;
7
+ exports.phoneNumberToWid = phoneNumberToWid;
8
+ exports.isMediaMessage = isMediaMessage;
9
+ exports.isInteractiveMessage = isInteractiveMessage;
10
+ exports.getFileExtension = getFileExtension;
11
+ exports.generateMessageId = generateMessageId;
12
+ exports.toDomainMessage = toDomainMessage;
13
+ exports.toWhatsAppFormat = toWhatsAppFormat;
14
+ var WhatsAppMessageType;
15
+ (function (WhatsAppMessageType) {
16
+ WhatsAppMessageType["TEXT"] = "chat";
17
+ WhatsAppMessageType["IMAGE"] = "image";
18
+ WhatsAppMessageType["VIDEO"] = "video";
19
+ WhatsAppMessageType["AUDIO"] = "audio";
20
+ WhatsAppMessageType["DOCUMENT"] = "document";
21
+ WhatsAppMessageType["STICKER"] = "sticker";
22
+ WhatsAppMessageType["LOCATION"] = "location";
23
+ WhatsAppMessageType["CONTACT"] = "contact";
24
+ WhatsAppMessageType["BUTTONS_RESPONSE"] = "buttons_response";
25
+ WhatsAppMessageType["LIST_RESPONSE"] = "list_response";
26
+ WhatsAppMessageType["TEMPLATE_BUTTON_REPLY"] = "template_button_reply";
27
+ })(WhatsAppMessageType || (exports.WhatsAppMessageType = WhatsAppMessageType = {}));
28
+ var WhatsAppConnectionState;
29
+ (function (WhatsAppConnectionState) {
30
+ WhatsAppConnectionState["CONNECTING"] = "CONNECTING";
31
+ WhatsAppConnectionState["AUTHENTICATING"] = "AUTHENTICATING";
32
+ WhatsAppConnectionState["CONNECTED"] = "CONNECTED";
33
+ WhatsAppConnectionState["DISCONNECTED"] = "DISCONNECTED";
34
+ WhatsAppConnectionState["FAILED"] = "FAILED";
35
+ })(WhatsAppConnectionState || (exports.WhatsAppConnectionState = WhatsAppConnectionState = {}));
36
+ function normalizePhoneNumber(phoneNumber) {
37
+ return phoneNumber.replace(/\D/g, '');
38
+ }
39
+ function extractPhoneNumberFromWid(wid) {
40
+ const match = wid.match(/^(\d+)@/);
41
+ return match ? match[1] : wid;
42
+ }
43
+ function widToPhoneNumber(wid) {
44
+ const phone = extractPhoneNumberFromWid(wid);
45
+ return normalizePhoneNumber(phone);
46
+ }
47
+ function phoneNumberToWid(phoneNumber) {
48
+ const normalized = normalizePhoneNumber(phoneNumber);
49
+ return `${normalized}@c.us`;
50
+ }
51
+ function isMediaMessage(messageType) {
52
+ return [
53
+ WhatsAppMessageType.IMAGE,
54
+ WhatsAppMessageType.VIDEO,
55
+ WhatsAppMessageType.AUDIO,
56
+ WhatsAppMessageType.DOCUMENT,
57
+ WhatsAppMessageType.STICKER,
58
+ ].includes(messageType);
59
+ }
60
+ function isInteractiveMessage(messageType) {
61
+ return [
62
+ WhatsAppMessageType.BUTTONS_RESPONSE,
63
+ WhatsAppMessageType.LIST_RESPONSE,
64
+ WhatsAppMessageType.TEMPLATE_BUTTON_REPLY,
65
+ ].includes(messageType);
66
+ }
67
+ function getFileExtension(mimetype) {
68
+ const extensions = {
69
+ 'image/jpeg': 'jpg',
70
+ 'image/png': 'png',
71
+ 'image/gif': 'gif',
72
+ 'image/webp': 'webp',
73
+ 'video/mp4': 'mp4',
74
+ 'video/3gpp': '3gp',
75
+ 'audio/ogg': 'ogg',
76
+ 'audio/mpeg': 'mp3',
77
+ 'application/pdf': 'pdf',
78
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
79
+ 'application/msword': 'doc',
80
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',
81
+ 'application/vnd.ms-excel': 'xls',
82
+ };
83
+ return extensions[mimetype] || 'bin';
84
+ }
85
+ function generateMessageId() {
86
+ return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
87
+ }
88
+ function toDomainMessage(message) {
89
+ return {
90
+ id: message.id._serialized,
91
+ from: widToPhoneNumber(message.from),
92
+ to: widToPhoneNumber(message.to),
93
+ content: message.body,
94
+ timestamp: new Date(message.timestamp * 1000),
95
+ metadata: {
96
+ hasMedia: message.hasMedia,
97
+ type: message.type,
98
+ fromMe: message.fromMe,
99
+ isGroup: message.isGroupMsg || false,
100
+ },
101
+ };
102
+ }
103
+ function toWhatsAppFormat(message) {
104
+ return {
105
+ to: phoneNumberToWid(message.to),
106
+ content: message.content,
107
+ options: message.metadata,
108
+ };
109
+ }
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WhatsAppConnectionState = exports.WhatsAppMessageType = void 0;
4
+ exports.normalizePhoneNumber = normalizePhoneNumber;
5
+ exports.extractPhoneNumberFromWid = extractPhoneNumberFromWid;
6
+ exports.widToPhoneNumber = widToPhoneNumber;
7
+ exports.phoneNumberToWid = phoneNumberToWid;
8
+ exports.isMediaMessage = isMediaMessage;
9
+ exports.isInteractiveMessage = isInteractiveMessage;
10
+ exports.getFileExtension = getFileExtension;
11
+ exports.generateMessageId = generateMessageId;
12
+ exports.toDomainMessage = toDomainMessage;
13
+ exports.toWhatsAppFormat = toWhatsAppFormat;
14
+ var WhatsAppMessageType;
15
+ (function (WhatsAppMessageType) {
16
+ WhatsAppMessageType["TEXT"] = "chat";
17
+ WhatsAppMessageType["IMAGE"] = "image";
18
+ WhatsAppMessageType["VIDEO"] = "video";
19
+ WhatsAppMessageType["AUDIO"] = "audio";
20
+ WhatsAppMessageType["DOCUMENT"] = "document";
21
+ WhatsAppMessageType["STICKER"] = "sticker";
22
+ WhatsAppMessageType["LOCATION"] = "location";
23
+ WhatsAppMessageType["CONTACT"] = "contact";
24
+ WhatsAppMessageType["BUTTONS_RESPONSE"] = "buttons_response";
25
+ WhatsAppMessageType["LIST_RESPONSE"] = "list_response";
26
+ WhatsAppMessageType["TEMPLATE_BUTTON_REPLY"] = "template_button_reply";
27
+ })(WhatsAppMessageType || (exports.WhatsAppMessageType = WhatsAppMessageType = {}));
28
+ var WhatsAppConnectionState;
29
+ (function (WhatsAppConnectionState) {
30
+ WhatsAppConnectionState["CONNECTING"] = "CONNECTING";
31
+ WhatsAppConnectionState["AUTHENTICATING"] = "AUTHENTICATING";
32
+ WhatsAppConnectionState["CONNECTED"] = "CONNECTED";
33
+ WhatsAppConnectionState["DISCONNECTED"] = "DISCONNECTED";
34
+ WhatsAppConnectionState["FAILED"] = "FAILED";
35
+ })(WhatsAppConnectionState || (exports.WhatsAppConnectionState = WhatsAppConnectionState = {}));
36
+ function normalizePhoneNumber(phoneNumber) {
37
+ return phoneNumber.replace(/\D/g, '');
38
+ }
39
+ function extractPhoneNumberFromWid(wid) {
40
+ const match = wid.match(/^(\d+)@/);
41
+ return match ? match[1] : wid;
42
+ }
43
+ function widToPhoneNumber(wid) {
44
+ const phone = extractPhoneNumberFromWid(wid);
45
+ return normalizePhoneNumber(phone);
46
+ }
47
+ function phoneNumberToWid(phoneNumber) {
48
+ const normalized = normalizePhoneNumber(phoneNumber);
49
+ return `${normalized}@c.us`;
50
+ }
51
+ function isMediaMessage(messageType) {
52
+ return [
53
+ WhatsAppMessageType.IMAGE,
54
+ WhatsAppMessageType.VIDEO,
55
+ WhatsAppMessageType.AUDIO,
56
+ WhatsAppMessageType.DOCUMENT,
57
+ WhatsAppMessageType.STICKER,
58
+ ].includes(messageType);
59
+ }
60
+ function isInteractiveMessage(messageType) {
61
+ return [
62
+ WhatsAppMessageType.BUTTONS_RESPONSE,
63
+ WhatsAppMessageType.LIST_RESPONSE,
64
+ WhatsAppMessageType.TEMPLATE_BUTTON_REPLY,
65
+ ].includes(messageType);
66
+ }
67
+ function getFileExtension(mimetype) {
68
+ const extensions = {
69
+ 'image/jpeg': 'jpg',
70
+ 'image/png': 'png',
71
+ 'image/gif': 'gif',
72
+ 'image/webp': 'webp',
73
+ 'video/mp4': 'mp4',
74
+ 'video/3gpp': '3gp',
75
+ 'audio/ogg': 'ogg',
76
+ 'audio/mpeg': 'mp3',
77
+ 'application/pdf': 'pdf',
78
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
79
+ 'application/msword': 'doc',
80
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',
81
+ 'application/vnd.ms-excel': 'xls',
82
+ };
83
+ return extensions[mimetype] || 'bin';
84
+ }
85
+ function generateMessageId() {
86
+ return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
87
+ }
88
+ function toDomainMessage(message) {
89
+ return {
90
+ id: message.id._serialized,
91
+ from: widToPhoneNumber(message.from),
92
+ to: widToPhoneNumber(message.to),
93
+ content: message.body,
94
+ timestamp: new Date(message.timestamp * 1000),
95
+ metadata: {
96
+ hasMedia: message.hasMedia,
97
+ type: message.type,
98
+ fromMe: message.fromMe,
99
+ isGroup: message.isGroupMsg || false,
100
+ },
101
+ };
102
+ }
103
+ function toWhatsAppFormat(message) {
104
+ return {
105
+ to: phoneNumberToWid(message.to),
106
+ content: message.content,
107
+ options: message.metadata,
108
+ };
109
+ }