@omnizap-system/omnizap 2.6.0 → 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.
Files changed (261) hide show
  1. package/.env.example +58 -13
  2. package/.github/workflows/ci.yml +5 -5
  3. package/.github/workflows/codeql.yml +1 -1
  4. package/.github/workflows/db-migration-check.yml +2 -2
  5. package/.github/workflows/dependency-review.yml +1 -1
  6. package/.github/workflows/deploy.yml +2 -2
  7. package/.github/workflows/release.yml +2 -2
  8. package/.github/workflows/security-attest-provenance.yml +2 -2
  9. package/.github/workflows/security-gitleaks.yml +13 -4
  10. package/.github/workflows/security-runner-hardening.yml +2 -2
  11. package/.github/workflows/security-scorecard.yml +1 -1
  12. package/.github/workflows/security-zap-baseline.yml +1 -1
  13. package/.github/workflows/security-zap-full-scan.yml +2 -1
  14. package/.github/workflows/security-zizmor.yml +1 -1
  15. package/.github/workflows/wiki-sync.yml +1 -1
  16. package/.gitleaksignore +9 -0
  17. package/CODE_OF_CONDUCT.md +2 -2
  18. package/GEMINI.md +64 -0
  19. package/README.md +52 -82
  20. package/SECURITY.md +1 -1
  21. package/app/config/index.js +2 -0
  22. package/app/configParts/adminIdentity.js +5 -5
  23. package/app/configParts/baileysConfig.js +230 -58
  24. package/app/configParts/groupUtils.js +5 -0
  25. package/app/configParts/messagePersistenceService.js +145 -4
  26. package/app/configParts/sessionConfig.js +157 -0
  27. package/app/connection/baileysCompatibility.test.js +1 -1
  28. package/app/connection/groupOwnerWriteStateResolver.js +109 -0
  29. package/app/connection/socketController.js +660 -158
  30. package/app/connection/socketController.multiSession.test.js +108 -0
  31. package/app/controllers/messageController.js +1 -1
  32. package/app/controllers/messagePipeline/commandMiddleware.js +12 -10
  33. package/app/controllers/messagePipeline/conversationMiddleware.js +2 -1
  34. package/app/controllers/messagePipeline/messagePipelineMiddlewares.test.js +104 -0
  35. package/app/controllers/messagePipeline/preProcessingMiddlewares.js +80 -2
  36. package/app/controllers/messageProcessingPipeline.js +93 -13
  37. package/app/controllers/messageProcessingPipeline.test.js +200 -0
  38. package/app/modules/adminModule/AGENT.md +1 -1
  39. package/app/modules/adminModule/commandConfig.json +3318 -1347
  40. package/app/modules/adminModule/groupCommandHandlers.js +858 -15
  41. package/app/modules/adminModule/groupCommandHandlers.test.js +378 -11
  42. package/app/modules/adminModule/groupWarningRepository.js +152 -0
  43. package/app/modules/aiModule/AGENT.md +47 -30
  44. package/app/modules/aiModule/aiConfigRuntime.js +1 -0
  45. package/app/modules/aiModule/catCommand.js +135 -27
  46. package/app/modules/aiModule/commandConfig.json +114 -28
  47. package/app/modules/analyticsModule/messageAnalysisEventRepository.js +54 -6
  48. package/app/modules/gameModule/AGENT.md +1 -1
  49. package/app/modules/gameModule/commandConfig.json +29 -0
  50. package/app/modules/menuModule/AGENT.md +1 -1
  51. package/app/modules/menuModule/commandConfig.json +45 -10
  52. package/app/modules/menuModule/menuCatalogService.js +190 -0
  53. package/app/modules/menuModule/menuCommandUsageRepository.js +109 -0
  54. package/app/modules/menuModule/menuDynamicService.js +511 -0
  55. package/app/modules/menuModule/menuDynamicService.test.js +141 -0
  56. package/app/modules/menuModule/menus.js +36 -5
  57. package/app/modules/playModule/AGENT.md +10 -5
  58. package/app/modules/playModule/commandConfig.json +140 -12
  59. package/app/modules/playModule/playCommand.js +1 -1417
  60. package/app/modules/playModule/playCommandConstants.js +80 -0
  61. package/app/modules/playModule/playCommandCore.js +361 -0
  62. package/app/modules/playModule/playCommandHandlers.js +41 -0
  63. package/app/modules/playModule/playCommandMediaClient.js +1872 -0
  64. package/app/modules/playModule/playConfigRuntime.js +245 -4
  65. package/app/modules/playModule/playModuleCriticalFlows.test.js +152 -0
  66. package/app/modules/quoteModule/AGENT.md +1 -1
  67. package/app/modules/quoteModule/commandConfig.json +29 -0
  68. package/app/modules/quoteModule/quoteCommand.js +3 -2
  69. package/app/modules/rpgPokemonModule/AGENT.md +1 -1
  70. package/app/modules/rpgPokemonModule/commandConfig.json +29 -0
  71. package/app/modules/rpgPokemonModule/rpgBattleCanvasRenderer.js +5 -4
  72. package/app/modules/rpgPokemonModule/rpgBattleService.test.js +2 -1
  73. package/app/modules/rpgPokemonModule/rpgPokemonDomain.js +2 -1
  74. package/app/modules/rpgPokemonModule/rpgPokemonService.js +38 -37
  75. package/app/modules/rpgPokemonModule/rpgProfileCanvasRenderer.js +4 -3
  76. package/app/modules/statsModule/AGENT.md +1 -1
  77. package/app/modules/statsModule/commandConfig.json +58 -0
  78. package/app/modules/statsModule/rankingCommon.js +5 -4
  79. package/app/modules/stickerModule/AGENT.md +1 -1
  80. package/app/modules/stickerModule/addStickerMetadata.js +4 -3
  81. package/app/modules/stickerModule/commandConfig.json +145 -0
  82. package/app/modules/stickerModule/stickerCommand.js +1 -1
  83. package/app/modules/stickerPackModule/AGENT.md +1 -1
  84. package/app/modules/stickerPackModule/autoPackCollectorService.js +5 -1
  85. package/app/modules/stickerPackModule/commandConfig.json +29 -0
  86. package/app/modules/stickerPackModule/semanticThemeClusterService.js +7 -6
  87. package/app/modules/stickerPackModule/stickerAutoPackByTagsRuntime.js +10 -9
  88. package/app/modules/stickerPackModule/stickerClassificationBackgroundRuntime.js +9 -8
  89. package/app/modules/stickerPackModule/stickerDomainEventConsumerRuntime.js +3 -2
  90. package/app/modules/stickerPackModule/stickerMarketplaceDriftService.js +2 -1
  91. package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +80 -58
  92. package/app/modules/stickerPackModule/stickerPackMarketplaceService.js +2 -1
  93. package/app/modules/stickerPackModule/stickerPackRepository.js +2 -1
  94. package/app/modules/stickerPackModule/stickerPackScoreSnapshotRuntime.js +5 -4
  95. package/app/modules/stickerPackModule/stickerPackService.js +13 -6
  96. package/app/modules/stickerPackModule/stickerStorageService.js +3 -2
  97. package/app/modules/stickerPackModule/stickerWorkerPipelineRuntime.js +2 -1
  98. package/app/modules/systemMetricsModule/AGENT.md +1 -1
  99. package/app/modules/systemMetricsModule/commandConfig.json +29 -0
  100. package/app/modules/systemMetricsModule/pingCommand.js +6 -5
  101. package/app/modules/tiktokModule/AGENT.md +1 -1
  102. package/app/modules/tiktokModule/commandConfig.json +29 -0
  103. package/app/modules/tiktokModule/tiktokCommand.js +2 -1
  104. package/app/modules/userModule/AGENT.md +1 -1
  105. package/app/modules/userModule/commandConfig.json +29 -0
  106. package/app/modules/userModule/userCommand.js +72 -23
  107. package/app/modules/waifuPicsModule/AGENT.md +57 -27
  108. package/app/modules/waifuPicsModule/commandConfig.json +87 -0
  109. package/app/modules/waifuPicsModule/waifuPicsCommand.js +3 -2
  110. package/app/observability/metrics.js +136 -0
  111. package/app/services/ai/commandConfigEnrichmentService.js +229 -47
  112. package/app/services/ai/conversationRouterService.js +4 -3
  113. package/app/services/ai/geminiService.js +132 -7
  114. package/app/services/ai/geminiService.test.js +59 -2
  115. package/app/services/ai/globalModuleAiHelpService.js +3 -2
  116. package/app/services/ai/messageCommandExecutionService.js +2 -1
  117. package/app/services/ai/moduleAiHelpCoreService.js +45 -14
  118. package/app/services/ai/moduleToolExecutorService.js +3 -2
  119. package/app/services/ai/moduleToolRegistryService.js +2 -1
  120. package/app/services/ai/toolCandidateSelectorService.js +6 -5
  121. package/app/services/auth/googleWebLinkService.js +3 -2
  122. package/app/services/auth/whatsappLoginLinkService.js +3 -2
  123. package/app/services/external/pokeApiService.js +4 -3
  124. package/app/services/group/groupMetadataService.js +24 -1
  125. package/app/services/infra/dbWriteQueue.js +57 -26
  126. package/app/services/infra/featureFlagService.js +2 -1
  127. package/app/services/messaging/captchaService.js +3 -2
  128. package/app/services/messaging/newsBroadcastService.js +846 -29
  129. package/app/services/multiSession/assignmentBalancerService.js +457 -0
  130. package/app/services/multiSession/groupOwnershipRepository.js +381 -0
  131. package/app/services/multiSession/groupOwnershipService.js +890 -0
  132. package/app/services/multiSession/groupOwnershipService.test.js +309 -0
  133. package/app/services/multiSession/sessionRegistryService.js +293 -0
  134. package/app/services/sticker/stickerFocusService.js +11 -10
  135. package/app/store/aiPromptStore.js +36 -19
  136. package/app/store/conversationSessionStore.js +7 -6
  137. package/app/store/groupConfigStore.js +41 -5
  138. package/app/store/premiumUserStore.js +21 -7
  139. package/app/utils/antiLink/antiLinkModule.js +352 -16
  140. package/app/workers/aiHelperContinuousLearningWorker.js +512 -0
  141. package/app/workers/aiLearningWorker.js +6 -5
  142. package/app/workers/commandConfigEnrichmentWorker.js +4 -3
  143. package/database/index.js +14 -8
  144. package/database/migrations/20260307_d0_hardening_down.sql +1 -1
  145. package/database/migrations/20260314_d7_canonical_sender_down.sql +1 -1
  146. package/database/migrations/20260406_d30_security_analytics_down.sql +1 -1
  147. package/database/migrations/20260411_d35_group_community_metadata_down.sql +59 -0
  148. package/database/migrations/20260411_d35_group_community_metadata_up.sql +62 -0
  149. package/database/migrations/20260412_d36_system_config_tables_down.sql +32 -0
  150. package/database/migrations/20260412_d36_system_config_tables_up.sql +66 -0
  151. package/database/migrations/20260413_d37_group_user_warnings_down.sql +11 -0
  152. package/database/migrations/20260413_d37_group_user_warnings_up.sql +24 -0
  153. package/database/migrations/20260414_d38_multi_session_foundation_down.sql +72 -0
  154. package/database/migrations/20260414_d38_multi_session_foundation_up.sql +125 -0
  155. package/database/migrations/20260414_d39_multi_session_cutover_down.sql +103 -0
  156. package/database/migrations/20260414_d39_multi_session_cutover_up.sql +83 -0
  157. package/database/schema.sql +102 -1
  158. package/docker-compose.yml +4 -1
  159. package/docs/compliance/acceptable-use-policy-2026-03-07.md +1 -1
  160. package/docs/compliance/dpa-b2b-standard-2026-03-07.md +1 -1
  161. package/docs/compliance/privacy-policy-2026-03-07.md +4 -4
  162. package/docs/security/dsar-lgpd-runbook-2026-03-07.md +1 -1
  163. package/docs/security/incident-response-lgpd-anpd-runbook-2026-03-07.md +1 -1
  164. package/docs/security/network-hardening-runbook-2026-03-07.md +53 -0
  165. package/docs/security/omnizap-static-security-headers.conf +25 -0
  166. package/docs/wiki/Home.md +1 -1
  167. package/ecosystem.prod.config.cjs +32 -12
  168. package/index.js +57 -23
  169. package/observability/alert-rules.yml +20 -0
  170. package/observability/grafana/dashboards/omnizap-system-admin.json +229 -0
  171. package/observability/mysql-setup.sql +4 -4
  172. package/observability/system-admin-observability.md +26 -0
  173. package/package.json +20 -6
  174. package/public/apple-touch-icon.png +0 -0
  175. package/public/comandos/commands-catalog.json +2853 -3326
  176. package/public/favicon-16x16.png +0 -0
  177. package/public/favicon-32x32.png +0 -0
  178. package/public/favicon.ico +0 -0
  179. package/public/js/apps/apiDocsApp.js +3 -2
  180. package/public/js/apps/commandsReactApp.js +280 -99
  181. package/public/js/apps/createPackApp.js +11 -10
  182. package/public/js/apps/homeReactApp.js +181 -130
  183. package/public/js/apps/loginReactApp.js +1 -1
  184. package/public/js/apps/stickersApp.js +263 -110
  185. package/public/js/apps/termsReactApp.js +73 -24
  186. package/public/js/apps/userApp.js +4 -3
  187. package/public/js/apps/userPasswordResetReactApp.js +406 -0
  188. package/public/js/apps/userReactApp.js +355 -280
  189. package/public/js/apps/userSystemAdmReactApp.js +1506 -0
  190. package/public/pages/api-docs.html +1 -1
  191. package/public/pages/aup.html +2 -2
  192. package/public/pages/dpa.html +3 -3
  193. package/public/pages/licenca.html +4 -4
  194. package/public/pages/login.html +1 -1
  195. package/public/pages/notice-and-takedown.html +2 -2
  196. package/public/pages/politica-de-privacidade.html +6 -6
  197. package/public/pages/seo-bot-whatsapp-para-grupo.html +3 -3
  198. package/public/pages/seo-bot-whatsapp-sem-programar.html +3 -3
  199. package/public/pages/seo-como-automatizar-avisos-no-whatsapp.html +3 -3
  200. package/public/pages/seo-como-criar-comandos-whatsapp.html +3 -3
  201. package/public/pages/seo-como-evitar-spam-no-whatsapp.html +3 -3
  202. package/public/pages/seo-como-moderar-grupo-whatsapp.html +3 -3
  203. package/public/pages/seo-como-organizar-comunidade-whatsapp.html +3 -3
  204. package/public/pages/seo-melhor-bot-whatsapp-para-grupos.html +3 -3
  205. package/public/pages/stickers-admin.html +1 -1
  206. package/public/pages/stickers-create.html +1 -1
  207. package/public/pages/stickers.html +6 -6
  208. package/public/pages/suboperadores.html +2 -2
  209. package/public/pages/termos-de-uso-texto-integral.html +6 -6
  210. package/public/pages/termos-de-uso.html +3 -3
  211. package/public/pages/user-password-reset.html +4 -5
  212. package/public/pages/user-systemadm.html +9 -463
  213. package/public/pages/user.html +2 -2
  214. package/scripts/clear-whatsapp-session.sh +123 -0
  215. package/scripts/core-ai-mode.mjs +163 -0
  216. package/scripts/deploy.sh +11 -1
  217. package/scripts/email-broadcast-terms-update.mjs +2 -1
  218. package/scripts/enrich-command-config-ux-openai.mjs +492 -0
  219. package/scripts/generate-commands-catalog.mjs +166 -2
  220. package/scripts/generate-module-agents.mjs +2 -1
  221. package/scripts/generate-seo-satellite-pages.mjs +5 -4
  222. package/scripts/github-deploy-notify.mjs +2 -1
  223. package/scripts/github-release-notify.mjs +25 -10
  224. package/scripts/new-whatsapp-session.sh +317 -0
  225. package/scripts/release.sh +2 -19
  226. package/scripts/security-smoketest.mjs +6 -5
  227. package/scripts/security-web-surface-check.mjs +218 -0
  228. package/scripts/sticker-catalog-loadtest.mjs +5 -4
  229. package/server/auth/googleWebAuth/googleWebAuthService.js +8 -7
  230. package/server/auth/jwt/webJwtService.js +1 -1
  231. package/server/auth/stickerCatalogAuthContext.js +2 -1
  232. package/server/auth/termsAcceptance/termsAcceptanceHandler.js +2 -1
  233. package/server/auth/userPassword/userPasswordAuthService.js +2 -1
  234. package/server/auth/userPassword/userPasswordRecoveryService.js +4 -3
  235. package/server/auth/webAccount/webAccountHandlers.js +9 -10
  236. package/server/controllers/admin/adminPanelHandlers.js +267 -16
  237. package/server/controllers/admin/systemAdminController.js +267 -0
  238. package/server/controllers/seo/stickerCatalogSeoContext.js +10 -9
  239. package/server/controllers/sticker/nonCatalogHandlers.js +2 -1
  240. package/server/controllers/sticker/stickerCatalogController.js +23 -36
  241. package/server/controllers/system/contactController.js +9 -17
  242. package/server/controllers/system/githubController.js +3 -2
  243. package/server/controllers/system/stickerCatalogSystemContext.js +41 -19
  244. package/server/controllers/system/systemController.js +254 -1
  245. package/server/controllers/system/systemMetricsController.js +2 -1
  246. package/server/controllers/userController.js +6 -0
  247. package/server/email/emailTemplateService.js +5 -3
  248. package/server/http/httpServer.js +11 -6
  249. package/server/middleware/rateLimit.js +2 -1
  250. package/server/middleware/securityHeaders.js +20 -1
  251. package/server/routes/admin/systemAdminRouter.js +6 -0
  252. package/server/routes/indexRouter.js +30 -6
  253. package/server/routes/observability/grafanaProxyRouter.js +254 -0
  254. package/server/routes/static/staticPageRouter.js +27 -1
  255. package/server/utils/publicContact.js +31 -0
  256. package/utils/time/timeModule.js +135 -0
  257. package/utils/time/timeModule.test.js +65 -0
  258. package/utils/whatsapp/contactEnv.js +39 -0
  259. package/vite.config.mjs +7 -1
  260. package/public/assets/images/brand-icon-192.png +0 -0
  261. package/scripts/sync-readme-snapshot.mjs +0 -133
