@fer2809fl/baileys 7.0.4 → 7.0.5
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/README.md +347 -50
- package/lib/Defaults/index.js +1 -1
- package/lib/Modded/message_builder.js +2356 -0
- package/lib/Socket/chats.d.ts +14 -0
- package/lib/Socket/chats.js +48 -0
- package/lib/Socket/index.d.ts +17 -0
- package/lib/Socket/messages-send.d.ts +18 -0
- package/lib/Socket/messages-send.js +50 -2
- package/lib/Utils/anti-ban.d.ts +41 -0
- package/lib/Utils/anti-ban.js +182 -0
- package/lib/Utils/banner.d.ts +8 -0
- package/lib/Utils/banner.js +76 -0
- package/lib/Utils/bot-utils.d.ts +57 -0
- package/lib/Utils/bot-utils.js +241 -0
- package/lib/Utils/enhanced-cache.d.ts +40 -0
- package/lib/Utils/enhanced-cache.js +242 -0
- package/lib/Utils/enhanced-logger.d.ts +41 -0
- package/lib/Utils/enhanced-logger.js +185 -0
- package/lib/Utils/index.d.ts +14 -0
- package/lib/Utils/index.js +13 -0
- package/lib/Utils/lid-utils.d.ts +139 -0
- package/lib/Utils/lid-utils.js +503 -0
- package/lib/Utils/message-queue.d.ts +47 -0
- package/lib/Utils/message-queue.js +226 -0
- package/lib/Utils/rich-message-utils.d.ts +21 -0
- package/lib/Utils/rich-message-utils.js +229 -0
- package/lib/Utils/rich-messages.d.ts +52 -0
- package/lib/Utils/rich-messages.js +185 -0
- package/lib/Utils/scheduled-messages.d.ts +122 -0
- package/lib/Utils/scheduled-messages.js +289 -0
- package/lib/Utils/smart-reconnect.d.ts +48 -0
- package/lib/Utils/smart-reconnect.js +207 -0
- package/lib/Utils/use-sqlite-auth-state.d.ts +11 -0
- package/lib/Utils/use-sqlite-auth-state.js +95 -0
- package/lib/VoIP/audio-feeder.d.ts +15 -0
- package/lib/VoIP/audio-feeder.js +132 -0
- package/lib/VoIP/index.js +277 -0
- package/lib/VoIP/relay-transport.d.ts +43 -0
- package/lib/VoIP/relay-transport.js +559 -0
- package/lib/VoIP/signaling.js +594 -0
- package/lib/VoIP/types.d.ts +69 -0
- package/lib/VoIP/types.js +17 -0
- package/lib/VoIP/wasm-engine.d.ts +103 -0
- package/lib/VoIP/wasm-engine.js +1214 -0
- package/lib/VoIP/worker-bootstrap.js +1042 -0
- package/lib/assets/wasm/loader.js +5 -0
- package/lib/assets/wasm/whatsapp.wasm +0 -0
- package/lib/assets/wasm/worker-modules.js +273 -0
- package/lib/index.d.ts +41 -0
- package/lib/index.js +3 -0
- package/package.json +10 -2
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { LRUCache } from 'lru-cache';
|
|
2
|
+
|
|
3
|
+
const PRIORITY = {
|
|
4
|
+
CRITICAL: 0,
|
|
5
|
+
HIGH: 1,
|
|
6
|
+
NORMAL: 2,
|
|
7
|
+
LOW: 3,
|
|
8
|
+
BACKGROUND: 4
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const QUEUE_CONFIG = {
|
|
12
|
+
MAX_QUEUE_SIZE: 1000,
|
|
13
|
+
PROCESS_INTERVAL: 50,
|
|
14
|
+
RATE_LIMITS: {
|
|
15
|
+
message: { count: 100, window: 60000 },
|
|
16
|
+
group: { count: 40, window: 60000 },
|
|
17
|
+
media: { count: 50, window: 60000 },
|
|
18
|
+
broadcast: { count: 200, window: 3600000 }
|
|
19
|
+
},
|
|
20
|
+
DELAYS: {
|
|
21
|
+
message: 300,
|
|
22
|
+
group: 500,
|
|
23
|
+
media: 800,
|
|
24
|
+
broadcast: 1500
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
class QueueItem {
|
|
29
|
+
constructor(task, priority = PRIORITY.NORMAL, metadata = {}) {
|
|
30
|
+
this.id = `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
31
|
+
this.task = task;
|
|
32
|
+
this.priority = priority;
|
|
33
|
+
this.metadata = metadata;
|
|
34
|
+
this.createdAt = Date.now();
|
|
35
|
+
this.attempts = 0;
|
|
36
|
+
this.maxAttempts = metadata.maxAttempts || 3;
|
|
37
|
+
this.status = 'pending';
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
class MessageQueue {
|
|
42
|
+
constructor(logger, config = {}) {
|
|
43
|
+
this.logger = logger;
|
|
44
|
+
this.config = { ...QUEUE_CONFIG, ...config };
|
|
45
|
+
this.queue = [];
|
|
46
|
+
this.processing = false;
|
|
47
|
+
this.paused = false;
|
|
48
|
+
this.rateLimiters = new Map();
|
|
49
|
+
this.processTimer = null;
|
|
50
|
+
this.stats = {
|
|
51
|
+
totalQueued: 0,
|
|
52
|
+
totalProcessed: 0,
|
|
53
|
+
totalFailed: 0,
|
|
54
|
+
averageWaitTime: 0
|
|
55
|
+
};
|
|
56
|
+
this.recentMessages = new LRUCache({ max: 500, ttl: 300000 });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
enqueue(task, priority = PRIORITY.NORMAL, metadata = {}) {
|
|
60
|
+
if (this.queue.length >= this.config.MAX_QUEUE_SIZE) {
|
|
61
|
+
this.logger?.warn('Queue is full, dropping oldest low priority items');
|
|
62
|
+
this._dropLowPriority();
|
|
63
|
+
}
|
|
64
|
+
const item = new QueueItem(task, priority, metadata);
|
|
65
|
+
const hash = this._hashTask(task, metadata);
|
|
66
|
+
if (this.recentMessages.has(hash) && !metadata.allowDuplicate) {
|
|
67
|
+
this.logger?.debug({ hash }, 'Duplicate message detected, skipping');
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
let inserted = false;
|
|
71
|
+
for (let i = 0; i < this.queue.length; i++) {
|
|
72
|
+
if (this.queue[i].priority > priority) {
|
|
73
|
+
this.queue.splice(i, 0, item);
|
|
74
|
+
inserted = true;
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (!inserted) this.queue.push(item);
|
|
79
|
+
this.stats.totalQueued++;
|
|
80
|
+
this.recentMessages.set(hash, true);
|
|
81
|
+
this.logger?.debug({ id: item.id, priority, queueSize: this.queue.length }, 'Task enqueued');
|
|
82
|
+
if (!this.processing && !this.paused) this._startProcessing();
|
|
83
|
+
return item.id;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
_hashTask(task, metadata) {
|
|
87
|
+
const data = JSON.stringify({ jid: metadata.jid, content: typeof task === 'function' ? metadata.contentHash : task });
|
|
88
|
+
return Buffer.from(data).toString('base64').substr(0, 32);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
_dropLowPriority() {
|
|
92
|
+
this.queue.sort((a, b) => b.priority - a.priority);
|
|
93
|
+
const toDrop = Math.ceil(this.queue.length * 0.1);
|
|
94
|
+
const dropped = this.queue.splice(0, toDrop);
|
|
95
|
+
this.logger?.warn({ dropped: dropped.length }, 'Dropped low priority items');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
_startProcessing() {
|
|
99
|
+
if (this.processTimer) return;
|
|
100
|
+
this.processing = true;
|
|
101
|
+
this.processTimer = setInterval(() => this._processNext(), this.config.PROCESS_INTERVAL);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
_stopProcessing() {
|
|
105
|
+
if (this.processTimer) {
|
|
106
|
+
clearInterval(this.processTimer);
|
|
107
|
+
this.processTimer = null;
|
|
108
|
+
}
|
|
109
|
+
this.processing = false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async _processNext() {
|
|
113
|
+
if (this.paused || this.queue.length === 0) {
|
|
114
|
+
if (this.queue.length === 0) this._stopProcessing();
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const item = this.queue.shift();
|
|
118
|
+
if (!item) return;
|
|
119
|
+
item.status = 'processing';
|
|
120
|
+
item.attempts++;
|
|
121
|
+
const waitTime = Date.now() - item.createdAt;
|
|
122
|
+
this._updateAverageWaitTime(waitTime);
|
|
123
|
+
try {
|
|
124
|
+
const type = item.metadata.type || 'message';
|
|
125
|
+
await this._checkRateLimit(type, item.metadata.jid);
|
|
126
|
+
const result = typeof item.task === 'function' ? await item.task() : item.task;
|
|
127
|
+
item.status = 'completed';
|
|
128
|
+
this.stats.totalProcessed++;
|
|
129
|
+
this.logger?.debug({ id: item.id, waitTime }, 'Task completed');
|
|
130
|
+
const delay = this.config.DELAYS[type] || this.config.DELAYS.message;
|
|
131
|
+
await this._delay(delay);
|
|
132
|
+
return result;
|
|
133
|
+
} catch (error) {
|
|
134
|
+
this.logger?.error({ id: item.id, error: error.message }, 'Task failed');
|
|
135
|
+
if (item.attempts < item.maxAttempts) {
|
|
136
|
+
item.priority = Math.min(item.priority + 1, PRIORITY.BACKGROUND);
|
|
137
|
+
item.status = 'pending';
|
|
138
|
+
this.queue.push(item);
|
|
139
|
+
this.logger?.debug({ id: item.id, attempts: item.attempts }, 'Task re-queued');
|
|
140
|
+
} else {
|
|
141
|
+
item.status = 'failed';
|
|
142
|
+
this.stats.totalFailed++;
|
|
143
|
+
this.logger?.warn({ id: item.id }, 'Task permanently failed');
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async _checkRateLimit(type, jid) {
|
|
149
|
+
const limit = this.config.RATE_LIMITS[type] || this.config.RATE_LIMITS.message;
|
|
150
|
+
const key = jid ? `${type}:${jid}` : type;
|
|
151
|
+
if (!this.rateLimiters.has(key)) this.rateLimiters.set(key, []);
|
|
152
|
+
const timestamps = this.rateLimiters.get(key);
|
|
153
|
+
const now = Date.now();
|
|
154
|
+
const valid = timestamps.filter(ts => now - ts < limit.window);
|
|
155
|
+
this.rateLimiters.set(key, valid);
|
|
156
|
+
if (valid.length >= limit.count) {
|
|
157
|
+
const oldestValid = valid[valid.length - limit.count];
|
|
158
|
+
const waitTime = limit.window - (now - oldestValid);
|
|
159
|
+
if (waitTime > 0) {
|
|
160
|
+
this.logger?.debug({ key, waitTime }, 'Rate limited, waiting');
|
|
161
|
+
await this._delay(waitTime);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
valid.push(now);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
_updateAverageWaitTime(newTime) {
|
|
168
|
+
const total = this.stats.totalProcessed;
|
|
169
|
+
this.stats.averageWaitTime = (this.stats.averageWaitTime * total + newTime) / (total + 1);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
_delay(ms) {
|
|
173
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
pause() {
|
|
177
|
+
this.paused = true;
|
|
178
|
+
this.logger?.info('Queue paused');
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
resume() {
|
|
182
|
+
this.paused = false;
|
|
183
|
+
if (this.queue.length > 0 && !this.processing) this._startProcessing();
|
|
184
|
+
this.logger?.info('Queue resumed');
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
clear(priority = null) {
|
|
188
|
+
if (priority !== null) this.queue = this.queue.filter(item => item.priority !== priority);
|
|
189
|
+
else this.queue = [];
|
|
190
|
+
this.logger?.info({ cleared: true, remaining: this.queue.length }, 'Queue cleared');
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
getStats() {
|
|
194
|
+
return {
|
|
195
|
+
...this.stats,
|
|
196
|
+
currentQueueSize: this.queue.length,
|
|
197
|
+
isProcessing: this.processing,
|
|
198
|
+
isPaused: this.paused,
|
|
199
|
+
pendingByPriority: {
|
|
200
|
+
critical: this.queue.filter(i => i.priority === PRIORITY.CRITICAL).length,
|
|
201
|
+
high: this.queue.filter(i => i.priority === PRIORITY.HIGH).length,
|
|
202
|
+
normal: this.queue.filter(i => i.priority === PRIORITY.NORMAL).length,
|
|
203
|
+
low: this.queue.filter(i => i.priority === PRIORITY.LOW).length,
|
|
204
|
+
background: this.queue.filter(i => i.priority === PRIORITY.BACKGROUND).length
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
cleanup() {
|
|
210
|
+
this._stopProcessing();
|
|
211
|
+
this.queue = [];
|
|
212
|
+
this.rateLimiters.clear();
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function createMessageQueue(logger, customConfig = {}) {
|
|
217
|
+
return new MessageQueue(logger, customConfig);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export {
|
|
221
|
+
PRIORITY,
|
|
222
|
+
QUEUE_CONFIG,
|
|
223
|
+
QueueItem,
|
|
224
|
+
MessageQueue,
|
|
225
|
+
createMessageQueue
|
|
226
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare function toUnified(submessages: any[], uuid?: string): { response_id: string; sections: any[] };
|
|
2
|
+
|
|
3
|
+
export interface RichResponseContent {
|
|
4
|
+
headerText?: string;
|
|
5
|
+
contentText?: string;
|
|
6
|
+
footerText?: string;
|
|
7
|
+
disclaimerText?: string;
|
|
8
|
+
code?: string;
|
|
9
|
+
language?: string;
|
|
10
|
+
table?: any[][];
|
|
11
|
+
title?: string;
|
|
12
|
+
noHeading?: boolean;
|
|
13
|
+
links?: Array<{ text: string; url?: string; title?: string; displayName?: string }>;
|
|
14
|
+
richResponse?: any[];
|
|
15
|
+
[key: string]: any;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export declare function prepareRichResponseMessage(content: RichResponseContent): any;
|
|
19
|
+
export declare function botMetadataSignature(): Uint8Array;
|
|
20
|
+
export declare function botMetadataCertificate(length?: number): Uint8Array;
|
|
21
|
+
export declare function wrapToBotForwardedMessage(richResponseMessage: any): any;
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { randomUUID, getRandomValues } from 'crypto';
|
|
2
|
+
import { proto } from '../../WAProto/index.js';
|
|
3
|
+
import { CodeHighlightType, RichSubMessageType, LANGUAGE_KEYWORDS } from './rich-messages.js';
|
|
4
|
+
|
|
5
|
+
const LEXER_REGEX = /(\/\/[^\n]*|\/\*[\s\S]*?\*\/|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|`(?:[^`\\]|\\.)*`|\b\d+\.?\d*\b|\b[a-zA-Z_$][\w$]*\b|\s+|[^\s\w$]+)/g;
|
|
6
|
+
const NOOP = new Set([]);
|
|
7
|
+
|
|
8
|
+
const tokenizeCode = (code, language = 'javascript') => {
|
|
9
|
+
const keywords = LANGUAGE_KEYWORDS[language] || NOOP;
|
|
10
|
+
const blocks = [];
|
|
11
|
+
LEXER_REGEX.lastIndex = 0;
|
|
12
|
+
let match;
|
|
13
|
+
while ((match = LEXER_REGEX.exec(code)) !== null) {
|
|
14
|
+
if (match[1]) {
|
|
15
|
+
blocks.push({ highlightType: CodeHighlightType.COMMENT, codeContent: match[1] });
|
|
16
|
+
} else if (match[2]) {
|
|
17
|
+
blocks.push({ highlightType: CodeHighlightType.STRING, codeContent: match[2] });
|
|
18
|
+
} else if (match[3]) {
|
|
19
|
+
blocks.push({
|
|
20
|
+
highlightType: keywords.has(match[3]) ? CodeHighlightType.KEYWORD : CodeHighlightType.METHOD,
|
|
21
|
+
codeContent: match[3]
|
|
22
|
+
});
|
|
23
|
+
} else if (match[4]) {
|
|
24
|
+
blocks.push({
|
|
25
|
+
highlightType: keywords.has(match[4]) ? CodeHighlightType.KEYWORD : CodeHighlightType.DEFAULT,
|
|
26
|
+
codeContent: match[4]
|
|
27
|
+
});
|
|
28
|
+
} else if (match[5]) {
|
|
29
|
+
blocks.push({ highlightType: CodeHighlightType.NUMBER, codeContent: match[5] });
|
|
30
|
+
} else {
|
|
31
|
+
blocks.push({ highlightType: CodeHighlightType.DEFAULT, codeContent: match[6] });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return blocks;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const toUnified = (submessages, uuid) => ({
|
|
38
|
+
response_id: uuid || randomUUID(),
|
|
39
|
+
sections: submessages.map(submessage => {
|
|
40
|
+
switch (submessage.messageType) {
|
|
41
|
+
case RichSubMessageType.CODE: {
|
|
42
|
+
const codeMetadata = submessage.codeMetadata;
|
|
43
|
+
return {
|
|
44
|
+
view_model: {
|
|
45
|
+
primitive: {
|
|
46
|
+
language: codeMetadata.codeLanguage,
|
|
47
|
+
code_blocks: codeMetadata.codeBlocks.map(block => ({
|
|
48
|
+
content: block.codeContent,
|
|
49
|
+
type: CodeHighlightType[block.highlightType]
|
|
50
|
+
})),
|
|
51
|
+
__typename: 'GenAICodeUXPrimitive'
|
|
52
|
+
},
|
|
53
|
+
__typename: 'GenAISingleLayoutViewModel'
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
case RichSubMessageType.TABLE: {
|
|
58
|
+
const tableMetadata = submessage.tableMetadata;
|
|
59
|
+
return {
|
|
60
|
+
view_model: {
|
|
61
|
+
primitive: {
|
|
62
|
+
title: tableMetadata.title,
|
|
63
|
+
rows: tableMetadata.rows.map(row => ({
|
|
64
|
+
is_header: row.isHeading,
|
|
65
|
+
cells: row.items,
|
|
66
|
+
markdown_cells: row.items.map(item => ({ text: item }))
|
|
67
|
+
})),
|
|
68
|
+
__typename: 'GenATableUXPrimitive'
|
|
69
|
+
},
|
|
70
|
+
__typename: 'GenAISingleLayoutViewModel'
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
case RichSubMessageType.TEXT:
|
|
75
|
+
return {
|
|
76
|
+
view_model: {
|
|
77
|
+
primitive: {
|
|
78
|
+
text: submessage.messageText,
|
|
79
|
+
inline_entities: submessage.inlineEntities || [],
|
|
80
|
+
__typename: 'GenAIMarkdownTextUXPrimitive'
|
|
81
|
+
},
|
|
82
|
+
__typename: 'GenAISingleLayoutViewModel'
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return submessage;
|
|
87
|
+
})
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const botMetadataSignature = () => {
|
|
91
|
+
const signature = new Uint8Array(64);
|
|
92
|
+
getRandomValues(signature);
|
|
93
|
+
return signature;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const botMetadataCertificate = (length = 685) => {
|
|
97
|
+
const certificate = new Uint8Array(length);
|
|
98
|
+
certificate[0] = 48;
|
|
99
|
+
certificate[1] = 130;
|
|
100
|
+
getRandomValues(certificate.subarray(2));
|
|
101
|
+
return certificate;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const wrapToBotForwardedMessage = richResponseMessage => ({
|
|
105
|
+
messageContextInfo: {
|
|
106
|
+
botMetadata: {
|
|
107
|
+
verificationMetadata: {
|
|
108
|
+
proofs: [
|
|
109
|
+
{
|
|
110
|
+
certificateChain: [
|
|
111
|
+
botMetadataCertificate(),
|
|
112
|
+
botMetadataCertificate(892)
|
|
113
|
+
],
|
|
114
|
+
version: 1,
|
|
115
|
+
useCase: 1,
|
|
116
|
+
signature: botMetadataSignature()
|
|
117
|
+
}
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
botForwardedMessage: {
|
|
123
|
+
message: { richResponseMessage }
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const prepareRichResponseMessage = content => {
|
|
128
|
+
const {
|
|
129
|
+
alignment, code, contentText, disclaimerText, footerText, headerText,
|
|
130
|
+
imageText, inlineImage, inlineVideo, items, language, latex, links,
|
|
131
|
+
noHeading, posts, products, suggested, richResponse, table, tapLinkUrl, title
|
|
132
|
+
} = content;
|
|
133
|
+
|
|
134
|
+
let submessages = [];
|
|
135
|
+
|
|
136
|
+
if (Array.isArray(richResponse)) {
|
|
137
|
+
submessages = richResponse.map(submessage => {
|
|
138
|
+
if (submessage.text) {
|
|
139
|
+
return { messageType: RichSubMessageType.TEXT, messageText: submessage.text, inlineEntities: submessage.inlineEntities };
|
|
140
|
+
} else if (submessage.code) {
|
|
141
|
+
return {
|
|
142
|
+
messageType: RichSubMessageType.CODE,
|
|
143
|
+
codeMetadata: {
|
|
144
|
+
codeLanguage: submessage.language || 'javascript',
|
|
145
|
+
codeBlocks: typeof submessage.code === 'string'
|
|
146
|
+
? tokenizeCode(submessage.code, submessage.language || 'javascript')
|
|
147
|
+
: submessage.code
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
} else if (submessage.table) {
|
|
151
|
+
return {
|
|
152
|
+
messageType: RichSubMessageType.TABLE,
|
|
153
|
+
tableMetadata: { title: submessage.title, rows: submessage.table }
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
return submessage;
|
|
157
|
+
});
|
|
158
|
+
} else {
|
|
159
|
+
if (headerText) submessages.push({ messageType: RichSubMessageType.TEXT, messageText: headerText });
|
|
160
|
+
if (contentText) submessages.push({ messageType: RichSubMessageType.TEXT, messageText: contentText });
|
|
161
|
+
if (code) {
|
|
162
|
+
const lang = language || 'javascript';
|
|
163
|
+
submessages.push({
|
|
164
|
+
messageType: RichSubMessageType.CODE,
|
|
165
|
+
codeMetadata: { codeLanguage: lang, codeBlocks: tokenizeCode(code, lang) }
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
if (links) {
|
|
169
|
+
links.forEach((linkField, index) => {
|
|
170
|
+
const prefix = 'SS_' + index;
|
|
171
|
+
submessages.push({
|
|
172
|
+
messageType: RichSubMessageType.TEXT,
|
|
173
|
+
messageText: linkField.text + ` {{${prefix}}}1{{/${prefix}}} `,
|
|
174
|
+
inlineEntities: [{
|
|
175
|
+
key: prefix,
|
|
176
|
+
metadata: {
|
|
177
|
+
reference_id: index + 1,
|
|
178
|
+
reference_url: linkField.url || '',
|
|
179
|
+
reference_title: linkField.title || 'Reference',
|
|
180
|
+
reference_display_name: linkField.displayName || 'Source',
|
|
181
|
+
sources: [],
|
|
182
|
+
__typename: 'GenAISearchCitationItem'
|
|
183
|
+
}
|
|
184
|
+
}]
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
if (table) {
|
|
189
|
+
submessages.push({
|
|
190
|
+
messageType: RichSubMessageType.TABLE,
|
|
191
|
+
tableMetadata: {
|
|
192
|
+
title,
|
|
193
|
+
rows: table.map((items, index) => ({ isHeading: !noHeading && index === 0, items }))
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
if (footerText) submessages.push({ messageType: RichSubMessageType.TEXT, messageText: footerText });
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const uuid = randomUUID();
|
|
201
|
+
const unified = toUnified(submessages, uuid);
|
|
202
|
+
|
|
203
|
+
const richResponseMessage = proto.AIRichResponseMessage.create({
|
|
204
|
+
submessages,
|
|
205
|
+
messageType: proto.AIRichResponseMessageType.AI_RICH_RESPONSE_TYPE_STANDARD,
|
|
206
|
+
unifiedResponse: { data: Buffer.from(JSON.stringify(unified)) },
|
|
207
|
+
contextInfo: {
|
|
208
|
+
isForwarded: true,
|
|
209
|
+
forwardingScore: 1,
|
|
210
|
+
forwardedAiBotMessageInfo: { botJid: '867051314767696@bot' },
|
|
211
|
+
forwardOrigin: 4
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
const message = wrapToBotForwardedMessage(richResponseMessage);
|
|
216
|
+
const botMetadata = message.messageContextInfo.botMetadata;
|
|
217
|
+
if (disclaimerText) botMetadata.messageDisclaimerText = disclaimerText;
|
|
218
|
+
botMetadata.botResponseId = uuid;
|
|
219
|
+
|
|
220
|
+
return message;
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
export {
|
|
224
|
+
toUnified,
|
|
225
|
+
prepareRichResponseMessage,
|
|
226
|
+
botMetadataSignature,
|
|
227
|
+
botMetadataCertificate,
|
|
228
|
+
wrapToBotForwardedMessage
|
|
229
|
+
};
|
|
@@ -273,5 +273,57 @@ export declare const generateLinkContentV2: (
|
|
|
273
273
|
message: any;
|
|
274
274
|
messageId: string;
|
|
275
275
|
};
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Opciones para generar un mensaje HTML embebido en WhatsApp.
|
|
279
|
+
*
|
|
280
|
+
* El mensaje resultante es renderizado por el cliente de WhatsApp como un
|
|
281
|
+
* WebView sandboxed dentro del bocadillo del mensaje, usando el campo interno
|
|
282
|
+
* `GenAIaeacdsnwHtmlPrimitive` del protocolo AIRichResponseMessage.
|
|
283
|
+
*/
|
|
284
|
+
export interface HtmlContentOptions extends RichMessageOptions {
|
|
285
|
+
/**
|
|
286
|
+
* Dominios que el WebView puede contactar (fetch, imágenes, fuentes, etc.).
|
|
287
|
+
* Sin esquema (ej: `["api.tuyo.com", "cdn.tuyo.com"]`).
|
|
288
|
+
* Default: `[]` (sin red).
|
|
289
|
+
*/
|
|
290
|
+
trustedSources?: string[];
|
|
291
|
+
/** Cabecera opcional arriba del HTML (markdown). */
|
|
292
|
+
headerText?: string;
|
|
293
|
+
/** Pie opcional debajo del HTML (markdown). */
|
|
294
|
+
footer?: string;
|
|
295
|
+
/**
|
|
296
|
+
* Texto mostrado en el submessage de respaldo si el cliente no soporta
|
|
297
|
+
* HTML. Default: `"Contenido interactivo"`.
|
|
298
|
+
*/
|
|
299
|
+
fallbackText?: string;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Construye un mensaje que el cliente de WhatsApp renderiza como un WebView
|
|
304
|
+
* embebido dentro del bocadillo del mensaje.
|
|
305
|
+
*
|
|
306
|
+
* Ver `HtmlContentOptions` para las limitaciones estructurales conocidas y
|
|
307
|
+
* el patrón recomendado (backend + inyección de estado + JWT).
|
|
308
|
+
*
|
|
309
|
+
* @example
|
|
310
|
+
* ```ts
|
|
311
|
+
* const html = `<body><h1>Hola ${jid}</h1></body>`;
|
|
312
|
+
* const { message, messageId } = generateHtmlContent(html, quoted, {
|
|
313
|
+
* trustedSources: ["api.tuyo.com"],
|
|
314
|
+
* headerText: "Demo HTML",
|
|
315
|
+
* });
|
|
316
|
+
* await sock.relayMessage(jid, message, { messageId });
|
|
317
|
+
* ```
|
|
318
|
+
*/
|
|
319
|
+
export declare const generateHtmlContent: (
|
|
320
|
+
html: string,
|
|
321
|
+
quoted?: QuotedMessage | null,
|
|
322
|
+
options?: HtmlContentOptions,
|
|
323
|
+
) => {
|
|
324
|
+
message: any;
|
|
325
|
+
messageId: string;
|
|
326
|
+
};
|
|
327
|
+
|
|
276
328
|
export {};
|
|
277
329
|
//# sourceMappingURL=rich-messages.d.ts.map
|