@omnizap-system/omnizap 2.5.12

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 (425) hide show
  1. package/.clusterfuzzlite/Dockerfile +10 -0
  2. package/.env.example +907 -0
  3. package/.github/codeql/codeql-config.yml +10 -0
  4. package/.github/dependabot.yml +35 -0
  5. package/.github/workflows/ci.yml +73 -0
  6. package/.github/workflows/codeql.yml +106 -0
  7. package/.github/workflows/db-migration-check.yml +98 -0
  8. package/.github/workflows/dependency-review.yml +22 -0
  9. package/.github/workflows/deploy.yml +95 -0
  10. package/.github/workflows/release.yml +106 -0
  11. package/.github/workflows/security-attest-provenance.yml +51 -0
  12. package/.github/workflows/security-gitleaks.yml +34 -0
  13. package/.github/workflows/security-runner-hardening.yml +31 -0
  14. package/.github/workflows/security-scorecard.yml +44 -0
  15. package/.github/workflows/security-zap-baseline.yml +44 -0
  16. package/.github/workflows/security-zap-full-scan.yml +43 -0
  17. package/.github/workflows/security-zizmor.yml +36 -0
  18. package/.github/workflows/wiki-sync.yml +44 -0
  19. package/.gitleaks.toml +15 -0
  20. package/.prettierrc +34 -0
  21. package/CODE_OF_CONDUCT.md +114 -0
  22. package/LICENSE +56 -0
  23. package/README.md +110 -0
  24. package/SECURITY.md +110 -0
  25. package/app/config/index.js +4 -0
  26. package/app/configParts/adminIdentity.js +92 -0
  27. package/app/configParts/baileysConfig.js +1818 -0
  28. package/app/configParts/groupUtils.js +692 -0
  29. package/app/configParts/loggerConfig.js +394 -0
  30. package/app/configParts/messagePersistenceService.js +305 -0
  31. package/app/connection/baileysCompatibility.test.js +40 -0
  32. package/app/connection/baileysDbAuthState.js +344 -0
  33. package/app/connection/socketController.js +2243 -0
  34. package/app/controllers/messageController.js +7 -0
  35. package/app/controllers/messagePipeline/commandMiddleware.js +146 -0
  36. package/app/controllers/messagePipeline/conversationMiddleware.js +183 -0
  37. package/app/controllers/messagePipeline/messagePipelineMiddlewares.test.js +522 -0
  38. package/app/controllers/messagePipeline/postProcessingMiddleware.js +41 -0
  39. package/app/controllers/messagePipeline/preProcessingMiddlewares.js +166 -0
  40. package/app/controllers/messageProcessingPipeline.js +699 -0
  41. package/app/modules/adminModule/AGENT.md +4056 -0
  42. package/app/modules/adminModule/adminAiHelpService.js +56 -0
  43. package/app/modules/adminModule/adminConfigRuntime.js +177 -0
  44. package/app/modules/adminModule/commandConfig.json +7122 -0
  45. package/app/modules/adminModule/groupCommandHandlers.js +1823 -0
  46. package/app/modules/adminModule/groupCommandHandlers.test.js +350 -0
  47. package/app/modules/adminModule/groupEventHandlers.js +399 -0
  48. package/app/modules/aiModule/AGENT.md +547 -0
  49. package/app/modules/aiModule/aiAiHelpService.js +14 -0
  50. package/app/modules/aiModule/aiConfigRuntime.js +135 -0
  51. package/app/modules/aiModule/catCommand.js +967 -0
  52. package/app/modules/aiModule/commandConfig.json +981 -0
  53. package/app/modules/analyticsModule/messageAnalysisEventRepository.js +83 -0
  54. package/app/modules/gameModule/AGENT.md +196 -0
  55. package/app/modules/gameModule/commandConfig.json +366 -0
  56. package/app/modules/gameModule/diceCommand.js +42 -0
  57. package/app/modules/gameModule/gameAiHelpService.js +14 -0
  58. package/app/modules/gameModule/gameConfigRuntime.js +68 -0
  59. package/app/modules/menuModule/AGENT.md +205 -0
  60. package/app/modules/menuModule/commandConfig.json +366 -0
  61. package/app/modules/menuModule/common.js +316 -0
  62. package/app/modules/menuModule/menuAiHelpService.js +14 -0
  63. package/app/modules/menuModule/menuConfigRuntime.js +68 -0
  64. package/app/modules/menuModule/menus.js +66 -0
  65. package/app/modules/playModule/AGENT.md +321 -0
  66. package/app/modules/playModule/commandConfig.json +584 -0
  67. package/app/modules/playModule/playAiHelpService.js +14 -0
  68. package/app/modules/playModule/playCommand.js +1417 -0
  69. package/app/modules/playModule/playConfigRuntime.js +68 -0
  70. package/app/modules/quoteModule/AGENT.md +199 -0
  71. package/app/modules/quoteModule/commandConfig.json +366 -0
  72. package/app/modules/quoteModule/quoteAiHelpService.js +14 -0
  73. package/app/modules/quoteModule/quoteCommand.js +842 -0
  74. package/app/modules/quoteModule/quoteConfigRuntime.js +68 -0
  75. package/app/modules/rpgPokemonModule/AGENT.md +229 -0
  76. package/app/modules/rpgPokemonModule/commandConfig.json +386 -0
  77. package/app/modules/rpgPokemonModule/rpgBattleCanvasRenderer.js +795 -0
  78. package/app/modules/rpgPokemonModule/rpgBattleService.js +2110 -0
  79. package/app/modules/rpgPokemonModule/rpgBattleService.test.js +770 -0
  80. package/app/modules/rpgPokemonModule/rpgEvolutionUtils.js +22 -0
  81. package/app/modules/rpgPokemonModule/rpgPokemonAiHelpService.js +14 -0
  82. package/app/modules/rpgPokemonModule/rpgPokemonCommand.js +174 -0
  83. package/app/modules/rpgPokemonModule/rpgPokemonConfigRuntime.js +68 -0
  84. package/app/modules/rpgPokemonModule/rpgPokemonDomain.js +192 -0
  85. package/app/modules/rpgPokemonModule/rpgPokemonDomain.test.js +93 -0
  86. package/app/modules/rpgPokemonModule/rpgPokemonEvolution.test.js +46 -0
  87. package/app/modules/rpgPokemonModule/rpgPokemonMessages.js +746 -0
  88. package/app/modules/rpgPokemonModule/rpgPokemonRepository.js +1847 -0
  89. package/app/modules/rpgPokemonModule/rpgPokemonService.js +6839 -0
  90. package/app/modules/rpgPokemonModule/rpgProfileCanvasRenderer.js +354 -0
  91. package/app/modules/statsModule/AGENT.md +320 -0
  92. package/app/modules/statsModule/commandConfig.json +540 -0
  93. package/app/modules/statsModule/globalRankingCommand.js +64 -0
  94. package/app/modules/statsModule/rankingCommand.js +41 -0
  95. package/app/modules/statsModule/rankingCommon.js +1305 -0
  96. package/app/modules/statsModule/statsAiHelpService.js +14 -0
  97. package/app/modules/statsModule/statsConfigRuntime.js +68 -0
  98. package/app/modules/stickerModule/AGENT.md +692 -0
  99. package/app/modules/stickerModule/addStickerMetadata.js +239 -0
  100. package/app/modules/stickerModule/commandConfig.json +1216 -0
  101. package/app/modules/stickerModule/convertToWebp.js +367 -0
  102. package/app/modules/stickerModule/stickerAiHelpService.js +14 -0
  103. package/app/modules/stickerModule/stickerCommand.js +446 -0
  104. package/app/modules/stickerModule/stickerConfigRuntime.js +68 -0
  105. package/app/modules/stickerModule/stickerConvertCommand.js +159 -0
  106. package/app/modules/stickerModule/stickerTextCommand.js +653 -0
  107. package/app/modules/stickerPackModule/AGENT.md +215 -0
  108. package/app/modules/stickerPackModule/autoPackCollectorRuntime.js +20 -0
  109. package/app/modules/stickerPackModule/autoPackCollectorService.js +357 -0
  110. package/app/modules/stickerPackModule/commandConfig.json +387 -0
  111. package/app/modules/stickerPackModule/domainEventOutboxRepository.js +227 -0
  112. package/app/modules/stickerPackModule/domainEvents.js +52 -0
  113. package/app/modules/stickerPackModule/semanticReclassificationEngine.js +429 -0
  114. package/app/modules/stickerPackModule/semanticReclassificationEngine.test.js +75 -0
  115. package/app/modules/stickerPackModule/semanticThemeClusterService.js +544 -0
  116. package/app/modules/stickerPackModule/stickerAssetClassificationRepository.js +400 -0
  117. package/app/modules/stickerPackModule/stickerAssetRepository.js +400 -0
  118. package/app/modules/stickerPackModule/stickerAssetReprocessQueueRepository.js +175 -0
  119. package/app/modules/stickerPackModule/stickerAutoPackByTagsRuntime.js +3702 -0
  120. package/app/modules/stickerPackModule/stickerClassificationBackgroundRuntime.js +559 -0
  121. package/app/modules/stickerPackModule/stickerClassificationService.js +557 -0
  122. package/app/modules/stickerPackModule/stickerDedicatedTaskWorkerRuntime.js +249 -0
  123. package/app/modules/stickerPackModule/stickerDomainEventBus.js +65 -0
  124. package/app/modules/stickerPackModule/stickerDomainEventConsumerRuntime.js +208 -0
  125. package/app/modules/stickerPackModule/stickerMarketplaceDriftService.js +99 -0
  126. package/app/modules/stickerPackModule/stickerObjectStorageService.js +285 -0
  127. package/app/modules/stickerPackModule/stickerPackAiHelpService.js +14 -0
  128. package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +1148 -0
  129. package/app/modules/stickerPackModule/stickerPackConfigRuntime.js +68 -0
  130. package/app/modules/stickerPackModule/stickerPackEngagementRepository.js +152 -0
  131. package/app/modules/stickerPackModule/stickerPackErrors.js +30 -0
  132. package/app/modules/stickerPackModule/stickerPackInteractionEventRepository.js +101 -0
  133. package/app/modules/stickerPackModule/stickerPackItemRepository.js +432 -0
  134. package/app/modules/stickerPackModule/stickerPackMarketplaceService.js +313 -0
  135. package/app/modules/stickerPackModule/stickerPackMessageService.js +268 -0
  136. package/app/modules/stickerPackModule/stickerPackRepository.js +450 -0
  137. package/app/modules/stickerPackModule/stickerPackScoreSnapshotRepository.js +179 -0
  138. package/app/modules/stickerPackModule/stickerPackScoreSnapshotRuntime.js +271 -0
  139. package/app/modules/stickerPackModule/stickerPackService.js +733 -0
  140. package/app/modules/stickerPackModule/stickerPackServiceRuntime.js +32 -0
  141. package/app/modules/stickerPackModule/stickerPackUtils.js +107 -0
  142. package/app/modules/stickerPackModule/stickerStorageService.js +559 -0
  143. package/app/modules/stickerPackModule/stickerWorkerPipelineRuntime.js +242 -0
  144. package/app/modules/stickerPackModule/stickerWorkerTaskQueueRepository.js +242 -0
  145. package/app/modules/systemMetricsModule/AGENT.md +193 -0
  146. package/app/modules/systemMetricsModule/commandConfig.json +344 -0
  147. package/app/modules/systemMetricsModule/pingCommand.js +399 -0
  148. package/app/modules/systemMetricsModule/systemMetricsAiHelpService.js +14 -0
  149. package/app/modules/systemMetricsModule/systemMetricsConfigRuntime.js +68 -0
  150. package/app/modules/tiktokModule/AGENT.md +196 -0
  151. package/app/modules/tiktokModule/commandConfig.json +366 -0
  152. package/app/modules/tiktokModule/tiktokAiHelpService.js +14 -0
  153. package/app/modules/tiktokModule/tiktokCommand.js +716 -0
  154. package/app/modules/tiktokModule/tiktokConfigRuntime.js +68 -0
  155. package/app/modules/userModule/AGENT.md +200 -0
  156. package/app/modules/userModule/commandConfig.json +386 -0
  157. package/app/modules/userModule/userAiHelpService.js +14 -0
  158. package/app/modules/userModule/userCommand.js +1155 -0
  159. package/app/modules/userModule/userConfigRuntime.js +68 -0
  160. package/app/modules/waifuPicsModule/AGENT.md +431 -0
  161. package/app/modules/waifuPicsModule/commandConfig.json +780 -0
  162. package/app/modules/waifuPicsModule/waifuPicsAiHelpService.js +14 -0
  163. package/app/modules/waifuPicsModule/waifuPicsCommand.js +586 -0
  164. package/app/modules/waifuPicsModule/waifuPicsConfigRuntime.js +68 -0
  165. package/app/observability/metrics.js +766 -0
  166. package/app/services/ai/aiHelpResponseCacheRepository.js +280 -0
  167. package/app/services/ai/aiLearningRepository.js +400 -0
  168. package/app/services/ai/commandConfigEnrichmentRepository.js +769 -0
  169. package/app/services/ai/commandConfigEnrichmentService.js +452 -0
  170. package/app/services/ai/commandConfigValidationService.js +443 -0
  171. package/app/services/ai/commandToolBuilderService.js +192 -0
  172. package/app/services/ai/conversationRouterService.js +516 -0
  173. package/app/services/ai/geminiService.js +115 -0
  174. package/app/services/ai/geminiService.test.js +87 -0
  175. package/app/services/ai/globalModuleAiHelpService.js +1412 -0
  176. package/app/services/ai/globalToolCallingService.js +203 -0
  177. package/app/services/ai/messageCommandExecutionService.js +391 -0
  178. package/app/services/ai/moduleAiHelpCoreService.js +1099 -0
  179. package/app/services/ai/moduleAiHelpWrapperFactory.js +65 -0
  180. package/app/services/ai/moduleCommandConfigRuntimeService.js +113 -0
  181. package/app/services/ai/moduleToolExecutorService.js +464 -0
  182. package/app/services/ai/moduleToolRegistryService.js +178 -0
  183. package/app/services/ai/toolCandidateSelectorService.js +781 -0
  184. package/app/services/auth/googleWebLinkService.js +80 -0
  185. package/app/services/auth/whatsappLoginLinkService.js +230 -0
  186. package/app/services/external/pokeApiService.js +398 -0
  187. package/app/services/group/groupMetadataService.js +311 -0
  188. package/app/services/infra/dbWriteQueue.js +874 -0
  189. package/app/services/infra/featureFlagService.js +131 -0
  190. package/app/services/infra/queueUtils.js +55 -0
  191. package/app/services/messaging/captchaService.js +491 -0
  192. package/app/services/messaging/messagePersistenceService.js +1 -0
  193. package/app/services/messaging/newsBroadcastService.js +347 -0
  194. package/app/services/sticker/stickerFocusService.js +347 -0
  195. package/app/services/sticker/stickerFocusService.test.js +43 -0
  196. package/app/store/aiPromptStore.js +38 -0
  197. package/app/store/conversationSessionStore.js +131 -0
  198. package/app/store/groupConfigStore.js +58 -0
  199. package/app/store/premiumUserStore.js +54 -0
  200. package/app/utils/antiLink/antiLinkModule.js +700 -0
  201. package/app/utils/http/getImageBufferModule.js +18 -0
  202. package/app/utils/json/jsonSanitizer.js +113 -0
  203. package/app/utils/json/jsonSanitizer.test.js +40 -0
  204. package/app/utils/systemMetrics/systemMetricsModule.js +88 -0
  205. package/app/workers/aiLearningWorker.js +605 -0
  206. package/app/workers/commandConfigEnrichmentWorker.js +242 -0
  207. package/database/index.js +2075 -0
  208. package/database/init.js +151 -0
  209. package/database/migrations/.gitkeep +0 -0
  210. package/database/migrations/20260307_d0_hardening_down.sql +64 -0
  211. package/database/migrations/20260307_d0_hardening_up.sql +79 -0
  212. package/database/migrations/20260307_d1_terms_acceptance_down.sql +11 -0
  213. package/database/migrations/20260307_d1_terms_acceptance_up.sql +37 -0
  214. package/database/migrations/20260307_d2_auth_hardening_down.sql +75 -0
  215. package/database/migrations/20260307_d2_auth_hardening_up.sql +100 -0
  216. package/database/migrations/20260314_d7_canonical_sender_down.sql +53 -0
  217. package/database/migrations/20260314_d7_canonical_sender_up.sql +114 -0
  218. package/database/migrations/20260406_d30_security_analytics_down.sql +95 -0
  219. package/database/migrations/20260406_d30_security_analytics_up.sql +292 -0
  220. package/database/migrations/20260407_d31_web_google_session_token_hardening_down.sql +2 -0
  221. package/database/migrations/20260407_d31_web_google_session_token_hardening_up.sql +17 -0
  222. package/database/migrations/20260408_d32_ai_help_response_cache_down.sql +1 -0
  223. package/database/migrations/20260408_d32_ai_help_response_cache_up.sql +22 -0
  224. package/database/migrations/20260409_d33_ai_learning_tables_down.sql +4 -0
  225. package/database/migrations/20260409_d33_ai_learning_tables_up.sql +52 -0
  226. package/database/migrations/20260410_d34_command_config_enrichment_down.sql +3 -0
  227. package/database/migrations/20260410_d34_command_config_enrichment_up.sql +48 -0
  228. package/database/schema.sql +1186 -0
  229. package/docker-compose.yml +104 -0
  230. package/docs/audits/stickerCatalogController-out-of-scope.md +103 -0
  231. package/docs/audits/stickerCatalogController-symbols.md +58 -0
  232. package/docs/compliance/acceptable-use-policy-2026-03-07.md +35 -0
  233. package/docs/compliance/dpa-b2b-standard-2026-03-07.md +80 -0
  234. package/docs/compliance/monthly-compliance-checklist-2026-03-07.md +88 -0
  235. package/docs/compliance/notice-and-takedown-policy-2026-03-07.md +34 -0
  236. package/docs/compliance/privacy-policy-2026-03-07.md +75 -0
  237. package/docs/compliance/subprocessors-inventory-2026-03-07.md +16 -0
  238. package/docs/database/production-db-evolution-runbook-2026q1.md +365 -0
  239. package/docs/security/dsar-lgpd-runbook-2026-03-07.md +86 -0
  240. package/docs/security/incident-response-lgpd-anpd-runbook-2026-03-07.md +77 -0
  241. package/docs/security/network-hardening-runbook-2026-03-07.md +137 -0
  242. package/docs/seo/omnizap-seo-playbook-br-2026-02-28.md +238 -0
  243. package/docs/seo/satellite-page-template.md +116 -0
  244. package/docs/seo/satellite-pages-phase1.json +364 -0
  245. package/docs/wiki/Home.md +120 -0
  246. package/docs/wiki/pair-extraordinaire-2026-03-08.md +3 -0
  247. package/docs/wiki/recent-changes-2026-03-08.md +47 -0
  248. package/ecosystem.prod.config.cjs +135 -0
  249. package/eslint.config.js +89 -0
  250. package/index.js +488 -0
  251. package/ml/clip_classifier/Dockerfile +18 -0
  252. package/ml/clip_classifier/README.md +118 -0
  253. package/ml/clip_classifier/adaptive_scoring.py +40 -0
  254. package/ml/clip_classifier/classifier.py +654 -0
  255. package/ml/clip_classifier/embedding_store.py +481 -0
  256. package/ml/clip_classifier/env_loader.py +15 -0
  257. package/ml/clip_classifier/llm_label_expander.py +144 -0
  258. package/ml/clip_classifier/main.py +213 -0
  259. package/ml/clip_classifier/requirements.txt +10 -0
  260. package/ml/clip_classifier/similarity_engine.py +74 -0
  261. package/new-logo.png +0 -0
  262. package/observability/alert-rules.yml +60 -0
  263. package/observability/grafana/dashboards/omnizap-mysql.json +136 -0
  264. package/observability/grafana/dashboards/omnizap-overview.json +170 -0
  265. package/observability/grafana/provisioning/dashboards/dashboards.yml +11 -0
  266. package/observability/grafana/provisioning/datasources/datasources.yml +15 -0
  267. package/observability/loki-config.yml +38 -0
  268. package/observability/mysql-setup.sql +46 -0
  269. package/observability/prometheus.yml +35 -0
  270. package/observability/promtail-config.yml +84 -0
  271. package/observability/sticker-catalog-slo.md +83 -0
  272. package/observability/sticker-scale-hardening-rollout.md +128 -0
  273. package/package.json +144 -0
  274. package/public/apple-touch-icon.png +0 -0
  275. package/public/assets/css/commands-react.input.css +71 -0
  276. package/public/assets/css/create-pack-react.input.css +31 -0
  277. package/public/assets/css/home-react.input.css +106 -0
  278. package/public/assets/css/login-react.input.css +58 -0
  279. package/public/assets/css/stickers-react.input.css +18 -0
  280. package/public/assets/css/terms-react.input.css +115 -0
  281. package/public/assets/css/user-react.input.css +57 -0
  282. package/public/assets/images/brand-icon-192.png +0 -0
  283. package/public/assets/images/brand-logo-128.webp +0 -0
  284. package/public/assets/images/hero-banner-1280.jpg +0 -0
  285. package/public/comandos/commands-catalog.json +4517 -0
  286. package/public/css/api-docs.css +161 -0
  287. package/public/css/stickers-admin.css +1288 -0
  288. package/public/css/styles.css +679 -0
  289. package/public/css/systemadm/admin.css +474 -0
  290. package/public/css/systemadm/base.css +73 -0
  291. package/public/css/systemadm/components.css +662 -0
  292. package/public/css/systemadm/layout.css +229 -0
  293. package/public/css/systemadm/tokens.css +56 -0
  294. package/public/favicon-16x16.png +0 -0
  295. package/public/favicon-32x32.png +0 -0
  296. package/public/favicon.ico +0 -0
  297. package/public/js/apps/apiDocsApp.js +235 -0
  298. package/public/js/apps/commandsReactApp.js +528 -0
  299. package/public/js/apps/createPackApp.js +1646 -0
  300. package/public/js/apps/homeReactApp.js +942 -0
  301. package/public/js/apps/loginReactApp.js +496 -0
  302. package/public/js/apps/stickersAdminApp.js +1753 -0
  303. package/public/js/apps/stickersApp.js +3797 -0
  304. package/public/js/apps/termsReactApp.js +528 -0
  305. package/public/js/apps/userApp.js +2540 -0
  306. package/public/js/apps/userProfile/actions.js +66 -0
  307. package/public/js/apps/userReactApp.js +547 -0
  308. package/public/js/catalog.js +950 -0
  309. package/public/pages/api-docs.html +40 -0
  310. package/public/pages/aup.html +158 -0
  311. package/public/pages/comandos.html +41 -0
  312. package/public/pages/dpa.html +227 -0
  313. package/public/pages/home.html +45 -0
  314. package/public/pages/licenca.html +182 -0
  315. package/public/pages/login.html +40 -0
  316. package/public/pages/notice-and-takedown.html +234 -0
  317. package/public/pages/politica-de-privacidade.html +251 -0
  318. package/public/pages/seo-bot-whatsapp-para-grupo.html +350 -0
  319. package/public/pages/seo-bot-whatsapp-sem-programar.html +350 -0
  320. package/public/pages/seo-como-automatizar-avisos-no-whatsapp.html +350 -0
  321. package/public/pages/seo-como-criar-comandos-whatsapp.html +350 -0
  322. package/public/pages/seo-como-evitar-spam-no-whatsapp.html +350 -0
  323. package/public/pages/seo-como-moderar-grupo-whatsapp.html +350 -0
  324. package/public/pages/seo-como-organizar-comunidade-whatsapp.html +350 -0
  325. package/public/pages/seo-melhor-bot-whatsapp-para-grupos.html +350 -0
  326. package/public/pages/stickers-admin.html +31 -0
  327. package/public/pages/stickers-create.html +41 -0
  328. package/public/pages/stickers.html +45 -0
  329. package/public/pages/suboperadores.html +237 -0
  330. package/public/pages/termos-de-uso-texto-integral.html +241 -0
  331. package/public/pages/termos-de-uso.html +41 -0
  332. package/public/pages/user-password-reset.html +32 -0
  333. package/public/pages/user-systemadm.html +508 -0
  334. package/public/pages/user.html +39 -0
  335. package/public/robots.txt +9 -0
  336. package/public/site.webmanifest +24 -0
  337. package/public/sitemap.xml +98 -0
  338. package/schemas/command-config.schema.json +582 -0
  339. package/scripts/baileys-compat-smoke.mjs +12 -0
  340. package/scripts/cache-bust.mjs +142 -0
  341. package/scripts/deploy.sh +916 -0
  342. package/scripts/email-broadcast-terms-update.mjs +170 -0
  343. package/scripts/enrich-command-discovery-fields.mjs +286 -0
  344. package/scripts/generate-command-config-schema.mjs +273 -0
  345. package/scripts/generate-commands-catalog.mjs +308 -0
  346. package/scripts/generate-module-agents.mjs +631 -0
  347. package/scripts/generate-seo-satellite-pages.mjs +400 -0
  348. package/scripts/github-deploy-notify.mjs +174 -0
  349. package/scripts/github-release-notify.mjs +219 -0
  350. package/scripts/release.sh +599 -0
  351. package/scripts/run-codeql-local.sh +116 -0
  352. package/scripts/run-prettier-all.mjs +25 -0
  353. package/scripts/security-smoketest.mjs +581 -0
  354. package/scripts/sticker-catalog-loadtest.mjs +210 -0
  355. package/scripts/sticker-worker-task.mjs +119 -0
  356. package/scripts/sync-readme-snapshot.mjs +133 -0
  357. package/scripts/validate-command-config-schema.mjs +130 -0
  358. package/scripts/validate-command-configs.mjs +15 -0
  359. package/scripts/wiki-sync.sh +191 -0
  360. package/server/auth/googleWebAuth/googleWebAuthRuntime.js +62 -0
  361. package/server/auth/googleWebAuth/googleWebAuthService.js +807 -0
  362. package/server/auth/jwt/webJwtService.js +147 -0
  363. package/server/auth/stickerCatalogAuthContext.js +165 -0
  364. package/server/auth/termsAcceptance/termsAcceptanceHandler.js +189 -0
  365. package/server/auth/userPassword/index.js +14 -0
  366. package/server/auth/userPassword/userPasswordAuthService.js +422 -0
  367. package/server/auth/userPassword/userPasswordCrypto.js +199 -0
  368. package/server/auth/userPassword/userPasswordCrypto.test.js +76 -0
  369. package/server/auth/userPassword/userPasswordRecoveryService.js +728 -0
  370. package/server/auth/validation/authSchemas.js +236 -0
  371. package/server/auth/webAccount/webAccountHandlers.js +1434 -0
  372. package/server/controllers/admin/adminBanService.js +138 -0
  373. package/server/controllers/admin/adminPanelHandlers.js +2083 -0
  374. package/server/controllers/admin/stickerCatalogAdminContext.js +17 -0
  375. package/server/controllers/admin/systemAdminController.js +201 -0
  376. package/server/controllers/email/emailAutomationController.js +239 -0
  377. package/server/controllers/metricsController.js +21 -0
  378. package/server/controllers/seo/stickerCatalogSeoContext.js +514 -0
  379. package/server/controllers/sticker/nonCatalogHandlers.js +303 -0
  380. package/server/controllers/sticker/stickerCatalogController.js +4700 -0
  381. package/server/controllers/system/contactController.js +115 -0
  382. package/server/controllers/system/githubController.js +137 -0
  383. package/server/controllers/system/stickerCatalogSystemContext.js +758 -0
  384. package/server/controllers/system/storageController.js +154 -0
  385. package/server/controllers/system/systemController.js +135 -0
  386. package/server/controllers/system/systemMetricsController.js +156 -0
  387. package/server/controllers/system/visitController.js +90 -0
  388. package/server/controllers/userController.js +145 -0
  389. package/server/email/emailAutomationRuntime.js +225 -0
  390. package/server/email/emailAutomationService.js +125 -0
  391. package/server/email/emailOutboxRepository.js +282 -0
  392. package/server/email/emailTemplateService.js +480 -0
  393. package/server/email/emailTransportService.js +156 -0
  394. package/server/http/clientIp.js +95 -0
  395. package/server/http/httpRequestUtils.js +262 -0
  396. package/server/http/httpRequestUtils.test.js +80 -0
  397. package/server/http/httpServer.js +180 -0
  398. package/server/http/requestContext.js +20 -0
  399. package/server/http/siteRoutingUtils.js +87 -0
  400. package/server/index.js +1 -0
  401. package/server/middleware/cachePolicy.js +26 -0
  402. package/server/middleware/cachePolicyHelpers.js +1 -0
  403. package/server/middleware/endpointRateLimit.js +181 -0
  404. package/server/middleware/rateLimit.js +70 -0
  405. package/server/middleware/requireAdminAuth.js +48 -0
  406. package/server/middleware/securityHeaders.js +97 -0
  407. package/server/routes/admin/systemAdminRouter.js +64 -0
  408. package/server/routes/email/emailAutomationRouter.js +46 -0
  409. package/server/routes/health/healthRouter.js +41 -0
  410. package/server/routes/indexRouter.js +234 -0
  411. package/server/routes/metrics/metricsRouter.js +58 -0
  412. package/server/routes/static/staticPageRouter.js +134 -0
  413. package/server/routes/sticker/catalogHandlers/catalogAdminHttp.js +105 -0
  414. package/server/routes/sticker/catalogHandlers/catalogAuthHttp.js +77 -0
  415. package/server/routes/sticker/catalogHandlers/catalogPublicHttp.js +120 -0
  416. package/server/routes/sticker/catalogHandlers/catalogUploadHttp.js +83 -0
  417. package/server/routes/sticker/catalogRouter.js +77 -0
  418. package/server/routes/sticker/stickerApiRouter.js +84 -0
  419. package/server/routes/sticker/stickerDataRouter.js +145 -0
  420. package/server/routes/sticker/stickerSiteRouter.js +43 -0
  421. package/server/routes/user/userApiPaths.js +66 -0
  422. package/server/routes/user/userRouter.js +65 -0
  423. package/server/utils/safePath.js +26 -0
  424. package/utils/logger/loggerModule.js +35 -0
  425. package/vite.config.mjs +38 -0
