@gamastudio/sendwave-provider 0.0.7-dev → 0.0.7-dev1
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/build/package.json +1 -1
- package/build/provider/provider.js +0 -11
- package/build/provider/sender.d.ts +1 -0
- package/build/provider/sender.js +66 -31
- package/build/utils/detectorMedia.d.ts +5 -2
- package/build/utils/detectorMedia.js +42 -33
- package/package.json +1 -1
- package/queue.class.log +0 -0
package/build/package.json
CHANGED
|
@@ -178,12 +178,6 @@ class SendWaveProvider extends bot_1.ProviderClass {
|
|
|
178
178
|
.then(() => {
|
|
179
179
|
this.beforeHttpServerInit();
|
|
180
180
|
this.start(methods, (routes) => {
|
|
181
|
-
// Log the actual server binding info
|
|
182
|
-
console.log(`🌐 Server binding: ${this.globalVendorArgs.host || 'localhost'}:${this.globalVendorArgs.port}`);
|
|
183
|
-
if (this.globalVendorArgs.host === "0.0.0.0") {
|
|
184
|
-
console.log(`🔗 External access: Server accessible from all network interfaces`);
|
|
185
|
-
console.log(`📡 Webhook URL for external services: http://<your-ip>:${this.globalVendorArgs.port}/webhook`);
|
|
186
|
-
}
|
|
187
181
|
this.emit("notice", {
|
|
188
182
|
title: "🛜 HTTP Server ON ",
|
|
189
183
|
instructions: routes,
|
|
@@ -363,11 +357,6 @@ class SendWaveProvider extends bot_1.ProviderClass {
|
|
|
363
357
|
detectorMedia_1.detectorMedia.updateLimits(this.globalVendorArgs.payloadLimits.media);
|
|
364
358
|
}
|
|
365
359
|
const { media, mediaType, fileName, size } = await detectorMedia_1.detectorMedia.processMedia(options.media);
|
|
366
|
-
// Log large media processing
|
|
367
|
-
if (size && size > 1024 * 1024) {
|
|
368
|
-
const sizeMB = Math.round(size / 1024 / 1024 * 100) / 100;
|
|
369
|
-
console.log(`[SendMessage] Processing ${mediaType} file: ${sizeMB}MB`);
|
|
370
|
-
}
|
|
371
360
|
switch (mediaType) {
|
|
372
361
|
case "image":
|
|
373
362
|
return await this.sender.sendImage({
|
|
@@ -8,6 +8,7 @@ export declare class SenderMessage implements ProviderInterface {
|
|
|
8
8
|
sendText(data: SendMessage): Promise<import("axios").AxiosResponse<any, any, {}> | undefined>;
|
|
9
9
|
sendList(data: SendList): Promise<import("axios").AxiosResponse<any, any, {}> | undefined>;
|
|
10
10
|
sendMedia(data: SendMedia): Promise<import("axios").AxiosResponse<any, any, {}> | undefined>;
|
|
11
|
+
private getDefaultMimeType;
|
|
11
12
|
sendFile(data: SendMedia): Promise<import("axios").AxiosResponse<any, any, {}> | undefined>;
|
|
12
13
|
sendImage(data: SendMedia): Promise<import("axios").AxiosResponse<any, any, {}> | undefined>;
|
|
13
14
|
sendAudio(data: SendMedia): Promise<import("axios").AxiosResponse<any, any, {}> | undefined>;
|
package/build/provider/sender.js
CHANGED
|
@@ -10,7 +10,7 @@ const detectorMedia_1 = require("../utils/detectorMedia");
|
|
|
10
10
|
class SenderMessage {
|
|
11
11
|
constructor(args) {
|
|
12
12
|
const payloadLimits = args.payloadLimits || {};
|
|
13
|
-
const maxContentLength = this.parseSize(payloadLimits.json ||
|
|
13
|
+
const maxContentLength = this.parseSize(payloadLimits.json || "50mb");
|
|
14
14
|
this.sendwaveApi = axios_1.default.create({
|
|
15
15
|
baseURL: args.url,
|
|
16
16
|
httpsAgent: new https_1.Agent({ rejectUnauthorized: false }),
|
|
@@ -26,16 +26,16 @@ class SenderMessage {
|
|
|
26
26
|
}
|
|
27
27
|
parseSize(size) {
|
|
28
28
|
const units = {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
b: 1,
|
|
30
|
+
kb: 1024,
|
|
31
|
+
mb: 1024 * 1024,
|
|
32
|
+
gb: 1024 * 1024 * 1024,
|
|
33
33
|
};
|
|
34
34
|
const match = size.toLowerCase().match(/^(\d+(?:\.\d+)?)\s*(b|kb|mb|gb)?$/);
|
|
35
35
|
if (!match)
|
|
36
36
|
return 50 * 1024 * 1024; // Default 50MB
|
|
37
37
|
const value = parseFloat(match[1]);
|
|
38
|
-
const unit = match[2] ||
|
|
38
|
+
const unit = match[2] || "b";
|
|
39
39
|
return Math.floor(value * units[unit]);
|
|
40
40
|
}
|
|
41
41
|
async sendPresence(data) {
|
|
@@ -121,12 +121,43 @@ class SenderMessage {
|
|
|
121
121
|
if ((_b = (_a = this.globalVendorArgs) === null || _a === void 0 ? void 0 : _a.payloadLimits) === null || _b === void 0 ? void 0 : _b.media) {
|
|
122
122
|
detectorMedia_1.detectorMedia.updateLimits(this.globalVendorArgs.payloadLimits.media);
|
|
123
123
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
124
|
+
let media;
|
|
125
|
+
let mimeType;
|
|
126
|
+
let mediaType;
|
|
127
|
+
// If mediaType is already specified (from sendImage, sendVideo, etc), use it
|
|
128
|
+
if (data.mediaType) {
|
|
129
|
+
console.log(`[SendMedia] Using predefined mediaType: ${data.mediaType}`);
|
|
130
|
+
// Just validate size and get media content without detection
|
|
131
|
+
if (detectorMedia_1.detectorMedia.isRemoteUrl(data.url)) {
|
|
132
|
+
// For remote URLs, validate size and use URL directly
|
|
133
|
+
await detectorMedia_1.detectorMedia.validateUrlSize(data.url, data.mediaType);
|
|
134
|
+
media = data.url;
|
|
135
|
+
// Get actual MIME type from server if possible
|
|
136
|
+
try {
|
|
137
|
+
const { mimeType: detectedMime } = await detectorMedia_1.detectorMedia.getMimeTypeFromUrl(data.url);
|
|
138
|
+
mimeType = detectedMime || this.getDefaultMimeType(data.mediaType);
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
mimeType = this.getDefaultMimeType(data.mediaType);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
// For local files, convert to base64
|
|
146
|
+
const result = await detectorMedia_1.detectorMedia.convertPathToBase64(data.url);
|
|
147
|
+
media = result.media;
|
|
148
|
+
mimeType = result.mimeType;
|
|
149
|
+
}
|
|
150
|
+
mediaType = data.mediaType;
|
|
129
151
|
}
|
|
152
|
+
else {
|
|
153
|
+
// If no mediaType specified, detect it (for generic sendMedia calls)
|
|
154
|
+
console.log(`[SendMedia] Auto-detecting mediaType for: ${data.url}`);
|
|
155
|
+
const result = await detectorMedia_1.detectorMedia.processMedia(data.url);
|
|
156
|
+
media = result.media;
|
|
157
|
+
mimeType = result.mimeType;
|
|
158
|
+
mediaType = result.mediaType;
|
|
159
|
+
}
|
|
160
|
+
console.log(`[SendMedia] Final - MediaType: ${mediaType}, MimeType: ${mimeType}`);
|
|
130
161
|
return await ((_c = this.sendwaveApi) === null || _c === void 0 ? void 0 : _c.post(`/message/sendMedia/${(_d = this.globalVendorArgs) === null || _d === void 0 ? void 0 : _d.name}`, {
|
|
131
162
|
number: data.from.split("@")[0],
|
|
132
163
|
caption: data.text,
|
|
@@ -139,25 +170,34 @@ class SenderMessage {
|
|
|
139
170
|
}
|
|
140
171
|
catch (e) {
|
|
141
172
|
// Enhanced error handling for large files
|
|
142
|
-
if (e.message && e.message.includes(
|
|
173
|
+
if (e.message && e.message.includes("exceeds limit")) {
|
|
143
174
|
console.error(`[SendMedia Error] File size validation failed: ${e.message}`);
|
|
144
175
|
throw new Error(`File too large: ${e.message}`);
|
|
145
176
|
}
|
|
146
177
|
else if (((_e = e.response) === null || _e === void 0 ? void 0 : _e.status) === 413) {
|
|
147
|
-
console.error(
|
|
148
|
-
throw new Error(
|
|
178
|
+
console.error("[SendMedia Error] Server rejected large payload");
|
|
179
|
+
throw new Error("File too large for server");
|
|
149
180
|
}
|
|
150
|
-
else if (e.code ===
|
|
151
|
-
console.error(
|
|
152
|
-
throw new Error(
|
|
181
|
+
else if (e.code === "ECONNABORTED") {
|
|
182
|
+
console.error("[SendMedia Error] Request timeout - file may be too large");
|
|
183
|
+
throw new Error("Upload timeout - file may be too large");
|
|
153
184
|
}
|
|
154
185
|
else {
|
|
155
|
-
const errorMsg = ((_h = (_g = (_f = e.response) === null || _f === void 0 ? void 0 : _f.data) === null || _g === void 0 ? void 0 : _g.response) === null || _h === void 0 ? void 0 : _h.message) || e.message ||
|
|
186
|
+
const errorMsg = ((_h = (_g = (_f = e.response) === null || _f === void 0 ? void 0 : _f.data) === null || _g === void 0 ? void 0 : _g.response) === null || _h === void 0 ? void 0 : _h.message) || e.message || "Unknown error";
|
|
156
187
|
console.error(`[SendMedia Error] ${errorMsg}`);
|
|
157
188
|
throw new Error(errorMsg);
|
|
158
189
|
}
|
|
159
190
|
}
|
|
160
191
|
}
|
|
192
|
+
getDefaultMimeType(mediaType) {
|
|
193
|
+
const defaults = {
|
|
194
|
+
image: 'image/jpeg',
|
|
195
|
+
video: 'video/mp4',
|
|
196
|
+
audio: 'audio/mpeg',
|
|
197
|
+
document: 'application/octet-stream'
|
|
198
|
+
};
|
|
199
|
+
return defaults[mediaType] || 'application/octet-stream';
|
|
200
|
+
}
|
|
161
201
|
async sendFile(data) {
|
|
162
202
|
try {
|
|
163
203
|
return await this.sendMedia({
|
|
@@ -210,12 +250,7 @@ class SenderMessage {
|
|
|
210
250
|
if ((_b = (_a = this.globalVendorArgs) === null || _a === void 0 ? void 0 : _a.payloadLimits) === null || _b === void 0 ? void 0 : _b.media) {
|
|
211
251
|
detectorMedia_1.detectorMedia.updateLimits(this.globalVendorArgs.payloadLimits.media);
|
|
212
252
|
}
|
|
213
|
-
const { media
|
|
214
|
-
// Log large audio processing
|
|
215
|
-
if (size && size > 1024 * 1024) {
|
|
216
|
-
const sizeMB = Math.round(size / 1024 / 1024 * 100) / 100;
|
|
217
|
-
console.log(`[SendVoice] Processing audio file: ${sizeMB}MB`);
|
|
218
|
-
}
|
|
253
|
+
const { media } = await detectorMedia_1.detectorMedia.processMedia(data.url);
|
|
219
254
|
await this.sendPresence({
|
|
220
255
|
from: data.from,
|
|
221
256
|
presence: "recording",
|
|
@@ -229,20 +264,20 @@ class SenderMessage {
|
|
|
229
264
|
}
|
|
230
265
|
catch (e) {
|
|
231
266
|
// Enhanced error handling for large audio files
|
|
232
|
-
if (e.message && e.message.includes(
|
|
267
|
+
if (e.message && e.message.includes("exceeds limit")) {
|
|
233
268
|
console.error(`[SendVoice Error] File size validation failed: ${e.message}`);
|
|
234
269
|
throw new Error(`Audio file too large: ${e.message}`);
|
|
235
270
|
}
|
|
236
271
|
else if (((_e = e.response) === null || _e === void 0 ? void 0 : _e.status) === 413) {
|
|
237
|
-
console.error(
|
|
238
|
-
throw new Error(
|
|
272
|
+
console.error("[SendVoice Error] Server rejected large payload");
|
|
273
|
+
throw new Error("Audio file too large for server");
|
|
239
274
|
}
|
|
240
|
-
else if (e.code ===
|
|
241
|
-
console.error(
|
|
242
|
-
throw new Error(
|
|
275
|
+
else if (e.code === "ECONNABORTED") {
|
|
276
|
+
console.error("[SendVoice Error] Request timeout - audio file may be too large");
|
|
277
|
+
throw new Error("Upload timeout - audio file may be too large");
|
|
243
278
|
}
|
|
244
279
|
else {
|
|
245
|
-
const errorMsg = ((_h = (_g = (_f = e.response) === null || _f === void 0 ? void 0 : _f.data) === null || _g === void 0 ? void 0 : _g.response) === null || _h === void 0 ? void 0 : _h.message) || e.message ||
|
|
280
|
+
const errorMsg = ((_h = (_g = (_f = e.response) === null || _f === void 0 ? void 0 : _f.data) === null || _g === void 0 ? void 0 : _g.response) === null || _h === void 0 ? void 0 : _h.message) || e.message || "Unknown error";
|
|
246
281
|
console.error(`[SendVoice Error] ${errorMsg}`);
|
|
247
282
|
throw new Error(errorMsg);
|
|
248
283
|
}
|
|
@@ -19,10 +19,13 @@ export declare class DetectorMedia {
|
|
|
19
19
|
updateLimits(limits: MediaLimits): void;
|
|
20
20
|
private parseSize;
|
|
21
21
|
private validateFileSize;
|
|
22
|
-
|
|
22
|
+
validateUrlSize(url: string, mediaType: string): Promise<number>;
|
|
23
23
|
isRemoteUrl(url: string): boolean;
|
|
24
24
|
convertPathToBase64(filePath: string): Promise<DetectorMediaProps>;
|
|
25
|
-
getMimeTypeFromUrl(url: string): Promise<
|
|
25
|
+
getMimeTypeFromUrl(url: string): Promise<{
|
|
26
|
+
mediaType: string | null;
|
|
27
|
+
mimeType: string | null;
|
|
28
|
+
}>;
|
|
26
29
|
extractFileNameFromUrl(url: string): Promise<string>;
|
|
27
30
|
/**
|
|
28
31
|
* Método unificado que acepta path o url y devuelve:
|
|
@@ -11,11 +11,11 @@ const axios_1 = __importDefault(require("axios"));
|
|
|
11
11
|
class DetectorMedia {
|
|
12
12
|
constructor(limits) {
|
|
13
13
|
this.mediaLimits = {
|
|
14
|
-
image:
|
|
15
|
-
video:
|
|
16
|
-
audio:
|
|
17
|
-
document:
|
|
18
|
-
...limits
|
|
14
|
+
image: "10mb",
|
|
15
|
+
video: "100mb",
|
|
16
|
+
audio: "50mb",
|
|
17
|
+
document: "25mb",
|
|
18
|
+
...limits,
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
21
|
static getInstance(limits) {
|
|
@@ -29,56 +29,56 @@ class DetectorMedia {
|
|
|
29
29
|
}
|
|
30
30
|
parseSize(size) {
|
|
31
31
|
const units = {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
b: 1,
|
|
33
|
+
kb: 1024,
|
|
34
|
+
mb: 1024 * 1024,
|
|
35
|
+
gb: 1024 * 1024 * 1024,
|
|
36
36
|
};
|
|
37
37
|
const match = size.toLowerCase().match(/^(\d+(?:\.\d+)?)\s*(b|kb|mb|gb)?$/);
|
|
38
38
|
if (!match)
|
|
39
39
|
return 10 * 1024 * 1024; // Default 10MB
|
|
40
40
|
const value = parseFloat(match[1]);
|
|
41
|
-
const unit = match[2] ||
|
|
41
|
+
const unit = match[2] || "b";
|
|
42
42
|
return Math.floor(value * units[unit]);
|
|
43
43
|
}
|
|
44
44
|
validateFileSize(filePath, mediaType) {
|
|
45
45
|
return new Promise((resolve, reject) => {
|
|
46
|
-
promises_1.default.stat(filePath)
|
|
46
|
+
promises_1.default.stat(filePath)
|
|
47
|
+
.then((stats) => {
|
|
47
48
|
const fileSize = stats.size;
|
|
48
|
-
const limitStr = this.mediaLimits[mediaType] ||
|
|
49
|
+
const limitStr = this.mediaLimits[mediaType] || "10mb";
|
|
49
50
|
const limit = this.parseSize(limitStr);
|
|
50
51
|
if (fileSize > limit) {
|
|
51
|
-
const fileSizeMB = Math.round(fileSize / 1024 / 1024 * 100) / 100;
|
|
52
|
-
const limitMB = Math.round(limit / 1024 / 1024 * 100) / 100;
|
|
52
|
+
const fileSizeMB = Math.round((fileSize / 1024 / 1024) * 100) / 100;
|
|
53
|
+
const limitMB = Math.round((limit / 1024 / 1024) * 100) / 100;
|
|
53
54
|
reject(new Error(`File size ${fileSizeMB}MB exceeds limit of ${limitMB}MB for ${mediaType} files`));
|
|
54
55
|
}
|
|
55
56
|
else {
|
|
56
57
|
resolve();
|
|
57
58
|
}
|
|
58
|
-
})
|
|
59
|
+
})
|
|
60
|
+
.catch(reject);
|
|
59
61
|
});
|
|
60
62
|
}
|
|
61
63
|
async validateUrlSize(url, mediaType) {
|
|
62
64
|
try {
|
|
63
65
|
const response = await axios_1.default.head(url);
|
|
64
|
-
const contentLength = parseInt(response.headers[
|
|
66
|
+
const contentLength = parseInt(response.headers["content-length"] || "0");
|
|
65
67
|
if (contentLength > 0) {
|
|
66
|
-
const limitStr = this.mediaLimits[mediaType] ||
|
|
68
|
+
const limitStr = this.mediaLimits[mediaType] || "10mb";
|
|
67
69
|
const limit = this.parseSize(limitStr);
|
|
68
70
|
if (contentLength > limit) {
|
|
69
|
-
const fileSizeMB = Math.round(contentLength / 1024 / 1024 * 100) / 100;
|
|
70
|
-
const limitMB = Math.round(limit / 1024 / 1024 * 100) / 100;
|
|
71
|
+
const fileSizeMB = Math.round((contentLength / 1024 / 1024) * 100) / 100;
|
|
72
|
+
const limitMB = Math.round((limit / 1024 / 1024) * 100) / 100;
|
|
71
73
|
throw new Error(`Remote file size ${fileSizeMB}MB exceeds limit of ${limitMB}MB for ${mediaType} files`);
|
|
72
74
|
}
|
|
73
75
|
}
|
|
74
76
|
return contentLength;
|
|
75
77
|
}
|
|
76
78
|
catch (error) {
|
|
77
|
-
if (error.message.includes(
|
|
79
|
+
if (error.message.includes("exceeds limit")) {
|
|
78
80
|
throw error;
|
|
79
81
|
}
|
|
80
|
-
// If we can't get size, assume it's valid but warn
|
|
81
|
-
console.warn(`[DetectorMedia] Could not validate size for URL: ${url}`);
|
|
82
82
|
return 0;
|
|
83
83
|
}
|
|
84
84
|
}
|
|
@@ -113,11 +113,15 @@ class DetectorMedia {
|
|
|
113
113
|
async getMimeTypeFromUrl(url) {
|
|
114
114
|
try {
|
|
115
115
|
const res = await axios_1.default.head(url);
|
|
116
|
-
const
|
|
117
|
-
|
|
116
|
+
const contentType = res.headers["content-type"];
|
|
117
|
+
const mediaType = this.mapMimeToCategory(contentType);
|
|
118
|
+
return {
|
|
119
|
+
mediaType: mediaType || null,
|
|
120
|
+
mimeType: contentType || null,
|
|
121
|
+
};
|
|
118
122
|
}
|
|
119
123
|
catch {
|
|
120
|
-
return null;
|
|
124
|
+
return { mediaType: null, mimeType: null };
|
|
121
125
|
}
|
|
122
126
|
}
|
|
123
127
|
async extractFileNameFromUrl(url) {
|
|
@@ -135,15 +139,15 @@ class DetectorMedia {
|
|
|
135
139
|
*/
|
|
136
140
|
async processMedia(input) {
|
|
137
141
|
if (this.isRemoteUrl(input)) {
|
|
138
|
-
const mediaType = await this.getMimeTypeFromUrl(input);
|
|
139
|
-
if (!mediaType)
|
|
142
|
+
const { mediaType, mimeType } = await this.getMimeTypeFromUrl(input);
|
|
143
|
+
if (!mediaType || !mimeType)
|
|
140
144
|
throw new Error("No se pudo determinar el tipo MIME de la URL remota");
|
|
141
145
|
// Validate remote file size
|
|
142
146
|
const size = await this.validateUrlSize(input, mediaType);
|
|
143
147
|
const fileName = await this.extractFileNameFromUrl(input);
|
|
144
148
|
return {
|
|
145
149
|
media: input,
|
|
146
|
-
mimeType:
|
|
150
|
+
mimeType: mimeType,
|
|
147
151
|
fileName,
|
|
148
152
|
mediaType,
|
|
149
153
|
size,
|
|
@@ -152,15 +156,20 @@ class DetectorMedia {
|
|
|
152
156
|
return this.convertPathToBase64(input);
|
|
153
157
|
}
|
|
154
158
|
mapMimeToCategory(mimeType) {
|
|
155
|
-
if (mimeType
|
|
159
|
+
if (!mimeType) {
|
|
160
|
+
return "unknown";
|
|
161
|
+
}
|
|
162
|
+
const normalizedMimeType = mimeType.toLowerCase().split(";")[0].trim();
|
|
163
|
+
if (normalizedMimeType.startsWith("image/"))
|
|
156
164
|
return "image";
|
|
157
|
-
if (
|
|
165
|
+
if (normalizedMimeType.startsWith("video/"))
|
|
158
166
|
return "video";
|
|
159
|
-
if (
|
|
167
|
+
if (normalizedMimeType.startsWith("audio/"))
|
|
160
168
|
return "audio";
|
|
161
|
-
if (
|
|
169
|
+
if (normalizedMimeType.startsWith("application/") ||
|
|
170
|
+
normalizedMimeType.startsWith("text/"))
|
|
162
171
|
return "document";
|
|
163
|
-
return "
|
|
172
|
+
return "document"; // Default to document instead of unknown for better compatibility
|
|
164
173
|
}
|
|
165
174
|
}
|
|
166
175
|
exports.DetectorMedia = DetectorMedia;
|
package/package.json
CHANGED
package/queue.class.log
ADDED
|
File without changes
|