@gamastudio/sendwave-provider 0.0.2
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/.claude/settings.local.json +9 -0
- package/.github/workflows/build.yml +31 -0
- package/README.md +374 -0
- package/build/constants/html/connect.d.ts +1 -0
- package/build/constants/html/connect.js +37 -0
- package/build/constants/html/error.d.ts +1 -0
- package/build/constants/html/error.js +42 -0
- package/build/constants/html/home.d.ts +1 -0
- package/build/constants/html/home.js +30 -0
- package/build/constants/svg/logo.d.ts +1 -0
- package/build/constants/svg/logo.js +4 -0
- package/build/constants/svg/wave-error.d.ts +1 -0
- package/build/constants/svg/wave-error.js +92 -0
- package/build/constants/svg/wave.d.ts +1 -0
- package/build/constants/svg/wave.js +92 -0
- package/build/core/interface/index.d.ts +3 -0
- package/build/core/interface/index.js +19 -0
- package/build/core/interface/parser.interface.d.ts +10 -0
- package/build/core/interface/parser.interface.js +2 -0
- package/build/core/interface/provider.interface.d.ts +16 -0
- package/build/core/interface/provider.interface.js +2 -0
- package/build/core/interface/types.d.ts +86 -0
- package/build/core/interface/types.js +2 -0
- package/build/index.d.ts +5 -0
- package/build/index.js +12 -0
- package/build/package.json +48 -0
- package/build/provider/core.d.ts +20 -0
- package/build/provider/core.js +112 -0
- package/build/provider/index.d.ts +1 -0
- package/build/provider/index.js +17 -0
- package/build/provider/provider.d.ts +85 -0
- package/build/provider/provider.js +375 -0
- package/build/provider/sender.d.ts +16 -0
- package/build/provider/sender.js +203 -0
- package/build/utils/detectorMedia.d.ts +24 -0
- package/build/utils/detectorMedia.js +92 -0
- package/build/utils/parserMsg.d.ts +2 -0
- package/build/utils/parserMsg.js +104 -0
- package/build/utils/queueFlow.d.ts +36 -0
- package/build/utils/queueFlow.js +82 -0
- package/package.json +48 -0
- package/public/assets/logo.png +0 -0
- package/queue.class.log +0 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SenderMessage = void 0;
|
|
7
|
+
const https_1 = require("https");
|
|
8
|
+
const axios_1 = __importDefault(require("axios"));
|
|
9
|
+
const detectorMedia_1 = require("../utils/detectorMedia");
|
|
10
|
+
class SenderMessage {
|
|
11
|
+
constructor(args) {
|
|
12
|
+
this.sendwaveApi = axios_1.default.create({
|
|
13
|
+
baseURL: args.url,
|
|
14
|
+
httpsAgent: new https_1.Agent({ rejectUnauthorized: false }),
|
|
15
|
+
headers: {
|
|
16
|
+
"Content-Type": "application/json",
|
|
17
|
+
apikey: args.apiKey,
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
this.globalVendorArgs = args;
|
|
21
|
+
}
|
|
22
|
+
async sendPresence(data) {
|
|
23
|
+
var _a, _b;
|
|
24
|
+
try {
|
|
25
|
+
return await ((_a = this.sendwaveApi) === null || _a === void 0 ? void 0 : _a.post(`/chat/sendPresence/${(_b = this.globalVendorArgs) === null || _b === void 0 ? void 0 : _b.name}`, {
|
|
26
|
+
number: data.from,
|
|
27
|
+
delay: data.delay || 2000,
|
|
28
|
+
presence: data.presence || "composing",
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
console.error(e.response.data.response.message);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async sendText(data) {
|
|
36
|
+
var _a, _b, _c;
|
|
37
|
+
try {
|
|
38
|
+
await this.sendPresence({
|
|
39
|
+
from: data.from,
|
|
40
|
+
presence: "composing",
|
|
41
|
+
delay: data.delay || 2000,
|
|
42
|
+
});
|
|
43
|
+
return await ((_a = this.sendwaveApi) === null || _a === void 0 ? void 0 : _a.post(`/message/sendText/${(_b = this.globalVendorArgs) === null || _b === void 0 ? void 0 : _b.name}`, {
|
|
44
|
+
number: data.from.split("@")[0],
|
|
45
|
+
text: data.text,
|
|
46
|
+
...this.globalVendorArgs,
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
console.error((_c = e === null || e === void 0 ? void 0 : e.response) === null || _c === void 0 ? void 0 : _c.data);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async sendList(data) {
|
|
54
|
+
var _a, _b, _c, _d, _e;
|
|
55
|
+
try {
|
|
56
|
+
if (!(data === null || data === void 0 ? void 0 : data.from))
|
|
57
|
+
throw new Error("sendList: falta 'from'");
|
|
58
|
+
if (!(data === null || data === void 0 ? void 0 : data.list))
|
|
59
|
+
throw new Error("sendList: falta 'list'");
|
|
60
|
+
const { title, description = "", footerText = "", button, content = [], } = data.list;
|
|
61
|
+
if (!Array.isArray(content) || content.length === 0)
|
|
62
|
+
throw new Error("sendList: 'content' debe ser un array no vacío");
|
|
63
|
+
const isSimple = typeof content[0] === "string";
|
|
64
|
+
const sections = isSimple
|
|
65
|
+
? [
|
|
66
|
+
{
|
|
67
|
+
title: "",
|
|
68
|
+
rows: content.map((t, i) => ({
|
|
69
|
+
rowId: `${i + 1}`,
|
|
70
|
+
title: t,
|
|
71
|
+
})),
|
|
72
|
+
},
|
|
73
|
+
]
|
|
74
|
+
: content.map((sec) => ({
|
|
75
|
+
title: sec.title || "",
|
|
76
|
+
rows: (sec.rows || []).map((r, i) => ({
|
|
77
|
+
rowId: `${i + 1}`,
|
|
78
|
+
title: r.title || "",
|
|
79
|
+
...(r.description && r.description.trim()
|
|
80
|
+
? { description: r.description.trim() }
|
|
81
|
+
: {}),
|
|
82
|
+
})),
|
|
83
|
+
}));
|
|
84
|
+
return await ((_a = this.sendwaveApi) === null || _a === void 0 ? void 0 : _a.post(`/message/sendList/${(_b = this.globalVendorArgs) === null || _b === void 0 ? void 0 : _b.name}`, {
|
|
85
|
+
number: data.from.split("@")[0],
|
|
86
|
+
title,
|
|
87
|
+
description,
|
|
88
|
+
footerText,
|
|
89
|
+
buttonText: button,
|
|
90
|
+
sections,
|
|
91
|
+
...this.globalVendorArgs,
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
console.error("[sendList Error]", ((_e = (_d = (_c = err.response) === null || _c === void 0 ? void 0 : _c.data) === null || _d === void 0 ? void 0 : _d.response) === null || _e === void 0 ? void 0 : _e.message) || err.message);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
async sendMedia(data) {
|
|
99
|
+
var _a, _b;
|
|
100
|
+
try {
|
|
101
|
+
const { media, mimeType, mediaType } = await detectorMedia_1.detectorMedia.processMedia(data.url);
|
|
102
|
+
return await ((_a = this.sendwaveApi) === null || _a === void 0 ? void 0 : _a.post(`/message/sendMedia/${(_b = this.globalVendorArgs) === null || _b === void 0 ? void 0 : _b.name}`, {
|
|
103
|
+
number: data.from.split("@")[0],
|
|
104
|
+
caption: data.text,
|
|
105
|
+
mediatype: mediaType,
|
|
106
|
+
mimetype: mimeType,
|
|
107
|
+
media: media,
|
|
108
|
+
fileName: data.fileName || crypto.randomUUID(),
|
|
109
|
+
...this.globalVendorArgs,
|
|
110
|
+
}));
|
|
111
|
+
}
|
|
112
|
+
catch (e) {
|
|
113
|
+
console.error(e.response.data.response.message);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async sendFile(data) {
|
|
117
|
+
try {
|
|
118
|
+
return await this.sendMedia({
|
|
119
|
+
...data,
|
|
120
|
+
fileName: data.fileName || crypto.randomUUID(),
|
|
121
|
+
mediaType: "document",
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
catch (e) {
|
|
125
|
+
console.error(e.response.data.response.message);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async sendImage(data) {
|
|
129
|
+
try {
|
|
130
|
+
return await this.sendMedia({
|
|
131
|
+
...data,
|
|
132
|
+
mediaType: "image",
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
catch (e) {
|
|
136
|
+
console.error(e.response.data.response.message);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async sendAudio(data) {
|
|
140
|
+
try {
|
|
141
|
+
return await this.sendMedia({
|
|
142
|
+
...data,
|
|
143
|
+
mediaType: "audio",
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
catch (e) {
|
|
147
|
+
console.error(e.response.data.response.message);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async sendVideo(data) {
|
|
151
|
+
try {
|
|
152
|
+
return await this.sendMedia({
|
|
153
|
+
...data,
|
|
154
|
+
mediaType: "video",
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
catch (e) {
|
|
158
|
+
console.error(e.response.data.response.message);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
async sendVoice(data) {
|
|
162
|
+
var _a, _b;
|
|
163
|
+
try {
|
|
164
|
+
const { media } = await detectorMedia_1.detectorMedia.processMedia(data.url);
|
|
165
|
+
await this.sendPresence({
|
|
166
|
+
from: data.from,
|
|
167
|
+
presence: "recording",
|
|
168
|
+
delay: data.delay || 2000,
|
|
169
|
+
});
|
|
170
|
+
return await ((_a = this.sendwaveApi) === null || _a === void 0 ? void 0 : _a.post(`/message/sendWhatsAppAudio/${(_b = this.globalVendorArgs) === null || _b === void 0 ? void 0 : _b.name}`, {
|
|
171
|
+
number: data.from,
|
|
172
|
+
audio: media,
|
|
173
|
+
...this.globalVendorArgs,
|
|
174
|
+
}));
|
|
175
|
+
}
|
|
176
|
+
catch (e) {
|
|
177
|
+
console.error(e.response.data.response.message);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
async sendButton(data) {
|
|
181
|
+
var _a, _b;
|
|
182
|
+
try {
|
|
183
|
+
return await ((_a = this.sendwaveApi) === null || _a === void 0 ? void 0 : _a.post(`/message/sendButtons/${(_b = this.globalVendorArgs) === null || _b === void 0 ? void 0 : _b.name}`, {
|
|
184
|
+
number: data.from.split("@")[0],
|
|
185
|
+
title: data.title,
|
|
186
|
+
body: data.body,
|
|
187
|
+
description: data.description,
|
|
188
|
+
footer: data.footer,
|
|
189
|
+
buttons: data.buttons.map((button, index) => ({
|
|
190
|
+
type: button.type,
|
|
191
|
+
title: button.text,
|
|
192
|
+
displayText: button.text,
|
|
193
|
+
id: `${index + 1}`,
|
|
194
|
+
})),
|
|
195
|
+
...this.globalVendorArgs,
|
|
196
|
+
}));
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
console.error(error.response.data.response.message);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
exports.SenderMessage = SenderMessage;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
interface DetectorMediaProps {
|
|
2
|
+
media?: string;
|
|
3
|
+
mimeType?: string;
|
|
4
|
+
mediaType?: string;
|
|
5
|
+
fileName?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare class DetectorMedia {
|
|
8
|
+
static instance: DetectorMedia;
|
|
9
|
+
static getInstance(): DetectorMedia;
|
|
10
|
+
isRemoteUrl(url: string): boolean;
|
|
11
|
+
convertPathToBase64(filePath: string): Promise<DetectorMediaProps>;
|
|
12
|
+
getMimeTypeFromUrl(url: string): Promise<string | null>;
|
|
13
|
+
extractFileNameFromUrl(url: string): Promise<string>;
|
|
14
|
+
/**
|
|
15
|
+
* Método unificado que acepta path o url y devuelve:
|
|
16
|
+
* - media (base64 si es path, url si es remota)
|
|
17
|
+
* - mimeType
|
|
18
|
+
* - fileName
|
|
19
|
+
*/
|
|
20
|
+
processMedia(input: string): Promise<DetectorMediaProps>;
|
|
21
|
+
mapMimeToCategory(mimeType: string): "image" | "video" | "audio" | "document" | "unknown";
|
|
22
|
+
}
|
|
23
|
+
export declare const detectorMedia: DetectorMedia;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.detectorMedia = exports.DetectorMedia = void 0;
|
|
7
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const mime_types_1 = __importDefault(require("mime-types"));
|
|
10
|
+
const axios_1 = __importDefault(require("axios"));
|
|
11
|
+
class DetectorMedia {
|
|
12
|
+
static getInstance() {
|
|
13
|
+
if (!DetectorMedia.instance) {
|
|
14
|
+
DetectorMedia.instance = new DetectorMedia();
|
|
15
|
+
}
|
|
16
|
+
return DetectorMedia.instance;
|
|
17
|
+
}
|
|
18
|
+
isRemoteUrl(url) {
|
|
19
|
+
try {
|
|
20
|
+
const u = new URL(url);
|
|
21
|
+
return u.protocol === "http:" || u.protocol === "https:";
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async convertPathToBase64(filePath) {
|
|
28
|
+
const fileBuffer = await promises_1.default.readFile(filePath);
|
|
29
|
+
const mediaType = this.mapMimeToCategory(mime_types_1.default.lookup(filePath).toString());
|
|
30
|
+
if (!mediaType)
|
|
31
|
+
throw new Error("No se pudo determinar el tipo MIME del archivo");
|
|
32
|
+
const base64Data = fileBuffer.toString("base64");
|
|
33
|
+
const media = base64Data;
|
|
34
|
+
const fileName = path_1.default.basename(filePath);
|
|
35
|
+
return {
|
|
36
|
+
media,
|
|
37
|
+
mediaType,
|
|
38
|
+
fileName,
|
|
39
|
+
mimeType: mime_types_1.default.lookup(filePath).toString(),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
async getMimeTypeFromUrl(url) {
|
|
43
|
+
try {
|
|
44
|
+
const res = await axios_1.default.head(url);
|
|
45
|
+
const mediaType = this.mapMimeToCategory(res.headers["content-type"]);
|
|
46
|
+
return mediaType || null;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async extractFileNameFromUrl(url) {
|
|
53
|
+
const urlObj = new URL(url);
|
|
54
|
+
const pathname = urlObj.pathname;
|
|
55
|
+
const name = pathname.split("/").pop();
|
|
56
|
+
return name || `file_${Date.now()}`;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Método unificado que acepta path o url y devuelve:
|
|
60
|
+
* - media (base64 si es path, url si es remota)
|
|
61
|
+
* - mimeType
|
|
62
|
+
* - fileName
|
|
63
|
+
*/
|
|
64
|
+
async processMedia(input) {
|
|
65
|
+
if (this.isRemoteUrl(input)) {
|
|
66
|
+
const mediaType = await this.getMimeTypeFromUrl(input);
|
|
67
|
+
if (!mediaType)
|
|
68
|
+
throw new Error("No se pudo determinar el tipo MIME de la URL remota");
|
|
69
|
+
const fileName = await this.extractFileNameFromUrl(input);
|
|
70
|
+
return {
|
|
71
|
+
media: input,
|
|
72
|
+
mimeType: mime_types_1.default.lookup(input).toString(),
|
|
73
|
+
fileName,
|
|
74
|
+
mediaType,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
return this.convertPathToBase64(input);
|
|
78
|
+
}
|
|
79
|
+
mapMimeToCategory(mimeType) {
|
|
80
|
+
if (mimeType.startsWith("image/"))
|
|
81
|
+
return "image";
|
|
82
|
+
if (mimeType.startsWith("video/"))
|
|
83
|
+
return "video";
|
|
84
|
+
if (mimeType.startsWith("audio/"))
|
|
85
|
+
return "audio";
|
|
86
|
+
if (mimeType.startsWith("application/") || mimeType.startsWith("text/"))
|
|
87
|
+
return "document";
|
|
88
|
+
return "unknown";
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
exports.DetectorMedia = DetectorMedia;
|
|
92
|
+
exports.detectorMedia = DetectorMedia.getInstance();
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseIncomingMsg = parseIncomingMsg;
|
|
4
|
+
const bot_1 = require("@builderbot/bot"); // Asegúrate de importar utils correctamente
|
|
5
|
+
function parseIncomingMsg(payload) {
|
|
6
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
7
|
+
try {
|
|
8
|
+
const msg = payload.data;
|
|
9
|
+
if (msg.messageType === "reactionMessage")
|
|
10
|
+
return null;
|
|
11
|
+
if (!msg) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
// if (msg.key.fromMe) return null
|
|
15
|
+
const fromMe = msg.key.fromMe;
|
|
16
|
+
const from = (_a = msg.key) === null || _a === void 0 ? void 0 : _a.remoteJid.split("@")[0];
|
|
17
|
+
const to = payload.instance || "";
|
|
18
|
+
const name = msg.pushName;
|
|
19
|
+
const messageContent = msg.message || {};
|
|
20
|
+
const messageType = msg.messageType || Object.keys(messageContent)[0];
|
|
21
|
+
let body = "";
|
|
22
|
+
let type = messageType;
|
|
23
|
+
let media;
|
|
24
|
+
let caption;
|
|
25
|
+
// 🎯 Primero detección especial de eventos por tipo de mensaje
|
|
26
|
+
if (messageContent.locationMessage) {
|
|
27
|
+
body = bot_1.utils.generateRefProvider("_event_location_");
|
|
28
|
+
type = "locationMessage";
|
|
29
|
+
}
|
|
30
|
+
else if (messageContent.orderMessage) {
|
|
31
|
+
body = bot_1.utils.generateRefProvider("_event_order_");
|
|
32
|
+
type = "orderMessage";
|
|
33
|
+
}
|
|
34
|
+
else if (messageContent.videoMessage) {
|
|
35
|
+
body = bot_1.utils.generateRefProvider("_event_media_");
|
|
36
|
+
type = "videoMessage";
|
|
37
|
+
media = (_b = messageContent.videoMessage) === null || _b === void 0 ? void 0 : _b.url;
|
|
38
|
+
caption = ((_c = messageContent.videoMessage) === null || _c === void 0 ? void 0 : _c.caption) || "";
|
|
39
|
+
}
|
|
40
|
+
else if (messageContent.stickerMessage) {
|
|
41
|
+
body = bot_1.utils.generateRefProvider("_event_media_");
|
|
42
|
+
type = "stickerMessage";
|
|
43
|
+
media = (_d = messageContent.stickerMessage) === null || _d === void 0 ? void 0 : _d.url;
|
|
44
|
+
}
|
|
45
|
+
else if (messageContent.imageMessage) {
|
|
46
|
+
body = bot_1.utils.generateRefProvider("_event_media_");
|
|
47
|
+
type = "imageMessage";
|
|
48
|
+
media = (_e = messageContent.imageMessage) === null || _e === void 0 ? void 0 : _e.url;
|
|
49
|
+
caption = ((_f = messageContent.imageMessage) === null || _f === void 0 ? void 0 : _f.caption) || "";
|
|
50
|
+
}
|
|
51
|
+
else if (messageContent.documentMessage ||
|
|
52
|
+
messageContent.documentWithCaptionMessage) {
|
|
53
|
+
body = bot_1.utils.generateRefProvider("_event_document_");
|
|
54
|
+
type = "documentMessage";
|
|
55
|
+
media =
|
|
56
|
+
((_g = messageContent.documentMessage) === null || _g === void 0 ? void 0 : _g.url) ||
|
|
57
|
+
((_h = messageContent.documentWithCaptionMessage) === null || _h === void 0 ? void 0 : _h.url);
|
|
58
|
+
caption =
|
|
59
|
+
((_j = messageContent.documentMessage) === null || _j === void 0 ? void 0 : _j.caption) ||
|
|
60
|
+
((_k = messageContent.documentWithCaptionMessage) === null || _k === void 0 ? void 0 : _k.caption) ||
|
|
61
|
+
"";
|
|
62
|
+
}
|
|
63
|
+
else if (messageContent.audioMessage) {
|
|
64
|
+
body = bot_1.utils.generateRefProvider("_event_voice_note_");
|
|
65
|
+
type = "audioMessage";
|
|
66
|
+
media = (_l = messageContent.audioMessage) === null || _l === void 0 ? void 0 : _l.url;
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
// 🎯 Si no es media especial, hacer parsing normal por tipo
|
|
70
|
+
switch (type) {
|
|
71
|
+
case "conversation":
|
|
72
|
+
body = messageContent.conversation || "";
|
|
73
|
+
break;
|
|
74
|
+
case "buttonsResponseMessage":
|
|
75
|
+
body = ((_m = messageContent.buttonsResponseMessage) === null || _m === void 0 ? void 0 : _m.selectedButtonId) || "";
|
|
76
|
+
break;
|
|
77
|
+
case "listResponseMessage":
|
|
78
|
+
body = ((_o = messageContent.listResponseMessage) === null || _o === void 0 ? void 0 : _o.title) || "";
|
|
79
|
+
break;
|
|
80
|
+
case "listMessage":
|
|
81
|
+
body =
|
|
82
|
+
`${(_p = messageContent.listMessage) === null || _p === void 0 ? void 0 : _p.title}${((_q = messageContent.listMessage) === null || _q === void 0 ? void 0 : _q.title) ? "\n" : ""}${(_r = messageContent.listMessage) === null || _r === void 0 ? void 0 : _r.description}` || "";
|
|
83
|
+
break;
|
|
84
|
+
default:
|
|
85
|
+
body = "Tipo de mensaje no soportado aún";
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
fromMe,
|
|
90
|
+
from,
|
|
91
|
+
to,
|
|
92
|
+
name,
|
|
93
|
+
body,
|
|
94
|
+
type,
|
|
95
|
+
media,
|
|
96
|
+
caption,
|
|
97
|
+
// originalPayload: payload,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
console.error("[parseIncomingMsg] Error:", error);
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { EventEmitter } from "events";
|
|
2
|
+
import { SendWaveProvider } from "../provider/provider";
|
|
3
|
+
interface QueueFlowConfig {
|
|
4
|
+
warningTimeout?: number;
|
|
5
|
+
endTimeout?: number;
|
|
6
|
+
warningMessage?: string;
|
|
7
|
+
}
|
|
8
|
+
declare class QueueFlow extends EventEmitter {
|
|
9
|
+
static instance: QueueFlow;
|
|
10
|
+
private userTimeouts;
|
|
11
|
+
ignoredUsers: Set<string>;
|
|
12
|
+
private config;
|
|
13
|
+
constructor(config?: QueueFlowConfig);
|
|
14
|
+
static getInstance(config?: QueueFlowConfig): QueueFlow;
|
|
15
|
+
updateConfig(config: Partial<QueueFlowConfig>): void;
|
|
16
|
+
clearUserTimeout(from: string): void;
|
|
17
|
+
resetUserTimeout: ({ provider, from, name, }: {
|
|
18
|
+
from: string;
|
|
19
|
+
provider: SendWaveProvider;
|
|
20
|
+
name?: string;
|
|
21
|
+
}) => {
|
|
22
|
+
isActive: boolean;
|
|
23
|
+
from: string;
|
|
24
|
+
name: string | undefined;
|
|
25
|
+
};
|
|
26
|
+
forceClearUser(from: string): void;
|
|
27
|
+
removeUserListeners(from: string): void;
|
|
28
|
+
getUserStats(): {
|
|
29
|
+
activeTimeouts: number;
|
|
30
|
+
ignoredUsers: number;
|
|
31
|
+
config: Required<QueueFlowConfig>;
|
|
32
|
+
};
|
|
33
|
+
isUserIgnored(from: string): boolean;
|
|
34
|
+
}
|
|
35
|
+
export declare const queueFlow: QueueFlow;
|
|
36
|
+
export { QueueFlow, type QueueFlowConfig };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.QueueFlow = exports.queueFlow = void 0;
|
|
4
|
+
const events_1 = require("events");
|
|
5
|
+
class QueueFlow extends events_1.EventEmitter {
|
|
6
|
+
constructor(config = {}) {
|
|
7
|
+
super();
|
|
8
|
+
this.userTimeouts = new Map();
|
|
9
|
+
this.ignoredUsers = new Set();
|
|
10
|
+
this.resetUserTimeout = ({ provider, from, name, }) => {
|
|
11
|
+
this.clearUserTimeout(from);
|
|
12
|
+
let isActive = true;
|
|
13
|
+
// 🔥 Timeout de advertencia (configurable)
|
|
14
|
+
const warningTimeout = setTimeout(async () => {
|
|
15
|
+
await provider.sendText({
|
|
16
|
+
from,
|
|
17
|
+
text: this.config.warningMessage,
|
|
18
|
+
});
|
|
19
|
+
this.emit(`userInactive-${from}`, { from, name, isActive: true });
|
|
20
|
+
// 🔥 Timeout para finalizar flujo (configurable después)
|
|
21
|
+
const endTimeout = setTimeout(async () => {
|
|
22
|
+
// 1. Marcar como ignorado INMEDIATAMENTE
|
|
23
|
+
this.ignoredUsers.add(from);
|
|
24
|
+
// 2. Esperar un momento para que se registre el ignore
|
|
25
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
26
|
+
// 3. Limpiar listeners
|
|
27
|
+
this.removeUserListeners(from);
|
|
28
|
+
// 4. Enviar flow para que ejecute endFlow correctamente
|
|
29
|
+
provider.sendFlow({ event: "END_FLOW", from, name: name || "" });
|
|
30
|
+
// 5. Emitir evento
|
|
31
|
+
this.emit(`userInactive-${from}`, { from, name, isActive: false });
|
|
32
|
+
}, this.config.endTimeout);
|
|
33
|
+
this.userTimeouts.set(from, endTimeout);
|
|
34
|
+
}, this.config.warningTimeout);
|
|
35
|
+
this.userTimeouts.set(from, warningTimeout);
|
|
36
|
+
return { isActive, from, name };
|
|
37
|
+
};
|
|
38
|
+
this.config = {
|
|
39
|
+
warningTimeout: config.warningTimeout || 30 * 60 * 1000, // 30 minutes
|
|
40
|
+
endTimeout: config.endTimeout || 2 * 60 * 1000, // 2 minutes
|
|
41
|
+
warningMessage: config.warningMessage || "⏳ Parece que has estado inactivo. ¿Sigues ahí?",
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
static getInstance(config) {
|
|
45
|
+
if (!this.instance) {
|
|
46
|
+
this.instance = new QueueFlow(config);
|
|
47
|
+
}
|
|
48
|
+
return this.instance;
|
|
49
|
+
}
|
|
50
|
+
updateConfig(config) {
|
|
51
|
+
this.config = { ...this.config, ...config };
|
|
52
|
+
}
|
|
53
|
+
clearUserTimeout(from) {
|
|
54
|
+
if (this.userTimeouts.has(from)) {
|
|
55
|
+
clearTimeout(this.userTimeouts.get(from));
|
|
56
|
+
this.userTimeouts.delete(from);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
forceClearUser(from) {
|
|
60
|
+
this.clearUserTimeout(from);
|
|
61
|
+
this.removeUserListeners(from);
|
|
62
|
+
}
|
|
63
|
+
removeUserListeners(from) {
|
|
64
|
+
// 🔥 Eliminar todos los listeners de este usuario
|
|
65
|
+
this.removeAllListeners(`userInactive-${from}`);
|
|
66
|
+
this.removeAllListeners(`forceClearTimeout-${from}`);
|
|
67
|
+
this.userTimeouts.delete(from);
|
|
68
|
+
this.ignoredUsers.delete(from);
|
|
69
|
+
}
|
|
70
|
+
getUserStats() {
|
|
71
|
+
return {
|
|
72
|
+
activeTimeouts: this.userTimeouts.size,
|
|
73
|
+
ignoredUsers: this.ignoredUsers.size,
|
|
74
|
+
config: this.config,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
isUserIgnored(from) {
|
|
78
|
+
return this.ignoredUsers.has(from);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exports.QueueFlow = QueueFlow;
|
|
82
|
+
exports.queueFlow = QueueFlow.getInstance();
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gamastudio/sendwave-provider",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Librería para interactuar con Sendwave usando configuración dinámica.",
|
|
5
|
+
"main": "build/index.js",
|
|
6
|
+
"types": "build/index.d.ts",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc && tsc-alias && copyfiles package.json build",
|
|
12
|
+
"test": "ts-node -r tsconfig-paths/register test/test.ts",
|
|
13
|
+
"dev": "ts-node-dev --respawn --transpile-only -r tsconfig-paths/register test/test.ts",
|
|
14
|
+
"prepublishOnly": "npm run build"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"Sendwave",
|
|
18
|
+
"Provider",
|
|
19
|
+
"Gamastudio",
|
|
20
|
+
"Bot"
|
|
21
|
+
],
|
|
22
|
+
"author": "Ameth Galarcio <amethgm@gmail.com>",
|
|
23
|
+
"license": "ISC",
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@builderbot/bot": "^1.3.1",
|
|
26
|
+
"@gamastudio/colorslog": "^0.1.6",
|
|
27
|
+
"@types/mime-types": "^2.1.4",
|
|
28
|
+
"axios": "^1.11.0",
|
|
29
|
+
"body-parser": "^2.2.0",
|
|
30
|
+
"cors": "^2.8.5",
|
|
31
|
+
"file-type": "^20.5.0",
|
|
32
|
+
"mime-types": "^3.0.1",
|
|
33
|
+
"queue-promise": "^2.2.1",
|
|
34
|
+
"sirv": "^3.0.1"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/axios": "^0.14.4",
|
|
38
|
+
"@types/body-parser": "^1.19.6",
|
|
39
|
+
"@types/cors": "^2.8.19",
|
|
40
|
+
"@types/node": "^22.18.0",
|
|
41
|
+
"copyfiles": "^2.4.1",
|
|
42
|
+
"ts-node": "^10.9.2",
|
|
43
|
+
"ts-node-dev": "^2.0.0",
|
|
44
|
+
"tsc-alias": "^1.8.16",
|
|
45
|
+
"tsconfig-paths": "^4.2.0",
|
|
46
|
+
"typescript": "^5.9.2"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
Binary file
|
package/queue.class.log
ADDED
|
File without changes
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"baseUrl": "./src",
|
|
4
|
+
"paths": {
|
|
5
|
+
"@provider/*": ["provider/*"],
|
|
6
|
+
"@interface/*": ["interface/*"],
|
|
7
|
+
"@utils/*": ["utils/*"],
|
|
8
|
+
"@core/*": ["core/*"]
|
|
9
|
+
},
|
|
10
|
+
"outDir": "build",
|
|
11
|
+
"module": "CommonJS",
|
|
12
|
+
"target": "ES2019",
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"esModuleInterop": true,
|
|
15
|
+
"strict": true,
|
|
16
|
+
"skipLibCheck": true
|
|
17
|
+
},
|
|
18
|
+
"include": ["src/**/*"]
|
|
19
|
+
}
|