@@ -1,3 +1,4 @@
1
+ import { now as __timeNow, nowIso as __timeNowIso, toUnixMs as __timeNowMs } from '#time';
1
2
  import logger from '#logger';
2
3
  import { sendAndStore } from '../../services/messaging/messagePersistenceService.js';
3
4
  import { getJidServer, isUserJid, normalizeJid } from '../../config/index.js';
@@ -6,8 +7,7 @@ import { STICKER_PACK_ERROR_CODES, StickerPackError } from './stickerPackErrors.
6
7
  import { captureIncomingStickerAsset, resolveStickerAssetForCommand } from './stickerStorageService.js';
7
8
  import { buildStickerPackMessage, sendStickerPackWithFallback } from './stickerPackMessageService.js';
8
9
  import { sanitizeText } from './stickerPackUtils.js';
9
- import { executeQuery, TABLES } from '../../../database/index.js';
10
- import { extractSenderInfoFromMessage, extractUserIdInfo, resolveUserId } from '../../config/index.js';
10
+ import { extractSenderInfoFromMessage, extractUserIdInfo, normalizePnToJid, primeLidCache, resolveCanonicalWhatsAppJid, resolveUserId, resolveUserIdCached } from '../../config/index.js';
11
11
  import { toWhatsAppPhoneDigits } from '../../services/auth/whatsappLoginLinkService.js';
