@fer2809fl/baileys 1.4.7 → 1.4.9

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.
@@ -131,34 +131,45 @@ const addTransactionCapability = (state, logger, { maxCommitRetries, delayBetwee
131
131
  if (transactionsInProgress === 1) {
132
132
  logger.trace('entering transaction');
133
133
  }
134
+
134
135
  try {
135
136
  result = await work();
137
+
136
138
  // commit if this is the outermost transaction
137
139
  if (transactionsInProgress === 1) {
138
140
  if (Object.keys(mutations).length) {
139
141
  logger.trace('committing transaction');
140
- // retry mechanism to ensure we've some recovery
141
- // in case a transaction fails in the first attempt
142
+
143
+ // 🔧 REPARADO: Retry mechanism con backoff exponencial
142
144
  let tries = maxCommitRetries;
143
- while (tries) {
145
+ let delayMs = delayBetweenTriesMs;
146
+
147
+ while (tries > 0) {
144
148
  tries -= 1;
145
149
  try {
146
150
  await state.set(mutations);
147
151
  logger.trace({ dbQueriesInTransaction }, 'committed transaction');
148
152
  break;
149
- }
150
- catch (error) {
151
- logger.warn(`failed to commit ${Object.keys(mutations).length} mutations, tries left=${tries}`);
152
- await (0, generics_1.delay)(delayBetweenTriesMs);
153
+ } catch (error) {
154
+ if (tries === 0) {
155
+ logger.error({ error }, `CRITICAL: Failed to commit after ${maxCommitRetries} retries`);
156
+ // No propagar error - evita crash del bot
157
+ break;
158
+ }
159
+
160
+ logger.warn(`Commit failed, retries left=${tries}, waiting ${delayMs}ms`);
161
+ await (0, generics_1.delay)(delayMs);
162
+ delayMs = Math.min(delayMs * 2, 30000); // Exponential backoff, max 30s
153
163
  }
154
164
  }
155
- }
156
- else {
165
+ } else {
157
166
  logger.trace('no mutations in transaction');
158
167
  }
159
168
  }
160
- }
161
- finally {
169
+ } catch (workError) {
170
+ logger.error({ workError }, 'Error in transaction work');
171
+ throw workError;
172
+ } finally {
162
173
  transactionsInProgress -= 1;
163
174
  if (transactionsInProgress === 0) {
164
175
  transactionCache = {};
@@ -166,6 +177,7 @@ const addTransactionCapability = (state, logger, { maxCommitRetries, delayBetwee
166
177
  dbQueriesInTransaction = 0;
167
178
  }
168
179
  }
180
+
169
181
  return result;
170
182
  }
171
183
  };
@@ -0,0 +1,151 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleButtonResponse = handleButtonResponse;
4
+ exports.setupButtonHandler = setupButtonHandler;
5
+
6
+ /**
7
+ * Maneja las respuestas de botones y las convierte en comandos ejecutables
8
+ */
9
+ async function handleButtonResponse(sock, m, plugins, db) {
10
+
11
+ // ========== DETECTAR SOLO BOTONES ==========
12
+ let seleccion = null
13
+ let tipoBoton = null
14
+
15
+ // Botón tipo quick_reply (interactive)
16
+ if (m.mtype === 'interactiveResponseMessage') {
17
+ const resp = m.message?.interactiveResponseMessage?.nativeFlowResponseMessage
18
+ if (resp?.name === 'quick_reply') {
19
+ seleccion = resp.id
20
+ tipoBoton = 'quick_reply'
21
+ }
22
+ }
23
+
24
+ // Botón tipo buttonsResponse (estilo antiguo)
25
+ if (m.mtype === 'buttonsResponseMessage') {
26
+ seleccion = m.message?.buttonsResponseMessage?.selectedButtonId
27
+ tipoBoton = 'buttonsResponse'
28
+ }
29
+
30
+ // Lista desplegable
31
+ if (m.mtype === 'listResponseMessage') {
32
+ seleccion = m.message?.listResponseMessage?.singleSelectReply?.selectedRowId
33
+ tipoBoton = 'listResponse'
34
+ }
35
+
36
+ // Si no es botón, salir
37
+ if (!seleccion) return false
38
+
39
+ console.log(`[Baileys] Botón detectado [${tipoBoton}]:`, seleccion)
40
+
41
+ // Limpiar el ID del botón
42
+ let cmd = seleccion.toString().toLowerCase().replace(/^[.#!/]/, '').trim()
43
+
44
+ // ========== BUSCAR PLUGIN ==========
45
+ let pluginFound = null
46
+
47
+ for (let name in plugins) {
48
+ let plugin = plugins[name]
49
+ if (!plugin || !plugin.command) continue
50
+
51
+ let commands = Array.isArray(plugin.command) ? plugin.command : [plugin.command]
52
+
53
+ const isMatch = commands.some(c => {
54
+ if (c instanceof RegExp) return c.test(cmd)
55
+ return c.toString().toLowerCase() === cmd
56
+ })
57
+
58
+ if (isMatch) {
59
+ pluginFound = plugin
60
+ break
61
+ }
62
+ }
63
+
64
+ if (!pluginFound) {
65
+ console.log(`[Baileys] No se encontró plugin para: ${cmd}`)
66
+ await sock.sendMessage(m.chat, {
67
+ text: `❌ *Comando no encontrado*\n\nEl botón "${seleccion}" no tiene un comando asociado.`
68
+ }, { quoted: m })
69
+ return true
70
+ }
71
+
72
+ // ========== OBTENER PERMISOS ==========
73
+ const groupMetadata = m.isGroup ? await sock.groupMetadata(m.chat).catch(() => null) || {} : {}
74
+ const participants = groupMetadata?.participants || []
75
+
76
+ const isAdmin = m.isGroup ? participants.find(p => p.id === m.sender)?.admin === 'admin' || participants.find(p => p.id === m.sender)?.admin === 'superadmin' : false
77
+ const isBotAdmin = m.isGroup ? participants.find(p => p.id === sock.user.id)?.admin === 'admin' || participants.find(p => p.id === sock.user.id)?.admin === 'superadmin' : false
78
+ const isOwner = [...global.owner || []].map(v => v + "@s.whatsapp.net").includes(m.sender)
79
+
80
+ // ========== VALIDAR PERMISOS ==========
81
+ if (pluginFound.rowner && !isOwner) {
82
+ await sock.sendMessage(m.chat, { text: `🔒 *Acceso denegado*\n\nEste comando es solo para los creadores del bot.` }, { quoted: m })
83
+ return true
84
+ }
85
+
86
+ if (pluginFound.owner && !isOwner) {
87
+ await sock.sendMessage(m.chat, { text: `🔒 *Acceso denegado*\n\nEste comando es solo para el owner del bot.` }, { quoted: m })
88
+ return true
89
+ }
90
+
91
+ if (pluginFound.admin && !isAdmin) {
92
+ await sock.sendMessage(m.chat, { text: `⚠️ *Permiso denegado*\n\nEste comando solo puede ser usado por administradores del grupo.` }, { quoted: m })
93
+ return true
94
+ }
95
+
96
+ if (pluginFound.botAdmin && !isBotAdmin) {
97
+ await sock.sendMessage(m.chat, { text: `🤖 *Bot sin permisos*\n\nNecesito ser administrador del grupo para ejecutar este comando.` }, { quoted: m })
98
+ return true
99
+ }
100
+
101
+ if (pluginFound.group && !m.isGroup) {
102
+ await sock.sendMessage(m.chat, { text: `👥 *Solo grupos*\n\nEste comando solo puede usarse en grupos.` }, { quoted: m })
103
+ return true
104
+ }
105
+
106
+ if (pluginFound.private && m.isGroup) {
107
+ await sock.sendMessage(m.chat, { text: `🔒 *Solo privado*\n\nEste comando solo puede usarse en chat privado.` }, { quoted: m })
108
+ return true
109
+ }
110
+
111
+ // ========== EJECUTAR PLUGIN ==========
112
+ try {
113
+ await pluginFound.call(sock, m, {
114
+ conn: sock,
115
+ usedPrefix: '',
116
+ command: cmd,
117
+ args: [],
118
+ text: '',
119
+ participants,
120
+ groupMetadata,
121
+ isAdmin,
122
+ isBotAdmin,
123
+ isOwner,
124
+ db
125
+ })
126
+ console.log(`[Baileys] Plugin ejecutado: ${cmd}`)
127
+ } catch (error) {
128
+ console.error(`[Baileys] Error:`, error)
129
+ await sock.sendMessage(m.chat, { text: `❌ *Error al ejecutar el comando*\n\n${error.message || error}` }, { quoted: m })
130
+ }
131
+
132
+ return true
133
+ }
134
+
135
+ /**
136
+ * Configura el handler de botones en el socket
137
+ */
138
+ function setupButtonHandler(sock, plugins, db) {
139
+ const originalHandler = sock.ev.listeners('messages.upsert')[0]
140
+
141
+ sock.ev.off('messages.upsert', originalHandler)
142
+
143
+ sock.ev.on('messages.upsert', async ({ messages }) => {
144
+ for (const m of messages) {
145
+ const fueBoton = await handleButtonResponse(sock, m, plugins, db)
146
+ if (!fueBoton && originalHandler) {
147
+ await originalHandler({ messages: [m] })
148
+ }
149
+ }
150
+ })
151
+ }
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.safeDecrypt = safeDecrypt;
4
+ exports.silenceBadMacErrors = silenceBadMacErrors;
5
+
6
+ /**
7
+ * Envuelve una función para capturar y silenciar errores Bad MAC
8
+ */
9
+ function safeDecrypt(fn) {
10
+ return async (...args) => {
11
+ try {
12
+ return await fn(...args);
13
+ } catch (error) {
14
+ if (error.message && error.message.includes('Bad MAC')) {
15
+ console.log('[Baileys] 🔇 Bad MAC silenciado');
16
+ return null;
17
+ }
18
+ throw error;
19
+ }
20
+ };
21
+ }
22
+
23
+ /**
24
+ * Parchea los métodos de libsignal para no mostrar errores Bad MAC
25
+ */
26
+ function silenceBadMacErrors() {
27
+ const originalConsoleError = console.error;
28
+ console.error = (...args) => {
29
+ const message = args.join(' ');
30
+ if (message.includes('Bad MAC') ||
31
+ message.includes('Failed to decrypt') ||
32
+ message.includes('No session found')) {
33
+ return; // No mostrar
34
+ }
35
+ originalConsoleError(...args);
36
+ };
37
+ }
@@ -15,3 +15,4 @@ export * from './use-multi-file-auth-state';
15
15
  export * from './link-preview';
16
16
  export * from './event-buffer';
17
17
  export * from './process-message';
18
+ export * from './interactive';
@@ -31,3 +31,4 @@ __exportStar(require("./use-multi-file-auth-state"), exports);
31
31
  __exportStar(require("./link-preview"), exports);
32
32
  __exportStar(require("./event-buffer"), exports);
33
33
  __exportStar(require("./process-message"), exports);
34
+ __exportStar(require("./interactive"), exports);
@@ -0,0 +1,254 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sendInteractiveMessage = exports.sendListMenu = exports.sendCallButton = exports.sendQuickReplyButtons = exports.sendUrlButton = exports.sendCopyButton = void 0;
4
+
5
+ /**
6
+ * Envía un mensaje con botón que copia texto al portapapeles
7
+ */
8
+ async function sendCopyButton(sock, jid, text, copyText, buttonText) {
9
+ try {
10
+ await sock.sendMessage(jid, {
11
+ interactiveMessage: {
12
+ body: { text: text },
13
+ footer: { text: '⚡ Asta-Bot' },
14
+ header: {
15
+ title: '📋 Copiar Código',
16
+ hasMediaAttachment: false
17
+ },
18
+ nativeFlowMessage: {
19
+ buttons: [{
20
+ name: 'cta_copy',
21
+ buttonParamsJson: JSON.stringify({
22
+ display_text: buttonText || '📋 Copiar',
23
+ copy_code: copyText
24
+ })
25
+ }]
26
+ }
27
+ }
28
+ });
29
+ } catch (error) {
30
+ console.error('[interactive] Error en sendCopyButton:', error);
31
+ await sock.sendMessage(jid, { text: `${text}\n\n📋 Copia esto: ${copyText}` });
32
+ }
33
+ }
34
+ exports.sendCopyButton = sendCopyButton;
35
+
36
+ /**
37
+ * Envía un mensaje con botón de enlace (URL)
38
+ */
39
+ async function sendUrlButton(sock, jid, text, url, buttonText) {
40
+ try {
41
+ await sock.sendMessage(jid, {
42
+ interactiveMessage: {
43
+ body: { text: text },
44
+ footer: { text: '⚡ Asta-Bot' },
45
+ header: {
46
+ title: '🔗 Enlace Rápido',
47
+ hasMediaAttachment: false
48
+ },
49
+ nativeFlowMessage: {
50
+ buttons: [{
51
+ name: 'cta_url',
52
+ buttonParamsJson: JSON.stringify({
53
+ display_text: buttonText || '🔗 Abrir Enlace',
54
+ url: url,
55
+ merchant_url: url
56
+ })
57
+ }]
58
+ }
59
+ }
60
+ });
61
+ } catch (error) {
62
+ console.error('[interactive] Error en sendUrlButton:', error);
63
+ await sock.sendMessage(jid, { text: `${text}\n\n🔗 Enlace: ${url}` });
64
+ }
65
+ }
66
+ exports.sendUrlButton = sendUrlButton;
67
+
68
+ /**
69
+ * Envía un mensaje con botones de respuesta rápida
70
+ */
71
+ async function sendQuickReplyButtons(sock, jid, text, buttons) {
72
+ try {
73
+ const interactiveButtons = buttons.map(btn => ({
74
+ name: 'quick_reply',
75
+ buttonParamsJson: JSON.stringify({
76
+ display_text: btn.text,
77
+ id: btn.id
78
+ })
79
+ }));
80
+
81
+ await sock.sendMessage(jid, {
82
+ interactiveMessage: {
83
+ body: { text: text },
84
+ footer: { text: '⚡ Asta-Bot - Selecciona una opción' },
85
+ header: {
86
+ hasMediaAttachment: false
87
+ },
88
+ nativeFlowMessage: {
89
+ buttons: interactiveButtons
90
+ }
91
+ }
92
+ });
93
+ } catch (error) {
94
+ console.error('[interactive] Error en sendQuickReplyButtons:', error);
95
+ const buttonsText = buttons.map(b => `• ${b.text} → ${b.id}`).join('\n');
96
+ await sock.sendMessage(jid, { text: `${text}\n\n${buttonsText}` });
97
+ }
98
+ }
99
+ exports.sendQuickReplyButtons = sendQuickReplyButtons;
100
+
101
+ /**
102
+ * Envía un mensaje con botón de llamada telefónica
103
+ */
104
+ async function sendCallButton(sock, jid, text, phoneNumber, buttonText) {
105
+ try {
106
+ await sock.sendMessage(jid, {
107
+ interactiveMessage: {
108
+ body: { text: text },
109
+ footer: { text: '⚡ Asta-Bot' },
110
+ header: {
111
+ title: '📞 Llamar',
112
+ hasMediaAttachment: false
113
+ },
114
+ nativeFlowMessage: {
115
+ buttons: [{
116
+ name: 'cta_call',
117
+ buttonParamsJson: JSON.stringify({
118
+ display_text: buttonText || '📞 Llamar Ahora',
119
+ phone_number: phoneNumber
120
+ })
121
+ }]
122
+ }
123
+ }
124
+ });
125
+ } catch (error) {
126
+ console.error('[interactive] Error en sendCallButton:', error);
127
+ await sock.sendMessage(jid, { text: `${text}\n\n📞 Llama a: ${phoneNumber}` });
128
+ }
129
+ }
130
+ exports.sendCallButton = sendCallButton;
131
+
132
+ /**
133
+ * Envía un mensaje con lista desplegable (single select)
134
+ */
135
+ async function sendListMenu(sock, jid, text, title, sections) {
136
+ try {
137
+ // Formatear secciones correctamente
138
+ const formattedSections = sections.map(section => ({
139
+ title: section.title,
140
+ rows: section.rows.map(row => ({
141
+ header: row.header || '',
142
+ title: row.title,
143
+ description: row.description || '',
144
+ id: row.id
145
+ }))
146
+ }));
147
+
148
+ await sock.sendMessage(jid, {
149
+ interactiveMessage: {
150
+ body: { text: text },
151
+ footer: { text: '⚡ Asta-Bot - Menú Interactivo' },
152
+ header: {
153
+ title: title || '📋 Menú de Opciones',
154
+ hasMediaAttachment: false
155
+ },
156
+ nativeFlowMessage: {
157
+ buttons: [{
158
+ name: 'single_select',
159
+ buttonParamsJson: JSON.stringify({
160
+ title: '📋 Ver opciones',
161
+ sections: formattedSections
162
+ })
163
+ }]
164
+ }
165
+ }
166
+ });
167
+ } catch (error) {
168
+ console.error('[interactive] Error en sendListMenu:', error);
169
+ let fallbackText = `${text}\n\n`;
170
+ sections.forEach(sec => {
171
+ fallbackText += `\n*${sec.title}*\n`;
172
+ sec.rows.forEach(row => {
173
+ fallbackText += `• ${row.id} - ${row.title}\n`;
174
+ });
175
+ });
176
+ await sock.sendMessage(jid, { text: fallbackText });
177
+ }
178
+ }
179
+ exports.sendListMenu = sendListMenu;
180
+
181
+ /**
182
+ * Envía un mensaje con múltiples botones combinados
183
+ */
184
+ async function sendInteractiveMessage(sock, jid, text, buttonsConfig) {
185
+ try {
186
+ const buttons = buttonsConfig.map(btn => {
187
+ let buttonParams = {};
188
+
189
+ switch (btn.type) {
190
+ case 'copy':
191
+ buttonParams = {
192
+ name: 'cta_copy',
193
+ buttonParamsJson: JSON.stringify({
194
+ display_text: btn.text,
195
+ copy_code: btn.value
196
+ })
197
+ };
198
+ break;
199
+ case 'url':
200
+ buttonParams = {
201
+ name: 'cta_url',
202
+ buttonParamsJson: JSON.stringify({
203
+ display_text: btn.text,
204
+ url: btn.value,
205
+ merchant_url: btn.value
206
+ })
207
+ };
208
+ break;
209
+ case 'call':
210
+ buttonParams = {
211
+ name: 'cta_call',
212
+ buttonParamsJson: JSON.stringify({
213
+ display_text: btn.text,
214
+ phone_number: btn.value
215
+ })
216
+ };
217
+ break;
218
+ case 'quick':
219
+ buttonParams = {
220
+ name: 'quick_reply',
221
+ buttonParamsJson: JSON.stringify({
222
+ display_text: btn.text,
223
+ id: btn.id || btn.value
224
+ })
225
+ };
226
+ break;
227
+ default:
228
+ buttonParams = {
229
+ name: 'quick_reply',
230
+ buttonParamsJson: JSON.stringify({
231
+ display_text: btn.text,
232
+ id: btn.id || btn.value
233
+ })
234
+ };
235
+ }
236
+ return buttonParams;
237
+ });
238
+
239
+ await sock.sendMessage(jid, {
240
+ interactiveMessage: {
241
+ body: { text: text },
242
+ footer: { text: '⚡ Asta-Bot' },
243
+ header: {
244
+ hasMediaAttachment: false
245
+ },
246
+ nativeFlowMessage: { buttons }
247
+ }
248
+ });
249
+ } catch (error) {
250
+ console.error('[interactive] Error en sendInteractiveMessage:', error);
251
+ await sock.sendMessage(jid, { text: text });
252
+ }
253
+ }
254
+ exports.sendInteractiveMessage = sendInteractiveMessage;
@@ -104,9 +104,9 @@ const prepareWAMessageMedia = async (message, options) => {
104
104
  }
105
105
  ],
106
106
  newsletter: {
107
- newsletterJid: "120363403176894973@newsletter",
107
+ newsletterJid: "120363399175402285@newsletter",
108
108
  serverMessageId: 0,
109
- newsletterName: "Delta",
109
+ newsletterName: "Asta",
110
110
  contentType: "UPDATE",
111
111
  }
112
112
  }
@@ -98,19 +98,31 @@ exports.getChatId = getChatId;
98
98
  * @param ctx additional info about the poll required for decryption
99
99
  * @returns list of SHA256 options
100
100
  */
101
+ // 🔧 REPARADO: Agregado try-catch completo
101
102
  function decryptPollVote({ encPayload, encIv }, { pollCreatorJid, pollMsgId, pollEncKey, voterJid, }) {
102
- const sign = Buffer.concat([
103
- toBinary(pollMsgId),
104
- toBinary(pollCreatorJid),
105
- toBinary(voterJid),
106
- toBinary('Poll Vote'),
107
- new Uint8Array([1])
108
- ]);
109
- const key0 = (0, crypto_1.hmacSign)(pollEncKey, new Uint8Array(32), 'sha256');
110
- const decKey = (0, crypto_1.hmacSign)(sign, key0, 'sha256');
111
- const aad = toBinary(`${pollMsgId}\u0000${voterJid}`);
112
- const decrypted = (0, crypto_1.aesDecryptGCM)(encPayload, decKey, encIv, aad);
113
- return WAProto_1.proto.Message.PollVoteMessage.decode(decrypted);
103
+ try {
104
+ // Validar que tenemos todos los datos necesarios
105
+ if (!encPayload || !encIv || !pollEncKey) {
106
+ return null;
107
+ }
108
+
109
+ const sign = Buffer.concat([
110
+ toBinary(pollMsgId),
111
+ toBinary(pollCreatorJid),
112
+ toBinary(voterJid),
113
+ toBinary('Poll Vote'),
114
+ new Uint8Array([1])
115
+ ]);
116
+ const key0 = (0, crypto_1.hmacSign)(pollEncKey, new Uint8Array(32), 'sha256');
117
+ const decKey = (0, crypto_1.hmacSign)(sign, key0, 'sha256');
118
+ const aad = toBinary(`${pollMsgId}\u0000${voterJid}`);
119
+ const decrypted = (0, crypto_1.aesDecryptGCM)(encPayload, decKey, encIv, aad);
120
+ return WAProto_1.proto.Message.PollVoteMessage.decode(decrypted);
121
+ } catch (err) {
122
+ // Silenciar errores de desencriptación de polls - no son críticos
123
+ return null;
124
+ }
125
+
114
126
  function toBinary(txt) {
115
127
  return Buffer.from(txt);
116
128
  }
@@ -367,6 +379,8 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
367
379
  const pollCreatorJid = (0, generics_1.getKeyAuthor)(creationMsgKey, meIdNormalised);
368
380
  const voterJid = (0, generics_1.getKeyAuthor)(message.key, meIdNormalised);
369
381
  const pollEncKey = (_s = pollMsg.messageContextInfo) === null || _s === void 0 ? void 0 : _s.messageSecret;
382
+
383
+ // 🔧 REPARADO: Manejo seguro de decryptPollVote
370
384
  try {
371
385
  const voteMsg = decryptPollVote(content.pollUpdateMessage.vote, {
372
386
  pollEncKey,
@@ -374,20 +388,24 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
374
388
  pollMsgId: creationMsgKey.id,
375
389
  voterJid,
376
390
  });
377
- ev.emit('messages.update', [
378
- {
379
- key: creationMsgKey,
380
- update: {
381
- pollUpdates: [
382
- {
383
- pollUpdateMessageKey: message.key,
384
- vote: voteMsg,
385
- senderTimestampMs: content.pollUpdateMessage.senderTimestampMs.toNumber(),
386
- }
387
- ]
391
+
392
+ // Solo emitir si se desencriptó correctamente
393
+ if (voteMsg) {
394
+ ev.emit('messages.update', [
395
+ {
396
+ key: creationMsgKey,
397
+ update: {
398
+ pollUpdates: [
399
+ {
400
+ pollUpdateMessageKey: message.key,
401
+ vote: voteMsg,
402
+ senderTimestampMs: content.pollUpdateMessage.senderTimestampMs.toNumber(),
403
+ }
404
+ ]
405
+ }
388
406
  }
389
- }
390
- ]);
407
+ ]);
408
+ }
391
409
  }
392
410
  catch (err) {
393
411
  logger === null || logger === void 0 ? void 0 : logger.warn({ err, creationMsgKey }, 'failed to decrypt poll vote');