@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,242 @@
1
+ import logger from '#logger';
2
+ import { setQueueDepth } from '../../observability/metrics.js';
3
+ import { isFeatureEnabled } from '../../services/infra/featureFlagService.js';
4
+ import { runStickerClassificationCycle } from './stickerClassificationBackgroundRuntime.js';
5
+ import { runStickerAutoPackByTagsCycle } from './stickerAutoPackByTagsRuntime.js';
6
+ import { claimWorkerTask, completeWorkerTask, countWorkerTasksByStatus, enqueueWorkerTask, failWorkerTask, hasPendingWorkerTask } from './stickerWorkerTaskQueueRepository.js';
7
+
8
+ const parseEnvBool = (value, fallback) => {
9
+ if (value === undefined || value === null || value === '') return fallback;
10
+ const normalized = String(value).trim().toLowerCase();
11
+ if (['1', 'true', 'yes', 'y', 'on'].includes(normalized)) return true;
12
+ if (['0', 'false', 'no', 'n', 'off'].includes(normalized)) return false;
13
+ return fallback;
14
+ };
15
+
16
+ const PIPELINE_ENABLED = parseEnvBool(process.env.STICKER_WORKER_PIPELINE_ENABLED, false);
17
+ const STARTUP_DELAY_MS = Math.max(1_000, Number(process.env.STICKER_WORKER_PIPELINE_STARTUP_DELAY_MS) || 12_000);
18
+ const SCHEDULER_INTERVAL_MS = Math.max(2_000, Number(process.env.STICKER_WORKER_PIPELINE_SCHEDULER_INTERVAL_MS) || 15_000);
19
+ const POLLER_INTERVAL_MS = Math.max(1_000, Number(process.env.STICKER_WORKER_PIPELINE_POLLER_INTERVAL_MS) || 4_000);
20
+ const WORKER_RETRY_DELAY_SECONDS = Math.max(5, Math.min(3600, Number(process.env.STICKER_WORKER_PIPELINE_RETRY_DELAY_SECONDS) || 45));
21
+ const INLINE_POLLER_ENABLED = parseEnvBool(process.env.STICKER_WORKER_PIPELINE_INLINE_POLLER_ENABLED, true);
22
+ const INLINE_POLLER_FORCE_ENABLED = parseEnvBool(process.env.STICKER_WORKER_PIPELINE_INLINE_POLLER_FORCE_ENABLED, false);
23
+ const INLINE_POLLER_LOOP_ACTIVE = INLINE_POLLER_ENABLED || INLINE_POLLER_FORCE_ENABLED;
24
+
25
+ const TASK_CADENCE_MS = {
26
+ classification_cycle: Math.max(10_000, Number(process.env.STICKER_WORKER_CLASSIFICATION_CADENCE_MS) || 120_000),
27
+ curation_cycle: Math.max(15_000, Number(process.env.STICKER_WORKER_CURATION_CADENCE_MS) || 180_000),
28
+ rebuild_cycle: Math.max(15_000, Number(process.env.STICKER_WORKER_REBUILD_CADENCE_MS) || 240_000),
29
+ };
30
+
31
+ const TASK_PRIORITY = {
32
+ classification_cycle: 70,
33
+ curation_cycle: 55,
34
+ rebuild_cycle: 50,
35
+ };
36
+ const PIPELINE_PROCESS_COHORT_KEY = String(process.env.STICKER_WORKER_PIPELINE_COHORT_KEY || process.env.HOSTNAME || process.pid).trim() || 'pipeline';
37
+
38
+ let startupHandle = null;
39
+ let schedulerHandle = null;
40
+ let pollerHandle = null;
41
+ let runningPoll = false;
42
+ let taskQueueAvailable = true;
43
+ const nextScheduleByTask = new Map();
44
+
45
+ const taskHandlers = {
46
+ classification_cycle: async () => runStickerClassificationCycle({ processPending: true, processReprocess: true }),
47
+ curation_cycle: async () => runStickerAutoPackByTagsCycle({ enableAdditions: true, enableRebuild: false }),
48
+ rebuild_cycle: async () => runStickerAutoPackByTagsCycle({ enableAdditions: false, enableRebuild: true }),
49
+ };
50
+
51
+ const refreshQueueDepthMetrics = async () => {
52
+ if (!taskQueueAvailable) return;
53
+ const [pending, processing, failed] = await Promise.all([countWorkerTasksByStatus('pending'), countWorkerTasksByStatus('processing'), countWorkerTasksByStatus('failed')]);
54
+ setQueueDepth('sticker_worker_tasks_pending', pending);
55
+ setQueueDepth('sticker_worker_tasks_processing', processing);
56
+ setQueueDepth('sticker_worker_tasks_failed', failed);
57
+ };
58
+
59
+ const canRunInlinePoller = async () => {
60
+ if (!INLINE_POLLER_ENABLED) return false;
61
+ if (INLINE_POLLER_FORCE_ENABLED) return true;
62
+ const dedicatedWorkersEnabled = await isFeatureEnabled('enable_worker_dedicated_processes', {
63
+ fallback: false,
64
+ subjectKey: `pipeline:inline_poller:${PIPELINE_PROCESS_COHORT_KEY}`,
65
+ });
66
+ return !dedicatedWorkersEnabled;
67
+ };
68
+
69
+ const scheduleTaskIfNeeded = async (taskType) => {
70
+ if (!taskQueueAvailable) return;
71
+ const cadence = TASK_CADENCE_MS[taskType];
72
+ if (!cadence) return;
73
+
74
+ const now = Date.now();
75
+ const nextDueAt = nextScheduleByTask.get(taskType) || 0;
76
+ if (now < nextDueAt) return;
77
+
78
+ const hasPending = await hasPendingWorkerTask(taskType);
79
+ if (hasPending) {
80
+ nextScheduleByTask.set(taskType, now + Math.floor(cadence / 2));
81
+ return;
82
+ }
83
+
84
+ await enqueueWorkerTask({
85
+ taskType,
86
+ payload: { scheduled_by: 'sticker_worker_pipeline' },
87
+ priority: TASK_PRIORITY[taskType] || 50,
88
+ idempotencyKey: `pipeline:${taskType}:${Math.floor(now / cadence)}`,
89
+ });
90
+ nextScheduleByTask.set(taskType, now + cadence);
91
+ };
92
+
93
+ const schedulerTick = async () => {
94
+ if (!PIPELINE_ENABLED) return;
95
+
96
+ try {
97
+ await Promise.all([scheduleTaskIfNeeded('classification_cycle'), scheduleTaskIfNeeded('curation_cycle'), scheduleTaskIfNeeded('rebuild_cycle')]);
98
+ await refreshQueueDepthMetrics();
99
+ } catch (error) {
100
+ if (error?.code === 'ER_NO_SUCH_TABLE') {
101
+ taskQueueAvailable = false;
102
+ logger.warn('Fila do pipeline de workers indisponivel (migração pendente).', {
103
+ action: 'sticker_worker_pipeline_queue_unavailable',
104
+ });
105
+ return;
106
+ }
107
+ throw error;
108
+ }
109
+ };
110
+
111
+ const processSingleTaskType = async (taskType) => {
112
+ if (!taskQueueAvailable) return false;
113
+ const task = await claimWorkerTask({ taskType });
114
+ if (!task) return false;
115
+
116
+ try {
117
+ const handler = taskHandlers[taskType];
118
+ if (typeof handler !== 'function') {
119
+ throw new Error(`handler_not_found:${taskType}`);
120
+ }
121
+
122
+ await handler(task.payload || {});
123
+ await completeWorkerTask(task.id);
124
+
125
+ logger.debug('Task de worker concluída.', {
126
+ action: 'sticker_worker_task_completed',
127
+ task_type: taskType,
128
+ task_id: task.id,
129
+ attempts: task.attempts,
130
+ });
131
+ return true;
132
+ } catch (error) {
133
+ await failWorkerTask(task.id, {
134
+ error: error?.message || 'worker_task_failed',
135
+ retryDelaySeconds: WORKER_RETRY_DELAY_SECONDS,
136
+ });
137
+
138
+ logger.warn('Task de worker falhou.', {
139
+ action: 'sticker_worker_task_failed',
140
+ task_type: taskType,
141
+ task_id: task.id,
142
+ attempts: task.attempts,
143
+ error: error?.message,
144
+ });
145
+ return true;
146
+ }
147
+ };
148
+
149
+ const pollerTick = async () => {
150
+ if (runningPoll || !PIPELINE_ENABLED) return;
151
+ runningPoll = true;
152
+
153
+ try {
154
+ if (!(await canRunInlinePoller())) return;
155
+
156
+ let progressed = false;
157
+
158
+ progressed = (await processSingleTaskType('classification_cycle')) || progressed;
159
+ progressed = (await processSingleTaskType('curation_cycle')) || progressed;
160
+ progressed = (await processSingleTaskType('rebuild_cycle')) || progressed;
161
+
162
+ if (progressed) {
163
+ await refreshQueueDepthMetrics();
164
+ }
165
+ } catch (error) {
166
+ if (error?.code === 'ER_NO_SUCH_TABLE') {
167
+ taskQueueAvailable = false;
168
+ logger.warn('Fila do pipeline de workers indisponivel durante o poll.', {
169
+ action: 'sticker_worker_pipeline_queue_unavailable_poll',
170
+ });
171
+ } else {
172
+ logger.error('Falha no poller do pipeline de workers.', {
173
+ action: 'sticker_worker_pipeline_poll_failed',
174
+ error: error?.message,
175
+ });
176
+ }
177
+ } finally {
178
+ runningPoll = false;
179
+ }
180
+ };
181
+
182
+ export const startStickerWorkerPipeline = () => {
183
+ if (!PIPELINE_ENABLED) {
184
+ logger.info('Pipeline de workers de sticker desabilitado.', {
185
+ action: 'sticker_worker_pipeline_disabled',
186
+ });
187
+ return;
188
+ }
189
+
190
+ if (startupHandle || schedulerHandle || pollerHandle) return;
191
+
192
+ logger.info('Iniciando pipeline de workers de sticker.', {
193
+ action: 'sticker_worker_pipeline_start',
194
+ startup_delay_ms: STARTUP_DELAY_MS,
195
+ scheduler_interval_ms: SCHEDULER_INTERVAL_MS,
196
+ poller_interval_ms: POLLER_INTERVAL_MS,
197
+ inline_poller_enabled: INLINE_POLLER_ENABLED,
198
+ inline_poller_loop_active: INLINE_POLLER_LOOP_ACTIVE,
199
+ cadence_ms: TASK_CADENCE_MS,
200
+ });
201
+
202
+ startupHandle = setTimeout(() => {
203
+ startupHandle = null;
204
+
205
+ void schedulerTick();
206
+ if (INLINE_POLLER_LOOP_ACTIVE) {
207
+ void pollerTick();
208
+ }
209
+
210
+ schedulerHandle = setInterval(() => {
211
+ void schedulerTick();
212
+ }, SCHEDULER_INTERVAL_MS);
213
+
214
+ if (INLINE_POLLER_LOOP_ACTIVE) {
215
+ pollerHandle = setInterval(() => {
216
+ void pollerTick();
217
+ }, POLLER_INTERVAL_MS);
218
+ }
219
+
220
+ if (typeof schedulerHandle.unref === 'function') schedulerHandle.unref();
221
+ if (typeof pollerHandle?.unref === 'function') pollerHandle.unref();
222
+ }, STARTUP_DELAY_MS);
223
+
224
+ if (typeof startupHandle.unref === 'function') startupHandle.unref();
225
+ };
226
+
227
+ export const stopStickerWorkerPipeline = () => {
228
+ if (startupHandle) {
229
+ clearTimeout(startupHandle);
230
+ startupHandle = null;
231
+ }
232
+ if (schedulerHandle) {
233
+ clearInterval(schedulerHandle);
234
+ schedulerHandle = null;
235
+ }
236
+ if (pollerHandle) {
237
+ clearInterval(pollerHandle);
238
+ pollerHandle = null;
239
+ }
240
+ };
241
+
242
+ export const isStickerWorkerPipelineEnabled = () => PIPELINE_ENABLED;
@@ -0,0 +1,242 @@
1
+ import { randomUUID } from 'node:crypto';
2
+
3
+ import { executeQuery, TABLES } from '../../../database/index.js';
4
+
5
+ const normalizeTaskType = (value) => {
6
+ const normalized = String(value || '')
7
+ .trim()
8
+ .toLowerCase();
9
+ if (['classification_cycle', 'curation_cycle', 'rebuild_cycle'].includes(normalized)) return normalized;
10
+ return null;
11
+ };
12
+
13
+ const normalizeStatus = (value) => {
14
+ const normalized = String(value || '')
15
+ .trim()
16
+ .toLowerCase();
17
+ if (['pending', 'processing', 'completed', 'failed'].includes(normalized)) return normalized;
18
+ return null;
19
+ };
20
+
21
+ const clampInt = (value, fallback, min, max) => {
22
+ const numeric = Number(value);
23
+ if (!Number.isFinite(numeric)) return fallback;
24
+ return Math.max(min, Math.min(max, Math.floor(numeric)));
25
+ };
26
+
27
+ const CLAIM_LOCK_TIMEOUT_SECONDS = clampInt(process.env.STICKER_WORKER_TASK_LOCK_TIMEOUT_SECONDS, 15 * 60, 30, 24 * 60 * 60);
28
+
29
+ const normalizeIdempotencyKey = (value) =>
30
+ String(value || '')
31
+ .trim()
32
+ .replace(/[^a-zA-Z0-9_:-]/g, '')
33
+ .slice(0, 180);
34
+
35
+ const parseJson = (value, fallback = null) => {
36
+ if (value === null || value === undefined) return fallback;
37
+ if (typeof value === 'object') return value;
38
+ if (Buffer.isBuffer(value)) {
39
+ try {
40
+ return JSON.parse(value.toString('utf8'));
41
+ } catch {
42
+ return fallback;
43
+ }
44
+ }
45
+
46
+ if (typeof value === 'string') {
47
+ try {
48
+ return JSON.parse(value);
49
+ } catch {
50
+ return fallback;
51
+ }
52
+ }
53
+
54
+ return fallback;
55
+ };
56
+
57
+ const normalizeRow = (row) => {
58
+ if (!row) return null;
59
+ return {
60
+ id: Number(row.id),
61
+ task_type: row.task_type,
62
+ payload: parseJson(row.payload, {}),
63
+ idempotency_key: row.idempotency_key || null,
64
+ priority: Number(row.priority || 0),
65
+ scheduled_at: row.scheduled_at || null,
66
+ status: row.status,
67
+ attempts: Number(row.attempts || 0),
68
+ max_attempts: Number(row.max_attempts || 0),
69
+ worker_token: row.worker_token || null,
70
+ last_error: row.last_error || null,
71
+ locked_at: row.locked_at || null,
72
+ processed_at: row.processed_at || null,
73
+ created_at: row.created_at || null,
74
+ updated_at: row.updated_at || null,
75
+ };
76
+ };
77
+
78
+ export async function enqueueWorkerTask({ taskType, payload = {}, priority = 50, scheduledAt = null, maxAttempts = 5, idempotencyKey = '' }, connection = null) {
79
+ const normalizedTaskType = normalizeTaskType(taskType);
80
+ if (!normalizedTaskType) return false;
81
+
82
+ const safePriority = clampInt(priority, 50, 1, 100);
83
+ const safeMaxAttempts = clampInt(maxAttempts, 5, 1, 20);
84
+ const safeScheduledAt = scheduledAt ? new Date(scheduledAt) : null;
85
+ const scheduledValue = safeScheduledAt && Number.isFinite(safeScheduledAt.valueOf()) ? safeScheduledAt : null;
86
+ const normalizedIdempotencyKey = normalizeIdempotencyKey(idempotencyKey) || null;
87
+
88
+ await executeQuery(
89
+ `INSERT INTO ${TABLES.STICKER_WORKER_TASK_QUEUE}
90
+ (task_type, idempotency_key, payload, priority, scheduled_at, status, attempts, max_attempts)
91
+ VALUES (?, ?, ?, ?, COALESCE(?, UTC_TIMESTAMP()), 'pending', 0, ?)
92
+ ON DUPLICATE KEY UPDATE
93
+ payload = IF(status IN ('pending', 'failed'), VALUES(payload), payload),
94
+ priority = GREATEST(priority, VALUES(priority)),
95
+ scheduled_at = LEAST(scheduled_at, VALUES(scheduled_at)),
96
+ status = IF(status = 'failed' AND attempts < max_attempts, 'pending', status),
97
+ updated_at = UTC_TIMESTAMP()`,
98
+ [normalizedTaskType, normalizedIdempotencyKey, JSON.stringify(payload || {}), safePriority, scheduledValue, safeMaxAttempts],
99
+ connection,
100
+ );
101
+ return true;
102
+ }
103
+
104
+ export async function hasPendingWorkerTask(taskType, connection = null) {
105
+ const normalizedTaskType = normalizeTaskType(taskType);
106
+ if (!normalizedTaskType) return false;
107
+
108
+ const rows = await executeQuery(
109
+ `SELECT id
110
+ FROM ${TABLES.STICKER_WORKER_TASK_QUEUE}
111
+ WHERE task_type = ?
112
+ AND (
113
+ status IN ('pending', 'processing')
114
+ OR (status = 'failed' AND attempts < max_attempts)
115
+ )
116
+ LIMIT 1`,
117
+ [normalizedTaskType],
118
+ connection,
119
+ );
120
+ return rows.length > 0;
121
+ }
122
+
123
+ export async function claimWorkerTask({ taskType, allowRetryFailed = true } = {}, connection = null) {
124
+ const normalizedTaskType = normalizeTaskType(taskType);
125
+ if (!normalizedTaskType) return null;
126
+
127
+ const workerToken = randomUUID();
128
+ const statusClause = allowRetryFailed
129
+ ? `(status = 'pending'
130
+ OR (status = 'failed' AND attempts < max_attempts)
131
+ OR (status = 'processing' AND locked_at <= (UTC_TIMESTAMP() - INTERVAL ${CLAIM_LOCK_TIMEOUT_SECONDS} SECOND)))`
132
+ : `(status = 'pending'
133
+ OR (status = 'processing' AND locked_at <= (UTC_TIMESTAMP() - INTERVAL ${CLAIM_LOCK_TIMEOUT_SECONDS} SECOND)))`;
134
+
135
+ await executeQuery(
136
+ `UPDATE ${TABLES.STICKER_WORKER_TASK_QUEUE}
137
+ SET status = 'processing',
138
+ worker_token = ?,
139
+ locked_at = UTC_TIMESTAMP(),
140
+ attempts = attempts + 1,
141
+ updated_at = UTC_TIMESTAMP()
142
+ WHERE id = (
143
+ SELECT id FROM (
144
+ SELECT id
145
+ FROM ${TABLES.STICKER_WORKER_TASK_QUEUE}
146
+ WHERE task_type = ?
147
+ AND ${statusClause}
148
+ AND scheduled_at <= UTC_TIMESTAMP()
149
+ ORDER BY priority DESC, scheduled_at ASC, id ASC
150
+ LIMIT 1
151
+ ) pick
152
+ )`,
153
+ [workerToken, normalizedTaskType],
154
+ connection,
155
+ );
156
+
157
+ const rows = await executeQuery(
158
+ `SELECT *
159
+ FROM ${TABLES.STICKER_WORKER_TASK_QUEUE}
160
+ WHERE worker_token = ?
161
+ AND status = 'processing'
162
+ ORDER BY id DESC
163
+ LIMIT 1`,
164
+ [workerToken],
165
+ connection,
166
+ );
167
+
168
+ return normalizeRow(rows?.[0] || null);
169
+ }
170
+
171
+ export async function completeWorkerTask(taskId, connection = null) {
172
+ if (!taskId) return false;
173
+ await executeQuery(
174
+ `UPDATE ${TABLES.STICKER_WORKER_TASK_QUEUE}
175
+ SET status = 'completed',
176
+ processed_at = UTC_TIMESTAMP(),
177
+ worker_token = NULL,
178
+ locked_at = NULL,
179
+ last_error = NULL,
180
+ updated_at = UTC_TIMESTAMP()
181
+ WHERE id = ?`,
182
+ [taskId],
183
+ connection,
184
+ );
185
+ return true;
186
+ }
187
+
188
+ export async function failWorkerTask(taskId, { error = null, retryDelaySeconds = 0 } = {}, connection = null) {
189
+ if (!taskId) return false;
190
+ const safeDelay = clampInt(retryDelaySeconds, 0, 0, 86400 * 7);
191
+ const message =
192
+ String(error || '')
193
+ .trim()
194
+ .slice(0, 255) || null;
195
+
196
+ await executeQuery(
197
+ `UPDATE ${TABLES.STICKER_WORKER_TASK_QUEUE}
198
+ SET status = IF(attempts >= max_attempts, 'failed', 'pending'),
199
+ worker_token = NULL,
200
+ locked_at = NULL,
201
+ last_error = ?,
202
+ scheduled_at = IF(attempts >= max_attempts, scheduled_at, UTC_TIMESTAMP() + INTERVAL ${safeDelay} SECOND),
203
+ updated_at = UTC_TIMESTAMP(),
204
+ processed_at = IF(attempts >= max_attempts, UTC_TIMESTAMP(), processed_at)
205
+ WHERE id = ?`,
206
+ [message, taskId],
207
+ connection,
208
+ );
209
+
210
+ await executeQuery(
211
+ `INSERT INTO ${TABLES.STICKER_WORKER_TASK_DLQ}
212
+ (task_id, task_type, payload, idempotency_key, attempts, max_attempts, priority, last_error)
213
+ SELECT id, task_type, payload, idempotency_key, attempts, max_attempts, priority, last_error
214
+ FROM ${TABLES.STICKER_WORKER_TASK_QUEUE}
215
+ WHERE id = ?
216
+ AND status = 'failed'
217
+ ON DUPLICATE KEY UPDATE
218
+ attempts = VALUES(attempts),
219
+ max_attempts = VALUES(max_attempts),
220
+ priority = VALUES(priority),
221
+ last_error = VALUES(last_error),
222
+ failed_at = CURRENT_TIMESTAMP`,
223
+ [taskId],
224
+ connection,
225
+ ).catch(() => null);
226
+
227
+ return true;
228
+ }
229
+
230
+ export async function countWorkerTasksByStatus(status = 'pending', connection = null) {
231
+ const normalizedStatus = normalizeStatus(status);
232
+ if (!normalizedStatus) return 0;
233
+
234
+ const rows = await executeQuery(
235
+ `SELECT COUNT(*) AS total
236
+ FROM ${TABLES.STICKER_WORKER_TASK_QUEUE}
237
+ WHERE status = ?`,
238
+ [normalizedStatus],
239
+ connection,
240
+ );
241
+ return Number(rows?.[0]?.total || 0);
242
+ }
@@ -0,0 +1,193 @@
1
+ # SystemMetricsModule 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/systemMetricsModule/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: `systemMetricsModule`
15
+ - source_files:
16
+ - pingCommand.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: sistema
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
+ ### statusbot
74
+
75
+ - id: systemmetrics.statusbot
76
+ - aliases: ping
77
+ - enabled: true
78
+ - categoria: sistema
79
+ - descricao: Exibe latencia e estado de saude do servidor.
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>statusbot
90
+ - mensagens_uso (variantes):
91
+ - default:
92
+ - <prefix>statusbot
93
+ - subcomandos:
94
+ - (nenhum)
95
+ - argumentos:
96
+ - (nenhum)
97
+ - pre_condicoes:
98
+ - requer_grupo: nao
99
+ - requer_admin: nao
100
+ - requer_admin_principal: nao
101
+ - requer_google_login: sim
102
+ - requer_nsfw: nao
103
+ - requer_midia: nao
104
+ - requer_mensagem_respondida: nao
105
+ - rate_limit:
106
+ - max: null
107
+ - janela_ms: null
108
+ - escopo: sem_rate_limit_explicito
109
+ - acesso:
110
+ - somente_premium: nao
111
+ - planos_permitidos: comum, premium
112
+ - limite_uso_por_plano:
113
+ - comum: max=40, janela_ms=60000, escopo=usuario
114
+ - premium: max=160, janela_ms=60000, escopo=usuario
115
+ - informacoes_coletadas:
116
+ - identificador do chat (remoteJid)
117
+ - identificador do remetente (senderJid)
118
+ - texto do comando e argumentos
119
+ - contexto da mensagem (citacao e mencoes, quando existir)
120
+ - metricas do sistema operacional (cpu, memoria, uptime)
121
+ - metricas avancadas do endpoint Prometheus (quando disponivel)
122
+ - dependencias_externas:
123
+ - coleta local de métricas
124
+ - endpoint Prometheus (opcional)
125
+ - efeitos_colaterais:
126
+ - consulta estado do servidor
127
+ - envia diagnóstico no chat
128
+ - respostas_padrao:
129
+ - success: Comando executado com sucesso.
130
+ - usage_error: Formato de uso inválido. Consulte metodos_de_uso.
131
+ - permission_error: Permissão insuficiente para executar este comando.
132
+ - sucesso: Comando executado com sucesso.
133
+ - erro_uso: Formato de uso inválido. Consulte metodos_de_uso.
134
+ - erro_permissao: Permissão insuficiente para executar este comando.
135
+ - mensagens_sistema:
136
+ - (nao informado)
137
+ - limites_operacionais:
138
+ - (nao informado)
139
+ - opcoes:
140
+ - toggle_on_off_status.type: toggle
141
+ - toggle_on_off_status.allowed_actions: on, off, status
142
+ - toggle_on_off_status.action_argument: acao
143
+ - add_remove_list.type: list_management
144
+ - add_remove_list.allowed_actions: add, remove, list
145
+ - add_remove_list.action_argument: acao
146
+ - approve_reject.type: moderation_decision
147
+ - approve_reject.allowed_actions: approve, reject
148
+ - approve_reject.action_argument: acao
149
+ - approve_reject.requires_targets: true
150
+ - set_status_reset.type: configuration_window
151
+ - set_status_reset.allowed_actions: set, status, reset
152
+ - set_status_reset.action_argument: valor
153
+ - observabilidade:
154
+ - event_name: command.executed
155
+ - analytics_event: whatsapp_command_ping
156
+ - tags_log: whatsapp, command, systemMetricsModule, ping
157
+ - nivel_log: info
158
+ - privacidade:
159
+ - dados_sensiveis:
160
+ - chat_identifier
161
+ - sender_identifier
162
+ - command_content
163
+ - retencao: standard_app_logs
164
+ - base_legal: service_execution_and_legitimate_interest
165
+ - docs:
166
+ - summary: Exibe latencia e estado de saude do servidor.
167
+ - usage_examples: <prefix>statusbot
168
+ - usage_variants.default: <prefix>statusbot
169
+ - behavior:
170
+ - type: simple_action
171
+ - allowed_actions: (nenhum)
172
+ - limits:
173
+ - usage_description: sem limite especifico
174
+ - rate_limit.max: null
175
+ - rate_limit.janela_ms: null
176
+ - rate_limit.escopo: sem_rate_limit_explicito
177
+ - access.somente_premium: false
178
+ - access.planos_permitidos: comum, premium
179
+ - plan_limits.comum.max: 40
180
+ - plan_limits.comum.janela_ms: 60000
181
+ - plan_limits.comum.escopo: usuario
182
+ - plan_limits.premium.max: 160
183
+ - plan_limits.premium.janela_ms: 60000
184
+ - plan_limits.premium.escopo: usuario
185
+ - discovery:
186
+ - keywords: statusbot, sistema, privado, grupo
187
+ - faq_queries: como usar statusbot, o que faz statusbot, comando statusbot
188
+ - user_phrasings: quero usar statusbot, me ajuda com statusbot, exibe latencia e estado
189
+ - suggestion_priority: 100
190
+ - handler:
191
+ - file: pingCommand.js
192
+ - method: handlePingCommand
193
+ - command_case: statusbot