12
12
 
13
13
  /**
@@ -18,6 +18,7 @@ const RATE_MAX_ACTIONS = Math.max(1, Number(process.env.STICKER_PACK_RATE_MAX_AC
18
18
  const MAX_PACK_ITEMS = Math.max(1, Number(process.env.STICKER_PACK_MAX_ITEMS) || 30);
19
19
  const MAX_PACK_NAME_LENGTH = 120;
20
20
  const LID_SERVERS = new Set(['lid', 'hosted.lid']);
21
+ const OWNER_ID_SERVERS = new Set(['s.whatsapp.net', 'c.us', 'hosted', ...LID_SERVERS]);
21
22
 
22
23
  const rateMap = new Map();
23
24
 
@@ -413,7 +414,7 @@ const formatErrorMessage = (error, commandPrefix) => {
413
414
  * @returns {{ limited: boolean, remainingMs: number }} Estado do limite.
414
415
  */
415
416
  const checkRateLimit = (ownerJid) => {
416
- const now = Date.now();
417
+ const now = __timeNowMs();
417
418
  const entry = rateMap.get(ownerJid);
418
419
 
419
420
  if (!entry || entry.resetAt <= now) {
@@ -456,7 +457,9 @@ const readSingleArgument = (input) => {
456
457
  };
457
458
 
458
459
  const buildOwnerLookupJids = (value) => {
459
- const normalized = normalizeJid(value) || '';
460
+ const normalizedValue = normalizeJid(value) || '';
461
+ const normalizedPn = normalizePnToJid(normalizedValue);
462
+ const normalized = normalizeJid(normalizedPn || normalizedValue) || normalizedPn || normalizedValue;
460
463
  if (!normalized || !normalized.includes('@')) return [];
461
464
  const lookup = new Set([normalized]);
462
465
  const digits = toWhatsAppPhoneDigits(normalized);
@@ -467,12 +470,39 @@ const buildOwnerLookupJids = (value) => {
467
470
  return Array.from(lookup).filter(Boolean);
468
471
  };
469
472
 
470
- const appendOwnerCandidate = (candidateSet, lookupSet, value) => {
471
- const normalized = normalizeJid(value) || '';
473
+ const appendOwnerCandidate = (candidateSet, value) => {
474
+ const normalizedValue = normalizeJid(value) || '';
475
+ const normalizedPn = normalizePnToJid(normalizedValue);
476
+ const normalized = normalizeJid(normalizedPn || normalizedValue) || normalizedPn || normalizedValue;
472
477
  if (!normalized || !normalized.includes('@')) return;
478
+ const server = getJidServer(normalized);
479
+ if (!server || !OWNER_ID_SERVERS.has(server)) return;
473
480
  candidateSet.add(normalized);
474
481
  for (const lookupJid of buildOwnerLookupJids(normalized)) {
475
- lookupSet.add(lookupJid);
482
+ candidateSet.add(lookupJid);
483
+ }
484
+ };
485
+
486
+ const appendOwnerCandidatesFromSource = (candidateSet, source) => {
487
+ if (!source) return;
488
+
489
+ const info = extractUserIdInfo(source);
490
+ appendOwnerCandidate(candidateSet, resolveUserIdCached(info));
491
+ appendOwnerCandidate(candidateSet, info.jid);
492
+ appendOwnerCandidate(candidateSet, info.lid);
493
+ appendOwnerCandidate(candidateSet, info.participantAlt);
494
+ appendOwnerCandidate(candidateSet, info.raw);
495
+
496
+ if (typeof source === 'object') {
497
+ appendOwnerCandidate(candidateSet, source.id);
498
+ appendOwnerCandidate(candidateSet, source.jid);
499
+ appendOwnerCandidate(candidateSet, source.lid);
500
+ appendOwnerCandidate(candidateSet, source.participant);
501
+ appendOwnerCandidate(candidateSet, source.participantAlt);
502
+ appendOwnerCandidate(candidateSet, source.remoteJid);
503
+ appendOwnerCandidate(candidateSet, source.remoteJidAlt);
504
+ } else {
505
+ appendOwnerCandidate(candidateSet, source);
476
506
  }
477
507
  };
478
508
 
@@ -504,58 +534,42 @@ const dedupePacksById = (packs = []) => {
504
534
 
505
535
  const resolveOwnerCandidatesForPackCommand = async ({ senderJid, messageInfo }) => {
506
536
  const candidates = new Set();
507
- const lookupByJid = new Set();
508
537
 
509
538
  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,
539
+ appendOwnerCandidatesFromSource(candidates, senderJid);
540
+ appendOwnerCandidatesFromSource(candidates, senderInfo);
541
+ appendOwnerCandidatesFromSource(candidates, messageInfo?.key);
542
+ appendOwnerCandidatesFromSource(candidates, {
522
543
  jid: senderInfo?.jid || senderJid || null,
544
+ lid: senderInfo?.lid || null,
523
545
  participantAlt: senderInfo?.participantAlt || null,
524
- }).catch(() => null);
525
- if (senderResolved) {
526
- appendOwnerCandidate(candidates, lookupByJid, senderResolved);
527
- }
546
+ remoteJid: senderInfo?.remoteJid || null,
547
+ remoteJidAlt: senderInfo?.remoteJidAlt || null,
548
+ });
528
549
 
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
- }
550
+ const lidCandidates = Array.from(candidates).filter((candidate) => LID_SERVERS.has(getJidServer(candidate)));
551
+ if (lidCandidates.length) {
552
+ await primeLidCache(lidCandidates).catch(() => null);
549
553
  }
550
554
 
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
- }
555
+ const currentCandidates = Array.from(candidates);
556
+ const resolvedCandidates = await Promise.all(
557
+ currentCandidates.map(async (candidate) => {
558
+ const info = extractUserIdInfo(candidate);
559
+ const resolvedCached = resolveUserIdCached(info);
560
+ const resolved = await resolveUserId(info).catch(() => null);
561
+ return [resolvedCached, resolved];
562
+ }),
563
+ );
564
+
565
+ for (const [resolvedCached, resolved] of resolvedCandidates) {
566
+ appendOwnerCandidate(candidates, resolvedCached);
567
+ appendOwnerCandidate(candidates, resolved);
557
568
  }
558
569
 
570
+ const canonicalWhatsApp = resolveCanonicalWhatsAppJid(...Array.from(candidates));
571
+ appendOwnerCandidate(candidates, canonicalWhatsApp);
572
+
559
573
  return Array.from(candidates);
560
574
  };
561
575
 
@@ -711,7 +725,7 @@ export async function handlePackCommand({ sock, remoteJid, messageInfo, expirati
711
725
  const name = normalizePackName(base);
712
726
  const publisher = options.publisher || options.pub || options.autor || senderName || 'OmniZap';
713
727
  const description = options.desc || options.description || '';
714
- const visibility = options.visibility || options.vis || 'public';
728
+ const visibility = options.visibility || options.vis || 'private';
715
729
 
716
730
  const created = await stickerPackService.createPack({
717
731
  ownerJid,
@@ -1120,16 +1134,24 @@ export async function maybeCaptureIncomingSticker({ messageInfo, senderJid, isMe
1120
1134
  if (!isUserJid(senderJid)) return null;
1121
1135
 
1122
1136
  const senderInfo = extractSenderInfoFromMessage(messageInfo);
1123
- let ownerJid = normalizeJid(senderJid) || senderJid;
1137
+ const senderIdentity = extractUserIdInfo({
1138
+ lid: senderInfo?.lid || null,
1139
+ jid: senderInfo?.jid || senderJid || null,
1140
+ participantAlt: senderInfo?.participantAlt || null,
1141
+ remoteJid: senderInfo?.remoteJid || null,
1142
+ remoteJidAlt: senderInfo?.remoteJidAlt || null,
1143
+ });
1144
+
1145
+ const cachedOwner = resolveUserIdCached(senderIdentity);
1146
+ let ownerJid = normalizeJid(cachedOwner || senderIdentity.jid || senderIdentity.lid || senderJid) || senderJid;
1124
1147
  try {
1125
- const resolvedOwner = await resolveUserId({
1126
- lid: senderInfo?.lid,
1127
- jid: senderInfo?.jid || senderJid || null,
1128
- participantAlt: senderInfo?.participantAlt || null,
1129
- });
1148
+ if (senderIdentity.lid) {
1149
+ await primeLidCache([senderIdentity.lid]).catch(() => null);
1150
+ }
1151
+ const resolvedOwner = await resolveUserId(senderIdentity);
1130
1152
  ownerJid = normalizeJid(resolvedOwner || ownerJid) || ownerJid;
1131
1153
  } catch {
1132
- ownerJid = normalizeJid(senderJid) || senderJid;
1154
+ ownerJid = normalizeJid(cachedOwner || senderJid) || senderJid;
1133
1155
  }
1134
1156
 
1135
1157
  try {
@@ -1,3 +1,4 @@
1
+ import { now as __timeNow, nowIso as __timeNowIso, toUnixMs as __timeNowMs } from '#time';
1
2
  const parseEnvList = (value) =>
2
3
  String(value || '')
3
4
  .split(',')
@@ -184,7 +185,7 @@ export const computePackSignals = ({ pack, engagement, packClassification, itemC
184
185
  const packScoreRaw = classificationConfidence * resolvedWeights.classification + engagementScore * resolvedWeights.engagement + qualityScore * resolvedWeights.quality + diversityScore * resolvedWeights.diversity - duplicatePenalty * 0.25;
185
186
  const packScore = Number(clamp(packScoreRaw, 0, 1.5).toFixed(6));
186
187
  const referenceDate = pack?.updated_at || pack?.created_at || null;
187
- const ageMs = referenceDate ? Date.now() - Date.parse(referenceDate) : 0;
188
+ const ageMs = referenceDate ? __timeNowMs() - Date.parse(referenceDate) : 0;
188
189
  const ageDays = Number.isFinite(ageMs) && ageMs > 0 ? ageMs / (24 * 60 * 60 * 1000) : 0;
189
190
  const decayWindow = Math.max(1, Number(ageDecayDays) || AGE_DECAY_DAYS);
190
191
  const ageDecayFactor = Number(Math.exp(-ageDays / decayWindow).toFixed(6));
@@ -1,3 +1,4 @@
1
+ import { now as __timeNow, nowIso as __timeNowIso, toUnixMs as __timeNowMs } from '#time';
1
2
  import { executeQuery, TABLES } from '../../../database/index.js';
2
3
  import { STICKER_DOMAIN_EVENTS } from './domainEvents.js';
3
4
  import { publishStickerDomainEvent } from './stickerDomainEventBus.js';
@@ -396,7 +397,7 @@ export async function softDeleteStickerPack(packId, connection = null) {
396
397
  return updateStickerPackFields(
397
398
  packId,
398
399
  {
399
- deleted_at: new Date(),
400
+ deleted_at: __timeNow(),
400
401
  },
401
402
  connection,
402
403
  );
@@ -1,3 +1,4 @@
1
+ import { now as __timeNow, nowIso as __timeNowIso, toUnixMs as __timeNowMs } from '#time';
1
2
  import { executeQuery, TABLES } from '../../../database/index.js';
2
3
  import logger from '#logger';
3
4
  import { getEmptyStickerPackEngagement, getStickerPackEngagementByPackId } from './stickerPackEngagementRepository.js';
@@ -155,7 +156,7 @@ export const runStickerPackScoreSnapshotCycle = async () => {
155
156
  }
156
157
 
157
158
  running = true;
158
- const startedAt = Date.now();
159
+ const startedAt = __timeNowMs();
159
160
  let scanned = 0;
160
161
  let written = 0;
161
162
  let fullRebuildExecuted = false;
@@ -199,7 +200,7 @@ export const runStickerPackScoreSnapshotCycle = async () => {
199
200
  pending_pack_ids: pendingPackIds.size,
200
201
  full_rebuild_executed: fullRebuildExecuted,
201
202
  full_rebuild_every_cycles: SNAPSHOT_FULL_REBUILD_EVERY_CYCLES,
202
- duration_ms: Date.now() - startedAt,
203
+ duration_ms: __timeNowMs() - startedAt,
203
204
  batch_size: SNAPSHOT_BATCH_SIZE,
204
205
  targeted_batch_size: SNAPSHOT_TARGETED_BATCH_SIZE,
205
206
  });
@@ -212,7 +213,7 @@ export const runStickerPackScoreSnapshotCycle = async () => {
212
213
  removed,
213
214
  pending_pack_ids: pendingPackIds.size,
214
215
  full_rebuild_executed: fullRebuildExecuted,
215
- duration_ms: Date.now() - startedAt,
216
+ duration_ms: __timeNowMs() - startedAt,
216
217
  };
217
218
  } catch (error) {
218
219
  logger.error('Falha no ciclo de snapshot de score de packs.', {
@@ -226,7 +227,7 @@ export const runStickerPackScoreSnapshotCycle = async () => {
226
227
  written,
227
228
  pending_pack_ids: pendingPackIds.size,
228
229
  full_rebuild_executed: fullRebuildExecuted,
229
- duration_ms: Date.now() - startedAt,
230
+ duration_ms: __timeNowMs() - startedAt,
230
231
  };
231
232
  } finally {
232
233
  running = false;
@@ -331,7 +331,7 @@ export function createStickerPackService(options = {}) {
331
331
  };
332
332
  };
333
333
 
334
- const sanitizeMetadata = ({ name, publisher, description, visibility }) => {
334
+ const sanitizeMetadata = ({ name, publisher, description, visibility, defaultVisibility = 'private' }) => {
335
335
  const normalizedName = sanitizeText(name, MAX_NAME_LENGTH, { allowEmpty: false });
336
336
  const normalizedPublisher = sanitizeText(publisher, MAX_PUBLISHER_LENGTH, {
337
337
  allowEmpty: false,
@@ -339,7 +339,7 @@ export function createStickerPackService(options = {}) {
339
339
  const normalizedDescription = sanitizeText(description, MAX_DESCRIPTION_LENGTH, {
340
340
  allowEmpty: true,
341
341
  });
342
- const normalizedVisibility = toVisibility(visibility, 'public');
342
+ const normalizedVisibility = toVisibility(visibility, defaultVisibility);
343
343
 
344
344
  ensureValue(normalizedName, STICKER_PACK_ERROR_CODES.INVALID_INPUT, 'Nome do pack é obrigatório.');
345
345
  ensureValue(normalizedPublisher, STICKER_PACK_ERROR_CODES.INVALID_INPUT, 'Publisher do pack é obrigatório.');
@@ -352,13 +352,20 @@ export function createStickerPackService(options = {}) {
352
352
  };
353
353
  };
354
354
 
355
- const createPack = async ({ ownerJid, name, publisher, description, visibility = 'public', status = 'published', packStatus = undefined, packThemeKey = undefined, packVolume = undefined, isAutoPack = undefined, lastRebalancedAt = undefined }) => {
355
+ const createPack = async ({ ownerJid, name, publisher, description, visibility = undefined, status = 'published', packStatus = undefined, packThemeKey = undefined, packVolume = undefined, isAutoPack = undefined, lastRebalancedAt = undefined }) => {
356
356
  const owner = resolveOwner(ownerJid);
357
+ const isAutoPackEnabled = isAutoPack === true || Number(isAutoPack || 0) === 1;
357
358
  const normalizedStatus = PACK_STATUS_VALUES.has(String(status || '').toLowerCase()) ? String(status).toLowerCase() : 'published';
358
359
 
359
360
  return runAction('create_pack', { owner_jid: owner }, async () => {
360
361
  return runInTransaction(async (connection) => {
361
- const metadata = sanitizeMetadata({ name, publisher, description, visibility });
362
+ const metadata = sanitizeMetadata({
363
+ name,
364
+ publisher,
365
+ description,
366
+ visibility,
367
+ defaultVisibility: isAutoPackEnabled ? 'public' : 'private',
368
+ });
362
369
  if (hasOwnerPackLimit) {
363
370
  const existing = await deps.packRepository.listStickerPacksByOwner(owner, {
364
371
  limit: maxPacksPerOwner + 1,
@@ -384,7 +391,7 @@ export function createStickerPackService(options = {}) {
384
391
  pack_status: packStatus,
385
392
  pack_theme_key: packThemeKey,
386
393
  pack_volume: packVolume,
387
- is_auto_pack: isAutoPack,
394
+ is_auto_pack: isAutoPackEnabled,
388
395
  last_rebalanced_at: lastRebalancedAt,
389
396
  version: 1,
390
397
  },
@@ -679,7 +686,7 @@ export function createStickerPackService(options = {}) {
679
686
  description: source.description,
680
687
  pack_key: packKey,
681
688
  cover_sticker_id: source.cover_sticker_id,
682
- visibility: 'public',
689
+ visibility: 'private',
683
690
  version: 1,
684
691
  },
685
692
  connection,
@@ -1,3 +1,4 @@
1
+ import { now as __timeNow, nowIso as __timeNowIso, toUnixMs as __timeNowMs } from '#time';
1
2
  import fs from 'node:fs/promises';
2
3
  import path from 'node:path';
3
4
  import { createHash, randomUUID } from 'node:crypto';
@@ -149,7 +150,7 @@ const rememberLastSticker = (ownerJid, assetId) => {
149
150
  const normalized = normalizeOwnerJid(ownerJid);
150
151
  lastStickerCache.set(normalized, {
151
152
  assetId,
152
- expiresAt: Date.now() + LAST_STICKER_TTL_MS,
153
+ expiresAt: __timeNowMs() + LAST_STICKER_TTL_MS,
153
154
  });
154
155
  };
155
156
 
@@ -164,7 +165,7 @@ const resolveLastStickerAssetId = (ownerJid) => {
164
165
  const entry = lastStickerCache.get(normalized);
165
166
  if (!entry) return null;
166
167
 
167
- if (entry.expiresAt <= Date.now()) {
168
+ if (entry.expiresAt <= __timeNowMs()) {
168
169
  lastStickerCache.delete(normalized);
169
170
  return null;
170
171
  }
@@ -1,3 +1,4 @@
1
+ import { now as __timeNow, nowIso as __timeNowIso, toUnixMs as __timeNowMs } from '#time';
1
2
  import logger from '#logger';
2
3
  import { setQueueDepth } from '../../observability/metrics.js';
3
4
  import { isFeatureEnabled } from '../../services/infra/featureFlagService.js';
@@ -71,7 +72,7 @@ const scheduleTaskIfNeeded = async (taskType) => {
71
72
  const cadence = TASK_CADENCE_MS[taskType];
72
73
  if (!cadence) return;
73
74
 
74
- const now = Date.now();
75
+ const now = __timeNowMs();
75
76
  const nextDueAt = nextScheduleByTask.get(taskType) || 0;
76
77
  if (now < nextDueAt) return;
77
78
 
@@ -7,7 +7,7 @@ Este arquivo e destinado a agentes de IA para gerar respostas no contexto dos co
7
7
  - arquivo_base: `app/modules/systemMetricsModule/commandConfig.json`
8
8
  - schema_version: `2.0.0`
9
9
  - module_enabled: `true`
10
- - generated_at: `2026-03-11T02:35:17.177Z`
10
+ - generated_at: `2026-03-17T04:04:14.195Z`
11
11
 
12
12
  ## Escopo do Modulo
13
13
 
@@ -335,6 +335,35 @@
335
335
  "schema": "legacy_v1_and_v2",
336
336
  "legacy_name": "statusbot",
337
337
  "legacy_fields_present": ["descricao", "metodos_de_uso", "permissao_necessaria", "local_de_uso", "informacoes_coletadas", "argumentos", "pre_condicoes", "dependencias_externas", "efeitos_colaterais", "observabilidade", "privacidade", "acesso", "limite_uso_por_plano"]
338
+ },
339
+ "user_experience": {
340
+ "resumo_usuario": "Exibe latência e estado de saúde do servidor com um comando simples. Não requer Premium.",
341
+ "quando_usar": ["Antes de iniciar tarefas importantes, para confirmar se o servidor está respondendo.", "Após perceber lentidão ou instabilidade, para checar o status rapidamente.", "Durante monitoramento rápido para verificar se tudo está estável ao longo do dia."],
342
+ "exemplos_reais": [
343
+ {
344
+ "situacao": "Checagem rápida antes de iniciar uma tarefa.",
345
+ "comando": "<prefix>statusbot",
346
+ "resposta_esperada": "Latência atual: 42 ms | Status: OK.",
347
+ "variacao": "ou <prefix>ping."
348
+ },
349
+ {
350
+ "situacao": "Lentidão percebida durante pico de tráfego.",
351
+ "comando": "<prefix>statusbot",
352
+ "resposta_esperada": "Latência atual: 320 ms | Status: Atenção - possíveis lentidões. Verifique sua rede.",
353
+ "variacao": "Se o problema persistir, tente novamente em alguns minutos."
354
+ },
355
+ {
356
+ "situacao": "Verificando disponibilidade após manutenção.",
357
+ "comando": "<prefix>statusbot",
358
+ "resposta_esperada": "Latência atual: 15 ms | Status: OK.",
359
+ "variacao": "Se retornar erro, espere e tente novamente."
360
+ }
361
+ ],
362
+ "resposta_esperada": ["Latência atual: <valor> ms | Status: OK.", "Latência atual: <valor> ms | Status: Atenção - verifique rede.", "Latência atual: <valor> ms | Status: ERRO - serviço indisponível."],
363
+ "erros_comuns_usuario": ["Esquecer de incluir o prefixo <prefix> ao digitar o comando.", "Executar sem estar conectado à internet ou com a rede instável.", "Esperar uma resposta com muitos detalhes além da latência e do status simples.", "Não estar logado com Google quando a autenticação for necessária.", "Tentar usar o comando em horários de manutenção sem observar a latência."],
364
+ "passos_se_der_erro": ["Verifique a sua conexão com a internet e tente novamente.", "Aguarde alguns segundos e execute novamente o comando: <prefix>statusbot.", "Confira se há mensagens de erro específicas (ex.: permissionError) e corrija as permissões se necessário.", "Se o problema persistir, tente em outro momento ou contate o suporte, descrevendo o que aconteceu."],
365
+ "resumo_usuario_origem": "auto_ia_assistida",
366
+ "resumo_usuario_revisao_pendente": true
338
367
  }
339
368
  }
340
369
  ],
@@ -1,3 +1,4 @@
1
+ import { now as __timeNow, nowIso as __timeNowIso, toUnixMs as __timeNowMs } from '#time';
1
2
  import logger from '#logger';
2
3
  import { getSystemMetrics } from '../../utils/systemMetrics/systemMetricsModule.js';
3
4
  import { sendAndStore } from '../../services/messaging/messagePersistenceService.js';
@@ -50,7 +51,7 @@ const formatStatusLevel = (status) => `${status.emoji} ${status.label}`;
50
51
 
51
52
  const padNumber = (value) => String(value).padStart(2, '0');
52
53
 
53
- const formatDateTime = (date = new Date()) => `${padNumber(date.getDate())}/${padNumber(date.getMonth() + 1)}/${date.getFullYear()} ${padNumber(date.getHours())}:${padNumber(date.getMinutes())}:${padNumber(date.getSeconds())}`;
54
+ const formatDateTime = (date = __timeNow()) => `${padNumber(date.getDate())}/${padNumber(date.getMonth() + 1)}/${date.getFullYear()} ${padNumber(date.getHours())}:${padNumber(date.getMinutes())}:${padNumber(date.getSeconds())}`;
54
55
 
55
56
  const parseLabels = (raw) => {
56
57
  if (!raw) return {};
@@ -260,7 +261,7 @@ const fetchMetricsSnapshot = async () => {
260
261
  const series = parsePrometheusText(text);
261
262
 
262
263
  const processStart = pickValue(series, 'omnizap_process_start_time_seconds');
263
- const nowSec = Date.now() / 1000;
264
+ const nowSec = __timeNowMs() / 1000;
264
265
  const processUptime = processStart ? formatSeconds(nowSec - processStart) : 'n/a';
265
266
 
266
267
  const cpuUserSec = pickValue(series, 'omnizap_process_cpu_user_seconds_total');
@@ -369,7 +370,7 @@ const fetchMetricsSnapshot = async () => {
369
370
 
370
371
  export async function handlePingCommand({ sock, remoteJid, messageInfo, expirationMessage }) {
371
372
  try {
372
- const startedAt = Date.now();
373
+ const startedAt = __timeNowMs();
373
374
  const systemMetrics = getSystemMetrics();
374
375
  let metricsSummary = null;
375
376
  let metricsOk = false;
@@ -388,8 +389,8 @@ export async function handlePingCommand({ sock, remoteJid, messageInfo, expirati
388
389
  metricsSummary,
389
390
  metricsOk,
390
391
  metricsError,
391
- latencyMs: Date.now() - startedAt,
392
- generatedAt: new Date(),
392
+ latencyMs: __timeNowMs() - startedAt,
393
+ generatedAt: __timeNow(),
393
394
  });
394
395
  await sendAndStore(sock, remoteJid, { text }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
395
396
  } catch (error) {
@@ -7,7 +7,7 @@ Este arquivo e destinado a agentes de IA para gerar respostas no contexto dos co
7
7
  - arquivo_base: `app/modules/tiktokModule/commandConfig.json`
8
8
  - schema_version: `2.0.0`
9
9
  - module_enabled: `true`
10
- - generated_at: `2026-03-11T02:35:17.177Z`
10
+ - generated_at: `2026-03-17T04:04:14.195Z`
11
11
 
12
12
  ## Escopo do Modulo
13
13
 
@@ -357,6 +357,35 @@
357
357
  "schema": "legacy_v1_and_v2",
358
358
  "legacy_name": "baixartiktok",
359
359
  "legacy_fields_present": ["descricao", "metodos_de_uso", "permissao_necessaria", "local_de_uso", "informacoes_coletadas", "argumentos", "pre_condicoes", "dependencias_externas", "efeitos_colaterais", "observabilidade", "privacidade", "acesso", "limite_uso_por_plano"]
360
+ },
361
+ "user_experience": {
362
+ "resumo_usuario": "Baixe vídeos do TikTok sem marca d'água a partir de URLs, direto no chat.",
363
+ "quando_usar": ["Quero salvar vídeos do TikTok sem a marca d’água para assistir offline.", "Preciso baixar até 5 vídeos de uma vez.", "Uso rápido: baixar rapidamente sem complicações."],
364
+ "exemplos_reais": [
365
+ {
366
+ "situacao": "Baixar um único vídeo.",
367
+ "comando": "<prefix>baixartiktok https://www.tiktok.com/@usuario/video/12345",
368
+ "resposta_esperada": "Comando executado com sucesso.",
369
+ "variacao": "<prefix>tt https://tiktok.com/@usuario/video/12345."
370
+ },
371
+ {
372
+ "situacao": "Baixar até 5 vídeos de uma vez.",
373
+ "comando": "<prefix>tt https://www.tiktok.com/@a/video/1 https://www.tiktok.com/@b/video/2",
374
+ "resposta_esperada": "Comando executado com sucesso.",
375
+ "variacao": "<prefix>baixartiktok https://tiktok.com/@a/video/1 https://tiktok.com/@b/video/2."
376
+ },
377
+ {
378
+ "situacao": "Formato de uso inválido.",
379
+ "comando": "<prefix>baixartiktok",
380
+ "resposta_esperada": "Formato de uso inválido. Consulte metodos_de_uso.",
381
+ "variacao": "<prefix>tt <url> <url> extra."
382
+ }
383
+ ],
384
+ "resposta_esperada": ["Comando executado com sucesso.", "Formato de uso inválido. Consulte metodos_de_uso.", "Permissão insuficiente para executar este comando."],
385
+ "erros_comuns_usuario": ["Não incluir URL(s) ou incluir mais de 5 URLs.", "Usar URLs que não são do TikTok.", "Esquecer de colocar o prefixo correto do comando.", "Tentar usar sem conexão estável."],
386
+ "passos_se_der_erro": ["Confira se inseriu entre 1 e 5 URLs válidas do TikTok.", "Use o formato correto: <prefix>baixartiktok <url> ou <prefix>tt <url1> <url2> ...", "Verifique a sua conexão com a internet.", "Se o erro persistir, tente novamente mais tarde ou contate o suporte."],
387
+ "resumo_usuario_origem": "auto_ia_assistida",
388
+ "resumo_usuario_revisao_pendente": true
360
389
  }
361
390
  }
362
391
  ],
@@ -1,3 +1,4 @@
1
+ import { now as __timeNow, nowIso as __timeNowIso, toUnixMs as __timeNowMs } from '#time';
1
2
  import axios from 'axios';
2
3
  import fs from 'node:fs';
3
4
  import fsp from 'node:fs/promises';
@@ -132,7 +133,7 @@ const safeUnlink = async (filePath) => {
132
133
  }
133
134
  };
134
135
 
135
- const buildTempFilePath = () => path.join(TEMP_DIR, `tiktok-${Date.now()}-${randomUUID()}.mp4`);
136
+ const buildTempFilePath = () => path.join(TEMP_DIR, `tiktok-${__timeNowMs()}-${randomUUID()}.mp4`);
136
137
 
137
138
  const requestExtract = async (videoUrl) => {
138
139
  const endpoint = `${TIKTOK_EXTRACT_BASE_URL}${TIKTOK_EXTRACT_PATH.startsWith('/') ? TIKTOK_EXTRACT_PATH : `/${TIKTOK_EXTRACT_PATH}`}`;
@@ -7,7 +7,7 @@ Este arquivo e destinado a agentes de IA para gerar respostas no contexto dos co
7
7
  - arquivo_base: `app/modules/userModule/commandConfig.json`
8
8
  - schema_version: `2.0.0`
9
9
  - module_enabled: `true`
10
- - generated_at: `2026-03-11T02:35:17.177Z`
10
+ - generated_at: `2026-03-17T04:04:14.195Z`
11
11
 
12
12
  ## Escopo do Modulo
13
13
 
@@ -377,6 +377,35 @@
377
377
  "schema": "legacy_v1_and_v2",
378
378
  "legacy_name": "perfil",
379
379
  "legacy_fields_present": ["descricao", "metodos_de_uso", "permissao_necessaria", "local_de_uso", "informacoes_coletadas", "argumentos", "pre_condicoes", "dependencias_externas", "efeitos_colaterais", "observabilidade", "privacidade", "acesso", "limite_uso_por_plano"]
380
+ },
381
+ "user_experience": {
382
+ "resumo_usuario": "Consulta o perfil e estatísticas de um usuário. Exibe dados básicos como nome, bio, foto e métricas rápidas.",
383
+ "quando_usar": ["Precisa ver informações de alguém no chat.", "Quer confirmar dados de um usuário pelo id, telefone ou menção.", "Antes de agir com base no perfil, verifique as informações obtidas."],
384
+ "exemplos_reais": [
385
+ {
386
+ "situacao": "Ver o próprio perfil.",
387
+ "comando": "<prefix>perfil perfil",
388
+ "resposta_esperada": "Perfil exibido com dados básicos do seu usuário.",
389
+ "variacao": "perfil."
390
+ },
391
+ {
392
+ "situacao": "Consultar perfil por ID.",
393
+ "comando": "<prefix>perfil perfil 12345",
394
+ "resposta_esperada": "Perfil do usuário 12345 exibido.",
395
+ "variacao": "<prefix>perfil perfil 12345."
396
+ },
397
+ {
398
+ "situacao": "Consultar perfil por @contato.",
399
+ "comando": "<prefix>usuario perfil @joana",
400
+ "resposta_esperada": "Perfil do contato exibido.",
401
+ "variacao": "<prefix>usuario perfil @joana."
402
+ }
403
+ ],
404
+ "resposta_esperada": ["Perfil exibido com sucesso com informações básicas e estatísticas.", "Erro: usuário não encontrado ou alvo inválido."],
405
+ "erros_comuns_usuario": ["Formato de uso inválido. Use <prefix>perfil perfil [alvo].", "Alvo ausente ou inválido (id, telefone ou menção).", "Não autorizado: verifique se está logado com sua conta Google."],
406
+ "passos_se_der_erro": ["Conferir formato do comando: <prefix>perfil perfil [alvo].", "Verificar o alvo informado (id, telefone ou menção).", "Garantir login com conta Google.", "Se o erro persistir, tente novamente mais tarde ou contate o suporte com o comando utilizado."],
407
+ "resumo_usuario_origem": "auto_ia_assistida",
408
+ "resumo_usuario_revisao_pendente": true
380
409
  }
381
410
  }
382
411
  ],