@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,89 @@
1
+ import js from '@eslint/js';
2
+
3
+ const nodeGlobals = {
4
+ process: 'readonly',
5
+ Buffer: 'readonly',
6
+ console: 'readonly',
7
+ setTimeout: 'readonly',
8
+ clearTimeout: 'readonly',
9
+ setInterval: 'readonly',
10
+ clearInterval: 'readonly',
11
+ setImmediate: 'readonly',
12
+ clearImmediate: 'readonly',
13
+ URL: 'readonly',
14
+ URLSearchParams: 'readonly',
15
+ fetch: 'readonly',
16
+ AbortController: 'readonly',
17
+ TextEncoder: 'readonly',
18
+ TextDecoder: 'readonly',
19
+ };
20
+
21
+ const browserGlobals = {
22
+ window: 'readonly',
23
+ document: 'readonly',
24
+ navigator: 'readonly',
25
+ localStorage: 'readonly',
26
+ sessionStorage: 'readonly',
27
+ history: 'readonly',
28
+ location: 'readonly',
29
+ fetch: 'readonly',
30
+ URL: 'readonly',
31
+ URLSearchParams: 'readonly',
32
+ atob: 'readonly',
33
+ btoa: 'readonly',
34
+ FileReader: 'readonly',
35
+ XMLHttpRequest: 'readonly',
36
+ performance: 'readonly',
37
+ MessageChannel: 'readonly',
38
+ AbortController: 'readonly',
39
+ Blob: 'readonly',
40
+ Element: 'readonly',
41
+ HTMLElement: 'readonly',
42
+ HTMLFormElement: 'readonly',
43
+ FormData: 'readonly',
44
+ MSApp: 'readonly',
45
+ };
46
+
47
+ export default [
48
+ {
49
+ ignores: ['node_modules/**', '.tmp_tools/**', 'logs/**', 'temp/**', '.eslintcache', '*.log', '**/*.min.js', 'coverage/**', 'dist/**', 'build/**', '**/.venv/**', 'ml/**/.venv/**', 'public/assets/js/**'],
50
+ },
51
+ js.configs.recommended,
52
+ {
53
+ files: ['**/*.{js,mjs,cjs}'],
54
+ languageOptions: {
55
+ ecmaVersion: 'latest',
56
+ sourceType: 'module',
57
+ globals: nodeGlobals,
58
+ },
59
+ linterOptions: {
60
+ reportUnusedDisableDirectives: 'warn',
61
+ },
62
+ rules: {
63
+ 'no-var': 'error',
64
+ 'prefer-const': 'warn',
65
+ 'no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_', ignoreRestSiblings: true }],
66
+ 'no-console': 'off',
67
+ },
68
+ },
69
+ {
70
+ files: ['public/js/**/*.{js,mjs,cjs}'],
71
+ languageOptions: {
72
+ globals: browserGlobals,
73
+ },
74
+ },
75
+ {
76
+ files: ['**/*.cjs'],
77
+ languageOptions: {
78
+ sourceType: 'commonjs',
79
+ globals: {
80
+ ...nodeGlobals,
81
+ module: 'readonly',
82
+ require: 'readonly',
83
+ exports: 'readonly',
84
+ __dirname: 'readonly',
85
+ __filename: 'readonly',
86
+ },
87
+ },
88
+ },
89
+ ];
package/index.js ADDED
@@ -0,0 +1,488 @@
1
+ /**
2
+ * Entry-point (bootstrap) do OmniZap System.
3
+ *
4
+ * Responsabilidades principais:
5
+ * - Inicializar o banco (garantindo DB e tabelas).
6
+ * - Subir servidor HTTP (catálogo web + endpoint de métricas).
7
+ * - Rodar backfill do lid_map (opcional, em background).
8
+ * - Conectar ao WhatsApp (Baileys).
9
+ * - Iniciar serviços auxiliares (ex: broadcast de notícias).
10
+ * - Registrar handlers de shutdown gracioso (SIGINT/SIGTERM) e falhas fatais
11
+ * (uncaughtException/unhandledRejection).
12
+ *
13
+ * Observações:
14
+ * - Este arquivo foi desenhado para ser "production-safe": tem timeouts, shutdown idempotente,
15
+ * e evita process.exit() imediato para não cortar logs/flush e não interromper fechamentos.
16
+ */
17
+
18
+ import 'dotenv/config';
19
+
20
+ import logger from '#logger';
21
+ import { connectToWhatsApp, getActiveSocket } from './app/connection/socketController.js';
22
+ import { backfillLidMapFromMessagesOnce } from './app/config/index.js';
23
+ import { initializeNewsBroadcastService, stopNewsBroadcastService } from './app/services/messaging/newsBroadcastService.js';
24
+ import initializeDatabase from './database/init.js';
25
+ import { startHttpServer, stopHttpServer } from './server/index.js';
26
+ import { startEmailAutomationRuntime, stopEmailAutomationRuntime } from './server/email/emailAutomationRuntime.js';
27
+ import { startStickerClassificationBackground, stopStickerClassificationBackground } from './app/modules/stickerPackModule/stickerClassificationBackgroundRuntime.js';
28
+ import { startStickerAutoPackByTagsBackground, stopStickerAutoPackByTagsBackground } from './app/modules/stickerPackModule/stickerAutoPackByTagsRuntime.js';
29
+ import { isStickerWorkerPipelineEnabled, startStickerWorkerPipeline, stopStickerWorkerPipeline } from './app/modules/stickerPackModule/stickerWorkerPipelineRuntime.js';
30
+ import { startStickerPackScoreSnapshotRuntime, stopStickerPackScoreSnapshotRuntime } from './app/modules/stickerPackModule/stickerPackScoreSnapshotRuntime.js';
31
+ import { startStickerDomainEventConsumer, stopStickerDomainEventConsumer } from './app/modules/stickerPackModule/stickerDomainEventConsumerRuntime.js';
32
+ import { startAiLearningWorker, stopAiLearningWorker } from './app/workers/aiLearningWorker.js';
33
+ import { startCommandConfigEnrichmentWorker, stopCommandConfigEnrichmentWorker } from './app/workers/commandConfigEnrichmentWorker.js';
34
+ import { formatCommandConfigValidationReport, validateAllCommandConfigs } from './app/services/ai/commandConfigValidationService.js';
35
+
36
+ /**
37
+ * Timeout máximo para inicialização do banco (criar/verificar DB + tabelas).
38
+ * Evita travar o processo em caso de MySQL indisponível ou DNS lento.
39
+ * @type {number}
40
+ */
41
+ const DB_INIT_TIMEOUT_MS = 15000;
42
+
43
+ /**
44
+ * Timeout máximo para conexão inicial do WhatsApp.
45
+ * Dependendo da rede/servidor, a conexão pode demorar, então é maior.
46
+ * @type {number}
47
+ */
48
+ const WHATSAPP_CONNECT_TIMEOUT_MS = 60000;
49
+
50
+ /**
51
+ * Tempo máximo que o shutdown deve aguardar o backfill finalizar.
52
+ * Como backfill é "best-effort", não devemos segurar o shutdown por muito tempo.
53
+ * @type {number}
54
+ */
55
+ const BACKFILL_SHUTDOWN_TIMEOUT_MS = 8000;
56
+
57
+ /**
58
+ * Flag para impedir múltiplos shutdowns concorrentes.
59
+ * @type {boolean}
60
+ */
61
+ let isShuttingDown = false;
62
+
63
+ /**
64
+ * Promise do shutdown em andamento (para idempotência).
65
+ * Se o shutdown for chamado novamente, devolvemos essa mesma promise.
66
+ * @type {Promise<void>|null}
67
+ */
68
+ let shutdownPromise = null;
69
+
70
+ /**
71
+ * Promise do backfill (quando habilitado).
72
+ * Guardamos para poder aguardar com timeout durante o shutdown.
73
+ * @type {Promise<any>|null}
74
+ */
75
+ let backfillPromise = null;
76
+
77
+ /**
78
+ * Erros transitórios conhecidos que não devem derrubar o serviço inteiro.
79
+ * Ex.: limite temporário da API do WhatsApp/Baileys.
80
+ *
81
+ * @param {unknown} reason
82
+ * @returns {boolean}
83
+ */
84
+ const isTransientUnhandledRejection = (reason) => {
85
+ const message = reason instanceof Error ? String(reason.message || '') : typeof reason === 'string' ? reason : String(reason || '');
86
+
87
+ const normalized = message.trim().toLowerCase();
88
+ if (!normalized) return false;
89
+
90
+ return normalized.includes('rate-overlimit') || normalized.includes('connection closed') || normalized.includes('timed out');
91
+ };
92
+
93
+ /**
94
+ * Executa uma Promise com um timeout.
95
+ *
96
+ * Útil para passos críticos que podem travar:
97
+ * - init do banco
98
+ * - conectar WhatsApp
99
+ * - fechar recursos no shutdown
100
+ *
101
+ * @template T
102
+ * @param {Promise<T>|T} promise - Promise (ou valor) a ser resolvido.
103
+ * @param {number} ms - Tempo máximo em milissegundos.
104
+ * @param {string} label - Nome curto do passo para mensagens de erro.
105
+ * @returns {Promise<T>} Resolve com o valor da Promise, ou rejeita com erro ETIMEOUT.
106
+ */
107
+ const withTimeout = (promise, ms, label) => {
108
+ /** @type {NodeJS.Timeout|undefined} */
109
+ let timeoutId;
110
+
111
+ const timeoutPromise = new Promise((_, reject) => {
112
+ timeoutId = setTimeout(() => {
113
+ const error = new Error(`${label} excedeu ${ms}ms`);
114
+ // Ajuda a filtrar em logs/telemetria
115
+ // @ts-ignore - code é campo comum, mas não está no tipo padrão de Error
116
+ error.code = 'ETIMEOUT';
117
+ reject(error);
118
+ }, ms);
119
+ });
120
+
121
+ return Promise.race([Promise.resolve(promise), timeoutPromise]).finally(() => {
122
+ if (timeoutId) {
123
+ clearTimeout(timeoutId);
124
+ }
125
+ });
126
+ };
127
+
128
+ /**
129
+ * Log helper para erros durante o shutdown, mantendo output consistente.
130
+ *
131
+ * @param {string} context - Texto curto do contexto (ex: "Detalhes do desligamento.").
132
+ * @param {unknown} error - Erro (ou reason) para log.
133
+ * @returns {void}
134
+ */
135
+ const logShutdownError = (context, error) => {
136
+ if (!error) return;
137
+
138
+ if (error instanceof Error) {
139
+ logger.error(context, { error: error.message, stack: error.stack });
140
+ return;
141
+ }
142
+
143
+ logger.error(context, { reason: error });
144
+ };
145
+
146
+ /**
147
+ * Encerra o pool de conexões do MySQL (se existir).
148
+ *
149
+ * Por que o import dinâmico?
150
+ * - Evita problemas de "import cycle" em cenários onde o DB module importa coisas
151
+ * que acabam importando este entrypoint (ou dependências).
152
+ * - Só carrega o módulo no momento do shutdown.
153
+ *
154
+ * @returns {Promise<void>}
155
+ */
156
+ async function closeDatabasePool() {
157
+ try {
158
+ const dbModule = await import('./database/index.js');
159
+ if (typeof dbModule.closePool !== 'function') {
160
+ // O módulo não expõe closePool, então não há o que encerrar aqui.
161
+ return;
162
+ }
163
+
164
+ logger.info('Encerrando pool MySQL...');
165
+ await withTimeout(dbModule.closePool(), 8000, 'closePool');
166
+ logger.info('Pool MySQL encerrado.');
167
+ } catch (error) {
168
+ logger.warn('Falha ao encerrar pool MySQL.', { error: error?.message });
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Inicializa o sistema e seus serviços principais.
174
+ *
175
+ * Fluxo de startup:
176
+ * 1) Inicializa DB (cria/verifica DB/tabelas)
177
+ * 2) Sobe servidor HTTP (catálogo + métricas)
178
+ * 3) Inicia backfill (opcional) em background
179
+ * 4) Conecta no WhatsApp
180
+ * 5) Inicia serviços auxiliares (news broadcast)
181
+ * 6) Sinaliza readiness (se estiver rodando sob PM2/cluster com IPC)
182
+ *
183
+ * Em caso de falha: seta exitCode e aciona shutdown gracioso.
184
+ *
185
+ * @returns {Promise<void>}
186
+ */
187
+ async function startApp() {
188
+ try {
189
+ logger.info('Iniciando OmniZap System...');
190
+
191
+ const shouldValidateCommandConfigs = process.env.COMMAND_CONFIG_VALIDATE_ON_BOOT !== 'false';
192
+ if (shouldValidateCommandConfigs) {
193
+ logger.info('Validando commandConfig dos modulos...');
194
+ const validation = validateAllCommandConfigs();
195
+ if (!validation.ok) {
196
+ const report = formatCommandConfigValidationReport(validation, { maxErrors: 60 });
197
+ logger.error('Validacao de commandConfig falhou.', { report });
198
+ throw new Error('commandConfig validation failed');
199
+ }
200
+ logger.info('Validacao de commandConfig concluida com sucesso.', {
201
+ modules: validation.modulesValidated,
202
+ commands: validation.commandsValidated,
203
+ });
204
+ } else {
205
+ logger.warn('Validacao de commandConfig no boot desativada via env.', {
206
+ env: 'COMMAND_CONFIG_VALIDATE_ON_BOOT=false',
207
+ });
208
+ }
209
+
210
+ logger.info('Iniciando banco de dados...');
211
+ await withTimeout(initializeDatabase(), DB_INIT_TIMEOUT_MS, 'Inicializacao do banco');
212
+ logger.info('Banco de dados pronto.');
213
+
214
+ logger.info('Inicializando servidor HTTP...');
215
+ startHttpServer();
216
+ startEmailAutomationRuntime();
217
+ if (isStickerWorkerPipelineEnabled()) {
218
+ startStickerWorkerPipeline();
219
+ } else {
220
+ startStickerClassificationBackground();
221
+ startStickerAutoPackByTagsBackground();
222
+ }
223
+ startStickerPackScoreSnapshotRuntime();
224
+ startStickerDomainEventConsumer();
225
+ startAiLearningWorker();
226
+ startCommandConfigEnrichmentWorker();
227
+
228
+ // Backfill é opcional, rodando em background.
229
+ const shouldBackfill = process.env.LID_BACKFILL_ON_START !== 'false';
230
+ if (shouldBackfill) {
231
+ const batchSize = Number(process.env.LID_BACKFILL_BATCH) || undefined;
232
+
233
+ logger.info('Iniciando backfill lid_map...');
234
+ backfillPromise = backfillLidMapFromMessagesOnce({ batchSize })
235
+ .then((result) => {
236
+ logger.info('Backfill lid_map concluido.', { batches: result?.batches });
237
+ return result;
238
+ })
239
+ .catch((error) => {
240
+ logger.warn('Backfill lid_map nao concluido.', { error: error.message });
241
+ return null;
242
+ });
243
+ }
244
+
245
+ logger.info('Conectando ao WhatsApp...');
246
+ await withTimeout(connectToWhatsApp(), WHATSAPP_CONNECT_TIMEOUT_MS, 'Conexao WhatsApp');
247
+ logger.info('WhatsApp conectado.');
248
+
249
+ logger.info('Inicializando servico de noticias...');
250
+ await initializeNewsBroadcastService();
251
+ logger.info('Servico de noticias pronto.');
252
+
253
+ logger.info('OmniZap System iniciado com sucesso.');
254
+
255
+ // Compatível com gerenciadores que esperam "ready" via IPC.
256
+ if (process.send) {
257
+ process.send('ready');
258
+ }
259
+ } catch (err) {
260
+ logger.error('Falha ao iniciar o OmniZap System:', { error: err.message, stack: err.stack });
261
+ process.exitCode = 1;
262
+ await shutdown('STARTUP_ERROR', err);
263
+ }
264
+ }
265
+
266
+ startApp();
267
+
268
+ /**
269
+ * Realiza desligamento gracioso do sistema (idempotente).
270
+ *
271
+ * O que fecha:
272
+ * - serviço de notícias (se stop existir)
273
+ * - aguarda backfill (com timeout curto)
274
+ * - encerra socket do WhatsApp
275
+ * - encerra servidor HTTP
276
+ * - encerra pool do MySQL
277
+ *
278
+ * Regras:
279
+ * - Se já estiver desligando, retorna a mesma promise.
280
+ * - Define process.exitCode se ainda não estiver definido.
281
+ * - Ao finalizar, encerra o processo explicitamente para permitir restart limpo no PM2.
282
+ *
283
+ * @param {string} signal - Origem do shutdown (SIGINT, SIGTERM, uncaughtException, etc).
284
+ * @param {unknown} [error] - Erro associado (se houver).
285
+ * @returns {Promise<void>}
286
+ */
287
+ async function shutdown(signal, error) {
288
+ if (isShuttingDown) {
289
+ return shutdownPromise;
290
+ }
291
+ isShuttingDown = true;
292
+
293
+ if (process.exitCode === undefined || process.exitCode === null) {
294
+ process.exitCode = error ? 1 : 0;
295
+ }
296
+
297
+ logger.warn(`${signal} recebido. Iniciando desligamento gracioso...`);
298
+ logShutdownError('Detalhes do desligamento.', error);
299
+
300
+ shutdownPromise = (async () => {
301
+ // 1) Serviços com timers/intervals (news broadcast)
302
+ try {
303
+ if (typeof stopNewsBroadcastService === 'function') {
304
+ logger.info('Encerrando servico de noticias...');
305
+ stopNewsBroadcastService();
306
+ logger.info('Servico de noticias encerrado.');
307
+ }
308
+ } catch (stopError) {
309
+ logger.warn('Falha ao encerrar servico de noticias.', { error: stopError.message });
310
+ }
311
+
312
+ // 2) Esperar backfill (best-effort) com timeout
313
+ if (backfillPromise) {
314
+ try {
315
+ logger.info('Aguardando backfill lid_map...');
316
+ await withTimeout(backfillPromise, BACKFILL_SHUTDOWN_TIMEOUT_MS, 'Backfill lid_map');
317
+ logger.info('Backfill lid_map finalizado.');
318
+ } catch (backfillError) {
319
+ logger.warn('Backfill lid_map nao finalizou antes do shutdown.', {
320
+ error: backfillError.message,
321
+ });
322
+ }
323
+ }
324
+
325
+ // 3) Encerrar conexão WhatsApp
326
+ const sock = getActiveSocket();
327
+ if (sock) {
328
+ try {
329
+ logger.info('Encerrando conexão do WhatsApp...');
330
+ await withTimeout(sock.end(), 8000, 'Encerramento WhatsApp');
331
+ logger.info('Conexao do WhatsApp encerrada.');
332
+ } catch (sockError) {
333
+ logger.error('Erro ao encerrar a conexão do WhatsApp:', {
334
+ error: sockError.message,
335
+ stack: sockError.stack,
336
+ });
337
+ }
338
+ }
339
+
340
+ // 4) Encerrar servidor HTTP
341
+ if (typeof stopHttpServer === 'function') {
342
+ try {
343
+ logger.info('Encerrando servidor HTTP...');
344
+ await withTimeout(stopHttpServer(), 8000, 'Encerramento HTTP');
345
+ logger.info('Servidor HTTP encerrado.');
346
+ } catch (httpError) {
347
+ logger.warn('Falha ao encerrar servidor HTTP.', { error: httpError.message });
348
+ }
349
+ }
350
+
351
+ // 4.1) Encerrar worker de classificação de stickers
352
+ try {
353
+ if (isStickerWorkerPipelineEnabled()) {
354
+ stopStickerWorkerPipeline();
355
+ } else {
356
+ stopStickerClassificationBackground();
357
+ }
358
+ } catch (workerError) {
359
+ logger.warn('Falha ao encerrar worker de classificação de stickers.', {
360
+ error: workerError?.message,
361
+ });
362
+ }
363
+
364
+ try {
365
+ if (!isStickerWorkerPipelineEnabled()) {
366
+ stopStickerAutoPackByTagsBackground();
367
+ }
368
+ } catch (workerError) {
369
+ logger.warn('Falha ao encerrar worker de auto-pack por tags.', {
370
+ error: workerError?.message,
371
+ });
372
+ }
373
+
374
+ try {
375
+ stopStickerPackScoreSnapshotRuntime();
376
+ } catch (snapshotError) {
377
+ logger.warn('Falha ao encerrar runtime de snapshot de score dos packs.', {
378
+ error: snapshotError?.message,
379
+ });
380
+ }
381
+
382
+ try {
383
+ stopStickerDomainEventConsumer();
384
+ } catch (consumerError) {
385
+ logger.warn('Falha ao encerrar consumidor interno de eventos de domínio.', {
386
+ error: consumerError?.message,
387
+ });
388
+ }
389
+
390
+ try {
391
+ stopAiLearningWorker();
392
+ } catch (learningWorkerError) {
393
+ logger.warn('Falha ao encerrar worker de aprendizado de IA.', {
394
+ error: learningWorkerError?.message,
395
+ });
396
+ }
397
+
398
+ try {
399
+ stopCommandConfigEnrichmentWorker();
400
+ } catch (commandConfigWorkerError) {
401
+ logger.warn('Falha ao encerrar worker de enriquecimento de commandConfig.', {
402
+ error: commandConfigWorkerError?.message,
403
+ });
404
+ }
405
+
406
+ try {
407
+ stopEmailAutomationRuntime();
408
+ } catch (emailRuntimeError) {
409
+ logger.warn('Falha ao encerrar runtime de automação de e-mail.', {
410
+ error: emailRuntimeError?.message,
411
+ });
412
+ }
413
+
414
+ // 5) Encerrar MySQL pool
415
+ await closeDatabasePool();
416
+
417
+ logger.info('OmniZap System desligado.');
418
+
419
+ const exitCode = Number(process.exitCode ?? (error ? 1 : 0));
420
+ logger.info('Encerrando processo Node.', { exitCode, signal });
421
+ // Força término para evitar processo "online" sem servidor HTTP ativo.
422
+ process.exit(exitCode);
423
+ })();
424
+
425
+ return shutdownPromise;
426
+ }
427
+
428
+ /**
429
+ * Handler para interrupção no terminal (Ctrl+C).
430
+ * @returns {void}
431
+ */
432
+ process.on('SIGINT', () => {
433
+ void shutdown('SIGINT');
434
+ });
435
+
436
+ /**
437
+ * Handler para encerramento solicitado pelo sistema (ex: container/PM2).
438
+ * @returns {void}
439
+ */
440
+ process.on('SIGTERM', () => {
441
+ void shutdown('SIGTERM');
442
+ });
443
+
444
+ /**
445
+ * Handler para exceções não capturadas (fatal).
446
+ * - seta exitCode=1
447
+ * - inicia shutdown gracioso para tentar fechar recursos antes de morrer
448
+ *
449
+ * @param {Error} err
450
+ * @returns {void}
451
+ */
452
+ process.on('uncaughtException', (err) => {
453
+ logger.error('Exceção não capturada:', { error: err.message, stack: err.stack });
454
+ process.exitCode = 1;
455
+ void shutdown('uncaughtException', err);
456
+ });
457
+
458
+ /**
459
+ * Handler para rejeições de promise sem catch (fatal).
460
+ * - loga reason
461
+ * - seta exitCode=1
462
+ * - inicia shutdown gracioso
463
+ *
464
+ * Observação: o parâmetro `promise` é incluído apenas para debug, mas geralmente não é útil.
465
+ *
466
+ * @param {unknown} reason
467
+ * @param {Promise<unknown>} promise
468
+ * @returns {void}
469
+ */
470
+ process.on('unhandledRejection', (reason, promise) => {
471
+ if (isTransientUnhandledRejection(reason)) {
472
+ logger.warn('Rejeição de promessa transitória ignorada para manter disponibilidade.', {
473
+ reason: reason instanceof Error ? reason.message : String(reason || ''),
474
+ });
475
+ return;
476
+ }
477
+
478
+ if (reason instanceof Error) {
479
+ logger.error('Rejeição de promessa não tratada:', {
480
+ error: reason.message,
481
+ stack: reason.stack,
482
+ });
483
+ } else {
484
+ logger.error('Rejeição de promessa não tratada:', { reason, promise });
485
+ }
486
+ process.exitCode = 1;
487
+ void shutdown('unhandledRejection', reason);
488
+ });
@@ -0,0 +1,18 @@
1
+ FROM python:3.11-slim@sha256:d6e4d224f70f9e0172a06a3a2eba2f768eb146811a349278b38fff3a36463b47
2
+
3
+ ENV PYTHONDONTWRITEBYTECODE=1 \
4
+ PYTHONUNBUFFERED=1 \
5
+ PIP_NO_CACHE_DIR=1
6
+
7
+ WORKDIR /app
8
+
9
+ COPY requirements.txt .
10
+ RUN pip wheel --wheel-dir /tmp/wheels -r requirements.txt \
11
+ && pip install /tmp/wheels/*.whl \
12
+ && rm -rf /tmp/wheels
13
+
14
+ COPY . .
15
+
16
+ EXPOSE 8008
17
+
18
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8008"]