@kaikybrofc/omnizap-system 2.3.2 → 2.3.4

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.
Files changed (40) hide show
  1. package/README.md +82 -487
  2. package/app/modules/stickerModule/stickerCommand.js +7 -2
  3. package/app/modules/stickerModule/stickerTextCommand.js +7 -2
  4. package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +224 -53
  5. package/app/services/lidMapService.js +83 -4
  6. package/package.json +1 -1
  7. package/public/api-docs/index.html +3 -2
  8. package/public/apple-touch-icon.png +0 -0
  9. package/public/bot-whatsapp-para-grupo/index.html +3 -1
  10. package/public/bot-whatsapp-sem-programar/index.html +3 -1
  11. package/public/comandos/index.html +3 -2
  12. package/public/como-automatizar-avisos-no-whatsapp/index.html +3 -1
  13. package/public/como-criar-comandos-whatsapp/index.html +3 -1
  14. package/public/como-evitar-spam-no-whatsapp/index.html +3 -1
  15. package/public/como-moderar-grupo-whatsapp/index.html +3 -1
  16. package/public/como-organizar-comunidade-whatsapp/index.html +3 -1
  17. package/public/favicon-16x16.png +0 -0
  18. package/public/favicon-32x32.png +0 -0
  19. package/public/favicon.ico +0 -0
  20. package/public/index.html +3 -2
  21. package/public/js/apps/createPackApp.js +4 -4
  22. package/public/js/apps/homeApp.js +4 -5
  23. package/public/js/apps/loginApp.js +83 -28
  24. package/public/js/apps/stickersAdminApp.js +1 -1
  25. package/public/js/apps/stickersApp.js +1 -1
  26. package/public/js/apps/userApp.js +8 -37
  27. package/public/licenca/index.html +3 -2
  28. package/public/login/index.html +20 -12
  29. package/public/melhor-bot-whatsapp-para-grupos/index.html +3 -1
  30. package/public/site.webmanifest +24 -0
  31. package/public/stickers/create/index.html +3 -1
  32. package/public/stickers/index.html +3 -1
  33. package/public/termos-de-uso/index.html +3 -2
  34. package/public/user/index.html +3 -2
  35. package/public/user/systemadm/index.html +3 -1
  36. package/server/controllers/stickerCatalog/nonCatalogHandlers.js +1 -26
  37. package/server/controllers/stickerCatalogController.js +161 -63
  38. package/server/middleware/cachePolicyHelpers.js +1 -2
  39. package/server/middleware/rateLimit.js +9 -2
  40. package/server/routes/indexRouter.js +1 -7
@@ -1,11 +1,14 @@
1
1
  import logger from '../../utils/logger/loggerModule.js';
2
2
  import { sendAndStore } from '../../services/messagePersistenceService.js';
3
- import { isUserJid } from '../../config/baileysConfig.js';
3
+ import { getJidServer, isUserJid, normalizeJid } from '../../config/baileysConfig.js';
4
4
  import stickerPackService from './stickerPackServiceRuntime.js';
5
5
  import { STICKER_PACK_ERROR_CODES, StickerPackError } from './stickerPackErrors.js';
6
6
  import { captureIncomingStickerAsset, resolveStickerAssetForCommand } from './stickerStorageService.js';
7
7
  import { buildStickerPackMessage, sendStickerPackWithFallback } from './stickerPackMessageService.js';
8
8
  import { sanitizeText } from './stickerPackUtils.js';
9
+ import { executeQuery, TABLES } from '../../../database/index.js';
10
+ import { extractSenderInfoFromMessage, extractUserIdInfo, resolveUserId } from '../../services/lidMapService.js';
11
+ import { toWhatsAppPhoneDigits } from '../../services/whatsappLoginLinkService.js';
9
12
 
10
13
  /**
11
14
  * Handlers de comando textual para gerenciamento de packs de figurinha.
@@ -14,6 +17,7 @@ const RATE_WINDOW_MS = Math.max(10_000, Number(process.env.STICKER_PACK_RATE_WIN
14
17
  const RATE_MAX_ACTIONS = Math.max(1, Number(process.env.STICKER_PACK_RATE_MAX_ACTIONS) || 20);
15
18
  const MAX_PACK_ITEMS = Math.max(1, Number(process.env.STICKER_PACK_MAX_ITEMS) || 30);
16
19
  const MAX_PACK_NAME_LENGTH = 120;
20
+ const LID_SERVERS = new Set(['lid', 'hosted.lid']);
17
21
 
18
22
  const rateMap = new Map();
19
23
 
@@ -159,20 +163,23 @@ const formatVisibilityLabel = (visibility) => {
159
163
  };
160
164
 
161
165
  /**
162
- * Detecta packs automáticos para ocultar em listagens do usuário.
166
+ * Detecta packs automáticos de curadoria temática para ocultar em listagens padrão.
167
+ * Mantém visível o auto-pack coletor do usuário (ex.: "minhasfigurinhas1").
163
168
  *
164
169
  * @param {object|null|undefined} pack Pack retornado pelo serviço.
165
- * @returns {boolean} Verdadeiro quando o pack é automático.
170
+ * @returns {boolean} Verdadeiro quando for auto-pack temático/curadoria.
166
171
  */
