@omnizap-system/omnizap 2.6.1 → 2.6.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/.env.example +54 -9
- package/.github/workflows/ci.yml +3 -3
- package/.github/workflows/security-runner-hardening.yml +1 -1
- package/.github/workflows/security-zap-full-scan.yml +1 -0
- package/app/config/index.js +2 -0
- package/app/configParts/adminIdentity.js +5 -5
- package/app/configParts/baileysConfig.js +226 -55
- package/app/configParts/groupUtils.js +5 -0
- package/app/configParts/messagePersistenceService.js +143 -3
- package/app/configParts/sessionConfig.js +157 -0
- package/app/connection/baileysCompatibility.test.js +1 -1
- package/app/connection/groupOwnerWriteStateResolver.js +109 -0
- package/app/connection/socketController.js +625 -124
- package/app/connection/socketController.multiSession.test.js +108 -0
- package/app/controllers/messageController.js +1 -1
- package/app/controllers/messagePipeline/commandMiddleware.js +12 -10
- package/app/controllers/messagePipeline/conversationMiddleware.js +2 -1
- package/app/controllers/messagePipeline/messagePipelineMiddlewares.test.js +104 -0
- package/app/controllers/messagePipeline/preProcessingMiddlewares.js +80 -2
- package/app/controllers/messageProcessingPipeline.js +88 -9
- package/app/controllers/messageProcessingPipeline.test.js +200 -0
- package/app/modules/adminModule/AGENT.md +1 -1
- package/app/modules/adminModule/commandConfig.json +3318 -1347
- package/app/modules/adminModule/groupCommandHandlers.js +856 -14
- package/app/modules/adminModule/groupCommandHandlers.test.js +375 -9
- package/app/modules/adminModule/groupWarningRepository.js +152 -0
- package/app/modules/aiModule/AGENT.md +47 -30
- package/app/modules/aiModule/aiConfigRuntime.js +1 -0
- package/app/modules/aiModule/catCommand.js +132 -25
- package/app/modules/aiModule/commandConfig.json +114 -28
- package/app/modules/analyticsModule/messageAnalysisEventRepository.js +54 -6
- package/app/modules/gameModule/AGENT.md +1 -1
- package/app/modules/gameModule/commandConfig.json +29 -0
- package/app/modules/menuModule/AGENT.md +1 -1
- package/app/modules/menuModule/commandConfig.json +45 -10
- package/app/modules/menuModule/menuCatalogService.js +190 -0
- package/app/modules/menuModule/menuCommandUsageRepository.js +109 -0
- package/app/modules/menuModule/menuDynamicService.js +511 -0
- package/app/modules/menuModule/menuDynamicService.test.js +141 -0
- package/app/modules/menuModule/menus.js +36 -5
- package/app/modules/playModule/AGENT.md +10 -5
- package/app/modules/playModule/commandConfig.json +74 -16
- package/app/modules/playModule/playCommandConstants.js +13 -7
- package/app/modules/playModule/playCommandCore.js +4 -6
- package/app/modules/playModule/{playCommandYtDlpClient.js → playCommandMediaClient.js} +684 -332
- package/app/modules/playModule/playConfigRuntime.js +5 -6
- package/app/modules/playModule/playModuleCriticalFlows.test.js +44 -59
- package/app/modules/quoteModule/AGENT.md +1 -1
- package/app/modules/quoteModule/commandConfig.json +29 -0
- package/app/modules/rpgPokemonModule/AGENT.md +1 -1
- package/app/modules/rpgPokemonModule/commandConfig.json +29 -0
- package/app/modules/statsModule/AGENT.md +1 -1
- package/app/modules/statsModule/commandConfig.json +58 -0
- package/app/modules/stickerModule/AGENT.md +1 -1
- package/app/modules/stickerModule/commandConfig.json +145 -0
- package/app/modules/stickerPackModule/AGENT.md +1 -1
- package/app/modules/stickerPackModule/autoPackCollectorService.js +5 -1
- package/app/modules/stickerPackModule/commandConfig.json +29 -0
- package/app/modules/stickerPackModule/stickerAutoPackByTagsRuntime.js +1 -1
- package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +78 -57
- package/app/modules/stickerPackModule/stickerPackService.js +13 -6
- package/app/modules/systemMetricsModule/AGENT.md +1 -1
- package/app/modules/systemMetricsModule/commandConfig.json +29 -0
- package/app/modules/tiktokModule/AGENT.md +1 -1
- package/app/modules/tiktokModule/commandConfig.json +29 -0
- package/app/modules/userModule/AGENT.md +1 -1
- package/app/modules/userModule/commandConfig.json +29 -0
- package/app/modules/waifuPicsModule/AGENT.md +57 -27
- package/app/modules/waifuPicsModule/commandConfig.json +87 -0
- package/app/observability/metrics.js +136 -0
- package/app/services/ai/commandConfigEnrichmentService.js +229 -47
- package/app/services/ai/geminiService.js +131 -7
- package/app/services/ai/geminiService.test.js +59 -2
- package/app/services/ai/moduleAiHelpCoreService.js +33 -4
- package/app/services/group/groupMetadataService.js +24 -1
- package/app/services/infra/dbWriteQueue.js +51 -21
- package/app/services/messaging/newsBroadcastService.js +843 -27
- package/app/services/multiSession/assignmentBalancerService.js +457 -0
- package/app/services/multiSession/groupOwnershipRepository.js +381 -0
- package/app/services/multiSession/groupOwnershipService.js +890 -0
- package/app/services/multiSession/groupOwnershipService.test.js +309 -0
- package/app/services/multiSession/sessionRegistryService.js +293 -0
- package/app/store/aiPromptStore.js +36 -19
- package/app/store/groupConfigStore.js +41 -5
- package/app/store/premiumUserStore.js +21 -7
- package/app/utils/antiLink/antiLinkModule.js +352 -16
- package/app/workers/aiHelperContinuousLearningWorker.js +512 -0
- package/database/index.js +6 -0
- package/database/migrations/20260307_d0_hardening_down.sql +1 -1
- package/database/migrations/20260314_d7_canonical_sender_down.sql +1 -1
- package/database/migrations/20260406_d30_security_analytics_down.sql +1 -1
- package/database/migrations/20260411_d35_group_community_metadata_down.sql +59 -0
- package/database/migrations/20260411_d35_group_community_metadata_up.sql +62 -0
- package/database/migrations/20260412_d36_system_config_tables_down.sql +32 -0
- package/database/migrations/20260412_d36_system_config_tables_up.sql +66 -0
- package/database/migrations/20260413_d37_group_user_warnings_down.sql +11 -0
- package/database/migrations/20260413_d37_group_user_warnings_up.sql +24 -0
- package/database/migrations/20260414_d38_multi_session_foundation_down.sql +72 -0
- package/database/migrations/20260414_d38_multi_session_foundation_up.sql +125 -0
- package/database/migrations/20260414_d39_multi_session_cutover_down.sql +103 -0
- package/database/migrations/20260414_d39_multi_session_cutover_up.sql +83 -0
- package/database/schema.sql +102 -1
- package/docker-compose.yml +4 -1
- package/docs/compliance/acceptable-use-policy-2026-03-07.md +1 -1
- package/docs/compliance/privacy-policy-2026-03-07.md +2 -2
- package/docs/security/dsar-lgpd-runbook-2026-03-07.md +1 -1
- package/docs/security/network-hardening-runbook-2026-03-07.md +53 -0
- package/docs/security/omnizap-static-security-headers.conf +25 -0
- package/ecosystem.prod.config.cjs +31 -11
- package/index.js +52 -18
- package/observability/alert-rules.yml +20 -0
- package/observability/grafana/dashboards/omnizap-system-admin.json +229 -0
- package/observability/mysql-setup.sql +4 -4
- package/observability/system-admin-observability.md +26 -0
- package/package.json +12 -5
- package/public/comandos/commands-catalog.json +2253 -78
- package/public/js/apps/commandsReactApp.js +267 -87
- package/public/js/apps/createPackApp.js +3 -3
- package/public/js/apps/stickersApp.js +255 -103
- package/public/js/apps/termsReactApp.js +57 -8
- package/public/js/apps/userPasswordResetReactApp.js +406 -0
- package/public/js/apps/userReactApp.js +96 -47
- package/public/js/apps/userSystemAdmReactApp.js +1506 -0
- package/public/pages/politica-de-privacidade.html +1 -1
- package/public/pages/stickers.html +5 -5
- package/public/pages/termos-de-uso-texto-integral.html +1 -1
- package/public/pages/termos-de-uso.html +1 -1
- package/public/pages/user-password-reset.html +3 -4
- package/public/pages/user-systemadm.html +8 -462
- package/public/pages/user.html +1 -1
- package/scripts/clear-whatsapp-session.sh +123 -0
- package/scripts/core-ai-mode.mjs +163 -0
- package/scripts/deploy.sh +10 -0
- package/scripts/enrich-command-config-ux-openai.mjs +492 -0
- package/scripts/generate-commands-catalog.mjs +155 -0
- package/scripts/new-whatsapp-session.sh +317 -0
- package/scripts/security-web-surface-check.mjs +218 -0
- package/server/controllers/admin/adminPanelHandlers.js +253 -3
- package/server/controllers/admin/systemAdminController.js +267 -0
- package/server/controllers/sticker/stickerCatalogController.js +9 -23
- package/server/controllers/system/contactController.js +9 -17
- package/server/controllers/system/stickerCatalogSystemContext.js +27 -6
- package/server/controllers/system/systemController.js +254 -1
- package/server/controllers/userController.js +6 -0
- package/server/email/emailTemplateService.js +3 -2
- package/server/http/httpServer.js +8 -4
- package/server/middleware/securityHeaders.js +20 -1
- package/server/routes/admin/systemAdminRouter.js +6 -0
- package/server/routes/indexRouter.js +30 -6
- package/server/routes/observability/grafanaProxyRouter.js +254 -0
- package/server/routes/static/staticPageRouter.js +27 -1
- package/server/utils/publicContact.js +31 -0
- package/utils/whatsapp/contactEnv.js +39 -0
- package/vite.config.mjs +2 -1
- package/app/modules/playModule/local/installYtDlp.js +0 -25
- package/app/modules/playModule/local/ytDlpInstaller.js +0 -28
|
@@ -13,20 +13,164 @@ import path from 'node:path';
|
|
|
13
13
|
import { pipeline } from 'node:stream/promises';
|
|
14
14
|
import { Readable } from 'node:stream';
|
|
15
15
|
import { fileURLToPath } from 'node:url';
|
|
16
|
+
import { getMultiSessionRuntimeConfig } from './sessionConfig.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Utilitários centrais de integração com Baileys.
|
|
20
|
+
*
|
|
21
|
+
* Responsabilidades deste módulo:
|
|
22
|
+
* - validar/normalizar JIDs e tipos de presença;
|
|
23
|
+
* - encapsular chamadas seguras no socket ativo;
|
|
24
|
+
* - extrair/detectar mídia em mensagens;
|
|
25
|
+
* - resolver mapeamento LID <-> JID com cache e persistência.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @typedef {import('@whiskeysockets/baileys').WASocket} BaileysSocket
|
|
30
|
+
* @typedef {import('@whiskeysockets/baileys').WAMessage} BaileysMessage
|
|
31
|
+
* @typedef {import('@whiskeysockets/baileys').WAProto.IMessage} BaileysProtoMessage
|
|
32
|
+
* @typedef {'lid'|'pn'} AddressingMode
|
|
33
|
+
* @typedef {{includeAllTypes?: boolean, includeQuoted?: boolean, includeUnknown?: boolean}} MediaExtractionOptions
|
|
34
|
+
* @typedef {{
|
|
35
|
+
* mediaType: string,
|
|
36
|
+
* mediaKey: Record<string, any>,
|
|
37
|
+
* messageKey: string,
|
|
38
|
+
* isQuoted: boolean,
|
|
39
|
+
* isBinary: boolean,
|
|
40
|
+
* isUnknownType?: boolean,
|
|
41
|
+
* hasUrl: boolean,
|
|
42
|
+
* hasDirectPath: boolean,
|
|
43
|
+
* hasMediaKey: boolean,
|
|
44
|
+
* hasFileEncSha256: boolean,
|
|
45
|
+
* mimetype: string|null,
|
|
46
|
+
* fileLength: number|string|null,
|
|
47
|
+
* fileName: string|null,
|
|
48
|
+
* caption: string|null
|
|
49
|
+
* }} MediaEntry
|
|
50
|
+
* @typedef {{
|
|
51
|
+
* mediaType: string,
|
|
52
|
+
* mediaKey: Record<string, any>,
|
|
53
|
+
* isQuoted: boolean,
|
|
54
|
+
* details: {
|
|
55
|
+
* messageKey: string,
|
|
56
|
+
* isBinary: boolean,
|
|
57
|
+
* isUnknownType?: boolean,
|
|
58
|
+
* hasUrl: boolean,
|
|
59
|
+
* hasDirectPath: boolean,
|
|
60
|
+
* hasMediaKey: boolean,
|
|
61
|
+
* hasFileEncSha256: boolean,
|
|
62
|
+
* mimetype: string|null,
|
|
63
|
+
* fileLength: number|string|null,
|
|
64
|
+
* fileName: string|null,
|
|
65
|
+
* caption: string|null,
|
|
66
|
+
* allMediaFound: MediaEntry[]|null
|
|
67
|
+
* }
|
|
68
|
+
* }} MediaExtractionResult
|
|
69
|
+
* @typedef {{lid?: string|null, jid?: string|null, participantAlt?: string|null}} IdentityParams
|
|
70
|
+
* @typedef {{jid: string|null, expiresAt: number, lastStoredAt: number|null}} LidCacheEntry
|
|
71
|
+
* @typedef {{
|
|
72
|
+
* lid: string|null,
|
|
73
|
+
* jid: string|null,
|
|
74
|
+
* participantAlt: string|null,
|
|
75
|
+
* remoteJid: string|null,
|
|
76
|
+
* remoteJidAlt: string|null,
|
|
77
|
+
* groupMessage: boolean
|
|
78
|
+
* }} SenderInfo
|
|
79
|
+
*/
|
|
16
80
|
|
|
17
81
|
const DEFAULT_BAILEYS_VERSION = [7, 0, 0];
|
|
82
|
+
const multiSessionRuntimeConfig = getMultiSessionRuntimeConfig();
|
|
83
|
+
const PRIMARY_BAILEYS_SESSION_ID = String(multiSessionRuntimeConfig?.primarySessionId || process.env.BAILEYS_AUTH_SESSION_ID || 'default').trim() || 'default';
|
|
84
|
+
|
|
85
|
+
const normalizeSessionId = (sessionId) => {
|
|
86
|
+
const normalized = String(sessionId || '').trim();
|
|
87
|
+
return normalized || PRIMARY_BAILEYS_SESSION_ID;
|
|
88
|
+
};
|
|
18
89
|
|
|
90
|
+
const sessionSocketMap = new Map();
|
|
19
91
|
let activeSocket = null;
|
|
20
92
|
|
|
21
|
-
|
|
22
|
-
|
|
93
|
+
/**
|
|
94
|
+
* Atualiza a referência global do socket ativo e o registro por sessão.
|
|
95
|
+
* Mantém compatibilidade com chamadas legadas que não informam `sessionId`.
|
|
96
|
+
* @param {BaileysSocket|null} socket Instância conectada ou `null` para limpar.
|
|
97
|
+
* @param {string} [sessionId=PRIMARY_BAILEYS_SESSION_ID] Sessão da conexão.
|
|
98
|
+
* @returns {void}
|
|
99
|
+
*/
|
|
100
|
+
export const setActiveSocket = (socket, sessionId = PRIMARY_BAILEYS_SESSION_ID) => {
|
|
101
|
+
const safeSessionId = normalizeSessionId(sessionId);
|
|
102
|
+
const previousSocket = sessionSocketMap.get(safeSessionId) || null;
|
|
103
|
+
|
|
104
|
+
if (socket) {
|
|
105
|
+
sessionSocketMap.set(safeSessionId, socket);
|
|
106
|
+
} else {
|
|
107
|
+
sessionSocketMap.delete(safeSessionId);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (safeSessionId === PRIMARY_BAILEYS_SESSION_ID) {
|
|
111
|
+
activeSocket = socket || null;
|
|
112
|
+
} else if (!socket && previousSocket && activeSocket === previousSocket) {
|
|
113
|
+
activeSocket = null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (!activeSocket) {
|
|
117
|
+
activeSocket = sessionSocketMap.get(PRIMARY_BAILEYS_SESSION_ID) || sessionSocketMap.values().next()?.value || null;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Atualiza o socket ativo de uma sessão específica.
|
|
123
|
+
* @param {string} sessionId Sessão alvo.
|
|
124
|
+
* @param {BaileysSocket|null} socket Instância conectada ou `null`.
|
|
125
|
+
* @returns {void}
|
|
126
|
+
*/
|
|
127
|
+
export const setSocketBySession = (sessionId, socket) => {
|
|
128
|
+
setActiveSocket(socket, sessionId);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Retorna a instância de socket ativa no processo.
|
|
133
|
+
* @returns {BaileysSocket|null}
|
|
134
|
+
*/
|
|
135
|
+
export const getActiveSocket = () => {
|
|
136
|
+
if (isSocketOpen(activeSocket)) return activeSocket;
|
|
137
|
+
|
|
138
|
+
const primarySocket = sessionSocketMap.get(PRIMARY_BAILEYS_SESSION_ID) || null;
|
|
139
|
+
if (isSocketOpen(primarySocket)) {
|
|
140
|
+
activeSocket = primarySocket;
|
|
141
|
+
return activeSocket;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
for (const socket of sessionSocketMap.values()) {
|
|
145
|
+
if (isSocketOpen(socket)) {
|
|
146
|
+
activeSocket = socket;
|
|
147
|
+
return activeSocket;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
activeSocket = null;
|
|
152
|
+
return activeSocket;
|
|
23
153
|
};
|
|
24
154
|
|
|
25
|
-
|
|
155
|
+
/**
|
|
156
|
+
* Retorna o socket ativo associado a uma sessão.
|
|
157
|
+
* @param {string} [sessionId=PRIMARY_BAILEYS_SESSION_ID]
|
|
158
|
+
* @returns {BaileysSocket|null}
|
|
159
|
+
*/
|
|
160
|
+
export const getSocketBySession = (sessionId = PRIMARY_BAILEYS_SESSION_ID) => {
|
|
161
|
+
const safeSessionId = normalizeSessionId(sessionId);
|
|
162
|
+
return sessionSocketMap.get(safeSessionId) || null;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Snapshot dos sockets ativos por sessão.
|
|
167
|
+
* @returns {Map<string, BaileysSocket>}
|
|
168
|
+
*/
|
|
169
|
+
export const getActiveSocketsBySession = () => new Map(sessionSocketMap);
|
|
26
170
|
|
|
27
171
|
/**
|
|
28
172
|
* Indica se uma instância de socket está aberta para operações.
|
|
29
|
-
* @param {
|
|
173
|
+
* @param {BaileysSocket|null|undefined} socket Instância de socket.
|
|
30
174
|
* @returns {boolean}
|
|
31
175
|
*/
|
|
32
176
|
export const isSocketOpen = (socket) => {
|
|
@@ -43,7 +187,7 @@ export const isActiveSocketOpen = () => isSocketOpen(activeSocket);
|
|
|
43
187
|
|
|
44
188
|
/**
|
|
45
189
|
* Executa um método em uma instância de socket validando disponibilidade.
|
|
46
|
-
* @param {
|
|
190
|
+
* @param {BaileysSocket|null|undefined} socket Instância de socket.
|
|
47
191
|
* @param {string} methodName Nome do método no socket.
|
|
48
192
|
* @param {...any} args Argumentos do método.
|
|
49
193
|
* @returns {Promise<any>}
|
|
@@ -69,9 +213,18 @@ export const runSocketMethod = async (socket, methodName, ...args) => {
|
|
|
69
213
|
*/
|
|
70
214
|
export const runActiveSocketMethod = async (methodName, ...args) => runSocketMethod(activeSocket, methodName, ...args);
|
|
71
215
|
|
|
216
|
+
/**
|
|
217
|
+
* Executa um método no socket de uma sessão específica.
|
|
218
|
+
* @param {string} sessionId Sessão alvo.
|
|
219
|
+
* @param {string} methodName Nome do método no socket.
|
|
220
|
+
* @param {...any} args Argumentos do método.
|
|
221
|
+
* @returns {Promise<any>}
|
|
222
|
+
*/
|
|
223
|
+
export const runSessionSocketMethod = async (sessionId, methodName, ...args) => runSocketMethod(getSocketBySession(sessionId), methodName, ...args);
|
|
224
|
+
|
|
72
225
|
/**
|
|
73
226
|
* Recupera a blocklist da conta conectada.
|
|
74
|
-
* @returns {Promise<
|
|
227
|
+
* @returns {Promise<string[]>}
|
|
75
228
|
*/
|
|
76
229
|
export const fetchBlocklistFromActiveSocket = async () => runActiveSocketMethod('fetchBlocklist');
|
|
77
230
|
|
|
@@ -128,7 +281,8 @@ const decodeJidParts = (() => {
|
|
|
128
281
|
|
|
129
282
|
/**
|
|
130
283
|
* Tipos de mensagem conhecidos do Baileys
|
|
131
|
-
*
|
|
284
|
+
* (mapeamento de chaves do proto.Message para tipos normalizados).
|
|
285
|
+
* @type {Record<string, string>}
|
|
132
286
|
*/
|
|
133
287
|
export const MEDIA_TYPE_MAPPING = {
|
|
134
288
|
conversation: 'text',
|
|
@@ -182,7 +336,8 @@ export const MEDIA_TYPE_MAPPING = {
|
|
|
182
336
|
};
|
|
183
337
|
|
|
184
338
|
/**
|
|
185
|
-
* Tipos de
|
|
339
|
+
* Tipos de mídia que carregam conteúdo binário/arquivo.
|
|
340
|
+
* @type {Set<string>}
|
|
186
341
|
*/
|
|
187
342
|
export const BINARY_MEDIA_TYPES = new Set(['image', 'video', 'videoNote', 'audio', 'voice', 'document', 'sticker']);
|
|
188
343
|
|
|
@@ -521,13 +676,22 @@ export function isWhatsAppJid(jid) {
|
|
|
521
676
|
return Boolean(server && WHATSAPP_USER_JID_SERVERS.has(server));
|
|
522
677
|
}
|
|
523
678
|
|
|
679
|
+
/**
|
|
680
|
+
* Modo de endereçamento por LID.
|
|
681
|
+
* @type {'lid'}
|
|
682
|
+
*/
|
|
524
683
|
export const ADDRESSING_MODE_LID = 'lid';
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* Modo de endereçamento por PN/JID canônico.
|
|
687
|
+
* @type {'pn'}
|
|
688
|
+
*/
|
|
525
689
|
export const ADDRESSING_MODE_PN = 'pn';
|
|
526
690
|
|
|
527
691
|
/**
|
|
528
692
|
* Normaliza um modo de endereçamento (lid/pn).
|
|
529
693
|
* @param {unknown} value
|
|
530
|
-
* @returns {
|
|
694
|
+
* @returns {AddressingMode|undefined}
|
|
531
695
|
*/
|
|
532
696
|
export const normalizeAddressingMode = (value) => {
|
|
533
697
|
if (value === undefined || value === null) return undefined;
|
|
@@ -540,8 +704,8 @@ export const normalizeAddressingMode = (value) => {
|
|
|
540
704
|
/**
|
|
541
705
|
* Resolve modo de endereçamento a partir da chave da mensagem.
|
|
542
706
|
* @param {object} [key={}]
|
|
543
|
-
* @param {
|
|
544
|
-
* @returns {
|
|
707
|
+
* @param {SenderInfo|Record<string, any>} [senderInfo={}]
|
|
708
|
+
* @returns {AddressingMode|undefined}
|
|
545
709
|
*/
|
|
546
710
|
export const resolveAddressingModeFromMessageKey = (key = {}, senderInfo = {}) => {
|
|
547
711
|
const explicit = normalizeAddressingMode(key?.addressingMode);
|
|
@@ -560,7 +724,7 @@ export const resolveAddressingModeFromMessageKey = (key = {}, senderInfo = {}) =
|
|
|
560
724
|
|
|
561
725
|
/**
|
|
562
726
|
* Resolve JID canônico de usuário WhatsApp a partir de candidatos.
|
|
563
|
-
* @param {...string} candidates
|
|
727
|
+
* @param {...(string|null|undefined)} candidates
|
|
564
728
|
* @returns {string}
|
|
565
729
|
*/
|
|
566
730
|
export const resolveCanonicalWhatsAppJid = (...candidates) => {
|
|
@@ -716,7 +880,7 @@ export async function resolveBaileysVersion() {
|
|
|
716
880
|
|
|
717
881
|
/**
|
|
718
882
|
* Baixa a foto de perfil associada à mensagem recebida.
|
|
719
|
-
* @param {
|
|
883
|
+
* @param {BaileysSocket} sock - Instância conectada do socket.
|
|
720
884
|
* @param {import('@whiskeysockets/baileys').proto.IWebMessageInfo} msg - Mensagem usada para resolver o JID.
|
|
721
885
|
* @returns {Promise<Buffer|null>} Buffer da imagem ou `null` se indisponível.
|
|
722
886
|
*/
|
|
@@ -740,17 +904,17 @@ export async function getProfilePicBuffer(sock, msg) {
|
|
|
740
904
|
|
|
741
905
|
/**
|
|
742
906
|
* Extrai o valor de expiração de uma mensagem do WhatsApp, ou retorna 24 horas (em segundos) por padrão.
|
|
743
|
-
* @param {{message?:
|
|
907
|
+
* @param {{message?: Record<string, any>}|null|undefined} messageInfo - Estrutura contendo a propriedade `message`.
|
|
744
908
|
* @returns {number} Tempo de expiração em segundos.
|
|
745
909
|
*/
|
|
746
|
-
export function getExpiration(
|
|
910
|
+
export function getExpiration(messageInfo) {
|
|
747
911
|
const DEFAULT_EXPIRATION_SECONDS = 24 * 60 * 60;
|
|
748
912
|
|
|
749
|
-
if (!
|
|
913
|
+
if (!messageInfo || typeof messageInfo !== 'object' || !messageInfo.message) {
|
|
750
914
|
return DEFAULT_EXPIRATION_SECONDS;
|
|
751
915
|
}
|
|
752
916
|
|
|
753
|
-
const normalizedMessage = normalizeMessage(
|
|
917
|
+
const normalizedMessage = normalizeMessage(messageInfo.message);
|
|
754
918
|
const expiration = findExpiration(normalizedMessage);
|
|
755
919
|
|
|
756
920
|
return typeof expiration === 'number' ? expiration : DEFAULT_EXPIRATION_SECONDS;
|
|
@@ -758,7 +922,7 @@ export function getExpiration(sock) {
|
|
|
758
922
|
|
|
759
923
|
/**
|
|
760
924
|
* Extrai o conteúdo de texto de uma mensagem do WhatsApp.
|
|
761
|
-
* @param {{message?:
|
|
925
|
+
* @param {{message?: Record<string, any>}} messageInfo - Objeto que contém o payload da mensagem.
|
|
762
926
|
* @returns {string} Conteúdo textual extraído ou descrição do tipo de mensagem.
|
|
763
927
|
*/
|
|
764
928
|
export const extractMessageContent = ({ message }) => {
|
|
@@ -810,7 +974,7 @@ export const extractMessageContent = ({ message }) => {
|
|
|
810
974
|
|
|
811
975
|
/**
|
|
812
976
|
* Faz o download de mídia a partir de uma mensagem do Baileys.
|
|
813
|
-
* @param {
|
|
977
|
+
* @param {BaileysProtoMessage} message - Objeto da mídia a ser baixada.
|
|
814
978
|
* @param {string} type - Tipo de mídia (ex.: `image`, `video`, `audio`, `document`).
|
|
815
979
|
* @param {string} outputPath - Diretório onde o arquivo será salvo.
|
|
816
980
|
* @returns {Promise<string|null>} Caminho do arquivo salvo ou `null` em caso de falha.
|
|
@@ -867,10 +1031,10 @@ export const downloadMediaMessage = async (message, type, outputPath) => {
|
|
|
867
1031
|
};
|
|
868
1032
|
|
|
869
1033
|
/**
|
|
870
|
-
* Detecta dinamicamente
|
|
871
|
-
* @param {
|
|
872
|
-
* @param {boolean} isQuoted
|
|
873
|
-
* @returns {
|
|
1034
|
+
* Detecta dinamicamente os tipos de mídia presentes em um payload de mensagem.
|
|
1035
|
+
* @param {Record<string, any>} messageContent Conteúdo da mensagem (normal ou quoted).
|
|
1036
|
+
* @param {boolean} [isQuoted=false] Sinaliza se o payload veio de uma citação.
|
|
1037
|
+
* @returns {MediaEntry[]} Lista de mídias detectadas (pode estar vazia).
|
|
874
1038
|
*/
|
|
875
1039
|
export function detectAllMediaTypes(messageContent, isQuoted = false) {
|
|
876
1040
|
if (!messageContent || typeof messageContent !== 'object') {
|
|
@@ -914,13 +1078,10 @@ export function detectAllMediaTypes(messageContent, isQuoted = false) {
|
|
|
914
1078
|
}
|
|
915
1079
|
|
|
916
1080
|
/**
|
|
917
|
-
* Extrai
|
|
918
|
-
* @param {
|
|
919
|
-
* @param {
|
|
920
|
-
* @
|
|
921
|
-
* @param {boolean} options.includeQuoted - Se deve incluir midia de mensagens citadas
|
|
922
|
-
* @param {boolean} options.includeUnknown - Se deve incluir tipos desconhecidos
|
|
923
|
-
* @returns {{mediaType: string, mediaKey: object, details: object}|null} - Detalhes da midia ou null se nao encontrada
|
|
1081
|
+
* Extrai a mídia primária de uma mensagem com filtros configuráveis.
|
|
1082
|
+
* @param {BaileysMessage|{message?: Record<string, any>}|Record<string, any>} message Objeto da mensagem.
|
|
1083
|
+
* @param {MediaExtractionOptions} [options={}] Opções de filtragem.
|
|
1084
|
+
* @returns {MediaExtractionResult|null} Estrutura da mídia primária ou `null` quando não houver mídia.
|
|
924
1085
|
*/
|
|
925
1086
|
export function extractMediaDetails(message, options = {}) {
|
|
926
1087
|
const { includeAllTypes = false, includeQuoted = true, includeUnknown = false } = options;
|
|
@@ -955,10 +1116,10 @@ export function extractMediaDetails(message, options = {}) {
|
|
|
955
1116
|
}
|
|
956
1117
|
|
|
957
1118
|
/**
|
|
958
|
-
* Extrai
|
|
959
|
-
* @param {
|
|
960
|
-
* @param {
|
|
961
|
-
* @returns {
|
|
1119
|
+
* Extrai todas as mídias detectadas de uma mensagem.
|
|
1120
|
+
* @param {BaileysMessage|{message?: Record<string, any>}|Record<string, any>} message Objeto da mensagem.
|
|
1121
|
+
* @param {MediaExtractionOptions} [options={}] Opções de filtragem.
|
|
1122
|
+
* @returns {MediaEntry[]} Array com todas as mídias encontradas.
|
|
962
1123
|
*/
|
|
963
1124
|
export function extractAllMediaDetails(message, options = {}) {
|
|
964
1125
|
const { includeAllTypes = true, includeQuoted = true, includeUnknown = true } = options;
|
|
@@ -968,10 +1129,10 @@ export function extractAllMediaDetails(message, options = {}) {
|
|
|
968
1129
|
}
|
|
969
1130
|
|
|
970
1131
|
/**
|
|
971
|
-
* Verifica se uma mensagem
|
|
972
|
-
* @param {
|
|
973
|
-
* @param {string} specificType
|
|
974
|
-
* @returns {boolean}
|
|
1132
|
+
* Verifica se uma mensagem contém mídia.
|
|
1133
|
+
* @param {BaileysMessage|{message?: Record<string, any>}|Record<string, any>} message Objeto da mensagem.
|
|
1134
|
+
* @param {string|null} [specificType=null] Tipo específico para filtrar (ex.: `image`).
|
|
1135
|
+
* @returns {boolean} `true` quando ao menos uma mídia compatível é encontrada.
|
|
975
1136
|
*/
|
|
976
1137
|
export function hasMedia(message, specificType = null) {
|
|
977
1138
|
const allMedia = collectMediaFromMessage(message, { includeQuoted: true });
|
|
@@ -989,8 +1150,13 @@ export function hasMedia(message, specificType = null) {
|
|
|
989
1150
|
}
|
|
990
1151
|
|
|
991
1152
|
/**
|
|
992
|
-
*
|
|
993
|
-
* @returns {
|
|
1153
|
+
* Obtém metadados dos tipos de mídia suportados.
|
|
1154
|
+
* @returns {{
|
|
1155
|
+
* knownTypes: string[],
|
|
1156
|
+
* binaryTypes: string[],
|
|
1157
|
+
* typeMapping: Record<string, string>,
|
|
1158
|
+
* totalKnownTypes: number
|
|
1159
|
+
* }}
|
|
994
1160
|
*/
|
|
995
1161
|
export function getMediaTypeInfo() {
|
|
996
1162
|
return {
|
|
@@ -1002,9 +1168,9 @@ export function getMediaTypeInfo() {
|
|
|
1002
1168
|
}
|
|
1003
1169
|
|
|
1004
1170
|
/**
|
|
1005
|
-
*
|
|
1171
|
+
* ===========================
|
|
1006
1172
|
* LID Map Utilities
|
|
1007
|
-
*
|
|
1173
|
+
* ===========================
|
|
1008
1174
|
*/
|
|
1009
1175
|
const CACHE_TTL_MS = 20 * 60 * 1000;
|
|
1010
1176
|
const NEGATIVE_TTL_MS = 5 * 60 * 1000;
|
|
@@ -1015,10 +1181,7 @@ const BACKFILL_SOURCE = 'backfill';
|
|
|
1015
1181
|
const __filename = fileURLToPath(import.meta.url);
|
|
1016
1182
|
const __dirname = path.dirname(__filename);
|
|
1017
1183
|
const BAILEYS_AUTH_DIR = path.resolve(__dirname, '../connection/auth');
|
|
1018
|
-
const BAILEYS_AUTH_SESSION_ID =
|
|
1019
|
-
const raw = String(process.env.BAILEYS_AUTH_SESSION_ID || '').trim();
|
|
1020
|
-
return raw || 'default';
|
|
1021
|
-
})();
|
|
1184
|
+
const BAILEYS_AUTH_SESSION_ID = PRIMARY_BAILEYS_SESSION_ID;
|
|
1022
1185
|
|
|
1023
1186
|
const lidCache = new Map();
|
|
1024
1187
|
const lidWriteBuffer = new Map();
|
|
@@ -1132,7 +1295,7 @@ const maskJid = (jid) => {
|
|
|
1132
1295
|
/**
|
|
1133
1296
|
* Busca entrada do cache (com expiração).
|
|
1134
1297
|
* @param {string|null|undefined} lid
|
|
1135
|
-
* @returns {
|
|
1298
|
+
* @returns {LidCacheEntry|null}
|
|
1136
1299
|
*/
|
|
1137
1300
|
const getCacheEntry = (lid) => {
|
|
1138
1301
|
if (!lid) return null;
|
|
@@ -1194,9 +1357,10 @@ export const getCachedJidForLid = (lid) => {
|
|
|
1194
1357
|
|
|
1195
1358
|
/**
|
|
1196
1359
|
* Divide lista em batches.
|
|
1197
|
-
* @
|
|
1360
|
+
* @template T
|
|
1361
|
+
* @param {T[]} items
|
|
1198
1362
|
* @param {number} [limit=BATCH_LIMIT]
|
|
1199
|
-
* @returns {
|
|
1363
|
+
* @returns {T[][]}
|
|
1200
1364
|
*/
|
|
1201
1365
|
const buildChunks = (items, limit = BATCH_LIMIT) => {
|
|
1202
1366
|
const chunks = [];
|
|
@@ -1326,7 +1490,7 @@ const buildServerLikeFilter = (column, servers) => {
|
|
|
1326
1490
|
/**
|
|
1327
1491
|
* Resolve candidatos principais de identidade de usuário.
|
|
1328
1492
|
* Centraliza regra usada por `resolveUserIdCached` e `resolveUserId`.
|
|
1329
|
-
* @param {
|
|
1493
|
+
* @param {IdentityParams} [params]
|
|
1330
1494
|
* @returns {{directJid: string|null, lidValue: string|null, fallback: string|null}}
|
|
1331
1495
|
*/
|
|
1332
1496
|
const resolveIdentityCandidates = ({ lid, jid, participantAlt } = {}) => {
|
|
@@ -1431,7 +1595,7 @@ export const queueLidUpdate = (lid, jid, source = 'message') => {
|
|
|
1431
1595
|
|
|
1432
1596
|
/**
|
|
1433
1597
|
* Resolve ID canônico usando apenas cache.
|
|
1434
|
-
* @param {
|
|
1598
|
+
* @param {IdentityParams} [params]
|
|
1435
1599
|
* @returns {string|null}
|
|
1436
1600
|
*/
|
|
1437
1601
|
export const resolveUserIdCached = ({ lid, jid, participantAlt } = {}) => {
|
|
@@ -1445,9 +1609,9 @@ export const resolveUserIdCached = ({ lid, jid, participantAlt } = {}) => {
|
|
|
1445
1609
|
};
|
|
1446
1610
|
|
|
1447
1611
|
/**
|
|
1448
|
-
* Extrai
|
|
1449
|
-
* @param {
|
|
1450
|
-
* @returns {
|
|
1612
|
+
* Extrai informações de identidade do remetente a partir da mensagem.
|
|
1613
|
+
* @param {BaileysMessage} msg
|
|
1614
|
+
* @returns {SenderInfo}
|
|
1451
1615
|
*/
|
|
1452
1616
|
export const extractSenderInfoFromMessage = (msg) => {
|
|
1453
1617
|
const remoteJid = normalizeJid(msg?.key?.remoteJid || '') || null;
|
|
@@ -1556,7 +1720,7 @@ const fetchJidByLid = async (lid) => {
|
|
|
1556
1720
|
|
|
1557
1721
|
/**
|
|
1558
1722
|
* Resolve ID canônico consultando banco se necessário.
|
|
1559
|
-
* @param {
|
|
1723
|
+
* @param {IdentityParams} [params]
|
|
1560
1724
|
* @returns {Promise<string|null>}
|
|
1561
1725
|
*/
|
|
1562
1726
|
export const resolveUserId = async ({ lid, jid, participantAlt } = {}) => {
|
|
@@ -1669,6 +1833,13 @@ export const flushLidQueue = async () => {
|
|
|
1669
1833
|
await lidFlushRunner.run();
|
|
1670
1834
|
};
|
|
1671
1835
|
|
|
1836
|
+
/**
|
|
1837
|
+
* Enfileira atualização de mapa LID/JID e retorna estado simplificado.
|
|
1838
|
+
* @param {string} lid
|
|
1839
|
+
* @param {string|null} jid
|
|
1840
|
+
* @param {string} [source='message']
|
|
1841
|
+
* @returns {Promise<{stored: boolean, reconciled: boolean}>}
|
|
1842
|
+
*/
|
|
1672
1843
|
export const maybeStoreLidMap = async (lid, jid, source = 'message') => {
|
|
1673
1844
|
const result = queueLidUpdate(lid, jid, source);
|
|
1674
1845
|
return { stored: result.queued, reconciled: result.reconciled };
|
|
@@ -288,6 +288,7 @@ export async function getGroupInfoAsync(groupId) {
|
|
|
288
288
|
const participants = parseParticipantsFromDb(data.participants || data.participants_json || null);
|
|
289
289
|
const creation = _normalizeNumberOrNull(data.creation);
|
|
290
290
|
const ephemeralDuration = _normalizeNumberOrNull(data.ephemeral_duration ?? data.ephemeralDuration);
|
|
291
|
+
const linkedParent = _normalizeGroupId(data.linked_parent_jid || data.linkedParent) || null;
|
|
291
292
|
|
|
292
293
|
const group = {
|
|
293
294
|
id: _normalizeGroupId(data.id) || normalizedGroupId,
|
|
@@ -299,6 +300,10 @@ export async function getGroupInfoAsync(groupId) {
|
|
|
299
300
|
restrict: Boolean(data.restrict),
|
|
300
301
|
announce: Boolean(data.announce),
|
|
301
302
|
isCommunity: Boolean(data.is_community ?? data.isCommunity),
|
|
303
|
+
isCommunityAnnounce: Boolean(data.is_community_announce ?? data.isCommunityAnnounce),
|
|
304
|
+
linkedParent,
|
|
305
|
+
memberAddMode: data.member_add_mode === null || data.member_add_mode === undefined ? null : Boolean(data.member_add_mode),
|
|
306
|
+
joinApprovalMode: data.join_approval_mode === null || data.join_approval_mode === undefined ? null : Boolean(data.join_approval_mode),
|
|
302
307
|
addressingMode: data.addressing_mode || data.addressingMode || null,
|
|
303
308
|
ephemeralDuration,
|
|
304
309
|
};
|