@@ -0,0 +1,399 @@
1
+ import logger from '#logger';
2
+ import { getSystemMetrics } from '../../utils/systemMetrics/systemMetricsModule.js';
3
+ import { sendAndStore } from '../../services/messaging/messagePersistenceService.js';
4
+
5
+ const METRICS_ENDPOINT = process.env.METRICS_ENDPOINT || `http://localhost:${process.env.METRICS_PORT || 9102}${process.env.METRICS_PATH || '/metrics'}`;
6
+ const METRICS_TOKEN = String(process.env.METRICS_TOKEN || process.env.METRICS_API_KEY || '').trim();
7
+ const METRICS_TIMEOUT_MS = Number(process.env.METRICS_PING_TIMEOUT_MS || 1500);
8
+
9
+ const formatLoadAverage = (values) => values.map((value) => value.toFixed(2)).join(' | ');
10
+
11
+ const formatBytes = (bytes) => {
12
+ if (!Number.isFinite(bytes)) return 'n/a';
13
+ const units = ['B', 'KB', 'MB', 'GB', 'TB'];
14
+ let value = bytes;
15
+ let idx = 0;
16
+ while (value >= 1024 && idx < units.length - 1) {
17
+ value /= 1024;
18
+ idx += 1;
19
+ }
20
+ return `${value.toFixed(value >= 100 ? 0 : 2)}${units[idx]}`;
21
+ };
22
+
23
+ const formatSeconds = (seconds) => {
24
+ if (!Number.isFinite(seconds)) return 'n/a';
25
+ const total = Math.max(0, Math.floor(seconds));
26
+ const days = Math.floor(total / 86400);
27
+ const hours = Math.floor((total % 86400) / 3600);
28
+ const minutes = Math.floor((total % 3600) / 60);
29
+ const secs = total % 60;
30
+ const time = [hours, minutes, secs].map((value) => String(value).padStart(2, '0')).join(':');
31
+ return days > 0 ? `${days}d ${time}` : time;
32
+ };
33
+
34
+ const parseMetricNumber = (value) => {
35
+ if (typeof value === 'number') return Number.isFinite(value) ? value : null;
36
+ if (typeof value !== 'string') return null;
37
+ const parsed = Number(value.replace(',', '.').trim());
38
+ return Number.isFinite(parsed) ? parsed : null;
39
+ };
40
+
41
+ const getStatusLevel = (value, warnAt, criticalAt) => {
42
+ const numericValue = parseMetricNumber(value);
43
+ if (numericValue === null) return { emoji: '⚪', label: 'sem dado' };
44
+ if (numericValue >= criticalAt) return { emoji: '🔴', label: 'crítico' };
45
+ if (numericValue >= warnAt) return { emoji: '🟡', label: 'atenção' };
46
+ return { emoji: '🟢', label: 'ok' };
47
+ };
48
+
49
+ const formatStatusLevel = (status) => `${status.emoji} ${status.label}`;
50
+
51
+ const padNumber = (value) => String(value).padStart(2, '0');
52
+
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
+
55
+ const parseLabels = (raw) => {
56
+ if (!raw) return {};
57
+ const labels = {};
58
+ const regex = /(\w+)="((?:\\.|[^"\\])*)"/g;
59
+ let match;
60
+ while ((match = regex.exec(raw)) !== null) {
61
+ labels[match[1]] = match[2].replace(/\\"/g, '"');
62
+ }
63
+ return labels;
64
+ };
65
+
66
+ const parsePrometheusText = (text) => {
67
+ const series = new Map();
68
+ const lines = text.split('\n');
69
+ for (const line of lines) {
70
+ const trimmed = line.trim();
71
+ if (!trimmed || trimmed.startsWith('#')) continue;
72
+ const [metricPart, valuePart] = trimmed.split(/\s+/, 2);
73
+ if (!metricPart || !valuePart) continue;
74
+ const value = Number(valuePart);
75
+ if (!Number.isFinite(value)) continue;
76
+ const labelStart = metricPart.indexOf('{');
77
+ let name = metricPart;
78
+ let labels = {};
79
+ if (labelStart !== -1) {
80
+ name = metricPart.slice(0, labelStart);
81
+ const labelBody = metricPart.slice(labelStart + 1, metricPart.lastIndexOf('}'));
82
+ labels = parseLabels(labelBody);
83
+ }
84
+ const list = series.get(name) || [];
85
+ list.push({ labels, value });
86
+ series.set(name, list);
87
+ }
88
+ return series;
89
+ };
90
+
91
+ const pickValue = (series, name, filter = null) => {
92
+ const list = series.get(name) || [];
93
+ if (!list.length) return null;
94
+ if (!filter) return list[0].value;
95
+ const hit = list.find((entry) => filter(entry.labels));
96
+ return hit ? hit.value : null;
97
+ };
98
+
99
+ const sumValues = (series, name, filter = null) => {
100
+ const list = series.get(name) || [];
101
+ return list.reduce((acc, entry) => {
102
+ if (filter && !filter(entry.labels)) return acc;
103
+ if (!Number.isFinite(entry.value)) return acc;
104
+ return acc + entry.value;
105
+ }, 0);
106
+ };
107
+
108
+ const getLabelValue = (series, name, labelKey) => {
109
+ const list = series.get(name) || [];
110
+ const entry = list.find((item) => item.labels && item.labels[labelKey]);
111
+ return entry ? entry.labels[labelKey] : null;
112
+ };
113
+
114
+ const buildPingMessage = ({ systemMetrics, metricsSummary, metricsOk, metricsError, latencyMs, generatedAt }) => {
115
+ const responseTime = Number.isFinite(latencyMs) ? `${Math.max(0, Math.round(latencyMs))}ms` : 'n/a';
116
+
117
+ const hostCpuStatus = getStatusLevel(systemMetrics.usoCpuPercentual, 65, 85);
118
+ const hostMemoryStatus = getStatusLevel(systemMetrics.usoMemoriaPercentual, 75, 90);
119
+
120
+ const load1 = Array.isArray(systemMetrics.cargaMedia) ? systemMetrics.cargaMedia[0] : null;
121
+ const loadPerCore = Number.isFinite(load1) && systemMetrics.totalCpus > 0 ? load1 / systemMetrics.totalCpus : null;
122
+ const loadStatus = getStatusLevel(loadPerCore, 0.9, 1.2);
123
+ const loadPerCoreText = loadPerCore === null ? 'n/a' : loadPerCore.toFixed(2);
124
+
125
+ const systemPart = `
126
+ 🖥️ *Servidor (máquina)*
127
+ • Host: ${systemMetrics.hostname}
128
+ • SO: ${systemMetrics.plataforma} ${systemMetrics.release} (${systemMetrics.arquitetura})
129
+ • Uptime do sistema: ${systemMetrics.uptimeSistema}
130
+ • CPU da máquina: ${formatStatusLevel(hostCpuStatus)} • ${systemMetrics.usoCpuPercentual}% (uso geral)
131
+ • Carga (1m|5m|15m): ${formatLoadAverage(systemMetrics.cargaMedia)}
132
+ • Pressão por núcleo (1m): ${loadPerCoreText} • ${formatStatusLevel(loadStatus)}
133
+ • RAM: ${formatStatusLevel(hostMemoryStatus)} • ${systemMetrics.memoriaUsada} / ${systemMetrics.memoriaTotal} (${systemMetrics.usoMemoriaPercentual}%)
134
+ `.trim();
135
+
136
+ if (!metricsOk) {
137
+ return `
138
+ 🏓 *Pong! Painel de saúde (modo básico)*
139
+ 🕐 Atualizado em: ${formatDateTime(generatedAt)}
140
+ ⚡ Tempo de resposta: ${responseTime}
141
+ 🧭 Legenda: 🟢 ok • 🟡 atenção • 🔴 crítico • ⚪ sem dado
142
+
143
+ ${systemPart}
144
+
145
+ ⚠️ *Métricas avançadas indisponíveis*
146
+ • Motivo: ${metricsError || 'sem detalhes'}
147
+ • Endpoint: ${METRICS_ENDPOINT}
148
+ • Timeout: ${METRICS_TIMEOUT_MS}ms
149
+
150
+ 💡 *Dica:* as métricas avançadas vêm do endpoint */metrics* (Prometheus).
151
+ `.trim();
152
+ }
153
+
154
+ const openFds = parseMetricNumber(metricsSummary.openFds);
155
+ const maxFds = parseMetricNumber(metricsSummary.maxFds);
156
+ const fdsUsage = openFds !== null && maxFds && maxFds > 0 ? (openFds / maxFds) * 100 : null;
157
+ const fdsStatus = getStatusLevel(fdsUsage, 60, 80);
158
+ const fdsUsageText = fdsUsage === null ? 'n/a' : `${fdsUsage.toFixed(1)}%`;
159
+
160
+ const lagP99 = parseMetricNumber(metricsSummary.lagP99);
161
+ const lagStatus = getStatusLevel(lagP99, 120, 300);
162
+
163
+ const dbTotal = parseMetricNumber(metricsSummary.dbTotal) || 0;
164
+ const dbSlow = parseMetricNumber(metricsSummary.dbSlow) || 0;
165
+ const slowRate = dbTotal > 0 ? (dbSlow / dbTotal) * 100 : null;
166
+ const dbStatus = getStatusLevel(slowRate, 5, 15);
167
+ const slowRateText = slowRate === null ? 'n/a' : `${slowRate.toFixed(2)}%`;
168
+
169
+ const queueValues = [metricsSummary.queues.messages, metricsSummary.queues.chats, metricsSummary.queues.lid_map].map((value) => parseMetricNumber(value)).filter((value) => value !== null);
170
+ const queuePeak = queueValues.length ? Math.max(...queueValues) : null;
171
+ const queueStatus = getStatusLevel(queuePeak, 30, 120);
172
+ const queuePeakText = queuePeak === null ? 'n/a' : String(Math.round(queuePeak));
173
+
174
+ const processPart = `
175
+ ⚙️ *Processo do bot*
176
+ • Uptime do processo: ${metricsSummary.processUptime}
177
+ • Node.js: ${metricsSummary.nodeVersion}
178
+ • CPU acumulada: total ${metricsSummary.cpuTotalSec}s (user ${metricsSummary.cpuUserSec}s | sys ${metricsSummary.cpuSysSec}s)
179
+ • Memória do processo: RSS ${metricsSummary.rss} | Heap ${metricsSummary.heap} | VMem ${metricsSummary.vmem}
180
+ • FDs abertos: ${metricsSummary.openFds}/${metricsSummary.maxFds} (${fdsUsageText}) • ${formatStatusLevel(fdsStatus)}
181
+ `.trim();
182
+
183
+ const nodePart = `
184
+ 🧠 *Event Loop (responsividade)*
185
+ • Lag p50: ${metricsSummary.lagP50}ms (comportamento normal)
186
+ • Lag p90: ${metricsSummary.lagP90}ms (picos frequentes)
187
+ • Lag p99: ${metricsSummary.lagP99}ms (pior caso recente)
188
+ • Status do loop: ${formatStatusLevel(lagStatus)} (quanto menor o lag, melhor)
189
+ `.trim();
190
+
191
+ const dbPart = `
192
+ 🗄️ *Banco*
193
+ • Queries totais: ${metricsSummary.dbTotal}
194
+ • Queries lentas: ${metricsSummary.dbSlow} (${slowRateText}) • ${formatStatusLevel(dbStatus)}
195
+ • Writes: messages ${metricsSummary.writes.messages} | lid_map ${metricsSummary.writes.lid_map} | groups ${metricsSummary.writes.groups_metadata}
196
+ • Últimas latências (ms): messages ${metricsSummary.lastQuery.messages} | lid_map ${metricsSummary.lastQuery.lid_map} | groups ${metricsSummary.lastQuery.groups_metadata}
197
+ `.trim();
198
+
199
+ const queuePart = `
200
+ 📦 *Filas internas (backlog)*
201
+ • messages ${metricsSummary.queues.messages} | chats ${metricsSummary.queues.chats} | lid_map ${metricsSummary.queues.lid_map}
202
+ • Pico atual: ${queuePeakText} • ${formatStatusLevel(queueStatus)} (quanto menor, melhor)
203
+ `.trim();
204
+
205
+ const upsertPart = `
206
+ 📬 *messages.upsert (entrada de mensagens)*
207
+ • Eventos recebidos: append ${metricsSummary.upsertEvents.append} | notify ${metricsSummary.upsertEvents.notify}
208
+ • Mensagens processadas: append ${metricsSummary.upsertMessages.append} | notify ${metricsSummary.upsertMessages.notify}
209
+ `.trim();
210
+
211
+ const glossaryPart = `
212
+ 📖 *Glossário rápido*
213
+ • RSS: memória real em RAM usada pelo processo
214
+ • Heap: memória JavaScript gerenciada pelo Node.js
215
+ • VMem: memória virtual reservada pelo processo
216
+ • Lag: atraso do Node para executar tarefas
217
+ `.trim();
218
+
219
+ return `
220
+ 🏓 *Pong! Painel de saúde do Omnizap*
221
+ 🕐 Atualizado em: ${formatDateTime(generatedAt)}
222
+ ⚡ Tempo de resposta: ${responseTime}
223
+ 🧭 Legenda: 🟢 ok • 🟡 atenção • 🔴 crítico • ⚪ sem dado
224
+
225
+ ${systemPart}
226
+
227
+ ${processPart}
228
+
229
+ ${nodePart}
230
+
231
+ ${dbPart}
232
+
233
+ ${queuePart}
234
+
235
+ ${upsertPart}
236
+
237
+ ${glossaryPart}
238
+ `.trim();
239
+ };
240
+
241
+ const fetchMetricsSnapshot = async () => {
242
+ const controller = typeof globalThis.AbortController === 'function' ? new globalThis.AbortController() : null;
243
+ const timeout = setTimeout(() => controller?.abort(), METRICS_TIMEOUT_MS);
244
+ try {
245
+ if (typeof globalThis.fetch !== 'function') {
246
+ throw new Error('fetch indisponível');
247
+ }
248
+ const headers = {};
249
+ if (METRICS_TOKEN) {
250
+ headers.Authorization = `Bearer ${METRICS_TOKEN}`;
251
+ }
252
+ const response = await globalThis.fetch(METRICS_ENDPOINT, {
253
+ ...(controller ? { signal: controller.signal } : {}),
254
+ ...(Object.keys(headers).length ? { headers } : {}),
255
+ });
256
+ if (!response.ok) {
257
+ throw new Error(`HTTP ${response.status}`);
258
+ }
259
+ const text = await response.text();
260
+ const series = parsePrometheusText(text);
261
+
262
+ const processStart = pickValue(series, 'omnizap_process_start_time_seconds');
263
+ const nowSec = Date.now() / 1000;
264
+ const processUptime = processStart ? formatSeconds(nowSec - processStart) : 'n/a';
265
+
266
+ const cpuUserSec = pickValue(series, 'omnizap_process_cpu_user_seconds_total');
267
+ const cpuSysSec = pickValue(series, 'omnizap_process_cpu_system_seconds_total');
268
+ const cpuTotalSec = pickValue(series, 'omnizap_process_cpu_seconds_total');
269
+
270
+ const rss = pickValue(series, 'omnizap_process_resident_memory_bytes');
271
+ const vmem = pickValue(series, 'omnizap_process_virtual_memory_bytes');
272
+ const heap = pickValue(series, 'omnizap_process_heap_bytes');
273
+
274
+ const openFds = pickValue(series, 'omnizap_process_open_fds');
275
+ const maxFds = pickValue(series, 'omnizap_process_max_fds');
276
+
277
+ const lagP50 = pickValue(series, 'omnizap_nodejs_eventloop_lag_p50_seconds');
278
+ const lagP90 = pickValue(series, 'omnizap_nodejs_eventloop_lag_p90_seconds');
279
+ const lagP99 = pickValue(series, 'omnizap_nodejs_eventloop_lag_p99_seconds');
280
+
281
+ const nodeVersion = getLabelValue(series, 'omnizap_nodejs_version_info', 'version') || 'n/a';
282
+
283
+ const dbTotal = sumValues(series, 'omnizap_db_query_total');
284
+ const dbSlow = sumValues(series, 'omnizap_db_slow_queries_total');
285
+
286
+ const writesByTable = {};
287
+ const writeSeries = series.get('omnizap_db_write_total') || [];
288
+ writeSeries.forEach((entry) => {
289
+ const table = entry.labels?.table || 'unknown';
290
+ writesByTable[table] = (writesByTable[table] || 0) + entry.value;
291
+ });
292
+
293
+ const lastQuerySeries = series.get('omnizap_db_last_query_duration_ms') || [];
294
+ const lastQuery = {};
295
+ lastQuerySeries.forEach((entry) => {
296
+ const table = entry.labels?.table;
297
+ if (!table) return;
298
+ lastQuery[table] = entry.value;
299
+ });
300
+
301
+ const queueSeries = series.get('omnizap_queue_depth') || [];
302
+ const queues = {};
303
+ queueSeries.forEach((entry) => {
304
+ const queue = entry.labels?.queue;
305
+ if (!queue) return;
306
+ queues[queue] = entry.value;
307
+ });
308
+
309
+ const upsertEvents = {};
310
+ const upsertSeries = series.get('omnizap_messages_upsert_total') || [];
311
+ upsertSeries.forEach((entry) => {
312
+ const type = entry.labels?.type || 'unknown';
313
+ upsertEvents[type] = (upsertEvents[type] || 0) + entry.value;
314
+ });
315
+
316
+ const upsertMessages = {};
317
+ const upsertMsgSeries = series.get('omnizap_messages_upsert_messages_total') || [];
318
+ upsertMsgSeries.forEach((entry) => {
319
+ const type = entry.labels?.type || 'unknown';
320
+ upsertMessages[type] = (upsertMessages[type] || 0) + entry.value;
321
+ });
322
+
323
+ const formatNumber = (value, digits = 2) => (Number.isFinite(value) ? value.toFixed(digits) : 'n/a');
324
+
325
+ return {
326
+ processUptime,
327
+ cpuUserSec: formatNumber(cpuUserSec),
328
+ cpuSysSec: formatNumber(cpuSysSec),
329
+ cpuTotalSec: formatNumber(cpuTotalSec),
330
+ rss: formatBytes(rss),
331
+ heap: formatBytes(heap),
332
+ vmem: formatBytes(vmem),
333
+ openFds: Number.isFinite(openFds) ? Math.round(openFds) : 'n/a',
334
+ maxFds: Number.isFinite(maxFds) ? Math.round(maxFds) : 'n/a',
335
+ nodeVersion,
336
+ lagP50: Number.isFinite(lagP50) ? (lagP50 * 1000).toFixed(2) : 'n/a',
337
+ lagP90: Number.isFinite(lagP90) ? (lagP90 * 1000).toFixed(2) : 'n/a',
338
+ lagP99: Number.isFinite(lagP99) ? (lagP99 * 1000).toFixed(2) : 'n/a',
339
+ dbTotal: Math.round(dbTotal),
340
+ dbSlow: Math.round(dbSlow),
341
+ writes: {
342
+ messages: Math.round(writesByTable.messages || 0),
343
+ lid_map: Math.round(writesByTable.lid_map || 0),
344
+ groups_metadata: Math.round(writesByTable.groups_metadata || 0),
345
+ },
346
+ lastQuery: {
347
+ messages: Number.isFinite(lastQuery.messages) ? lastQuery.messages.toFixed(2) : 'n/a',
348
+ lid_map: Number.isFinite(lastQuery.lid_map) ? lastQuery.lid_map.toFixed(2) : 'n/a',
349
+ groups_metadata: Number.isFinite(lastQuery.groups_metadata) ? lastQuery.groups_metadata.toFixed(2) : 'n/a',
350
+ },
351
+ queues: {
352
+ messages: Math.round(queues.messages || 0),
353
+ chats: Math.round(queues.chats || 0),
354
+ lid_map: Math.round(queues.lid_map || 0),
355
+ },
356
+ upsertEvents: {
357
+ append: Math.round(upsertEvents.append || 0),
358
+ notify: Math.round(upsertEvents.notify || 0),
359
+ },
360
+ upsertMessages: {
361
+ append: Math.round(upsertMessages.append || 0),
362
+ notify: Math.round(upsertMessages.notify || 0),
363
+ },
364
+ };
365
+ } finally {
366
+ clearTimeout(timeout);
367
+ }
368
+ };
369
+
370
+ export async function handlePingCommand({ sock, remoteJid, messageInfo, expirationMessage }) {
371
+ try {
372
+ const startedAt = Date.now();
373
+ const systemMetrics = getSystemMetrics();
374
+ let metricsSummary = null;
375
+ let metricsOk = false;
376
+ let metricsError = null;
377
+
378
+ try {
379
+ metricsSummary = await fetchMetricsSnapshot();
380
+ metricsOk = true;
381
+ } catch (error) {
382
+ metricsError = error.message;
383
+ logger.warn('Falha ao buscar métricas Prometheus para /ping.', { error: error.message });
384
+ }
385
+
386
+ const text = buildPingMessage({
387
+ systemMetrics,
388
+ metricsSummary,
389
+ metricsOk,
390
+ metricsError,
391
+ latencyMs: Date.now() - startedAt,
392
+ generatedAt: new Date(),
393
+ });
394
+ await sendAndStore(sock, remoteJid, { text }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
395
+ } catch (error) {
396
+ logger.error('Erro ao gerar status do sistema:', { error: error.message });
397
+ await sendAndStore(sock, remoteJid, { text: 'Erro ao obter informações do sistema.' }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
398
+ }
399
+ }
@@ -0,0 +1,14 @@
1
+ import path from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { createModuleAiHelpWrapper } from '../../services/ai/moduleAiHelpWrapperFactory.js';
4
+
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = path.dirname(__filename);
7
+
8
+ export const systemMetricsAiHelpWrapper = createModuleAiHelpWrapper({
9
+ moduleKey: 'system_metrics',
10
+ moduleLabel: 'comandos de metricas',
11
+ envPrefix: 'SYSTEM_METRICS_AI_HELP',
12
+ moduleDirPath: __dirname,
13
+ moduleNameFallback: 'systemMetricsModule',
14
+ });
@@ -0,0 +1,68 @@
1
+ import path from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+
4
+ import { createModuleCommandConfigRuntime } from '../../services/ai/moduleCommandConfigRuntimeService.js';
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+ const CONFIG_PATH = path.join(__dirname, 'commandConfig.json');
9
+
10
+ const DEFAULT_TEXTS = {
11
+ usage_header: '',
12
+ };
13
+
14
+ const runtime = createModuleCommandConfigRuntime({
15
+ configPath: CONFIG_PATH,
16
+ fallbackConfig: {
17
+ module: 'systemMetricsModule',
18
+ commands: [],
19
+ textos: DEFAULT_TEXTS,
20
+ },
21
+ });
22
+
23
+ const renderUsageMethod = (method, commandPrefix) => String(method || '').replaceAll('<prefix>', String(commandPrefix || '/'));
24
+
25
+ const resolveUsageLines = (entry, variant) => {
26
+ if (!entry || typeof entry !== 'object') return [];
27
+
28
+ const usageMessages = entry?.mensagens_uso && typeof entry.mensagens_uso === 'object' ? entry.mensagens_uso : null;
29
+
30
+ if (usageMessages) {
31
+ const variantKey = typeof variant === 'string' ? variant.trim() : '';
32
+ const picked = (variantKey && usageMessages[variantKey]) || usageMessages.default || null;
33
+ if (Array.isArray(picked)) {
34
+ return picked.filter(Boolean).map((value) => String(value));
35
+ }
36
+ if (typeof picked === 'string' && picked.trim()) {
37
+ return [picked.trim()];
38
+ }
39
+ }
40
+
41
+ const methods = Array.isArray(entry?.metodos_de_uso) ? entry.metodos_de_uso : [];
42
+ return methods.filter(Boolean).map((value) => String(value));
43
+ };
44
+
45
+ export const getSystemMetricsModuleConfig = () => runtime.getModuleConfig();
46
+
47
+ export const resolveSystemMetricsCommandName = (command) => runtime.resolveCommandName(command);
48
+ export const getSystemMetricsCommandEntry = (command) => runtime.getCommandEntry(command);
49
+ export const listEnabledSystemMetricsCommands = () => runtime.listEnabledCommands();
50
+
51
+ export const getSystemMetricsTextConfig = () => {
52
+ const config = getSystemMetricsModuleConfig();
53
+ const raw = config?.textos && typeof config.textos === 'object' ? config.textos : {};
54
+ return {
55
+ ...DEFAULT_TEXTS,
56
+ ...raw,
57
+ };
58
+ };
59
+
60
+ export const getSystemMetricsUsageText = (command, { commandPrefix = '/', header, variant } = {}) => {
61
+ const entry = getSystemMetricsCommandEntry(command);
62
+ const methods = resolveUsageLines(entry, variant);
63
+ if (!methods.length) return '';
64
+
65
+ const prefixHeader = typeof header === 'string' ? header : getSystemMetricsTextConfig().usage_header || DEFAULT_TEXTS.usage_header;
66
+ const lines = methods.map((method) => renderUsageMethod(method, commandPrefix));
67
+ return prefixHeader ? [prefixHeader, ...lines].join('\n') : lines.join('\n');
68
+ };
@@ -0,0 +1,196 @@
1
+ # TiktokModule Agent Guide
2
+
3
+ Este arquivo e destinado a agentes de IA para gerar respostas no contexto dos comandos deste modulo.
4
+
5
+ ## Fonte de Verdade
6
+
7
+ - arquivo_base: `app/modules/tiktokModule/commandConfig.json`
8
+ - schema_version: `2.0.0`
9
+ - module_enabled: `true`
10
+ - generated_at: `2026-03-11T02:35:17.177Z`
11
+
12
+ ## Escopo do Modulo
13
+
14
+ - module: `tiktokModule`
15
+ - source_files:
16
+ - tiktokCommand.js
17
+ - total_commands: `1`
18
+ - total_enabled_commands: `1`
19
+
20
+ ## Defaults Schema v2
21
+
22
+ - inheritance_mode: deep_merge_with_command_overrides
23
+ - compatibility_mode: legacy_and_v2_fields
24
+ - legacy_field_aliases:
25
+ - descricao: description
26
+ - metodos_de_uso: usage
27
+ - permissao_necessaria: permission
28
+ - local_de_uso: contexts
29
+ - informacoes_coletadas: collected_data
30
+ - pre_condicoes: requirements
31
+ - dependencias_externas: dependencies
32
+ - efeitos_colaterais: side_effects
33
+ - observabilidade: observability
34
+ - privacidade: privacy
35
+ - limite_uso_por_plano: plan_limits
36
+ - argumentos: arguments
37
+ - acesso: access
38
+ - defaults.command:
39
+ - enabled: true
40
+ - category: midia
41
+ - version: 1.0.0
42
+ - stability: stable
43
+ - deprecated: false
44
+ - replaced_by: null
45
+ - risk_level: medium
46
+ - defaults.requirements (legacy view):
47
+ - requer_grupo: nao
48
+ - requer_admin: nao
49
+ - requer_admin_principal: nao
50
+ - requer_google_login: sim
51
+ - requer_nsfw: nao
52
+ - requer_midia: nao
53
+ - requer_mensagem_respondida: nao
54
+
55
+ ## Protocolo de Resposta para IA
56
+
57
+ - Passo 1: identificar comando pelo token apos o prefixo.
58
+ - Passo 2: resolver alias para nome canonico usando campo `aliases`.
59
+ - Passo 3: validar `enabled`, `pre_condicoes`, permissao e local de uso.
60
+ - Passo 4: se houver erro de uso, responder com `mensagens_uso` (quando existir) ou `metodos_de_uso`.
61
+ - Passo 5: seguir `respostas_padrao` como fallback de texto.
62
+ - Passo 6: considerar `informacoes_coletadas`, `privacidade` e `observabilidade` ao elaborar resposta.
63
+
64
+ ## Regras de Seguranca para IA
65
+
66
+ - A IA orienta, mas nao executa acao administrativa automaticamente.
67
+ - Nao inventar comandos, subcomandos ou permissao fora do JSON.
68
+ - Sempre informar onde pode usar (grupo/privado) e quem pode usar.
69
+ - Em duvida de permissao, responder com orientacao conservadora.
70
+
71
+ ## Catalogo de Comandos
72
+
73
+ ### baixartiktok
74
+
75
+ - id: tiktok.baixartiktok
76
+ - aliases: tt, tiktok
77
+ - enabled: true
78
+ - categoria: midia
79
+ - descricao: Baixa midia do TikTok sem marca d'agua.
80
+ - permissao_necessaria: usuario comum
81
+ - version: 1.0.0
82
+ - stability: stable
83
+ - deprecated: nao
84
+ - risk_level: low
85
+ - local_de_uso:
86
+ - privado
87
+ - grupo
88
+ - metodos_de_uso:
89
+ - <prefix>baixartiktok <url>
90
+ - <prefix>tt <url1> <url2>
91
+ - mensagens_uso (variantes):
92
+ - default:
93
+ - 🎬 _Baixartiktok Downloader_
94
+ - Uso: _<prefix>baixartiktok <link1> [link2 ...]_
95
+ - Exemplo: _<prefix>baixartiktok https://www.baixartiktok.com/@usuario/video/123_
96
+ - subcomandos:
97
+ - (nenhum)
98
+ - argumentos:
99
+ - urls | tipo: array | obrigatorio | validacao: 1 a 5 URLs do TikTok | default: null | posicao: 0
100
+ - pre_condicoes:
101
+ - requer_grupo: nao
102
+ - requer_admin: nao
103
+ - requer_admin_principal: nao
104
+ - requer_google_login: sim
105
+ - requer_nsfw: nao
106
+ - requer_midia: nao
107
+ - requer_mensagem_respondida: nao
108
+ - rate_limit:
109
+ - max: 5
110
+ - janela_ms: null
111
+ - escopo: por_execucao
112
+ - acesso:
113
+ - somente_premium: nao
114
+ - planos_permitidos: comum, premium
115
+ - limite_uso_por_plano:
116
+ - comum: max=4, janela_ms=600000, escopo=usuario
117
+ - premium: max=15, janela_ms=600000, escopo=usuario
118
+ - informacoes_coletadas:
119
+ - identificador do chat (remoteJid)
120
+ - identificador do remetente (senderJid)
121
+ - texto do comando e argumentos
122
+ - contexto da mensagem (citacao e mencoes, quando existir)
123
+ - URLs do TikTok extraidas do texto
124
+ - metadados do post (autor, descricao, estatisticas)
125
+ - tamanho dos arquivos para enforce de limite
126
+ - dependencias_externas:
127
+ - serviço extractor de TikTok
128
+ - efeitos_colaterais:
129
+ - baixa mídia temporária
130
+ - envia vídeo/imagens no chat
131
+ - respostas_padrao:
132
+ - success: Comando executado com sucesso.
133
+ - usage_error: Formato de uso inválido. Consulte metodos_de_uso.
134
+ - permission_error: Permissão insuficiente para executar este comando.
135
+ - sucesso: Comando executado com sucesso.
136
+ - erro_uso: Formato de uso inválido. Consulte metodos_de_uso.
137
+ - erro_permissao: Permissão insuficiente para executar este comando.
138
+ - mensagens_sistema:
139
+ - (nao informado)
140
+ - limites_operacionais:
141
+ - (nao informado)
142
+ - opcoes:
143
+ - toggle_on_off_status.type: toggle
144
+ - toggle_on_off_status.allowed_actions: on, off, status
145
+ - toggle_on_off_status.action_argument: acao
146
+ - add_remove_list.type: list_management
147
+ - add_remove_list.allowed_actions: add, remove, list
148
+ - add_remove_list.action_argument: acao
149
+ - approve_reject.type: moderation_decision
150
+ - approve_reject.allowed_actions: approve, reject
151
+ - approve_reject.action_argument: acao
152
+ - approve_reject.requires_targets: true
153
+ - set_status_reset.type: configuration_window
154
+ - set_status_reset.allowed_actions: set, status, reset
155
+ - set_status_reset.action_argument: valor
156
+ - observabilidade:
157
+ - event_name: command.executed
158
+ - analytics_event: whatsapp_command_tiktok
159
+ - tags_log: whatsapp, command, tiktokModule, tiktok
160
+ - nivel_log: info
161
+ - privacidade:
162
+ - dados_sensiveis:
163
+ - chat_identifier
164
+ - sender_identifier
165
+ - command_content
166
+ - retencao: standard_app_logs
167
+ - base_legal: service_execution_and_legitimate_interest
168
+ - docs:
169
+ - summary: Baixa midia do TikTok sem marca d'agua.
170
+ - usage_examples: <prefix>baixartiktok <url>, <prefix>tt <url1> <url2>
171
+ - usage*variants.default: 🎬 \_Baixartiktok Downloader*, , Uso: _<prefix>baixartiktok <link1> [link2 ...]_, , Exemplo: _<prefix>baixartiktok https://www.baixartiktok.com/@usuario/video/123_
172
+ - behavior:
173
+ - type: argument_driven
174
+ - allowed_actions: (nenhum)
175
+ - limits:
176
+ - usage_description: ate 5 URLs por comando e ate 80 MB por arquivo (padrao)
177
+ - rate_limit.max: 5
178
+ - rate_limit.janela_ms: null
179
+ - rate_limit.escopo: por_execucao
180
+ - access.somente_premium: false
181
+ - access.planos_permitidos: comum, premium
182
+ - plan_limits.comum.max: 4
183
+ - plan_limits.comum.janela_ms: 600000
184
+ - plan_limits.comum.escopo: usuario
185
+ - plan_limits.premium.max: 15
186
+ - plan_limits.premium.janela_ms: 600000
187
+ - plan_limits.premium.escopo: usuario
188
+ - discovery:
189
+ - keywords: baixartiktok, tt, midia, privado, grupo
190
+ - faq_queries: como usar baixartiktok, o que faz baixartiktok, comando baixartiktok
191
+ - user_phrasings: quero usar baixartiktok, me ajuda com baixartiktok, baixa midia do baixartiktok
192
+ - suggestion_priority: 100
193
+ - handler:
194
+ - file: tiktokCommand.js
195
+ - method: handleTikTokCommand
196
+ - command_case: baixartiktok