167
- const isAutomaticPack = (pack) => {
172
+ const isThemeCurationPack = (pack) => {
168
173
  if (!pack || typeof pack !== 'object') return false;
169
- if (pack.is_auto_pack === true || Number(pack.is_auto_pack || 0) === 1) return true;
170
174
 
171
175
  const name = String(pack.name || '').trim();
172
176
  if (/^\[auto\]/i.test(name)) return true;
173
177
 
174
178
  const description = String(pack.description || '').toLowerCase();
175
- return description.includes('[auto-theme:') || description.includes('[auto-tag:');
179
+ if (description.includes('[auto-theme:') || description.includes('[auto-tag:')) return true;
180
+
181
+ const themeKey = String(pack.pack_theme_key || '').trim();
182
+ return Boolean(themeKey);
176
183
  };
177
184
 
178
185
  /**
@@ -448,6 +455,142 @@ const readSingleArgument = (input) => {
448
455
  return value ? value : null;
449
456
  };
450
457
 
458
+ const buildOwnerLookupJids = (value) => {
459
+ const normalized = normalizeJid(value) || '';
460
+ if (!normalized || !normalized.includes('@')) return [];
461
+ const lookup = new Set([normalized]);
462
+ const digits = toWhatsAppPhoneDigits(normalized);
463
+ if (!digits) return Array.from(lookup);
464
+ lookup.add(normalizeJid(`${digits}@s.whatsapp.net`) || '');
465
+ lookup.add(normalizeJid(`${digits}@c.us`) || '');
466
+ lookup.add(normalizeJid(`${digits}@hosted`) || '');
467
+ return Array.from(lookup).filter(Boolean);
468
+ };
469
+
470
+ const appendOwnerCandidate = (candidateSet, lookupSet, value) => {
471
+ const normalized = normalizeJid(value) || '';
472
+ if (!normalized || !normalized.includes('@')) return;
473
+ candidateSet.add(normalized);
474
+ for (const lookupJid of buildOwnerLookupJids(normalized)) {
475
+ lookupSet.add(lookupJid);
476
+ }
477
+ };
478
+
479
+ const dedupePacksById = (packs = []) => {
480
+ const dedup = new Map();
481
+ for (const pack of Array.isArray(packs) ? packs : []) {
482
+ if (!pack?.id) continue;
483
+ const existing = dedup.get(pack.id);
484
+ if (!existing) {
485
+ dedup.set(pack.id, pack);
486
+ continue;
487
+ }
488
+ const currentUpdatedAt = Date.parse(String(pack.updated_at || pack.created_at || ''));
489
+ const existingUpdatedAt = Date.parse(String(existing.updated_at || existing.created_at || ''));
490
+ if (Number.isFinite(currentUpdatedAt) && (!Number.isFinite(existingUpdatedAt) || currentUpdatedAt > existingUpdatedAt)) {
491
+ dedup.set(pack.id, pack);
492
+ }
493
+ }
494
+
495
+ return Array.from(dedup.values()).sort((a, b) => {
496
+ const aUpdatedAt = Date.parse(String(a?.updated_at || a?.created_at || ''));
497
+ const bUpdatedAt = Date.parse(String(b?.updated_at || b?.created_at || ''));
498
+ if (!Number.isFinite(aUpdatedAt) && !Number.isFinite(bUpdatedAt)) return 0;
499
+ if (!Number.isFinite(aUpdatedAt)) return 1;
500
+ if (!Number.isFinite(bUpdatedAt)) return -1;
501
+ return bUpdatedAt - aUpdatedAt;
502
+ });
503
+ };
504
+
505
+ const resolveOwnerCandidatesForPackCommand = async ({ senderJid, messageInfo }) => {
506
+ const candidates = new Set();
507
+ const lookupByJid = new Set();
508
+
509
+ const senderInfo = extractSenderInfoFromMessage(messageInfo);
510
+ appendOwnerCandidate(candidates, lookupByJid, senderJid);
511
+ appendOwnerCandidate(candidates, lookupByJid, senderInfo?.jid);
512
+ appendOwnerCandidate(candidates, lookupByJid, senderInfo?.participantAlt);
513
+ appendOwnerCandidate(candidates, lookupByJid, senderInfo?.lid);
514
+
515
+ const directResolved = await resolveUserId(extractUserIdInfo(senderJid)).catch(() => null);
516
+ if (directResolved) {
517
+ appendOwnerCandidate(candidates, lookupByJid, directResolved);
518
+ }
519
+
520
+ const senderResolved = await resolveUserId({
521
+ lid: senderInfo?.lid,
522
+ jid: senderInfo?.jid || senderJid || null,
523
+ participantAlt: senderInfo?.participantAlt || null,
524
+ }).catch(() => null);
525
+ if (senderResolved) {
526
+ appendOwnerCandidate(candidates, lookupByJid, senderResolved);
527
+ }
528
+
529
+ const lookupValues = Array.from(lookupByJid).filter(Boolean);
530
+ for (let offset = 0; offset < lookupValues.length; offset += 200) {
531
+ const chunk = lookupValues.slice(offset, offset + 200);
532
+ if (!chunk.length) continue;
533
+ const placeholders = chunk.map(() => '?').join(', ');
534
+ const lookupParams = [...chunk, ...chunk];
535
+ const rows = await executeQuery(
536
+ `SELECT lid, jid
537
+ FROM ${TABLES.LID_MAP}
538
+ WHERE jid IN (${placeholders})
539
+ OR lid IN (${placeholders})
540
+ ORDER BY last_seen DESC
541
+ LIMIT 500`,
542
+ lookupParams,
543
+ ).catch(() => []);
544
+
545
+ for (const row of Array.isArray(rows) ? rows : []) {
546
+ appendOwnerCandidate(candidates, lookupByJid, row?.jid || '');
547
+ appendOwnerCandidate(candidates, lookupByJid, row?.lid || '');
548
+ }
549
+ }
550
+
551
+ const lidCandidates = Array.from(candidates).filter((candidate) => LID_SERVERS.has(getJidServer(candidate)));
552
+ for (const lidValue of lidCandidates) {
553
+ const resolved = await resolveUserId(extractUserIdInfo(lidValue)).catch(() => null);
554
+ if (resolved) {
555
+ appendOwnerCandidate(candidates, lookupByJid, resolved);
556
+ }
557
+ }
558
+
559
+ return Array.from(candidates);
560
+ };
561
+
562
+ const pickPrimaryOwnerCandidate = (ownerCandidates, senderJid) => {
563
+ const preferred = (Array.isArray(ownerCandidates) ? ownerCandidates : []).find((candidate) => {
564
+ const server = getJidServer(candidate);
565
+ if (!server || LID_SERVERS.has(server)) return false;
566
+ return server !== 'google.oauth';
567
+ });
568
+ if (preferred) return preferred;
569
+
570
+ const normalizedSender = normalizeJid(senderJid) || '';
571
+ if (normalizedSender) return normalizedSender;
572
+ return Array.isArray(ownerCandidates) && ownerCandidates.length ? ownerCandidates[0] : senderJid;
573
+ };
574
+
575
+ const runWithOwnerFallback = async (ownerCandidates, action) => {
576
+ const owners = Array.isArray(ownerCandidates) && ownerCandidates.length ? ownerCandidates : [];
577
+ let notFoundError = null;
578
+ for (const candidateOwner of owners) {
579
+ try {
580
+ return await action(candidateOwner);
581
+ } catch (error) {
582
+ if (error instanceof StickerPackError && error.code === STICKER_PACK_ERROR_CODES.PACK_NOT_FOUND) {
583
+ notFoundError = notFoundError || error;
584
+ continue;
585
+ }
586
+ throw error;
587
+ }
588
+ }
589
+
590
+ if (notFoundError) throw notFoundError;
591
+ throw new StickerPackError(STICKER_PACK_ERROR_CODES.PACK_NOT_FOUND, 'Pack não encontrado para este usuário.');
592
+ };
593
+
451
594
  /**
452
595
  * Normaliza e valida nome de pack (permite espaços e emojis).
453
596
  *
@@ -530,7 +673,9 @@ const resolveStickerFromCommandContext = async ({ messageInfo, ownerJid, include
530
673
  * @returns {Promise<void>}
531
674
  */
532
675
  export async function handlePackCommand({ sock, remoteJid, messageInfo, expirationMessage, senderJid, senderName, text, commandPrefix }) {
533
- const ownerJid = senderJid;
676
+ const ownerCandidatesRaw = await resolveOwnerCandidatesForPackCommand({ senderJid, messageInfo }).catch(() => []);
677
+ const ownerJid = pickPrimaryOwnerCandidate(ownerCandidatesRaw, senderJid);
678
+ const ownerCandidates = Array.from(new Set([ownerJid, ...ownerCandidatesRaw].filter(Boolean)));
534
679
  const rate = checkRateLimit(ownerJid);
535
680
 
536
681
  if (rate.limited) {
@@ -590,8 +735,9 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
590
735
  }
591
736
 
592
737
  case 'list': {
593
- const packs = await stickerPackService.listPacks({ ownerJid, limit: 100 });
594
- const manualPacks = packs.filter((pack) => !isAutomaticPack(pack));
738
+ const packLists = await Promise.all(ownerCandidates.map((candidateOwner) => stickerPackService.listPacks({ ownerJid: candidateOwner, limit: 100 })));
739
+ const packs = dedupePacksById(packLists.flatMap((items) => (Array.isArray(items) ? items : [])));
740
+ const manualPacks = packs.filter((pack) => !isThemeCurationPack(pack));
595
741
 
596
742
  await sendReply({
597
743
  sock,
@@ -605,7 +751,7 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
605
751
 
606
752
  case 'info': {
607
753
  const identifier = readSingleArgument(rest);
608
- const pack = await stickerPackService.getPackInfo({ ownerJid, identifier });
754
+ const pack = await runWithOwnerFallback(ownerCandidates, (candidateOwner) => stickerPackService.getPackInfo({ ownerJid: candidateOwner, identifier }));
609
755
 
610
756
  await sendReply({
611
757
  sock,
@@ -620,7 +766,7 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
620
766
  case 'rename': {
621
767
  const { identifier, value } = parseIdentifierAndValue(rest);
622
768
  const normalizedName = normalizePackName(value, { label: 'Novo nome do pack' });
623
- const updated = await stickerPackService.renamePack({ ownerJid, identifier, name: normalizedName });
769
+ const updated = await runWithOwnerFallback(ownerCandidates, (candidateOwner) => stickerPackService.renamePack({ ownerJid: candidateOwner, identifier, name: normalizedName }));
624
770
 
625
771
  await sendReply({
626
772
  sock,
@@ -639,7 +785,7 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
639
785
 
640
786
  case 'setpub': {
641
787
  const { identifier, value } = parseIdentifierAndValue(rest);
642
- const updated = await stickerPackService.setPackPublisher({ ownerJid, identifier, publisher: value });
788
+ const updated = await runWithOwnerFallback(ownerCandidates, (candidateOwner) => stickerPackService.setPackPublisher({ ownerJid: candidateOwner, identifier, publisher: value }));
643
789
 
644
790
  await sendReply({
645
791
  sock,
@@ -659,7 +805,7 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
659
805
  case 'setdesc': {
660
806
  const { identifier, value } = parseIdentifierAndValue(rest);
661
807
  const description = value === '-' || value.toLowerCase() === 'clear' ? '' : value;
662
- const updated = await stickerPackService.setPackDescription({ ownerJid, identifier, description });
808
+ const updated = await runWithOwnerFallback(ownerCandidates, (candidateOwner) => stickerPackService.setPackDescription({ ownerJid: candidateOwner, identifier, description }));
663
809
 
664
810
  await sendReply({
665
811
  sock,
@@ -684,11 +830,13 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
684
830
  throw new StickerPackError(STICKER_PACK_ERROR_CODES.STICKER_NOT_FOUND, 'Não encontrei uma figurinha para definir como capa.');
685
831
  }
686
832
 
687
- const updated = await stickerPackService.setPackCover({
688
- ownerJid,
689
- identifier,
690
- stickerId: asset.id,
691
- });
833
+ const updated = await runWithOwnerFallback(ownerCandidates, (candidateOwner) =>
834
+ stickerPackService.setPackCover({
835
+ ownerJid: candidateOwner,
836
+ identifier,
837
+ stickerId: asset.id,
838
+ }),
839
+ );
692
840
 
693
841
  await sendReply({
694
842
  sock,
@@ -715,13 +863,15 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
715
863
  throw new StickerPackError(STICKER_PACK_ERROR_CODES.STICKER_NOT_FOUND, 'Não encontrei uma figurinha para adicionar.');
716
864
  }
717
865
 
718
- const updated = await stickerPackService.addStickerToPack({
719
- ownerJid,
720
- identifier,
721
- asset,
722
- emojis: options.emojis,
723
- accessibilityLabel: options.label || options.accessibility || null,
724
- });
866
+ const updated = await runWithOwnerFallback(ownerCandidates, (candidateOwner) =>
867
+ stickerPackService.addStickerToPack({
868
+ ownerJid: candidateOwner,
869
+ identifier,
870
+ asset,
871
+ emojis: options.emojis,
872
+ accessibilityLabel: options.label || options.accessibility || null,
873
+ }),
874
+ );
725
875
 
726
876
  await sendReply({
727
877
  sock,
@@ -742,11 +892,13 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
742
892
  const { token: identifier, rest: selectorRest } = readToken(rest);
743
893
  const { token: selector } = readToken(selectorRest);
744
894
 
745
- const result = await stickerPackService.removeStickerFromPack({
746
- ownerJid,
747
- identifier,
748
- selector,
749
- });
895
+ const result = await runWithOwnerFallback(ownerCandidates, (candidateOwner) =>
896
+ stickerPackService.removeStickerFromPack({
897
+ ownerJid: candidateOwner,
898
+ identifier,
899
+ selector,
900
+ }),
901
+ );
750
902
 
751
903
  await sendReply({
752
904
  sock,
@@ -765,16 +917,18 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
765
917
 
766
918
  case 'reorder': {
767
919
  const { token: identifier, rest: rawOrder } = readToken(rest);
768
- const orderStickerIds = await parseReorderInput({
769
- ownerJid,
770
- identifier,
771
- rawOrder,
772
- });
920
+ const updated = await runWithOwnerFallback(ownerCandidates, async (candidateOwner) => {
921
+ const orderStickerIds = await parseReorderInput({
922
+ ownerJid: candidateOwner,
923
+ identifier,
924
+ rawOrder,
925
+ });
773
926
 
774
- const updated = await stickerPackService.reorderPackItems({
775
- ownerJid,
776
- identifier,
777
- orderStickerIds,
927
+ return stickerPackService.reorderPackItems({
928
+ ownerJid: candidateOwner,
929
+ identifier,
930
+ orderStickerIds,
931
+ });
778
932
  });
779
933
 
780
934
  await sendReply({
@@ -796,11 +950,13 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
796
950
  const { token: identifier, rest: cloneNameRaw } = readToken(rest);
797
951
  const cloneName = normalizePackName(cloneNameRaw, { label: 'Novo nome do clone' });
798
952
 
799
- const cloned = await stickerPackService.clonePack({
800
- ownerJid,
801
- identifier,
802
- newName: cloneName,
803
- });
953
+ const cloned = await runWithOwnerFallback(ownerCandidates, (candidateOwner) =>
954
+ stickerPackService.clonePack({
955
+ ownerJid: candidateOwner,
956
+ identifier,
957
+ newName: cloneName,
958
+ }),
959
+ );
804
960
 
805
961
  await sendReply({
806
962
  sock,
@@ -819,7 +975,7 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
819
975
 
820
976
  case 'delete': {
821
977
  const identifier = readSingleArgument(rest);
822
- const deleted = await stickerPackService.deletePack({ ownerJid, identifier });
978
+ const deleted = await runWithOwnerFallback(ownerCandidates, (candidateOwner) => stickerPackService.deletePack({ ownerJid: candidateOwner, identifier }));
823
979
 
824
980
  await sendReply({
825
981
  sock,
@@ -840,11 +996,13 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
840
996
  const { token: identifier, rest: visibilityRaw } = readToken(rest);
841
997
  const visibility = unquote(visibilityRaw);
842
998
 
843
- const updated = await stickerPackService.setPackVisibility({
844
- ownerJid,
845
- identifier,
846
- visibility,
847
- });
999
+ const updated = await runWithOwnerFallback(ownerCandidates, (candidateOwner) =>
1000
+ stickerPackService.setPackVisibility({
1001
+ ownerJid: candidateOwner,
1002
+ identifier,
1003
+ visibility,
1004
+ }),
1005
+ );
848
1006
 
849
1007
  await sendReply({
850
1008
  sock,
@@ -863,7 +1021,7 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
863
1021
 
864
1022
  case 'send': {
865
1023
  const identifier = readSingleArgument(rest);
866
- const packDetails = await stickerPackService.getPackInfoForSend({ ownerJid, identifier });
1024
+ const packDetails = await runWithOwnerFallback(ownerCandidates, (candidateOwner) => stickerPackService.getPackInfoForSend({ ownerJid: candidateOwner, identifier }));
867
1025
  const packBuild = await buildStickerPackMessage(packDetails);
868
1026
  const sendResult = await sendStickerPackWithFallback({
869
1027
  sock,
@@ -942,15 +1100,28 @@ export async function maybeCaptureIncomingSticker({ messageInfo, senderJid, isMe
942
1100
  if (isMessageFromBot) return null;
943
1101
  if (!isUserJid(senderJid)) return null;
944
1102
 
1103
+ const senderInfo = extractSenderInfoFromMessage(messageInfo);
1104
+ let ownerJid = normalizeJid(senderJid) || senderJid;
1105
+ try {
1106
+ const resolvedOwner = await resolveUserId({
1107
+ lid: senderInfo?.lid,
1108
+ jid: senderInfo?.jid || senderJid || null,
1109
+ participantAlt: senderInfo?.participantAlt || null,
1110
+ });
1111
+ ownerJid = normalizeJid(resolvedOwner || ownerJid) || ownerJid;
1112
+ } catch {
1113
+ ownerJid = normalizeJid(senderJid) || senderJid;
1114
+ }
1115
+
945
1116
  try {
946
1117
  return await captureIncomingStickerAsset({
947
1118
  messageInfo,
948
- ownerJid: senderJid,
1119
+ ownerJid,
949
1120
  });
950
1121
  } catch (error) {
951
1122
  logger.warn('Falha ao capturar figurinha recebida para storage.', {
952
1123
  action: 'pack_capture_warning',
953
- owner_jid: senderJid,
1124
+ owner_jid: ownerJid,
954
1125
  error: error.message,
955
1126
  });
956
1127
  return null;
@@ -1,3 +1,6 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
1
4
  import logger from '../utils/logger/loggerModule.js';
2
5
  import { executeQuery, TABLES } from '../../database/index.js';
3
6
  import { getJidServer, normalizeJid, isGroupJid } from '../config/baileysConfig.js';
@@ -10,12 +13,16 @@ const STORE_COOLDOWN_MS = 10 * 60 * 1000;
10
13
  const BATCH_LIMIT = 800;
11
14
  const BACKFILL_DEFAULT_BATCH = 50000;
12
15
  const BACKFILL_SOURCE = 'backfill';
16
+ const __filename = fileURLToPath(import.meta.url);
17
+ const __dirname = path.dirname(__filename);
18
+ const BAILEYS_AUTH_DIR = path.resolve(__dirname, '../connection/auth');
13
19
 
14
20
  const LID_SERVERS = new Set(['lid', 'hosted.lid']);
15
21
  const PN_SERVERS = new Set(['s.whatsapp.net', 'c.us', 'hosted']);
16
22
 
17
23
  const lidCache = new Map();
18
24
  const lidWriteBuffer = new Map();
25
+ const authReverseLidCache = new Map();
19
26
 
20
27
  let backfillPromise = null;
21
28
 
@@ -55,6 +62,54 @@ const normalizeWhatsAppJid = (jid) => {
55
62
  return normalized || null;
56
63
  };
57
64
 
65
+ const toDigits = (value) => String(value || '').replace(/\D+/g, '');
66
+
67
+ const parseReverseMappingPhoneDigits = (content) => {
68
+ const raw = String(content || '').trim();
69
+ if (!raw) return '';
70
+
71
+ let parsed = raw;
72
+ try {
73
+ parsed = JSON.parse(raw);
74
+ } catch {
75
+ parsed = raw;
76
+ }
77
+
78
+ const digits = toDigits(parsed);
79
+ return digits.length >= 10 && digits.length <= 15 ? digits : '';
80
+ };
81
+
82
+ const resolveAuthStoreJidByLid = async (lid) => {
83
+ const normalizedLid = normalizeLid(lid);
84
+ if (!normalizedLid) return null;
85
+
86
+ const [rawUser] = normalizedLid.split('@');
87
+ const rootUser = rawUser ? rawUser.split(':')[0] : '';
88
+ if (!rootUser || !/^\d+$/.test(rootUser)) return null;
89
+
90
+ if (authReverseLidCache.has(rootUser)) {
91
+ return authReverseLidCache.get(rootUser);
92
+ }
93
+
94
+ const reverseFilePath = path.join(BAILEYS_AUTH_DIR, `lid-mapping-${rootUser}_reverse.json`);
95
+ try {
96
+ const content = await readFile(reverseFilePath, 'utf8');
97
+ const phoneDigits = parseReverseMappingPhoneDigits(content);
98
+ const resolvedJid = phoneDigits ? normalizeWhatsAppJid(`${phoneDigits}@s.whatsapp.net`) : null;
99
+ authReverseLidCache.set(rootUser, resolvedJid);
100
+ return resolvedJid;
101
+ } catch (error) {
102
+ if (error?.code !== 'ENOENT') {
103
+ logger.warn('Falha ao resolver LID via auth store local.', {
104
+ lid: normalizedLid,
105
+ error: error?.message,
106
+ });
107
+ }
108
+ authReverseLidCache.set(rootUser, null);
109
+ return null;
110
+ }
111
+ };
112
+
58
113
  /**
59
114
  * Mascara um JID para logs.
60
115
  * @param {string|null|undefined} jid
@@ -191,8 +246,21 @@ export const primeLidCache = async (lids = []) => {
191
246
  const base = baseByLid.get(lid);
192
247
  const direct = rowMap.has(lid) ? rowMap.get(lid) : undefined;
193
248
  const baseValue = base && base !== lid && rowMap.has(base) ? rowMap.get(base) : undefined;
194
- const resolved = direct ?? baseValue ?? null;
195
- setCacheEntry(lid, resolved, resolved ? CACHE_TTL_MS : NEGATIVE_TTL_MS);
249
+ let resolved = direct ?? baseValue ?? null;
250
+
251
+ if (!resolved) {
252
+ const authStoreResolved = await resolveAuthStoreJidByLid(lid);
253
+ if (authStoreResolved) {
254
+ resolved = authStoreResolved;
255
+ }
256
+ }
257
+
258
+ const directHasJid = typeof direct === 'string' && direct.length > 0;
259
+ const shouldSeed = Boolean(resolved && (!directHasJid || direct !== resolved));
260
+ setCacheEntry(lid, resolved, resolved ? CACHE_TTL_MS : NEGATIVE_TTL_MS, shouldSeed ? 0 : undefined);
261
+ if (shouldSeed) {
262
+ queueLidUpdate(lid, resolved, 'prime');
263
+ }
196
264
  results.set(lid, resolved);
197
265
  }
198
266
 
@@ -379,6 +447,15 @@ const fetchJidByLid = async (lid) => {
379
447
  const direct = rowMap.has(lid) ? rowMap.get(lid) : undefined;
380
448
  const baseValue = base && base !== lid && rowMap.has(base) ? rowMap.get(base) : undefined;
381
449
  let resolved = direct ?? baseValue ?? null;
450
+ let resolveSource = 'db';
451
+
452
+ if (!resolved) {
453
+ const authStoreResolved = await resolveAuthStoreJidByLid(lid);
454
+ if (authStoreResolved) {
455
+ resolved = authStoreResolved;
456
+ resolveSource = 'auth-store';
457
+ }
458
+ }
382
459
 
383
460
  if (!resolved) {
384
461
  const normalized = base || lid;
@@ -404,16 +481,18 @@ const fetchJidByLid = async (lid) => {
404
481
  const derivedJid = derivedRows?.[0]?.jid;
405
482
  if (derivedJid && isWhatsAppJid(derivedJid)) {
406
483
  resolved = normalizeJid(derivedJid);
484
+ resolveSource = 'derived';
407
485
  }
408
486
  }
409
487
  }
410
488
 
411
- const shouldSeedDerived = Boolean(resolved && direct === undefined);
489
+ const directHasJid = typeof direct === 'string' && direct.length > 0;
490
+ const shouldSeedDerived = Boolean(resolved && (!directHasJid || direct !== resolved));
412
491
 
413
492
  setCacheEntry(lid, resolved, resolved ? CACHE_TTL_MS : NEGATIVE_TTL_MS, shouldSeedDerived ? 0 : undefined);
414
493
 
415
494
  if (shouldSeedDerived) {
416
- queueLidUpdate(lid, resolved, 'derived');
495
+ queueLidUpdate(lid, resolved, resolveSource === 'auth-store' ? 'auth-store' : 'derived');
417
496
  }
418
497
 
419
498
  return resolved;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaikybrofc/omnizap-system",
3
- "version": "2.3.2",
3
+ "version": "2.3.4",
4
4
  "description": "Sistema profissional de automação WhatsApp com tecnologia Baileys",
5
5
  "main": "index.js",
6
6
  "publishConfig": {
@@ -9,8 +9,9 @@
9
9
  <meta name="author" content="OmniZap System" />
10
10
  <meta name="robots" content="index, follow, max-snippet:-1" />
11
11
  <link rel="canonical" href="https://omnizap.shop/api-docs/" />
12
- <link rel="icon" type="image/jpeg" href="https://iili.io/FC3FABe.jpg" />
13
- <link rel="apple-touch-icon" href="https://iili.io/FC3FABe.jpg" />
12
+ <link rel="icon" href="/favicon.ico" sizes="any" />
13
+ <link rel="manifest" href="/site.webmanifest" />
14
+ <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
14
15
  <link rel="sitemap" type="application/xml" href="https://omnizap.shop/sitemap.xml" />
15
16
  <meta property="og:type" content="website" />
16
17
  <meta property="og:locale" content="pt_BR" />
Binary file
@@ -8,7 +8,9 @@
8
8
  <meta name="keywords" content="bot para grupo whatsapp, bot whatsapp pronto, automacao para grupos, moderacao grupo whatsapp" />
9
9
  <meta name="robots" content="index, follow" />
10
10
  <link rel="canonical" href="https://omnizap.shop/bot-whatsapp-para-grupo/" />
11
- <link rel="icon" type="image/png" href="/assets/images/brand-icon-192.png" />
11
+ <link rel="icon" href="/favicon.ico" sizes="any" />
12
+ <link rel="manifest" href="/site.webmanifest" />
13
+ <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
12
14
 
13
15
  <meta property="og:type" content="article" />
14
16
  <meta property="og:locale" content="pt_BR" />
@@ -8,7 +8,9 @@
8
8
  <meta name="keywords" content="bot whatsapp sem programar, bot pronto whatsapp, automacao whatsapp sem codigo" />
9
9
  <meta name="robots" content="index, follow" />
10
10
  <link rel="canonical" href="https://omnizap.shop/bot-whatsapp-sem-programar/" />
11
- <link rel="icon" type="image/png" href="/assets/images/brand-icon-192.png" />
11
+ <link rel="icon" href="/favicon.ico" sizes="any" />
12
+ <link rel="manifest" href="/site.webmanifest" />
13
+ <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
12
14
 
13
15
  <meta property="og:type" content="article" />
14
16
  <meta property="og:locale" content="pt_BR" />
@@ -8,8 +8,9 @@
8
8
  <meta name="keywords" content="comandos bot whatsapp, comandos omnizap, bot para grupo whatsapp, automacao whatsapp" />
9
9
  <meta name="robots" content="index, follow, max-snippet:-1" />
10
10
  <link rel="canonical" href="https://omnizap.shop/comandos/" />
11
- <link rel="icon" type="image/png" href="/assets/images/brand-icon-192.png" />
12
- <link rel="apple-touch-icon" href="/assets/images/brand-icon-192.png" />
11
+ <link rel="icon" href="/favicon.ico" sizes="any" />
12
+ <link rel="manifest" href="/site.webmanifest" />
13
+ <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
13
14
  <link rel="preconnect" href="https://fonts.googleapis.com" />
14
15
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
15
16
  <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&family=Sora:wght@600;700;800&display=swap" />
@@ -8,7 +8,9 @@
8
8
  <meta name="keywords" content="automatizar avisos whatsapp, lembrete automatico whatsapp, bot para avisos" />
9
9
  <meta name="robots" content="index, follow" />
10
10
  <link rel="canonical" href="https://omnizap.shop/como-automatizar-avisos-no-whatsapp/" />
11
- <link rel="icon" type="image/png" href="/assets/images/brand-icon-192.png" />
11
+ <link rel="icon" href="/favicon.ico" sizes="any" />
12
+ <link rel="manifest" href="/site.webmanifest" />
13
+ <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
12
14
 
13
15
  <meta property="og:type" content="article" />
14
16
  <meta property="og:locale" content="pt_BR" />
@@ -8,7 +8,9 @@
8
8
  <meta name="keywords" content="comandos whatsapp, bot com comandos, automacao de respostas whatsapp" />
9
9
  <meta name="robots" content="index, follow" />
10
10
  <link rel="canonical" href="https://omnizap.shop/como-criar-comandos-whatsapp/" />
11
- <link rel="icon" type="image/png" href="/assets/images/brand-icon-192.png" />
11
+ <link rel="icon" href="/favicon.ico" sizes="any" />
12
+ <link rel="manifest" href="/site.webmanifest" />
13
+ <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
12
14
 
13
15
  <meta property="og:type" content="article" />
14
16
  <meta property="og:locale" content="pt_BR" />
@@ -8,7 +8,9 @@
8
8
  <meta name="keywords" content="como evitar spam whatsapp, bot anti spam whatsapp, moderacao whatsapp" />
9
9
  <meta name="robots" content="index, follow" />
10
10
  <link rel="canonical" href="https://omnizap.shop/como-evitar-spam-no-whatsapp/" />
11
- <link rel="icon" type="image/png" href="/assets/images/brand-icon-192.png" />
11
+ <link rel="icon" href="/favicon.ico" sizes="any" />
12
+ <link rel="manifest" href="/site.webmanifest" />
13
+ <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
12
14
 
13
15
  <meta property="og:type" content="article" />
14
16
  <meta property="og:locale" content="pt_BR" />