@builderbot/provider-evolution-api 1.2.7 → 1.2.8-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/dist/evolution/core.d.ts +16 -25
- package/dist/evolution/core.d.ts.map +1 -1
- package/dist/evolution/provider.d.ts +108 -19
- package/dist/evolution/provider.d.ts.map +1 -1
- package/dist/index.cjs +519 -589
- package/dist/interface/evolution.d.ts +13 -8
- package/dist/interface/evolution.d.ts.map +1 -1
- package/dist/types.d.ts +68 -191
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/download.d.ts +8 -0
- package/dist/utils/download.d.ts.map +1 -0
- package/dist/utils/index.d.ts +1 -5
- package/dist/utils/index.d.ts.map +1 -1
- package/package.json +5 -9
- package/dist/utils/downloadFile.d.ts +0 -16
- package/dist/utils/downloadFile.d.ts.map +0 -1
- package/dist/utils/mediaUrl.d.ts +0 -3
- package/dist/utils/mediaUrl.d.ts.map +0 -1
- package/dist/utils/number.d.ts +0 -2
- package/dist/utils/number.d.ts.map +0 -1
- package/dist/utils/processIncomingMsg.d.ts +0 -3
- package/dist/utils/processIncomingMsg.d.ts.map +0 -1
- package/dist/utils/profile.d.ts +0 -4
- package/dist/utils/profile.d.ts.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -3,19 +3,69 @@
|
|
|
3
3
|
var bot = require('@builderbot/bot');
|
|
4
4
|
var require$$1 = require('util');
|
|
5
5
|
var stream = require('stream');
|
|
6
|
-
var
|
|
6
|
+
var path$1 = require('path');
|
|
7
7
|
var require$$3 = require('http');
|
|
8
8
|
var require$$4 = require('https');
|
|
9
9
|
var require$$0$1 = require('url');
|
|
10
|
-
var
|
|
10
|
+
var fs$1 = require('fs');
|
|
11
11
|
var crypto = require('crypto');
|
|
12
12
|
var require$$4$1 = require('assert');
|
|
13
|
-
var require$$1$
|
|
13
|
+
var require$$1$1 = require('tty');
|
|
14
14
|
var require$$0$2 = require('os');
|
|
15
15
|
var zlib = require('zlib');
|
|
16
16
|
var require$$0$3 = require('events');
|
|
17
|
+
var promises = require('fs/promises');
|
|
18
|
+
var node_crypto = require('node:crypto');
|
|
17
19
|
var EventEmitter = require('node:events');
|
|
18
20
|
|
|
21
|
+
function getDefaultExportFromCjs (x) {
|
|
22
|
+
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
var json = function (opts={}) {
|
|
26
|
+
const limit = opts.limit || 100 * 1024; // 100kb
|
|
27
|
+
const type = opts.type || 'application/json';
|
|
28
|
+
|
|
29
|
+
return function (req, res, next) {
|
|
30
|
+
if (req._body) return next();
|
|
31
|
+
req.body = req.body || {};
|
|
32
|
+
|
|
33
|
+
const head = req.headers;
|
|
34
|
+
const ctype = head['content-type'];
|
|
35
|
+
const clength = parseInt(head['content-length'], 10);
|
|
36
|
+
|
|
37
|
+
if (isNaN(clength) && head['transfer-encoding'] == null) return next(); // no body
|
|
38
|
+
if (ctype && !ctype.includes(type)) return next(); // not json
|
|
39
|
+
if (clength === 0) return next(); // is empty
|
|
40
|
+
|
|
41
|
+
let bits = [];
|
|
42
|
+
let length = 0;
|
|
43
|
+
req.on('data', x => {
|
|
44
|
+
length += Buffer.byteLength(x);
|
|
45
|
+
if (length <= limit) {
|
|
46
|
+
bits.push(x);
|
|
47
|
+
} else {
|
|
48
|
+
next({
|
|
49
|
+
code: 413,
|
|
50
|
+
details: 'Exceeded JSON limit'
|
|
51
|
+
});
|
|
52
|
+
req.destroy();
|
|
53
|
+
}
|
|
54
|
+
}).on('end', () => {
|
|
55
|
+
try {
|
|
56
|
+
req.body = JSON.parse(bits);
|
|
57
|
+
req._body = true;
|
|
58
|
+
next();
|
|
59
|
+
} catch (err) {
|
|
60
|
+
err.code = 422;
|
|
61
|
+
err.details = err.message;
|
|
62
|
+
err.message = 'Invalid JSON';
|
|
63
|
+
next(err);
|
|
64
|
+
}
|
|
65
|
+
}).on('error', next);
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
|
|
19
69
|
function bind$1(fn, thisArg) {
|
|
20
70
|
return function wrap() {
|
|
21
71
|
return fn.apply(thisArg, arguments);
|
|
@@ -861,10 +911,6 @@ AxiosError$1.from = (error, code, config, request, response, customProps) => {
|
|
|
861
911
|
return axiosError;
|
|
862
912
|
};
|
|
863
913
|
|
|
864
|
-
function getDefaultExportFromCjs (x) {
|
|
865
|
-
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
866
|
-
}
|
|
867
|
-
|
|
868
914
|
var Stream$2 = stream.Stream;
|
|
869
915
|
var util$2 = require$$1;
|
|
870
916
|
|
|
@@ -11915,7 +11961,7 @@ var mimeDb = require$$0;
|
|
|
11915
11961
|
*/
|
|
11916
11962
|
|
|
11917
11963
|
var db = mimeDb;
|
|
11918
|
-
var extname =
|
|
11964
|
+
var extname = path$1.extname;
|
|
11919
11965
|
|
|
11920
11966
|
/**
|
|
11921
11967
|
* Module variables.
|
|
@@ -13385,11 +13431,11 @@ var populate$1 = function(dst, src) {
|
|
|
13385
13431
|
|
|
13386
13432
|
var CombinedStream = combined_stream;
|
|
13387
13433
|
var util = require$$1;
|
|
13388
|
-
var path =
|
|
13389
|
-
var http$
|
|
13390
|
-
var https$
|
|
13434
|
+
var path = path$1;
|
|
13435
|
+
var http$2 = require$$3;
|
|
13436
|
+
var https$2 = require$$4;
|
|
13391
13437
|
var parseUrl$2 = require$$0$1.parse;
|
|
13392
|
-
var fs =
|
|
13438
|
+
var fs = fs$1;
|
|
13393
13439
|
var Stream = stream.Stream;
|
|
13394
13440
|
var mime = mimeTypes;
|
|
13395
13441
|
var asynckit = asynckit$1;
|
|
@@ -13836,9 +13882,9 @@ FormData$1.prototype.submit = function(params, cb) {
|
|
|
13836
13882
|
|
|
13837
13883
|
// https if specified, fallback to http in any other case
|
|
13838
13884
|
if (options.protocol == 'https:') {
|
|
13839
|
-
request = https$
|
|
13885
|
+
request = https$2.request(options);
|
|
13840
13886
|
} else {
|
|
13841
|
-
request = http$
|
|
13887
|
+
request = http$2.request(options);
|
|
13842
13888
|
}
|
|
13843
13889
|
|
|
13844
13890
|
// get content length and fire away
|
|
@@ -14372,12 +14418,12 @@ const hasStandardBrowserWebWorkerEnv = (() => {
|
|
|
14372
14418
|
const origin = hasBrowserEnv && window.location.href || 'http://localhost';
|
|
14373
14419
|
|
|
14374
14420
|
var utils = /*#__PURE__*/Object.freeze({
|
|
14375
|
-
|
|
14376
|
-
|
|
14377
|
-
|
|
14378
|
-
|
|
14379
|
-
|
|
14380
|
-
|
|
14421
|
+
__proto__: null,
|
|
14422
|
+
hasBrowserEnv: hasBrowserEnv,
|
|
14423
|
+
hasStandardBrowserEnv: hasStandardBrowserEnv,
|
|
14424
|
+
hasStandardBrowserWebWorkerEnv: hasStandardBrowserWebWorkerEnv,
|
|
14425
|
+
navigator: _navigator,
|
|
14426
|
+
origin: origin
|
|
14381
14427
|
});
|
|
14382
14428
|
|
|
14383
14429
|
var platform = {
|
|
@@ -16007,7 +16053,7 @@ function requireSupportsColor () {
|
|
|
16007
16053
|
if (hasRequiredSupportsColor) return supportsColor_1;
|
|
16008
16054
|
hasRequiredSupportsColor = 1;
|
|
16009
16055
|
const os = require$$0$2;
|
|
16010
|
-
const tty = require$$1$
|
|
16056
|
+
const tty = require$$1$1;
|
|
16011
16057
|
const hasFlag = requireHasFlag();
|
|
16012
16058
|
|
|
16013
16059
|
const {env} = process;
|
|
@@ -16153,7 +16199,7 @@ function requireNode () {
|
|
|
16153
16199
|
if (hasRequiredNode) return node.exports;
|
|
16154
16200
|
hasRequiredNode = 1;
|
|
16155
16201
|
(function (module, exports) {
|
|
16156
|
-
const tty = require$$1$
|
|
16202
|
+
const tty = require$$1$1;
|
|
16157
16203
|
const util = require$$1;
|
|
16158
16204
|
|
|
16159
16205
|
/**
|
|
@@ -16452,8 +16498,8 @@ var debug_1 = function () {
|
|
|
16452
16498
|
|
|
16453
16499
|
var url = require$$0$1;
|
|
16454
16500
|
var URL$1 = url.URL;
|
|
16455
|
-
var http = require$$3;
|
|
16456
|
-
var https = require$$4;
|
|
16501
|
+
var http$1 = require$$3;
|
|
16502
|
+
var https$1 = require$$4;
|
|
16457
16503
|
var Writable = stream.Writable;
|
|
16458
16504
|
var assert = require$$4$1;
|
|
16459
16505
|
var debug = debug_1;
|
|
@@ -17134,7 +17180,7 @@ function isURL(value) {
|
|
|
17134
17180
|
}
|
|
17135
17181
|
|
|
17136
17182
|
// Exports
|
|
17137
|
-
followRedirects$1.exports = wrap({ http: http, https: https });
|
|
17183
|
+
followRedirects$1.exports = wrap({ http: http$1, https: https$1 });
|
|
17138
17184
|
followRedirects$1.exports.wrap = wrap;
|
|
17139
17185
|
|
|
17140
17186
|
var followRedirectsExports = followRedirects$1.exports;
|
|
@@ -19830,302 +19876,258 @@ var _events=_interopRequireDefault(require$$0$3);Object.defineProperty(exports,"
|
|
|
19830
19876
|
var distExports = dist.exports;
|
|
19831
19877
|
var Queue = /*@__PURE__*/getDefaultExportFromCjs(distExports);
|
|
19832
19878
|
|
|
19833
|
-
|
|
19834
|
-
|
|
19835
|
-
|
|
19836
|
-
|
|
19837
|
-
|
|
19838
|
-
|
|
19839
|
-
|
|
19840
|
-
|
|
19841
|
-
|
|
19842
|
-
|
|
19843
|
-
|
|
19844
|
-
|
|
19845
|
-
}
|
|
19846
|
-
}
|
|
19847
|
-
|
|
19848
|
-
|
|
19849
|
-
|
|
19850
|
-
|
|
19851
|
-
|
|
19852
|
-
|
|
19853
|
-
|
|
19854
|
-
|
|
19855
|
-
|
|
19856
|
-
|
|
19857
|
-
|
|
19858
|
-
|
|
19859
|
-
|
|
19860
|
-
|
|
19861
|
-
|
|
19862
|
-
|
|
19863
|
-
|
|
19864
|
-
|
|
19865
|
-
|
|
19866
|
-
|
|
19867
|
-
|
|
19868
|
-
|
|
19869
|
-
|
|
19870
|
-
|
|
19871
|
-
|
|
19872
|
-
|
|
19873
|
-
|
|
19874
|
-
|
|
19875
|
-
|
|
19876
|
-
|
|
19877
|
-
|
|
19878
|
-
|
|
19879
|
-
|
|
19880
|
-
|
|
19881
|
-
|
|
19882
|
-
|
|
19883
|
-
|
|
19884
|
-
|
|
19885
|
-
|
|
19886
|
-
|
|
19887
|
-
|
|
19888
|
-
|
|
19889
|
-
|
|
19890
|
-
|
|
19891
|
-
|
|
19892
|
-
|
|
19893
|
-
|
|
19894
|
-
|
|
19895
|
-
|
|
19896
|
-
type: message.type,
|
|
19897
|
-
from: message.from,
|
|
19898
|
-
url: imageUrl,
|
|
19899
|
-
fileData,
|
|
19900
|
-
caption: message?.image?.caption,
|
|
19901
|
-
to,
|
|
19902
|
-
body: bot.utils.generateRefProvider('_event_media_'),
|
|
19903
|
-
pushName,
|
|
19904
|
-
name: pushName,
|
|
19905
|
-
};
|
|
19906
|
-
break;
|
|
19907
|
-
}
|
|
19908
|
-
case 'document': {
|
|
19909
|
-
const documentUrl = await getMediaUrl(version, message.document?.id, numberId, jwtToken);
|
|
19910
|
-
responseObj = {
|
|
19911
|
-
type: message.type,
|
|
19912
|
-
from: message.from,
|
|
19913
|
-
url: documentUrl,
|
|
19914
|
-
fileData,
|
|
19915
|
-
to,
|
|
19916
|
-
body: bot.utils.generateRefProvider('_event_document_'),
|
|
19917
|
-
pushName,
|
|
19918
|
-
name: pushName,
|
|
19919
|
-
};
|
|
19920
|
-
break;
|
|
19921
|
-
}
|
|
19922
|
-
case 'video': {
|
|
19923
|
-
const videoUrl = await getMediaUrl(version, message.video?.id, numberId, jwtToken);
|
|
19924
|
-
responseObj = {
|
|
19925
|
-
type: message.type,
|
|
19926
|
-
from: message.from,
|
|
19927
|
-
url: videoUrl,
|
|
19928
|
-
fileData,
|
|
19929
|
-
caption: message?.video?.caption,
|
|
19930
|
-
to,
|
|
19931
|
-
body: bot.utils.generateRefProvider('_event_media_'),
|
|
19932
|
-
pushName,
|
|
19933
|
-
name: pushName,
|
|
19934
|
-
};
|
|
19935
|
-
break;
|
|
19936
|
-
}
|
|
19937
|
-
case 'location': {
|
|
19938
|
-
responseObj = {
|
|
19939
|
-
type: message.type,
|
|
19940
|
-
from: message.from,
|
|
19941
|
-
to,
|
|
19942
|
-
latitude: message.location.latitude,
|
|
19943
|
-
longitude: message.location.longitude,
|
|
19944
|
-
body: bot.utils.generateRefProvider('_event_location_'),
|
|
19945
|
-
pushName,
|
|
19946
|
-
name: pushName,
|
|
19947
|
-
};
|
|
19948
|
-
break;
|
|
19949
|
-
}
|
|
19950
|
-
case 'audio': {
|
|
19951
|
-
const audioUrl = await getMediaUrl(version, message.audio?.id, numberId, jwtToken);
|
|
19952
|
-
responseObj = {
|
|
19953
|
-
type: message.type,
|
|
19954
|
-
from: message.from,
|
|
19955
|
-
url: audioUrl,
|
|
19956
|
-
fileData,
|
|
19957
|
-
to,
|
|
19958
|
-
body: bot.utils.generateRefProvider('_event_voice_note_'),
|
|
19959
|
-
pushName,
|
|
19960
|
-
name: pushName,
|
|
19961
|
-
};
|
|
19962
|
-
break;
|
|
19963
|
-
}
|
|
19964
|
-
case 'sticker': {
|
|
19965
|
-
responseObj = {
|
|
19966
|
-
type: message.type,
|
|
19967
|
-
from: message.from,
|
|
19968
|
-
to,
|
|
19969
|
-
id: message.sticker.id,
|
|
19970
|
-
body: bot.utils.generateRefProvider('_event_media_'),
|
|
19971
|
-
pushName,
|
|
19972
|
-
name: pushName,
|
|
19973
|
-
};
|
|
19974
|
-
break;
|
|
19975
|
-
}
|
|
19976
|
-
case 'contacts': {
|
|
19977
|
-
responseObj = {
|
|
19978
|
-
type: message.type,
|
|
19979
|
-
from: message.from,
|
|
19980
|
-
contacts: [
|
|
19981
|
-
{
|
|
19982
|
-
name: message.contacts[0].name,
|
|
19983
|
-
phones: message.contacts[0].phones,
|
|
19984
|
-
},
|
|
19985
|
-
],
|
|
19986
|
-
to,
|
|
19987
|
-
body: bot.utils.generateRefProvider('_event_contacts_'),
|
|
19988
|
-
pushName,
|
|
19989
|
-
name: pushName,
|
|
19990
|
-
};
|
|
19991
|
-
break;
|
|
19879
|
+
const { http, https } = followRedirects;
|
|
19880
|
+
/**
|
|
19881
|
+
* Extraer el mimetype from buffer
|
|
19882
|
+
* @param response - La respuesta HTTP
|
|
19883
|
+
* @returns Un objeto con el tipo y la extensión del archivo
|
|
19884
|
+
*/
|
|
19885
|
+
const fileTypeFromFile = async (response) => {
|
|
19886
|
+
const type = response.headers['content-type'] ?? '';
|
|
19887
|
+
const ext = mime$1.extension(type);
|
|
19888
|
+
return {
|
|
19889
|
+
type,
|
|
19890
|
+
ext,
|
|
19891
|
+
};
|
|
19892
|
+
};
|
|
19893
|
+
/**
|
|
19894
|
+
* Descargar archivo binario en tmp
|
|
19895
|
+
* @param url - La URL del archivo a descargar
|
|
19896
|
+
* @returns La ruta al archivo descargado
|
|
19897
|
+
*/
|
|
19898
|
+
const generalDownload = async (url, pathToSave, headers) => {
|
|
19899
|
+
const checkIsLocal = fs$1.existsSync(url);
|
|
19900
|
+
const handleDownload = () => {
|
|
19901
|
+
try {
|
|
19902
|
+
const checkProtocol = url.startsWith('http');
|
|
19903
|
+
const handleHttp = checkProtocol ? https : http;
|
|
19904
|
+
const fileName = path$1.basename(checkProtocol ? new URL(url).pathname : url);
|
|
19905
|
+
const name = path$1.parse(fileName).name;
|
|
19906
|
+
const fullPath = path$1.join(pathToSave ?? require$$0$2.tmpdir(), name);
|
|
19907
|
+
const file = fs$1.createWriteStream(fullPath);
|
|
19908
|
+
if (checkIsLocal) {
|
|
19909
|
+
/**
|
|
19910
|
+
* From Local
|
|
19911
|
+
*/
|
|
19912
|
+
return new Promise((res) => {
|
|
19913
|
+
const response = {
|
|
19914
|
+
headers: {
|
|
19915
|
+
'content-type': mime$1.contentType(path$1.extname(url)) || '',
|
|
19916
|
+
},
|
|
19917
|
+
};
|
|
19918
|
+
res({ response, fullPath: url });
|
|
19919
|
+
});
|
|
19920
|
+
}
|
|
19921
|
+
else {
|
|
19922
|
+
/**
|
|
19923
|
+
* From URL
|
|
19924
|
+
*/
|
|
19925
|
+
return new Promise((res, rej) => {
|
|
19926
|
+
const options = {
|
|
19927
|
+
headers: headers ?? {},
|
|
19928
|
+
};
|
|
19929
|
+
handleHttp.get(url, options, function (response) {
|
|
19930
|
+
response.pipe(file);
|
|
19931
|
+
file.on('finish', async function () {
|
|
19932
|
+
file.close();
|
|
19933
|
+
res({ response, fullPath });
|
|
19934
|
+
});
|
|
19935
|
+
file.on('error', function () {
|
|
19936
|
+
file.close();
|
|
19937
|
+
rej(new Error('Error downloading file'));
|
|
19938
|
+
});
|
|
19939
|
+
});
|
|
19940
|
+
});
|
|
19941
|
+
}
|
|
19992
19942
|
}
|
|
19993
|
-
|
|
19994
|
-
|
|
19995
|
-
|
|
19996
|
-
from: message.from,
|
|
19997
|
-
to,
|
|
19998
|
-
order: {
|
|
19999
|
-
catalog_id: message.order.catalog_id,
|
|
20000
|
-
product_items: message.order.product_items,
|
|
20001
|
-
},
|
|
20002
|
-
body: bot.utils.generateRefProvider('_event_order_'),
|
|
20003
|
-
pushName,
|
|
20004
|
-
name: pushName,
|
|
20005
|
-
};
|
|
20006
|
-
break;
|
|
19943
|
+
catch (err) {
|
|
19944
|
+
console.error('Error downloading file', err);
|
|
19945
|
+
return;
|
|
20007
19946
|
}
|
|
20008
|
-
}
|
|
20009
|
-
return {
|
|
20010
|
-
...responseObj,
|
|
20011
|
-
message_id: messageId,
|
|
20012
|
-
timestamp: messageTimestamp,
|
|
20013
19947
|
};
|
|
19948
|
+
const handleFile = (pathInput, ext) => {
|
|
19949
|
+
return new Promise((resolve, reject) => {
|
|
19950
|
+
if (!ext) {
|
|
19951
|
+
reject(new Error('No extension found for the file'));
|
|
19952
|
+
return;
|
|
19953
|
+
}
|
|
19954
|
+
const fullPath = checkIsLocal ? `${pathInput}` : `${pathInput}.${ext}`;
|
|
19955
|
+
fs$1.rename(pathInput, fullPath, (err) => {
|
|
19956
|
+
if (err)
|
|
19957
|
+
reject(err);
|
|
19958
|
+
resolve(fullPath);
|
|
19959
|
+
});
|
|
19960
|
+
});
|
|
19961
|
+
};
|
|
19962
|
+
const httpResponse = await handleDownload();
|
|
19963
|
+
const { ext } = await fileTypeFromFile(httpResponse.response);
|
|
19964
|
+
if (!ext)
|
|
19965
|
+
throw new Error('Unable to determine file extension');
|
|
19966
|
+
const getPath = await handleFile(httpResponse.fullPath, ext);
|
|
19967
|
+
return getPath;
|
|
20014
19968
|
};
|
|
20015
19969
|
|
|
20016
19970
|
/**
|
|
20017
|
-
*
|
|
19971
|
+
* Genera un UUID único con un prefijo opcional.
|
|
19972
|
+
* @param prefix - Prefijo opcional para el UUID.
|
|
19973
|
+
* @returns Un identificador único (UUID v4).
|
|
19974
|
+
*/
|
|
19975
|
+
const generateRefProvider = (prefix) => {
|
|
19976
|
+
const id = node_crypto.randomUUID();
|
|
19977
|
+
return prefix ? `${prefix}_${id}` : id;
|
|
19978
|
+
};
|
|
19979
|
+
/**
|
|
19980
|
+
* Elimina el dominio del JID de WhatsApp (e.g., "@s.whatsapp.net").
|
|
19981
|
+
* @param jid - JID completo.
|
|
19982
|
+
* @returns El número limpio.
|
|
19983
|
+
*/
|
|
19984
|
+
const cleanJid = (jid) => {
|
|
19985
|
+
return jid?.split('@')[0] ?? '';
|
|
19986
|
+
};
|
|
19987
|
+
/**
|
|
19988
|
+
* Class representing EvolutionCoreVendor, a vendor class for WhatsApp Business API integration.
|
|
19989
|
+
* Handles webhook validation, message reception, and processing through Meta's Cloud API.
|
|
20018
19990
|
* @extends EventEmitter
|
|
20019
19991
|
*/
|
|
20020
19992
|
class EvolutionCoreVendor extends EventEmitter {
|
|
20021
19993
|
/**
|
|
20022
|
-
*
|
|
20023
|
-
* @param {Queue} _queue - The queue instance.
|
|
19994
|
+
* Creates an instance of EvolutionCoreVendor.
|
|
19995
|
+
* @param {Queue} _queue - The queue instance for managing message processing.
|
|
20024
19996
|
*/
|
|
20025
19997
|
constructor(_queue) {
|
|
20026
19998
|
super();
|
|
20027
19999
|
/**
|
|
20028
|
-
* Middleware function for
|
|
20000
|
+
* Middleware function for health check endpoint.
|
|
20001
|
+
* Returns a simple response to verify the service is running.
|
|
20029
20002
|
* @type {polka.Middleware}
|
|
20030
20003
|
*/
|
|
20031
20004
|
this.indexHome = (_, res) => {
|
|
20032
|
-
|
|
20033
|
-
|
|
20034
|
-
/**
|
|
20035
|
-
* Middleware function for verifying token.
|
|
20036
|
-
* @type {polka.Middleware}
|
|
20037
|
-
*/
|
|
20038
|
-
this.verifyToken = async (req, res) => {
|
|
20039
|
-
const { query } = req;
|
|
20040
|
-
const mode = query?.['hub.mode'];
|
|
20041
|
-
const token = query?.['hub.verify_token'];
|
|
20042
|
-
const challenge = query?.['hub.challenge'];
|
|
20043
|
-
const globalVendorArgs = req['globalVendorArgs'] ?? null;
|
|
20044
|
-
if (!mode || !token) {
|
|
20045
|
-
res.statusCode = 403;
|
|
20046
|
-
res.end('No token!');
|
|
20047
|
-
return;
|
|
20005
|
+
try {
|
|
20006
|
+
res.end('ok');
|
|
20048
20007
|
}
|
|
20049
|
-
|
|
20050
|
-
|
|
20051
|
-
res.statusCode =
|
|
20052
|
-
res.end(
|
|
20053
|
-
return;
|
|
20008
|
+
catch (error) {
|
|
20009
|
+
console.error('Error in indexHome middleware:', error);
|
|
20010
|
+
res.statusCode = 500;
|
|
20011
|
+
res.end('Internal server error');
|
|
20054
20012
|
}
|
|
20055
|
-
res.statusCode = 403;
|
|
20056
|
-
res.end('Invalid token!');
|
|
20057
20013
|
};
|
|
20058
20014
|
/**
|
|
20059
|
-
* Middleware function for handling incoming messages.
|
|
20015
|
+
* Middleware function for handling incoming webhook messages.
|
|
20016
|
+
* Processes incoming messages from WhatsApp and adds them to the processing queue.
|
|
20060
20017
|
* @type {polka.Middleware}
|
|
20061
20018
|
*/
|
|
20062
20019
|
this.incomingMsg = async (req, res) => {
|
|
20063
|
-
const globalVendorArgs = req['globalVendorArgs'] ?? null;
|
|
20064
|
-
const body = req?.body;
|
|
20065
|
-
const { jwtToken, numberId, version } = globalVendorArgs;
|
|
20066
|
-
const someErrors = this.extractStatus(body);
|
|
20067
|
-
const findError = someErrors.find((s) => s.status === 'failed');
|
|
20068
|
-
if (findError) {
|
|
20069
|
-
this.emit('notice', {
|
|
20070
|
-
title: '🔔 META ALERT 🔔',
|
|
20071
|
-
instructions: [findError.reason],
|
|
20072
|
-
});
|
|
20073
|
-
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
20074
|
-
return res.end(JSON.stringify(someErrors));
|
|
20075
|
-
}
|
|
20076
|
-
const messages = body?.entry?.[0]?.changes?.[0]?.value?.messages;
|
|
20077
|
-
const contacts = body?.entry?.[0]?.changes?.[0]?.value?.contacts;
|
|
20078
|
-
const messageId = body?.entry?.[0]?.changes?.[0]?.value?.messages?.[0]?.id;
|
|
20079
|
-
const messageTimestamp = body?.entry?.[0]?.changes?.[0]?.value?.messages?.[0]?.timestamp;
|
|
20080
|
-
if (!messages?.length) {
|
|
20081
|
-
res.statusCode = 200;
|
|
20082
|
-
res.end('empty endpoint');
|
|
20083
|
-
return;
|
|
20084
|
-
}
|
|
20085
20020
|
try {
|
|
20086
|
-
|
|
20087
|
-
|
|
20088
|
-
|
|
20089
|
-
|
|
20090
|
-
|
|
20091
|
-
|
|
20092
|
-
|
|
20093
|
-
|
|
20094
|
-
|
|
20095
|
-
|
|
20096
|
-
|
|
20097
|
-
|
|
20098
|
-
|
|
20099
|
-
|
|
20100
|
-
|
|
20101
|
-
|
|
20102
|
-
|
|
20103
|
-
|
|
20104
|
-
|
|
20105
|
-
|
|
20106
|
-
|
|
20107
|
-
|
|
20108
|
-
|
|
20109
|
-
|
|
20110
|
-
|
|
20111
|
-
|
|
20112
|
-
|
|
20021
|
+
const globalVendorArgs = req['globalVendorArgs'] ?? null;
|
|
20022
|
+
if (!globalVendorArgs) {
|
|
20023
|
+
res.statusCode = 400;
|
|
20024
|
+
res.end('Missing vendor arguments');
|
|
20025
|
+
return;
|
|
20026
|
+
}
|
|
20027
|
+
console.log(' body', JSON.stringify(req.body, null, 2));
|
|
20028
|
+
const { event, data } = req.body;
|
|
20029
|
+
if (!req.body) {
|
|
20030
|
+
res.statusCode = 400;
|
|
20031
|
+
res.end('Invalid request body');
|
|
20032
|
+
return;
|
|
20033
|
+
}
|
|
20034
|
+
switch (event) {
|
|
20035
|
+
case 'messages.upsert':
|
|
20036
|
+
if (data.message) {
|
|
20037
|
+
const { message } = data;
|
|
20038
|
+
const from = cleanJid(data.key?.remoteJid);
|
|
20039
|
+
const name = data.pushName;
|
|
20040
|
+
let responseObj = null;
|
|
20041
|
+
if (message.documentMessage) {
|
|
20042
|
+
responseObj = {
|
|
20043
|
+
type: data.messageType,
|
|
20044
|
+
from,
|
|
20045
|
+
mimetype: message.documentMessage.mimetype,
|
|
20046
|
+
body: generateRefProvider('_event_document_'),
|
|
20047
|
+
name,
|
|
20048
|
+
caption: message.documentMessage.caption,
|
|
20049
|
+
base64: message.base64,
|
|
20050
|
+
};
|
|
20051
|
+
}
|
|
20052
|
+
else if (message.videoMessage) {
|
|
20053
|
+
responseObj = {
|
|
20054
|
+
type: data.messageType,
|
|
20055
|
+
from,
|
|
20056
|
+
mimetype: message.videoMessage.mimetype,
|
|
20057
|
+
body: generateRefProvider('_event_media_'),
|
|
20058
|
+
name,
|
|
20059
|
+
caption: message.videoMessage.caption || '',
|
|
20060
|
+
base64: message.base64,
|
|
20061
|
+
};
|
|
20062
|
+
}
|
|
20063
|
+
else if (message.imageMessage) {
|
|
20064
|
+
responseObj = {
|
|
20065
|
+
type: data.messageType,
|
|
20066
|
+
from,
|
|
20067
|
+
mimetype: message.imageMessage.mimetype,
|
|
20068
|
+
body: generateRefProvider('_event_media_'),
|
|
20069
|
+
name,
|
|
20070
|
+
caption: message.imageMessage.caption || '',
|
|
20071
|
+
base64: message.base64,
|
|
20072
|
+
};
|
|
20073
|
+
}
|
|
20074
|
+
else if (message.audioMessage) {
|
|
20075
|
+
responseObj = {
|
|
20076
|
+
type: data.messageType,
|
|
20077
|
+
from,
|
|
20078
|
+
mimetype: message.audioMessage.mimetype,
|
|
20079
|
+
body: generateRefProvider('_event_voice_note_'),
|
|
20080
|
+
name,
|
|
20081
|
+
caption: message.audioMessage.caption || '',
|
|
20082
|
+
base64: message.base64,
|
|
20083
|
+
};
|
|
20084
|
+
}
|
|
20085
|
+
else if (message.locationMessage || message.liveLocationMessage) {
|
|
20086
|
+
responseObj = {
|
|
20087
|
+
type: data.messageType,
|
|
20088
|
+
from,
|
|
20089
|
+
latitude: message.locationMessage?.degreesLatitude ??
|
|
20090
|
+
message.liveLocationMessage?.degreesLatitude,
|
|
20091
|
+
longitude: message.locationMessage?.degreesLongitude ??
|
|
20092
|
+
message.liveLocationMessage?.degreesLongitude,
|
|
20093
|
+
body: generateRefProvider('_event_location_'),
|
|
20094
|
+
name,
|
|
20095
|
+
};
|
|
20096
|
+
}
|
|
20097
|
+
else if (message.conversation) {
|
|
20098
|
+
responseObj = {
|
|
20099
|
+
type: data.messageType,
|
|
20100
|
+
from,
|
|
20101
|
+
body: message.conversation,
|
|
20102
|
+
name,
|
|
20103
|
+
};
|
|
20104
|
+
}
|
|
20105
|
+
if (responseObj) {
|
|
20106
|
+
const enrichedMessage = { ...data, ...responseObj };
|
|
20107
|
+
await this.queue.enqueue(() => this.processMessage(enrichedMessage));
|
|
20108
|
+
}
|
|
20109
|
+
}
|
|
20110
|
+
}
|
|
20113
20111
|
res.statusCode = 200;
|
|
20114
|
-
res.end('
|
|
20112
|
+
res.end('Message processed successfully');
|
|
20113
|
+
// Check for errors reported by Meta
|
|
20115
20114
|
}
|
|
20116
20115
|
catch (error) {
|
|
20116
|
+
console.error('Error processing incoming message:', error);
|
|
20117
20117
|
this.emit('notice', {
|
|
20118
|
-
title: '🔔
|
|
20119
|
-
instructions: [error.message || 'An error occurred while processing
|
|
20118
|
+
title: '🔔 EVOLUTION API ALERT 🔔',
|
|
20119
|
+
instructions: [error.message || 'An error occurred while processing message.'],
|
|
20120
20120
|
});
|
|
20121
|
-
res.writeHead(
|
|
20122
|
-
res.end(JSON.stringify({
|
|
20121
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
20122
|
+
res.end(JSON.stringify({
|
|
20123
|
+
error: error.message || 'An error occurred while processing message.',
|
|
20124
|
+
stack: process.env.NODE_ENV === 'development' ? error.stack : undefined,
|
|
20125
|
+
}));
|
|
20123
20126
|
}
|
|
20124
20127
|
};
|
|
20125
20128
|
/**
|
|
20126
|
-
*
|
|
20127
|
-
* @param
|
|
20128
|
-
* @returns {Promise<void>} Promise that resolves when processing is complete.
|
|
20129
|
+
* Procesa un mensaje entrante y lo emite al flujo del bot.
|
|
20130
|
+
* @param message - Objeto de mensaje enriquecido.
|
|
20129
20131
|
*/
|
|
20130
20132
|
this.processMessage = (message) => {
|
|
20131
20133
|
return new Promise((resolve, reject) => {
|
|
@@ -20138,41 +20140,22 @@ class EvolutionCoreVendor extends EventEmitter {
|
|
|
20138
20140
|
}
|
|
20139
20141
|
});
|
|
20140
20142
|
};
|
|
20143
|
+
if (!_queue) {
|
|
20144
|
+
throw new Error('Queue instance is required');
|
|
20145
|
+
}
|
|
20141
20146
|
this.queue = _queue;
|
|
20142
20147
|
}
|
|
20143
|
-
/**
|
|
20144
|
-
* Check if the token is valid.
|
|
20145
|
-
* @param {string} mode - The mode parameter.
|
|
20146
|
-
* @param {string} token - The token parameter.
|
|
20147
|
-
* @param {string} originToken - The origin token parameter.
|
|
20148
|
-
* @returns {boolean} Returns true if token is valid, false otherwise.
|
|
20149
|
-
*/
|
|
20150
|
-
tokenIsValid(mode, token, originToken) {
|
|
20151
|
-
return mode === 'subscribe' && originToken === token;
|
|
20152
|
-
}
|
|
20153
|
-
extractStatus(obj) {
|
|
20154
|
-
const entry = obj.entry || [];
|
|
20155
|
-
const statusArray = [];
|
|
20156
|
-
entry.forEach((entryItem) => {
|
|
20157
|
-
const changes = entryItem.changes || [];
|
|
20158
|
-
changes.forEach((change) => {
|
|
20159
|
-
const values = change.value || {};
|
|
20160
|
-
const statuses = values.statuses || [];
|
|
20161
|
-
statuses.forEach((status) => {
|
|
20162
|
-
const recipient_id = status.recipient_id || 'N/A';
|
|
20163
|
-
const errorDetails = status.errors?.[0]?.error_data?.details || 'Unknown';
|
|
20164
|
-
statusArray.push({
|
|
20165
|
-
status: status.status || 'Unknown',
|
|
20166
|
-
reason: `Number(${recipient_id}): ${errorDetails}`,
|
|
20167
|
-
});
|
|
20168
|
-
});
|
|
20169
|
-
});
|
|
20170
|
-
});
|
|
20171
|
-
return statusArray;
|
|
20172
|
-
}
|
|
20173
20148
|
}
|
|
20174
20149
|
|
|
20150
|
+
/**
|
|
20151
|
+
* Evolution API Provider implementation
|
|
20152
|
+
* Handles all communication with Evolution API for sending messages, media, etc.
|
|
20153
|
+
*/
|
|
20175
20154
|
class EvolutionProvider extends bot.ProviderClass {
|
|
20155
|
+
/**
|
|
20156
|
+
* Creates an instance of Evolution Provider
|
|
20157
|
+
* @param args Provider configuration
|
|
20158
|
+
*/
|
|
20176
20159
|
constructor(args) {
|
|
20177
20160
|
super();
|
|
20178
20161
|
this.queue = new Queue();
|
|
@@ -20181,108 +20164,164 @@ class EvolutionProvider extends bot.ProviderClass {
|
|
|
20181
20164
|
apiKey: '',
|
|
20182
20165
|
baseURL: 'http://localhost:8080',
|
|
20183
20166
|
instanceName: '',
|
|
20167
|
+
port: 3000,
|
|
20184
20168
|
};
|
|
20185
|
-
|
|
20186
|
-
|
|
20187
|
-
|
|
20188
|
-
|
|
20189
|
-
|
|
20190
|
-
|
|
20191
|
-
|
|
20192
|
-
|
|
20193
|
-
|
|
20194
|
-
|
|
20195
|
-
|
|
20196
|
-
|
|
20197
|
-
|
|
20198
|
-
{
|
|
20199
|
-
|
|
20200
|
-
|
|
20201
|
-
|
|
20169
|
+
/**
|
|
20170
|
+
* Punto de entrada para envío de archivos multimedia.
|
|
20171
|
+
* Detecta el tipo de archivo y redirige a la función correspondiente.
|
|
20172
|
+
*
|
|
20173
|
+
* @param number Número de destino
|
|
20174
|
+
* @param mediaUrl URL o path del archivo
|
|
20175
|
+
* @param caption Texto opcional
|
|
20176
|
+
*/
|
|
20177
|
+
this.sendMedia = async (number, mediaUrl, caption) => {
|
|
20178
|
+
const fileDownloaded = await generalDownload(mediaUrl);
|
|
20179
|
+
const mimeType = mime$1.lookup(fileDownloaded);
|
|
20180
|
+
if (!mimeType)
|
|
20181
|
+
throw new Error('No se pudo determinar el tipo MIME');
|
|
20182
|
+
if (mimeType.includes('image')) {
|
|
20183
|
+
return this.sendImage(number, fileDownloaded, caption || '');
|
|
20184
|
+
}
|
|
20185
|
+
if (mimeType.includes('video')) {
|
|
20186
|
+
return this.sendVideo(number, fileDownloaded, caption || '');
|
|
20187
|
+
}
|
|
20188
|
+
if (mimeType.includes('audio')) {
|
|
20189
|
+
return this.sendAudio(number, fileDownloaded);
|
|
20190
|
+
}
|
|
20191
|
+
return this.sendFile(number, fileDownloaded, caption || '');
|
|
20192
|
+
};
|
|
20193
|
+
/**
|
|
20194
|
+
* Envía una imagen al número dado.
|
|
20195
|
+
* @param number Número destino
|
|
20196
|
+
* @param filePath Ruta local de la imagen
|
|
20197
|
+
* @param caption Texto opcional
|
|
20198
|
+
*/
|
|
20199
|
+
this.sendImage = async (number, filePath, caption) => {
|
|
20200
|
+
const mediaBase64 = fs$1.readFileSync(filePath, { encoding: 'base64' });
|
|
20201
|
+
const mimeType = mime$1.lookup(filePath);
|
|
20202
|
+
const body = {
|
|
20203
|
+
number,
|
|
20204
|
+
media: mediaBase64,
|
|
20205
|
+
mimetype: mimeType,
|
|
20206
|
+
mediatype: 'image',
|
|
20207
|
+
caption: caption || path$1.basename(filePath),
|
|
20208
|
+
delay: 0,
|
|
20209
|
+
};
|
|
20210
|
+
return this.sendMessageEvoApi(body, '/message/sendMedia/');
|
|
20211
|
+
};
|
|
20212
|
+
/**
|
|
20213
|
+
* Envía un video al número dado.
|
|
20214
|
+
* @param number Número destino
|
|
20215
|
+
* @param filePath Ruta local del video
|
|
20216
|
+
* @param caption Texto opcional
|
|
20217
|
+
*/
|
|
20218
|
+
this.sendVideo = async (number, filePath, caption) => {
|
|
20219
|
+
const mediaBase64 = fs$1.readFileSync(filePath, { encoding: 'base64' });
|
|
20220
|
+
const mimeType = mime$1.lookup(filePath);
|
|
20221
|
+
const body = {
|
|
20222
|
+
number,
|
|
20223
|
+
media: mediaBase64,
|
|
20224
|
+
mimetype: mimeType,
|
|
20225
|
+
mediatype: 'video',
|
|
20226
|
+
caption: caption || path$1.basename(filePath),
|
|
20227
|
+
delay: 0,
|
|
20228
|
+
};
|
|
20229
|
+
return this.sendMessageEvoApi(body, '/message/sendMedia/');
|
|
20230
|
+
};
|
|
20231
|
+
/**
|
|
20232
|
+
* Envía un archivo de audio en formato compatible (OPUS).
|
|
20233
|
+
* @param number Número destino
|
|
20234
|
+
* @param filePath Ruta local del archivo de audio
|
|
20235
|
+
*/
|
|
20236
|
+
this.sendAudio = async (number, filePath) => {
|
|
20237
|
+
const mediaBase64 = fs$1.readFileSync(filePath, { encoding: 'base64' });
|
|
20238
|
+
const body = {
|
|
20239
|
+
number,
|
|
20240
|
+
media: mediaBase64,
|
|
20241
|
+
mimetype: 'audio/ogg; codecs=opus',
|
|
20242
|
+
mediatype: 'audio',
|
|
20243
|
+
delay: 0,
|
|
20244
|
+
};
|
|
20245
|
+
return this.sendMessageEvoApi(body, '/message/sendMedia/');
|
|
20246
|
+
};
|
|
20247
|
+
/**
|
|
20248
|
+
* Envía un documento genérico al número dado.
|
|
20249
|
+
* @param number Número destino
|
|
20250
|
+
* @param filePath Ruta local del archivo
|
|
20251
|
+
* @param caption Texto opcional
|
|
20252
|
+
*/
|
|
20253
|
+
this.sendFile = async (number, filePath, caption) => {
|
|
20254
|
+
const mediaBase64 = fs$1.readFileSync(filePath, { encoding: 'base64' });
|
|
20255
|
+
const mimeType = mime$1.lookup(filePath);
|
|
20256
|
+
const fileName = path$1.basename(filePath);
|
|
20257
|
+
const body = {
|
|
20258
|
+
number,
|
|
20259
|
+
media: mediaBase64,
|
|
20260
|
+
mimetype: mimeType,
|
|
20261
|
+
mediatype: 'document',
|
|
20262
|
+
fileName,
|
|
20263
|
+
caption: caption || path$1.basename(filePath),
|
|
20264
|
+
delay: 0,
|
|
20265
|
+
};
|
|
20266
|
+
return this.sendMessageEvoApi(body, '/message/sendMedia/');
|
|
20267
|
+
};
|
|
20268
|
+
/**
|
|
20269
|
+
* Envía un mensaje de texto plano.
|
|
20270
|
+
* @param number Número destino
|
|
20271
|
+
* @param message Contenido del mensaje
|
|
20272
|
+
*/
|
|
20273
|
+
this.sendText = async (number, message) => {
|
|
20274
|
+
const ruta = '/message/sendText/';
|
|
20275
|
+
const body = {
|
|
20276
|
+
number,
|
|
20277
|
+
text: message,
|
|
20278
|
+
delay: 0,
|
|
20279
|
+
};
|
|
20280
|
+
return this.sendMessageEvoApi(body, ruta);
|
|
20281
|
+
};
|
|
20282
|
+
/**
|
|
20283
|
+
* Función general para hacer peticiones POST a la API externa.
|
|
20284
|
+
* @param body Cuerpo de la petición
|
|
20285
|
+
* @param ruta Ruta relativa del endpoint (optional)
|
|
20286
|
+
*/
|
|
20287
|
+
this.sendMessageToApi = async (body, ruta = '/message/') => {
|
|
20288
|
+
const { baseURL, instanceName, apiKey } = this.globalVendorArgs;
|
|
20289
|
+
const response = await fetch(`${baseURL}${ruta}${instanceName}`, {
|
|
20290
|
+
method: 'POST',
|
|
20291
|
+
headers: {
|
|
20292
|
+
'Content-Type': 'application/json',
|
|
20293
|
+
apikey: apiKey,
|
|
20202
20294
|
},
|
|
20203
|
-
|
|
20204
|
-
|
|
20205
|
-
|
|
20206
|
-
|
|
20207
|
-
|
|
20208
|
-
|
|
20209
|
-
|
|
20210
|
-
|
|
20211
|
-
|
|
20212
|
-
|
|
20213
|
-
|
|
20214
|
-
|
|
20215
|
-
|
|
20216
|
-
|
|
20217
|
-
// 'apikey': apiKey
|
|
20218
|
-
// }
|
|
20219
|
-
// }
|
|
20220
|
-
// )
|
|
20221
|
-
// } catch (error) {
|
|
20222
|
-
// console.error('Error sending location:', error)
|
|
20223
|
-
// throw error
|
|
20224
|
-
// }
|
|
20225
|
-
// }
|
|
20226
|
-
// async sendContact(to: string, contact: Contact): Promise<any> {
|
|
20227
|
-
// const { baseURL, instanceName, apiKey } = this.globalVendorArgs
|
|
20228
|
-
// try {
|
|
20229
|
-
// return await axios.post(
|
|
20230
|
-
// `${baseURL}/message/contact/${instanceName}`,
|
|
20231
|
-
// {
|
|
20232
|
-
// number: to,
|
|
20233
|
-
// contact
|
|
20234
|
-
// },
|
|
20235
|
-
// {
|
|
20236
|
-
// headers: {
|
|
20237
|
-
// 'apikey': apiKey
|
|
20238
|
-
// }
|
|
20239
|
-
// }
|
|
20240
|
-
// )
|
|
20241
|
-
// } catch (error) {
|
|
20242
|
-
// console.error('Error sending contact:', error)
|
|
20243
|
-
// throw error
|
|
20244
|
-
// }
|
|
20245
|
-
// }
|
|
20246
|
-
// async sendReaction(to: string, message: string): Promise<any> {
|
|
20247
|
-
// const { baseURL, instanceName, apiKey } = this.globalVendorArgs
|
|
20248
|
-
// try {
|
|
20249
|
-
// return await axios.post(
|
|
20250
|
-
// `${baseURL}/message/reaction/${instanceName}`,
|
|
20251
|
-
// {
|
|
20252
|
-
// number: to,
|
|
20253
|
-
// reaction: message
|
|
20254
|
-
// },
|
|
20255
|
-
// {
|
|
20256
|
-
// headers: {
|
|
20257
|
-
// 'apikey': apiKey
|
|
20258
|
-
// }
|
|
20259
|
-
// }
|
|
20260
|
-
// )
|
|
20261
|
-
// } catch (error) {
|
|
20262
|
-
// console.error('Error sending reaction:', error)
|
|
20263
|
-
// throw error
|
|
20264
|
-
// }
|
|
20265
|
-
// }
|
|
20266
|
-
// Métodos auxiliares requeridos por la interfaz
|
|
20267
|
-
this.sendMessageMeta = (body) => {
|
|
20295
|
+
body: JSON.stringify(body),
|
|
20296
|
+
});
|
|
20297
|
+
if (!response.ok) {
|
|
20298
|
+
throw new Error(`Error sending message: ${response.statusText}`);
|
|
20299
|
+
}
|
|
20300
|
+
const data = await response.json();
|
|
20301
|
+
return data;
|
|
20302
|
+
};
|
|
20303
|
+
/**
|
|
20304
|
+
* Encola el envío de un mensaje para asegurar orden y evitar conflictos.
|
|
20305
|
+
* @param body Cuerpo del mensaje
|
|
20306
|
+
* @param ruta Ruta del endpoint
|
|
20307
|
+
*/
|
|
20308
|
+
this.sendMessageEvoApi = (body, ruta) => {
|
|
20268
20309
|
return new Promise((resolve) => this.queue.add(async () => {
|
|
20269
|
-
const resp = await this.sendMessageToApi(body);
|
|
20310
|
+
const resp = await this.sendMessageToApi(body, ruta);
|
|
20270
20311
|
resolve(resp);
|
|
20271
20312
|
}));
|
|
20272
20313
|
};
|
|
20273
|
-
this.
|
|
20274
|
-
const { baseURL, instanceName, apiKey } = this.globalVendorArgs;
|
|
20314
|
+
this.saveFile = async (ctx, options = {}) => {
|
|
20275
20315
|
try {
|
|
20276
|
-
const
|
|
20277
|
-
|
|
20278
|
-
|
|
20279
|
-
|
|
20280
|
-
|
|
20281
|
-
return
|
|
20316
|
+
const buffer = ctx.base64;
|
|
20317
|
+
const extension = mime$1.extension(ctx.mimetype);
|
|
20318
|
+
const fileName = `file-${Date.now()}.${extension}`;
|
|
20319
|
+
const pathFile = path$1.join(options?.path ?? require$$0$2.tmpdir(), fileName);
|
|
20320
|
+
await promises.writeFile(pathFile, buffer);
|
|
20321
|
+
return path$1.resolve(pathFile);
|
|
20282
20322
|
}
|
|
20283
20323
|
catch (error) {
|
|
20284
|
-
|
|
20285
|
-
throw error;
|
|
20324
|
+
return Promise.reject(error);
|
|
20286
20325
|
}
|
|
20287
20326
|
};
|
|
20288
20327
|
this.globalVendorArgs = { ...this.globalVendorArgs, ...args };
|
|
@@ -20292,215 +20331,106 @@ class EvolutionProvider extends bot.ProviderClass {
|
|
|
20292
20331
|
start: true,
|
|
20293
20332
|
});
|
|
20294
20333
|
}
|
|
20334
|
+
/**
|
|
20335
|
+
* Initialize HTTP server middleware
|
|
20336
|
+
*/
|
|
20295
20337
|
beforeHttpServerInit() {
|
|
20296
20338
|
this.server = this.server
|
|
20339
|
+
.use(json())
|
|
20297
20340
|
.use((req, _, next) => {
|
|
20298
20341
|
req['globalVendorArgs'] = this.globalVendorArgs;
|
|
20299
20342
|
return next();
|
|
20300
20343
|
})
|
|
20301
|
-
.post('/', this.vendor.indexHome)
|
|
20344
|
+
.post('/', this.vendor.indexHome)
|
|
20345
|
+
.post('/webhook', this.vendor.incomingMsg);
|
|
20302
20346
|
}
|
|
20303
|
-
|
|
20347
|
+
/**
|
|
20348
|
+
* Initialize vendor core
|
|
20349
|
+
*/
|
|
20350
|
+
initVendor() {
|
|
20304
20351
|
const vendor = new EvolutionCoreVendor(this.queue);
|
|
20305
20352
|
this.vendor = vendor;
|
|
20306
20353
|
return Promise.resolve(this.vendor);
|
|
20307
20354
|
}
|
|
20308
|
-
|
|
20355
|
+
/**
|
|
20356
|
+
* Build standard headers for API requests
|
|
20357
|
+
* @param additionalHeaders Optional additional headers to include
|
|
20358
|
+
* @returns Headers object with apiKey
|
|
20359
|
+
*/
|
|
20360
|
+
builderHeader(additionalHeaders = {}) {
|
|
20361
|
+
const { apiKey } = this.globalVendorArgs;
|
|
20362
|
+
return {
|
|
20363
|
+
apikey: apiKey,
|
|
20364
|
+
...additionalHeaders,
|
|
20365
|
+
};
|
|
20366
|
+
}
|
|
20367
|
+
/**
|
|
20368
|
+
* Verify connection with Evolution API after HTTP server initialization
|
|
20369
|
+
*/ async afterHttpServerInit() {
|
|
20309
20370
|
try {
|
|
20310
|
-
const { baseURL, instanceName
|
|
20311
|
-
//
|
|
20371
|
+
const { baseURL, instanceName } = this.globalVendorArgs;
|
|
20372
|
+
// Verify connection with Evolution API
|
|
20312
20373
|
const response = await axios.get(`${baseURL}/instance/connectionState/${instanceName}`, {
|
|
20313
|
-
headers:
|
|
20314
|
-
apikey: apiKey,
|
|
20315
|
-
},
|
|
20374
|
+
headers: this.builderHeader(),
|
|
20316
20375
|
});
|
|
20317
|
-
|
|
20376
|
+
const state = response.data.state ?? response.data.instance.state ?? 'close';
|
|
20377
|
+
if (state === 'open') {
|
|
20318
20378
|
this.emit('ready');
|
|
20319
20379
|
}
|
|
20320
20380
|
else {
|
|
20321
|
-
throw new Error(
|
|
20381
|
+
throw new Error(`Instance state: ${state}`);
|
|
20322
20382
|
}
|
|
20323
20383
|
}
|
|
20324
20384
|
catch (err) {
|
|
20385
|
+
const errorMessage = err instanceof Error ? err.message : 'Unknown error';
|
|
20325
20386
|
this.emit('notice', {
|
|
20326
20387
|
title: '🟠 ERROR AUTH 🟠',
|
|
20327
20388
|
instructions: [
|
|
20328
20389
|
'Error connecting to Evolution API, please check your credentials',
|
|
20329
20390
|
'Make sure your instance is connected',
|
|
20391
|
+
`Details: ${errorMessage}`,
|
|
20330
20392
|
],
|
|
20331
20393
|
});
|
|
20332
20394
|
}
|
|
20333
20395
|
}
|
|
20334
|
-
|
|
20335
|
-
|
|
20336
|
-
|
|
20337
|
-
|
|
20338
|
-
|
|
20339
|
-
|
|
20340
|
-
|
|
20341
|
-
|
|
20342
|
-
|
|
20343
|
-
|
|
20344
|
-
|
|
20345
|
-
|
|
20346
|
-
|
|
20347
|
-
|
|
20348
|
-
|
|
20349
|
-
|
|
20350
|
-
|
|
20351
|
-
|
|
20352
|
-
|
|
20353
|
-
|
|
20354
|
-
|
|
20355
|
-
try {
|
|
20356
|
-
const { baseURL, instanceName, apiKey } = this.globalVendorArgs;
|
|
20357
|
-
return await axios.post(`${baseURL}/message/sendMedia/${instanceName}`, {
|
|
20358
|
-
number: to,
|
|
20359
|
-
mediaType: 'image',
|
|
20360
|
-
mimeType: mime$1.lookup(mediaUrl) || 'image/png',
|
|
20361
|
-
caption: caption,
|
|
20362
|
-
media: mediaUrl,
|
|
20363
|
-
fileName: mediaName || 'image.png',
|
|
20364
|
-
}, {
|
|
20365
|
-
headers: {
|
|
20366
|
-
apikey: apiKey,
|
|
20367
|
-
},
|
|
20368
|
-
});
|
|
20369
|
-
}
|
|
20370
|
-
catch (error) {
|
|
20371
|
-
console.error('Error sending image:', error);
|
|
20372
|
-
throw error;
|
|
20373
|
-
}
|
|
20374
|
-
}
|
|
20375
|
-
async sendImageUrl(to, url, mediaName, caption) {
|
|
20376
|
-
return this.sendImage(to, url, mediaName, caption);
|
|
20377
|
-
}
|
|
20378
|
-
async sendVideo(to, mediaUrl, mediaName, caption) {
|
|
20379
|
-
try {
|
|
20380
|
-
const { baseURL, instanceName, apiKey } = this.globalVendorArgs;
|
|
20381
|
-
return await axios.post(`${baseURL}/message/video/${instanceName}`, {
|
|
20382
|
-
number: to,
|
|
20383
|
-
mediaType: 'video',
|
|
20384
|
-
mimeType: 'video/mp4',
|
|
20385
|
-
caption: caption,
|
|
20386
|
-
media: mediaUrl,
|
|
20387
|
-
fileName: mediaName || 'video.mp4',
|
|
20388
|
-
}, {
|
|
20389
|
-
headers: {
|
|
20390
|
-
apikey: apiKey,
|
|
20391
|
-
},
|
|
20392
|
-
});
|
|
20393
|
-
}
|
|
20394
|
-
catch (error) {
|
|
20395
|
-
console.error('Error sending video:', error);
|
|
20396
|
-
throw error;
|
|
20397
|
-
}
|
|
20398
|
-
}
|
|
20399
|
-
async sendVideoUrl(to, url, mediaName, caption) {
|
|
20400
|
-
return this.sendVideo(to, url, mediaName, caption);
|
|
20401
|
-
}
|
|
20402
|
-
async sendAudio(to, mediaUrl, mediaName, caption) {
|
|
20403
|
-
try {
|
|
20404
|
-
const { baseURL, instanceName, apiKey } = this.globalVendorArgs;
|
|
20405
|
-
return await axios.post(`${baseURL}/message/audio/${instanceName}`, {
|
|
20406
|
-
number: to,
|
|
20407
|
-
mediaType: 'audio',
|
|
20408
|
-
mimeType: 'audio/mp3',
|
|
20409
|
-
caption: caption,
|
|
20410
|
-
media: mediaUrl,
|
|
20411
|
-
fileName: mediaName || 'audio.mp3',
|
|
20412
|
-
}, {
|
|
20413
|
-
headers: {
|
|
20414
|
-
apikey: apiKey,
|
|
20415
|
-
},
|
|
20416
|
-
});
|
|
20417
|
-
}
|
|
20418
|
-
catch (error) {
|
|
20419
|
-
console.error('Error sending audio:', error);
|
|
20420
|
-
throw error;
|
|
20421
|
-
}
|
|
20422
|
-
}
|
|
20423
|
-
async sendAudioUrl(to, url, mediaName, caption) {
|
|
20424
|
-
return this.sendAudio(to, url, mediaName, caption);
|
|
20425
|
-
}
|
|
20426
|
-
async sendMedia(to, file, type) {
|
|
20427
|
-
const { baseURL, instanceName, apiKey } = this.globalVendorArgs;
|
|
20428
|
-
try {
|
|
20429
|
-
return await axios.post(`${baseURL}/message/${type}/${instanceName}`, {
|
|
20430
|
-
number: to,
|
|
20431
|
-
[type]: file,
|
|
20432
|
-
}, {
|
|
20433
|
-
headers: {
|
|
20434
|
-
apikey: apiKey,
|
|
20435
|
-
},
|
|
20436
|
-
});
|
|
20437
|
-
}
|
|
20438
|
-
catch (error) {
|
|
20439
|
-
console.error(`Error sending ${type}:`, error);
|
|
20440
|
-
throw error;
|
|
20441
|
-
}
|
|
20442
|
-
}
|
|
20443
|
-
// async sendButtons(to: string, buttons: Button[] = [], text: string): Promise<any> {
|
|
20444
|
-
// try {
|
|
20445
|
-
// const { baseURL, instanceName, apiKey } = this.globalVendorArgs
|
|
20446
|
-
// return await axios.post(
|
|
20447
|
-
// `${baseURL}/message/buttons/${instanceName}`,
|
|
20448
|
-
// {
|
|
20449
|
-
// number: to,
|
|
20450
|
-
// buttons: buttons.map(btn => ({
|
|
20451
|
-
// buttonText: btn.body,
|
|
20452
|
-
// buttonId: btn.id
|
|
20453
|
-
// })),
|
|
20454
|
-
// text
|
|
20455
|
-
// },
|
|
20456
|
-
// {
|
|
20457
|
-
// headers: {
|
|
20458
|
-
// 'apikey': apiKey
|
|
20459
|
-
// }
|
|
20460
|
-
// }
|
|
20461
|
-
// )
|
|
20462
|
-
// } catch (error) {
|
|
20463
|
-
// console.error('Error sending buttons:', error)
|
|
20464
|
-
// throw error
|
|
20465
|
-
// }
|
|
20466
|
-
// }
|
|
20467
|
-
async sendList(to, list) {
|
|
20468
|
-
try {
|
|
20469
|
-
const { baseURL, instanceName, apiKey } = this.globalVendorArgs;
|
|
20470
|
-
return await axios.post(`${baseURL}/message/list/${instanceName}`, {
|
|
20471
|
-
number: to,
|
|
20472
|
-
list,
|
|
20473
|
-
}, {
|
|
20474
|
-
headers: {
|
|
20475
|
-
apikey: apiKey,
|
|
20396
|
+
/**
|
|
20397
|
+
* Event bus configuration
|
|
20398
|
+
*/
|
|
20399
|
+
busEvents() {
|
|
20400
|
+
return [
|
|
20401
|
+
{
|
|
20402
|
+
event: 'auth_failure',
|
|
20403
|
+
func: (payload) => this.emit('auth_failure', payload),
|
|
20404
|
+
},
|
|
20405
|
+
{
|
|
20406
|
+
event: 'notice',
|
|
20407
|
+
func: ({ instructions, title }) => this.emit('notice', { instructions, title }),
|
|
20408
|
+
},
|
|
20409
|
+
{
|
|
20410
|
+
event: 'ready',
|
|
20411
|
+
func: () => this.emit('ready', true),
|
|
20412
|
+
},
|
|
20413
|
+
{
|
|
20414
|
+
event: 'message',
|
|
20415
|
+
func: (payload) => {
|
|
20416
|
+
this.emit('message', payload);
|
|
20476
20417
|
},
|
|
20477
|
-
}
|
|
20478
|
-
|
|
20479
|
-
catch (error) {
|
|
20480
|
-
console.error('Error sending list:', error);
|
|
20481
|
-
throw error;
|
|
20482
|
-
}
|
|
20483
|
-
}
|
|
20484
|
-
async sendListComplete(to, list) {
|
|
20485
|
-
return this.sendList(to, list);
|
|
20418
|
+
},
|
|
20419
|
+
];
|
|
20486
20420
|
}
|
|
20487
|
-
|
|
20488
|
-
|
|
20489
|
-
|
|
20490
|
-
|
|
20491
|
-
|
|
20492
|
-
|
|
20493
|
-
|
|
20494
|
-
|
|
20495
|
-
|
|
20496
|
-
|
|
20497
|
-
|
|
20498
|
-
|
|
20499
|
-
|
|
20500
|
-
// console.error(`[Error saving file]:`, err.message)
|
|
20501
|
-
// return 'ERROR'
|
|
20502
|
-
// }
|
|
20503
|
-
return '';
|
|
20421
|
+
/**
|
|
20422
|
+
* Enrutador general para envío de mensajes.
|
|
20423
|
+
* Si incluye media, se envía como archivo. Si no, como texto plano.
|
|
20424
|
+
*
|
|
20425
|
+
* @param number Número destino
|
|
20426
|
+
* @param message Mensaje de texto
|
|
20427
|
+
* @param options Opciones adicionales (media, etc.)
|
|
20428
|
+
*/
|
|
20429
|
+
async sendMessage(number, message, options) {
|
|
20430
|
+
options = { ...options, ...options['options'] };
|
|
20431
|
+
if (options.media)
|
|
20432
|
+
return this.sendMedia(number, options.media, message);
|
|
20433
|
+
return this.sendText(number, message);
|
|
20504
20434
|
}
|
|
20505
20435
|
}
|
|
20506
20436
|
|