@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.
- package/.clusterfuzzlite/Dockerfile +10 -0
- package/.env.example +907 -0
- package/.github/codeql/codeql-config.yml +10 -0
- package/.github/dependabot.yml +35 -0
- package/.github/workflows/ci.yml +73 -0
- package/.github/workflows/codeql.yml +106 -0
- package/.github/workflows/db-migration-check.yml +98 -0
- package/.github/workflows/dependency-review.yml +22 -0
- package/.github/workflows/deploy.yml +95 -0
- package/.github/workflows/release.yml +106 -0
- package/.github/workflows/security-attest-provenance.yml +51 -0
- package/.github/workflows/security-gitleaks.yml +34 -0
- package/.github/workflows/security-runner-hardening.yml +31 -0
- package/.github/workflows/security-scorecard.yml +44 -0
- package/.github/workflows/security-zap-baseline.yml +44 -0
- package/.github/workflows/security-zap-full-scan.yml +43 -0
- package/.github/workflows/security-zizmor.yml +36 -0
- package/.github/workflows/wiki-sync.yml +44 -0
- package/.gitleaks.toml +15 -0
- package/.prettierrc +34 -0
- package/CODE_OF_CONDUCT.md +114 -0
- package/LICENSE +56 -0
- package/README.md +110 -0
- package/SECURITY.md +110 -0
- package/app/config/index.js +4 -0
- package/app/configParts/adminIdentity.js +92 -0
- package/app/configParts/baileysConfig.js +1818 -0
- package/app/configParts/groupUtils.js +692 -0
- package/app/configParts/loggerConfig.js +394 -0
- package/app/configParts/messagePersistenceService.js +305 -0
- package/app/connection/baileysCompatibility.test.js +40 -0
- package/app/connection/baileysDbAuthState.js +344 -0
- package/app/connection/socketController.js +2243 -0
- package/app/controllers/messageController.js +7 -0
- package/app/controllers/messagePipeline/commandMiddleware.js +146 -0
- package/app/controllers/messagePipeline/conversationMiddleware.js +183 -0
- package/app/controllers/messagePipeline/messagePipelineMiddlewares.test.js +522 -0
- package/app/controllers/messagePipeline/postProcessingMiddleware.js +41 -0
- package/app/controllers/messagePipeline/preProcessingMiddlewares.js +166 -0
- package/app/controllers/messageProcessingPipeline.js +699 -0
- package/app/modules/adminModule/AGENT.md +4056 -0
- package/app/modules/adminModule/adminAiHelpService.js +56 -0
- package/app/modules/adminModule/adminConfigRuntime.js +177 -0
- package/app/modules/adminModule/commandConfig.json +7122 -0
- package/app/modules/adminModule/groupCommandHandlers.js +1823 -0
- package/app/modules/adminModule/groupCommandHandlers.test.js +350 -0
- package/app/modules/adminModule/groupEventHandlers.js +399 -0
- package/app/modules/aiModule/AGENT.md +547 -0
- package/app/modules/aiModule/aiAiHelpService.js +14 -0
- package/app/modules/aiModule/aiConfigRuntime.js +135 -0
- package/app/modules/aiModule/catCommand.js +967 -0
- package/app/modules/aiModule/commandConfig.json +981 -0
- package/app/modules/analyticsModule/messageAnalysisEventRepository.js +83 -0
- package/app/modules/gameModule/AGENT.md +196 -0
- package/app/modules/gameModule/commandConfig.json +366 -0
- package/app/modules/gameModule/diceCommand.js +42 -0
- package/app/modules/gameModule/gameAiHelpService.js +14 -0
- package/app/modules/gameModule/gameConfigRuntime.js +68 -0
- package/app/modules/menuModule/AGENT.md +205 -0
- package/app/modules/menuModule/commandConfig.json +366 -0
- package/app/modules/menuModule/common.js +316 -0
- package/app/modules/menuModule/menuAiHelpService.js +14 -0
- package/app/modules/menuModule/menuConfigRuntime.js +68 -0
- package/app/modules/menuModule/menus.js +66 -0
- package/app/modules/playModule/AGENT.md +321 -0
- package/app/modules/playModule/commandConfig.json +584 -0
- package/app/modules/playModule/playAiHelpService.js +14 -0
- package/app/modules/playModule/playCommand.js +1417 -0
- package/app/modules/playModule/playConfigRuntime.js +68 -0
- package/app/modules/quoteModule/AGENT.md +199 -0
- package/app/modules/quoteModule/commandConfig.json +366 -0
- package/app/modules/quoteModule/quoteAiHelpService.js +14 -0
- package/app/modules/quoteModule/quoteCommand.js +842 -0
- package/app/modules/quoteModule/quoteConfigRuntime.js +68 -0
- package/app/modules/rpgPokemonModule/AGENT.md +229 -0
- package/app/modules/rpgPokemonModule/commandConfig.json +386 -0
- package/app/modules/rpgPokemonModule/rpgBattleCanvasRenderer.js +795 -0
- package/app/modules/rpgPokemonModule/rpgBattleService.js +2110 -0
- package/app/modules/rpgPokemonModule/rpgBattleService.test.js +770 -0
- package/app/modules/rpgPokemonModule/rpgEvolutionUtils.js +22 -0
- package/app/modules/rpgPokemonModule/rpgPokemonAiHelpService.js +14 -0
- package/app/modules/rpgPokemonModule/rpgPokemonCommand.js +174 -0
- package/app/modules/rpgPokemonModule/rpgPokemonConfigRuntime.js +68 -0
- package/app/modules/rpgPokemonModule/rpgPokemonDomain.js +192 -0
- package/app/modules/rpgPokemonModule/rpgPokemonDomain.test.js +93 -0
- package/app/modules/rpgPokemonModule/rpgPokemonEvolution.test.js +46 -0
- package/app/modules/rpgPokemonModule/rpgPokemonMessages.js +746 -0
- package/app/modules/rpgPokemonModule/rpgPokemonRepository.js +1847 -0
- package/app/modules/rpgPokemonModule/rpgPokemonService.js +6839 -0
- package/app/modules/rpgPokemonModule/rpgProfileCanvasRenderer.js +354 -0
- package/app/modules/statsModule/AGENT.md +320 -0
- package/app/modules/statsModule/commandConfig.json +540 -0
- package/app/modules/statsModule/globalRankingCommand.js +64 -0
- package/app/modules/statsModule/rankingCommand.js +41 -0
- package/app/modules/statsModule/rankingCommon.js +1305 -0
- package/app/modules/statsModule/statsAiHelpService.js +14 -0
- package/app/modules/statsModule/statsConfigRuntime.js +68 -0
- package/app/modules/stickerModule/AGENT.md +692 -0
- package/app/modules/stickerModule/addStickerMetadata.js +239 -0
- package/app/modules/stickerModule/commandConfig.json +1216 -0
- package/app/modules/stickerModule/convertToWebp.js +367 -0
- package/app/modules/stickerModule/stickerAiHelpService.js +14 -0
- package/app/modules/stickerModule/stickerCommand.js +446 -0
- package/app/modules/stickerModule/stickerConfigRuntime.js +68 -0
- package/app/modules/stickerModule/stickerConvertCommand.js +159 -0
- package/app/modules/stickerModule/stickerTextCommand.js +653 -0
- package/app/modules/stickerPackModule/AGENT.md +215 -0
- package/app/modules/stickerPackModule/autoPackCollectorRuntime.js +20 -0
- package/app/modules/stickerPackModule/autoPackCollectorService.js +357 -0
- package/app/modules/stickerPackModule/commandConfig.json +387 -0
- package/app/modules/stickerPackModule/domainEventOutboxRepository.js +227 -0
- package/app/modules/stickerPackModule/domainEvents.js +52 -0
- package/app/modules/stickerPackModule/semanticReclassificationEngine.js +429 -0
- package/app/modules/stickerPackModule/semanticReclassificationEngine.test.js +75 -0
- package/app/modules/stickerPackModule/semanticThemeClusterService.js +544 -0
- package/app/modules/stickerPackModule/stickerAssetClassificationRepository.js +400 -0
- package/app/modules/stickerPackModule/stickerAssetRepository.js +400 -0
- package/app/modules/stickerPackModule/stickerAssetReprocessQueueRepository.js +175 -0
- package/app/modules/stickerPackModule/stickerAutoPackByTagsRuntime.js +3702 -0
- package/app/modules/stickerPackModule/stickerClassificationBackgroundRuntime.js +559 -0
- package/app/modules/stickerPackModule/stickerClassificationService.js +557 -0
- package/app/modules/stickerPackModule/stickerDedicatedTaskWorkerRuntime.js +249 -0
- package/app/modules/stickerPackModule/stickerDomainEventBus.js +65 -0
- package/app/modules/stickerPackModule/stickerDomainEventConsumerRuntime.js +208 -0
- package/app/modules/stickerPackModule/stickerMarketplaceDriftService.js +99 -0
- package/app/modules/stickerPackModule/stickerObjectStorageService.js +285 -0
- package/app/modules/stickerPackModule/stickerPackAiHelpService.js +14 -0
- package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +1148 -0
- package/app/modules/stickerPackModule/stickerPackConfigRuntime.js +68 -0
- package/app/modules/stickerPackModule/stickerPackEngagementRepository.js +152 -0
- package/app/modules/stickerPackModule/stickerPackErrors.js +30 -0
- package/app/modules/stickerPackModule/stickerPackInteractionEventRepository.js +101 -0
- package/app/modules/stickerPackModule/stickerPackItemRepository.js +432 -0
- package/app/modules/stickerPackModule/stickerPackMarketplaceService.js +313 -0
- package/app/modules/stickerPackModule/stickerPackMessageService.js +268 -0
- package/app/modules/stickerPackModule/stickerPackRepository.js +450 -0
- package/app/modules/stickerPackModule/stickerPackScoreSnapshotRepository.js +179 -0
- package/app/modules/stickerPackModule/stickerPackScoreSnapshotRuntime.js +271 -0
- package/app/modules/stickerPackModule/stickerPackService.js +733 -0
- package/app/modules/stickerPackModule/stickerPackServiceRuntime.js +32 -0
- package/app/modules/stickerPackModule/stickerPackUtils.js +107 -0
- package/app/modules/stickerPackModule/stickerStorageService.js +559 -0
- package/app/modules/stickerPackModule/stickerWorkerPipelineRuntime.js +242 -0
- package/app/modules/stickerPackModule/stickerWorkerTaskQueueRepository.js +242 -0
- package/app/modules/systemMetricsModule/AGENT.md +193 -0
- package/app/modules/systemMetricsModule/commandConfig.json +344 -0
- package/app/modules/systemMetricsModule/pingCommand.js +399 -0
- package/app/modules/systemMetricsModule/systemMetricsAiHelpService.js +14 -0
- package/app/modules/systemMetricsModule/systemMetricsConfigRuntime.js +68 -0
- package/app/modules/tiktokModule/AGENT.md +196 -0
- package/app/modules/tiktokModule/commandConfig.json +366 -0
- package/app/modules/tiktokModule/tiktokAiHelpService.js +14 -0
- package/app/modules/tiktokModule/tiktokCommand.js +716 -0
- package/app/modules/tiktokModule/tiktokConfigRuntime.js +68 -0
- package/app/modules/userModule/AGENT.md +200 -0
- package/app/modules/userModule/commandConfig.json +386 -0
- package/app/modules/userModule/userAiHelpService.js +14 -0
- package/app/modules/userModule/userCommand.js +1155 -0
- package/app/modules/userModule/userConfigRuntime.js +68 -0
- package/app/modules/waifuPicsModule/AGENT.md +431 -0
- package/app/modules/waifuPicsModule/commandConfig.json +780 -0
- package/app/modules/waifuPicsModule/waifuPicsAiHelpService.js +14 -0
- package/app/modules/waifuPicsModule/waifuPicsCommand.js +586 -0
- package/app/modules/waifuPicsModule/waifuPicsConfigRuntime.js +68 -0
- package/app/observability/metrics.js +766 -0
- package/app/services/ai/aiHelpResponseCacheRepository.js +280 -0
- package/app/services/ai/aiLearningRepository.js +400 -0
- package/app/services/ai/commandConfigEnrichmentRepository.js +769 -0
- package/app/services/ai/commandConfigEnrichmentService.js +452 -0
- package/app/services/ai/commandConfigValidationService.js +443 -0
- package/app/services/ai/commandToolBuilderService.js +192 -0
- package/app/services/ai/conversationRouterService.js +516 -0
- package/app/services/ai/geminiService.js +115 -0
- package/app/services/ai/geminiService.test.js +87 -0
- package/app/services/ai/globalModuleAiHelpService.js +1412 -0
- package/app/services/ai/globalToolCallingService.js +203 -0
- package/app/services/ai/messageCommandExecutionService.js +391 -0
- package/app/services/ai/moduleAiHelpCoreService.js +1099 -0
- package/app/services/ai/moduleAiHelpWrapperFactory.js +65 -0
- package/app/services/ai/moduleCommandConfigRuntimeService.js +113 -0
- package/app/services/ai/moduleToolExecutorService.js +464 -0
- package/app/services/ai/moduleToolRegistryService.js +178 -0
- package/app/services/ai/toolCandidateSelectorService.js +781 -0
- package/app/services/auth/googleWebLinkService.js +80 -0
- package/app/services/auth/whatsappLoginLinkService.js +230 -0
- package/app/services/external/pokeApiService.js +398 -0
- package/app/services/group/groupMetadataService.js +311 -0
- package/app/services/infra/dbWriteQueue.js +874 -0
- package/app/services/infra/featureFlagService.js +131 -0
- package/app/services/infra/queueUtils.js +55 -0
- package/app/services/messaging/captchaService.js +491 -0
- package/app/services/messaging/messagePersistenceService.js +1 -0
- package/app/services/messaging/newsBroadcastService.js +347 -0
- package/app/services/sticker/stickerFocusService.js +347 -0
- package/app/services/sticker/stickerFocusService.test.js +43 -0
- package/app/store/aiPromptStore.js +38 -0
- package/app/store/conversationSessionStore.js +131 -0
- package/app/store/groupConfigStore.js +58 -0
- package/app/store/premiumUserStore.js +54 -0
- package/app/utils/antiLink/antiLinkModule.js +700 -0
- package/app/utils/http/getImageBufferModule.js +18 -0
- package/app/utils/json/jsonSanitizer.js +113 -0
- package/app/utils/json/jsonSanitizer.test.js +40 -0
- package/app/utils/systemMetrics/systemMetricsModule.js +88 -0
- package/app/workers/aiLearningWorker.js +605 -0
- package/app/workers/commandConfigEnrichmentWorker.js +242 -0
- package/database/index.js +2075 -0
- package/database/init.js +151 -0
- package/database/migrations/.gitkeep +0 -0
- package/database/migrations/20260307_d0_hardening_down.sql +64 -0
- package/database/migrations/20260307_d0_hardening_up.sql +79 -0
- package/database/migrations/20260307_d1_terms_acceptance_down.sql +11 -0
- package/database/migrations/20260307_d1_terms_acceptance_up.sql +37 -0
- package/database/migrations/20260307_d2_auth_hardening_down.sql +75 -0
- package/database/migrations/20260307_d2_auth_hardening_up.sql +100 -0
- package/database/migrations/20260314_d7_canonical_sender_down.sql +53 -0
- package/database/migrations/20260314_d7_canonical_sender_up.sql +114 -0
- package/database/migrations/20260406_d30_security_analytics_down.sql +95 -0
- package/database/migrations/20260406_d30_security_analytics_up.sql +292 -0
- package/database/migrations/20260407_d31_web_google_session_token_hardening_down.sql +2 -0
- package/database/migrations/20260407_d31_web_google_session_token_hardening_up.sql +17 -0
- package/database/migrations/20260408_d32_ai_help_response_cache_down.sql +1 -0
- package/database/migrations/20260408_d32_ai_help_response_cache_up.sql +22 -0
- package/database/migrations/20260409_d33_ai_learning_tables_down.sql +4 -0
- package/database/migrations/20260409_d33_ai_learning_tables_up.sql +52 -0
- package/database/migrations/20260410_d34_command_config_enrichment_down.sql +3 -0
- package/database/migrations/20260410_d34_command_config_enrichment_up.sql +48 -0
- package/database/schema.sql +1186 -0
- package/docker-compose.yml +104 -0
- package/docs/audits/stickerCatalogController-out-of-scope.md +103 -0
- package/docs/audits/stickerCatalogController-symbols.md +58 -0
- package/docs/compliance/acceptable-use-policy-2026-03-07.md +35 -0
- package/docs/compliance/dpa-b2b-standard-2026-03-07.md +80 -0
- package/docs/compliance/monthly-compliance-checklist-2026-03-07.md +88 -0
- package/docs/compliance/notice-and-takedown-policy-2026-03-07.md +34 -0
- package/docs/compliance/privacy-policy-2026-03-07.md +75 -0
- package/docs/compliance/subprocessors-inventory-2026-03-07.md +16 -0
- package/docs/database/production-db-evolution-runbook-2026q1.md +365 -0
- package/docs/security/dsar-lgpd-runbook-2026-03-07.md +86 -0
- package/docs/security/incident-response-lgpd-anpd-runbook-2026-03-07.md +77 -0
- package/docs/security/network-hardening-runbook-2026-03-07.md +137 -0
- package/docs/seo/omnizap-seo-playbook-br-2026-02-28.md +238 -0
- package/docs/seo/satellite-page-template.md +116 -0
- package/docs/seo/satellite-pages-phase1.json +364 -0
- package/docs/wiki/Home.md +120 -0
- package/docs/wiki/pair-extraordinaire-2026-03-08.md +3 -0
- package/docs/wiki/recent-changes-2026-03-08.md +47 -0
- package/ecosystem.prod.config.cjs +135 -0
- package/eslint.config.js +89 -0
- package/index.js +488 -0
- package/ml/clip_classifier/Dockerfile +18 -0
- package/ml/clip_classifier/README.md +118 -0
- package/ml/clip_classifier/adaptive_scoring.py +40 -0
- package/ml/clip_classifier/classifier.py +654 -0
- package/ml/clip_classifier/embedding_store.py +481 -0
- package/ml/clip_classifier/env_loader.py +15 -0
- package/ml/clip_classifier/llm_label_expander.py +144 -0
- package/ml/clip_classifier/main.py +213 -0
- package/ml/clip_classifier/requirements.txt +10 -0
- package/ml/clip_classifier/similarity_engine.py +74 -0
- package/new-logo.png +0 -0
- package/observability/alert-rules.yml +60 -0
- package/observability/grafana/dashboards/omnizap-mysql.json +136 -0
- package/observability/grafana/dashboards/omnizap-overview.json +170 -0
- package/observability/grafana/provisioning/dashboards/dashboards.yml +11 -0
- package/observability/grafana/provisioning/datasources/datasources.yml +15 -0
- package/observability/loki-config.yml +38 -0
- package/observability/mysql-setup.sql +46 -0
- package/observability/prometheus.yml +35 -0
- package/observability/promtail-config.yml +84 -0
- package/observability/sticker-catalog-slo.md +83 -0
- package/observability/sticker-scale-hardening-rollout.md +128 -0
- package/package.json +144 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/assets/css/commands-react.input.css +71 -0
- package/public/assets/css/create-pack-react.input.css +31 -0
- package/public/assets/css/home-react.input.css +106 -0
- package/public/assets/css/login-react.input.css +58 -0
- package/public/assets/css/stickers-react.input.css +18 -0
- package/public/assets/css/terms-react.input.css +115 -0
- package/public/assets/css/user-react.input.css +57 -0
- package/public/assets/images/brand-icon-192.png +0 -0
- package/public/assets/images/brand-logo-128.webp +0 -0
- package/public/assets/images/hero-banner-1280.jpg +0 -0
- package/public/comandos/commands-catalog.json +4517 -0
- package/public/css/api-docs.css +161 -0
- package/public/css/stickers-admin.css +1288 -0
- package/public/css/styles.css +679 -0
- package/public/css/systemadm/admin.css +474 -0
- package/public/css/systemadm/base.css +73 -0
- package/public/css/systemadm/components.css +662 -0
- package/public/css/systemadm/layout.css +229 -0
- package/public/css/systemadm/tokens.css +56 -0
- package/public/favicon-16x16.png +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/js/apps/apiDocsApp.js +235 -0
- package/public/js/apps/commandsReactApp.js +528 -0
- package/public/js/apps/createPackApp.js +1646 -0
- package/public/js/apps/homeReactApp.js +942 -0
- package/public/js/apps/loginReactApp.js +496 -0
- package/public/js/apps/stickersAdminApp.js +1753 -0
- package/public/js/apps/stickersApp.js +3797 -0
- package/public/js/apps/termsReactApp.js +528 -0
- package/public/js/apps/userApp.js +2540 -0
- package/public/js/apps/userProfile/actions.js +66 -0
- package/public/js/apps/userReactApp.js +547 -0
- package/public/js/catalog.js +950 -0
- package/public/pages/api-docs.html +40 -0
- package/public/pages/aup.html +158 -0
- package/public/pages/comandos.html +41 -0
- package/public/pages/dpa.html +227 -0
- package/public/pages/home.html +45 -0
- package/public/pages/licenca.html +182 -0
- package/public/pages/login.html +40 -0
- package/public/pages/notice-and-takedown.html +234 -0
- package/public/pages/politica-de-privacidade.html +251 -0
- package/public/pages/seo-bot-whatsapp-para-grupo.html +350 -0
- package/public/pages/seo-bot-whatsapp-sem-programar.html +350 -0
- package/public/pages/seo-como-automatizar-avisos-no-whatsapp.html +350 -0
- package/public/pages/seo-como-criar-comandos-whatsapp.html +350 -0
- package/public/pages/seo-como-evitar-spam-no-whatsapp.html +350 -0
- package/public/pages/seo-como-moderar-grupo-whatsapp.html +350 -0
- package/public/pages/seo-como-organizar-comunidade-whatsapp.html +350 -0
- package/public/pages/seo-melhor-bot-whatsapp-para-grupos.html +350 -0
- package/public/pages/stickers-admin.html +31 -0
- package/public/pages/stickers-create.html +41 -0
- package/public/pages/stickers.html +45 -0
- package/public/pages/suboperadores.html +237 -0
- package/public/pages/termos-de-uso-texto-integral.html +241 -0
- package/public/pages/termos-de-uso.html +41 -0
- package/public/pages/user-password-reset.html +32 -0
- package/public/pages/user-systemadm.html +508 -0
- package/public/pages/user.html +39 -0
- package/public/robots.txt +9 -0
- package/public/site.webmanifest +24 -0
- package/public/sitemap.xml +98 -0
- package/schemas/command-config.schema.json +582 -0
- package/scripts/baileys-compat-smoke.mjs +12 -0
- package/scripts/cache-bust.mjs +142 -0
- package/scripts/deploy.sh +916 -0
- package/scripts/email-broadcast-terms-update.mjs +170 -0
- package/scripts/enrich-command-discovery-fields.mjs +286 -0
- package/scripts/generate-command-config-schema.mjs +273 -0
- package/scripts/generate-commands-catalog.mjs +308 -0
- package/scripts/generate-module-agents.mjs +631 -0
- package/scripts/generate-seo-satellite-pages.mjs +400 -0
- package/scripts/github-deploy-notify.mjs +174 -0
- package/scripts/github-release-notify.mjs +219 -0
- package/scripts/release.sh +599 -0
- package/scripts/run-codeql-local.sh +116 -0
- package/scripts/run-prettier-all.mjs +25 -0
- package/scripts/security-smoketest.mjs +581 -0
- package/scripts/sticker-catalog-loadtest.mjs +210 -0
- package/scripts/sticker-worker-task.mjs +119 -0
- package/scripts/sync-readme-snapshot.mjs +133 -0
- package/scripts/validate-command-config-schema.mjs +130 -0
- package/scripts/validate-command-configs.mjs +15 -0
- package/scripts/wiki-sync.sh +191 -0
- package/server/auth/googleWebAuth/googleWebAuthRuntime.js +62 -0
- package/server/auth/googleWebAuth/googleWebAuthService.js +807 -0
- package/server/auth/jwt/webJwtService.js +147 -0
- package/server/auth/stickerCatalogAuthContext.js +165 -0
- package/server/auth/termsAcceptance/termsAcceptanceHandler.js +189 -0
- package/server/auth/userPassword/index.js +14 -0
- package/server/auth/userPassword/userPasswordAuthService.js +422 -0
- package/server/auth/userPassword/userPasswordCrypto.js +199 -0
- package/server/auth/userPassword/userPasswordCrypto.test.js +76 -0
- package/server/auth/userPassword/userPasswordRecoveryService.js +728 -0
- package/server/auth/validation/authSchemas.js +236 -0
- package/server/auth/webAccount/webAccountHandlers.js +1434 -0
- package/server/controllers/admin/adminBanService.js +138 -0
- package/server/controllers/admin/adminPanelHandlers.js +2083 -0
- package/server/controllers/admin/stickerCatalogAdminContext.js +17 -0
- package/server/controllers/admin/systemAdminController.js +201 -0
- package/server/controllers/email/emailAutomationController.js +239 -0
- package/server/controllers/metricsController.js +21 -0
- package/server/controllers/seo/stickerCatalogSeoContext.js +514 -0
- package/server/controllers/sticker/nonCatalogHandlers.js +303 -0
- package/server/controllers/sticker/stickerCatalogController.js +4700 -0
- package/server/controllers/system/contactController.js +115 -0
- package/server/controllers/system/githubController.js +137 -0
- package/server/controllers/system/stickerCatalogSystemContext.js +758 -0
- package/server/controllers/system/storageController.js +154 -0
- package/server/controllers/system/systemController.js +135 -0
- package/server/controllers/system/systemMetricsController.js +156 -0
- package/server/controllers/system/visitController.js +90 -0
- package/server/controllers/userController.js +145 -0
- package/server/email/emailAutomationRuntime.js +225 -0
- package/server/email/emailAutomationService.js +125 -0
- package/server/email/emailOutboxRepository.js +282 -0
- package/server/email/emailTemplateService.js +480 -0
- package/server/email/emailTransportService.js +156 -0
- package/server/http/clientIp.js +95 -0
- package/server/http/httpRequestUtils.js +262 -0
- package/server/http/httpRequestUtils.test.js +80 -0
- package/server/http/httpServer.js +180 -0
- package/server/http/requestContext.js +20 -0
- package/server/http/siteRoutingUtils.js +87 -0
- package/server/index.js +1 -0
- package/server/middleware/cachePolicy.js +26 -0
- package/server/middleware/cachePolicyHelpers.js +1 -0
- package/server/middleware/endpointRateLimit.js +181 -0
- package/server/middleware/rateLimit.js +70 -0
- package/server/middleware/requireAdminAuth.js +48 -0
- package/server/middleware/securityHeaders.js +97 -0
- package/server/routes/admin/systemAdminRouter.js +64 -0
- package/server/routes/email/emailAutomationRouter.js +46 -0
- package/server/routes/health/healthRouter.js +41 -0
- package/server/routes/indexRouter.js +234 -0
- package/server/routes/metrics/metricsRouter.js +58 -0
- package/server/routes/static/staticPageRouter.js +134 -0
- package/server/routes/sticker/catalogHandlers/catalogAdminHttp.js +105 -0
- package/server/routes/sticker/catalogHandlers/catalogAuthHttp.js +77 -0
- package/server/routes/sticker/catalogHandlers/catalogPublicHttp.js +120 -0
- package/server/routes/sticker/catalogHandlers/catalogUploadHttp.js +83 -0
- package/server/routes/sticker/catalogRouter.js +77 -0
- package/server/routes/sticker/stickerApiRouter.js +84 -0
- package/server/routes/sticker/stickerDataRouter.js +145 -0
- package/server/routes/sticker/stickerSiteRouter.js +43 -0
- package/server/routes/user/userApiPaths.js +66 -0
- package/server/routes/user/userRouter.js +65 -0
- package/server/utils/safePath.js +26 -0
- package/utils/logger/loggerModule.js +35 -0
- package/vite.config.mjs +38 -0
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
import pino from 'pino';
|
|
2
|
+
import { criarInstanciaLogger } from '@kaikybrofc/logger-module';
|
|
3
|
+
import baseLogger from '#logger';
|
|
4
|
+
|
|
5
|
+
const DEFAULT_BAILEYS_LABEL = 'baileys';
|
|
6
|
+
const DEFAULT_BAILEYS_LOGGER_MODE = 'child';
|
|
7
|
+
const BAILEYS_LOGGER_MODES = new Set(['child', 'instance']);
|
|
8
|
+
const DEFAULT_BAILEYS_SOCKET_LOGGER_MODE = 'silent';
|
|
9
|
+
const BAILEYS_SOCKET_LOGGER_MODES = new Set(['silent', 'pino', 'bridge']);
|
|
10
|
+
const DEFAULT_PINO_LEVEL = 'info';
|
|
11
|
+
const DEFAULT_PINO_SILENT_LEVEL = 'silent';
|
|
12
|
+
const PINO_LEVELS = new Set(['trace', 'debug', 'info', 'warn', 'error', 'fatal', 'silent']);
|
|
13
|
+
const PINO_LEVEL_PRIORITY = Object.freeze({
|
|
14
|
+
trace: 10,
|
|
15
|
+
debug: 20,
|
|
16
|
+
info: 30,
|
|
17
|
+
warn: 40,
|
|
18
|
+
error: 50,
|
|
19
|
+
fatal: 60,
|
|
20
|
+
silent: Number.POSITIVE_INFINITY,
|
|
21
|
+
});
|
|
22
|
+
const BAILEYS_TO_WINSTON_LEVEL = Object.freeze({
|
|
23
|
+
trace: 'debug',
|
|
24
|
+
debug: 'debug',
|
|
25
|
+
info: 'info',
|
|
26
|
+
warn: 'warn',
|
|
27
|
+
error: 'error',
|
|
28
|
+
});
|
|
29
|
+
const BAILEYS_LOG_METHOD_PRIORITY = Object.freeze({
|
|
30
|
+
trace: 10,
|
|
31
|
+
debug: 20,
|
|
32
|
+
info: 30,
|
|
33
|
+
warn: 40,
|
|
34
|
+
error: 50,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const parseEnvBool = (value, fallback) => {
|
|
38
|
+
if (value === undefined || value === null || value === '') return fallback;
|
|
39
|
+
const normalized = String(value).trim().toLowerCase();
|
|
40
|
+
if (['1', 'true', 'yes', 'y', 'on'].includes(normalized)) return true;
|
|
41
|
+
if (['0', 'false', 'no', 'n', 'off'].includes(normalized)) return false;
|
|
42
|
+
return fallback;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const parseJsonObject = (value, fallback = {}, context = 'JSON') => {
|
|
46
|
+
if (value === undefined || value === null || String(value).trim() === '') {
|
|
47
|
+
return { ...fallback };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const parsed = JSON.parse(String(value));
|
|
52
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
53
|
+
return parsed;
|
|
54
|
+
}
|
|
55
|
+
return { ...fallback };
|
|
56
|
+
} catch (error) {
|
|
57
|
+
baseLogger.warn(`Valor inválido em ${context}. Usando fallback.`, {
|
|
58
|
+
errorMessage: error?.message,
|
|
59
|
+
});
|
|
60
|
+
return { ...fallback };
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const parseTransportDefinitions = (value) => {
|
|
65
|
+
if (value === undefined || value === null || String(value).trim() === '') {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
const parsed = JSON.parse(String(value));
|
|
71
|
+
if (!Array.isArray(parsed)) return undefined;
|
|
72
|
+
|
|
73
|
+
const validDefinitions = parsed.filter((entry) => entry && typeof entry === 'object' && typeof entry.type === 'string' && entry.options && typeof entry.options === 'object');
|
|
74
|
+
return validDefinitions.length > 0 ? validDefinitions : undefined;
|
|
75
|
+
} catch (error) {
|
|
76
|
+
baseLogger.warn('Valor inválido em BAILEYS_LOGGER_TRANSPORT_DEFINITIONS_JSON. Ignorando customização de transportes.', {
|
|
77
|
+
errorMessage: error?.message,
|
|
78
|
+
});
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const normalizeLoggerMode = (value, fallback = DEFAULT_BAILEYS_LOGGER_MODE) => {
|
|
84
|
+
const normalized = String(value || '')
|
|
85
|
+
.trim()
|
|
86
|
+
.toLowerCase();
|
|
87
|
+
return BAILEYS_LOGGER_MODES.has(normalized) ? normalized : fallback;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const normalizeSocketLoggerMode = (value, fallback = DEFAULT_BAILEYS_SOCKET_LOGGER_MODE) => {
|
|
91
|
+
const normalized = String(value || '')
|
|
92
|
+
.trim()
|
|
93
|
+
.toLowerCase();
|
|
94
|
+
return BAILEYS_SOCKET_LOGGER_MODES.has(normalized) ? normalized : fallback;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const normalizeLabel = (value, fallback = DEFAULT_BAILEYS_LABEL) => {
|
|
98
|
+
const normalized = String(value || '')
|
|
99
|
+
.trim()
|
|
100
|
+
.replace(/\s+/g, '_');
|
|
101
|
+
return normalized || fallback;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const normalizePinoLevel = (value, fallback = DEFAULT_PINO_LEVEL) => {
|
|
105
|
+
const normalized = String(value || '')
|
|
106
|
+
.trim()
|
|
107
|
+
.toLowerCase();
|
|
108
|
+
return PINO_LEVELS.has(normalized) ? normalized : fallback;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const mapWinstonLevelToPinoLevel = (value) => {
|
|
112
|
+
const normalized = String(value || '')
|
|
113
|
+
.trim()
|
|
114
|
+
.toLowerCase();
|
|
115
|
+
|
|
116
|
+
if (['fatal', 'emerg', 'alert', 'crit'].includes(normalized)) return 'fatal';
|
|
117
|
+
if (normalized === 'error') return 'error';
|
|
118
|
+
if (['warn', 'notice'].includes(normalized)) return 'warn';
|
|
119
|
+
if (['info', 'success', 'http'].includes(normalized)) return 'info';
|
|
120
|
+
if (['debug', 'verbose'].includes(normalized)) return 'debug';
|
|
121
|
+
if (normalized === 'silly') return 'trace';
|
|
122
|
+
|
|
123
|
+
return DEFAULT_PINO_LEVEL;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const shouldEmitByPinoLevel = (level, method) => {
|
|
127
|
+
const normalizedLevel = normalizePinoLevel(level, DEFAULT_PINO_LEVEL);
|
|
128
|
+
const threshold = PINO_LEVEL_PRIORITY[normalizedLevel] ?? PINO_LEVEL_PRIORITY[DEFAULT_PINO_LEVEL];
|
|
129
|
+
const methodPriority = BAILEYS_LOG_METHOD_PRIORITY[method] ?? BAILEYS_LOG_METHOD_PRIORITY.info;
|
|
130
|
+
return methodPriority >= threshold;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const resolveBaseServiceName = () => {
|
|
134
|
+
const raw = String(process.env.name || process.env.ECOSYSTEM_NAME || '').trim();
|
|
135
|
+
return raw || 'sistema';
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const createLoggerChild = (logger, defaultMeta) => {
|
|
139
|
+
if (logger && typeof logger.child === 'function') {
|
|
140
|
+
return logger.child(defaultMeta);
|
|
141
|
+
}
|
|
142
|
+
return logger || baseLogger;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const resolveBaileysLoggerConfig = (overrides = {}) => {
|
|
146
|
+
const mode = normalizeLoggerMode(overrides.mode ?? process.env.BAILEYS_LOGGER_MODE, DEFAULT_BAILEYS_LOGGER_MODE);
|
|
147
|
+
const level = String(overrides.level ?? process.env.BAILEYS_LOGGER_LEVEL ?? '').trim() || undefined;
|
|
148
|
+
const label = normalizeLabel(overrides.label ?? process.env.BAILEYS_LOGGER_LABEL, DEFAULT_BAILEYS_LABEL);
|
|
149
|
+
const service = String(overrides.service ?? process.env.BAILEYS_LOGGER_SERVICE ?? '').trim() || `${resolveBaseServiceName()}-baileys`;
|
|
150
|
+
const enableCustomMeta = parseEnvBool(process.env.BAILEYS_LOGGER_ENABLE_META_JSON, true);
|
|
151
|
+
const envMeta = enableCustomMeta ? parseJsonObject(process.env.BAILEYS_LOGGER_META_JSON, {}, 'BAILEYS_LOGGER_META_JSON') : {};
|
|
152
|
+
const overrideMeta = overrides.defaultMeta && typeof overrides.defaultMeta === 'object' ? overrides.defaultMeta : {};
|
|
153
|
+
const defaultMeta = {
|
|
154
|
+
...envMeta,
|
|
155
|
+
...overrideMeta,
|
|
156
|
+
label,
|
|
157
|
+
service,
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const transportDefinitions = overrides.transportDefinitions || parseTransportDefinitions(process.env.BAILEYS_LOGGER_TRANSPORT_DEFINITIONS_JSON);
|
|
161
|
+
const transports = Array.isArray(overrides.transports) ? overrides.transports : undefined;
|
|
162
|
+
const format = overrides.format;
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
mode,
|
|
166
|
+
level,
|
|
167
|
+
label,
|
|
168
|
+
service,
|
|
169
|
+
defaultMeta,
|
|
170
|
+
transportDefinitions,
|
|
171
|
+
transports,
|
|
172
|
+
format,
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const resolveBaileysSocketLoggerConfig = (overrides = {}) => {
|
|
177
|
+
const mode = normalizeSocketLoggerMode(overrides.mode ?? process.env.BAILEYS_SOCKET_LOGGER_MODE, DEFAULT_BAILEYS_SOCKET_LOGGER_MODE);
|
|
178
|
+
const fallbackLevel = mode === 'silent' ? DEFAULT_PINO_SILENT_LEVEL : DEFAULT_PINO_LEVEL;
|
|
179
|
+
const level = normalizePinoLevel(overrides.level ?? process.env.BAILEYS_SOCKET_LOGGER_LEVEL, fallbackLevel);
|
|
180
|
+
const enableCustomMeta = parseEnvBool(process.env.BAILEYS_SOCKET_LOGGER_ENABLE_META_JSON, true);
|
|
181
|
+
const envBase = enableCustomMeta ? parseJsonObject(process.env.BAILEYS_SOCKET_LOGGER_META_JSON, {}, 'BAILEYS_SOCKET_LOGGER_META_JSON') : {};
|
|
182
|
+
const overrideBase = overrides.base && typeof overrides.base === 'object' ? overrides.base : {};
|
|
183
|
+
const base = {
|
|
184
|
+
...envBase,
|
|
185
|
+
...overrideBase,
|
|
186
|
+
};
|
|
187
|
+
const envOptions = parseJsonObject(process.env.BAILEYS_SOCKET_LOGGER_OPTIONS_JSON, {}, 'BAILEYS_SOCKET_LOGGER_OPTIONS_JSON');
|
|
188
|
+
const overrideOptions = overrides.options && typeof overrides.options === 'object' ? overrides.options : {};
|
|
189
|
+
const options = {
|
|
190
|
+
...envOptions,
|
|
191
|
+
...overrideOptions,
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
mode,
|
|
196
|
+
level,
|
|
197
|
+
base,
|
|
198
|
+
options,
|
|
199
|
+
};
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const createConfiguredBaileysLogger = (overrides = {}) => {
|
|
203
|
+
const config = resolveBaileysLoggerConfig(overrides);
|
|
204
|
+
|
|
205
|
+
if (config.mode === 'instance') {
|
|
206
|
+
return criarInstanciaLogger({
|
|
207
|
+
level: config.level,
|
|
208
|
+
defaultMeta: config.defaultMeta,
|
|
209
|
+
transportDefinitions: config.transportDefinitions,
|
|
210
|
+
transports: config.transports,
|
|
211
|
+
format: config.format,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const childLogger = createLoggerChild(baseLogger, config.defaultMeta);
|
|
216
|
+
if (config.level && typeof childLogger === 'object' && childLogger) {
|
|
217
|
+
childLogger.level = config.level;
|
|
218
|
+
}
|
|
219
|
+
return childLogger;
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const serializeError = (error) => ({
|
|
223
|
+
errorName: error?.name || 'Error',
|
|
224
|
+
errorMessage: error?.message || String(error),
|
|
225
|
+
errorStack: error?.stack,
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
const resolveLogEntry = (obj, msg) => {
|
|
229
|
+
const providedMessage = typeof msg === 'string' ? msg.trim() : '';
|
|
230
|
+
let message = providedMessage;
|
|
231
|
+
let metadata;
|
|
232
|
+
|
|
233
|
+
if (obj instanceof Error) {
|
|
234
|
+
metadata = serializeError(obj);
|
|
235
|
+
if (!message) message = obj.message || 'erro_em_logger_baileys';
|
|
236
|
+
} else if (obj && typeof obj === 'object' && !Array.isArray(obj)) {
|
|
237
|
+
metadata = { ...obj };
|
|
238
|
+
if (!message && typeof obj.msg === 'string') {
|
|
239
|
+
message = obj.msg.trim();
|
|
240
|
+
}
|
|
241
|
+
if (!message && typeof obj.message === 'string') {
|
|
242
|
+
message = obj.message.trim();
|
|
243
|
+
}
|
|
244
|
+
} else if (obj !== undefined && obj !== null) {
|
|
245
|
+
if (!message && typeof obj === 'string') {
|
|
246
|
+
message = obj.trim();
|
|
247
|
+
} else {
|
|
248
|
+
metadata = { value: obj };
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (!message) {
|
|
253
|
+
message = 'baileys_socket_event';
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return {
|
|
257
|
+
message,
|
|
258
|
+
metadata: metadata && Object.keys(metadata).length > 0 ? metadata : undefined,
|
|
259
|
+
};
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const writeBridgeLog = (targetLogger, method, obj, msg) => {
|
|
263
|
+
const methodName = BAILEYS_TO_WINSTON_LEVEL[method] || 'info';
|
|
264
|
+
const { message, metadata } = resolveLogEntry(obj, msg);
|
|
265
|
+
const targetMethod = typeof targetLogger?.[methodName] === 'function' ? targetLogger[methodName].bind(targetLogger) : null;
|
|
266
|
+
|
|
267
|
+
if (targetMethod) {
|
|
268
|
+
if (metadata) {
|
|
269
|
+
targetMethod(message, metadata);
|
|
270
|
+
} else {
|
|
271
|
+
targetMethod(message);
|
|
272
|
+
}
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (typeof targetLogger?.log === 'function') {
|
|
277
|
+
if (metadata) {
|
|
278
|
+
targetLogger.log(methodName, message, metadata);
|
|
279
|
+
} else {
|
|
280
|
+
targetLogger.log(methodName, message);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
const createBaileysSocketBridgeLogger = (rootLogger, level) => {
|
|
286
|
+
const sharedState = {
|
|
287
|
+
level: normalizePinoLevel(level, mapWinstonLevelToPinoLevel(rootLogger?.level)),
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
const createAdapter = (targetLogger) => ({
|
|
291
|
+
get level() {
|
|
292
|
+
return sharedState.level;
|
|
293
|
+
},
|
|
294
|
+
set level(nextLevel) {
|
|
295
|
+
sharedState.level = normalizePinoLevel(nextLevel, sharedState.level);
|
|
296
|
+
},
|
|
297
|
+
child(bindings = {}) {
|
|
298
|
+
const normalizedBindings = bindings && typeof bindings === 'object' ? bindings : {};
|
|
299
|
+
const childLogger = createLoggerChild(targetLogger, normalizedBindings);
|
|
300
|
+
return createAdapter(childLogger);
|
|
301
|
+
},
|
|
302
|
+
trace(obj, msg) {
|
|
303
|
+
if (!shouldEmitByPinoLevel(sharedState.level, 'trace')) return;
|
|
304
|
+
writeBridgeLog(targetLogger, 'trace', obj, msg);
|
|
305
|
+
},
|
|
306
|
+
debug(obj, msg) {
|
|
307
|
+
if (!shouldEmitByPinoLevel(sharedState.level, 'debug')) return;
|
|
308
|
+
writeBridgeLog(targetLogger, 'debug', obj, msg);
|
|
309
|
+
},
|
|
310
|
+
info(obj, msg) {
|
|
311
|
+
if (!shouldEmitByPinoLevel(sharedState.level, 'info')) return;
|
|
312
|
+
writeBridgeLog(targetLogger, 'info', obj, msg);
|
|
313
|
+
},
|
|
314
|
+
warn(obj, msg) {
|
|
315
|
+
if (!shouldEmitByPinoLevel(sharedState.level, 'warn')) return;
|
|
316
|
+
writeBridgeLog(targetLogger, 'warn', obj, msg);
|
|
317
|
+
},
|
|
318
|
+
error(obj, msg) {
|
|
319
|
+
if (!shouldEmitByPinoLevel(sharedState.level, 'error')) return;
|
|
320
|
+
writeBridgeLog(targetLogger, 'error', obj, msg);
|
|
321
|
+
},
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
return createAdapter(rootLogger || baseLogger);
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
let cachedBaileysRootLogger = null;
|
|
328
|
+
let cachedBaileysSocketLogger = null;
|
|
329
|
+
|
|
330
|
+
const getDefaultBaileysRootLogger = () => {
|
|
331
|
+
if (!cachedBaileysRootLogger) {
|
|
332
|
+
cachedBaileysRootLogger = createConfiguredBaileysLogger();
|
|
333
|
+
}
|
|
334
|
+
return cachedBaileysRootLogger;
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
const createConfiguredBaileysSocketLogger = (overrides = {}) => {
|
|
338
|
+
const config = resolveBaileysSocketLoggerConfig(overrides);
|
|
339
|
+
const mergedBase = {
|
|
340
|
+
...(config.options?.base && typeof config.options.base === 'object' ? config.options.base : {}),
|
|
341
|
+
...config.base,
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
if (config.mode === 'bridge') {
|
|
345
|
+
const bridgeLogger = createBaileysScopedLogger('socket', mergedBase);
|
|
346
|
+
return createBaileysSocketBridgeLogger(bridgeLogger, config.level);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const level = config.mode === 'silent' ? DEFAULT_PINO_SILENT_LEVEL : config.level;
|
|
350
|
+
const pinoOptions = {
|
|
351
|
+
...config.options,
|
|
352
|
+
level,
|
|
353
|
+
};
|
|
354
|
+
if (Object.keys(mergedBase).length > 0) {
|
|
355
|
+
pinoOptions.base = mergedBase;
|
|
356
|
+
}
|
|
357
|
+
return pino(pinoOptions);
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
export const createBaileysLogger = (overrides = {}) => {
|
|
361
|
+
if (!overrides || Object.keys(overrides).length === 0) {
|
|
362
|
+
return getDefaultBaileysRootLogger();
|
|
363
|
+
}
|
|
364
|
+
return createConfiguredBaileysLogger(overrides);
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
export const createBaileysScopedLogger = (scope, metadata = {}) => {
|
|
368
|
+
const rootLogger = getDefaultBaileysRootLogger();
|
|
369
|
+
const rootLabel = resolveBaileysLoggerConfig().label;
|
|
370
|
+
const normalizedScope = normalizeLabel(scope, '');
|
|
371
|
+
const scopedLabel = normalizedScope ? `${rootLabel}.${normalizedScope}` : rootLabel;
|
|
372
|
+
const scopedMeta = {
|
|
373
|
+
...metadata,
|
|
374
|
+
label: scopedLabel,
|
|
375
|
+
};
|
|
376
|
+
return createLoggerChild(rootLogger, scopedMeta);
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
export const createBaileysSocketLogger = (overrides = {}) => {
|
|
380
|
+
if (!overrides || Object.keys(overrides).length === 0) {
|
|
381
|
+
if (!cachedBaileysSocketLogger) {
|
|
382
|
+
cachedBaileysSocketLogger = createConfiguredBaileysSocketLogger();
|
|
383
|
+
}
|
|
384
|
+
return cachedBaileysSocketLogger;
|
|
385
|
+
}
|
|
386
|
+
return createConfiguredBaileysSocketLogger(overrides);
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
export const baileysLogger = createBaileysScopedLogger('');
|
|
390
|
+
export const baileysConnectionLogger = createBaileysScopedLogger('connection');
|
|
391
|
+
export const baileysConfigLogger = createBaileysScopedLogger('config');
|
|
392
|
+
export const baileysAuthLogger = createBaileysScopedLogger('auth');
|
|
393
|
+
export const baileysGroupsLogger = createBaileysScopedLogger('groups');
|
|
394
|
+
export const baileysSocketLogger = createBaileysSocketLogger();
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { baileysConnectionLogger as logger } from './loggerConfig.js';
|
|
2
|
+
import { queueMessageInsert } from '../services/infra/dbWriteQueue.js';
|
|
3
|
+
import { parseEnvBool, parseEnvInt, normalizeJid, isGroupJid, isStatusJid, isBroadcastJid, isNewsletterJid, normalizeWAPresence } from './baileysConfig.js';
|
|
4
|
+
|
|
5
|
+
const BAILEYS_SEND_RETRY_ATTEMPTS = parseEnvInt(process.env.BAILEYS_SEND_RETRY_ATTEMPTS, 2, 1, 5);
|
|
6
|
+
const BAILEYS_SEND_RETRY_BASE_DELAY_MS = parseEnvInt(process.env.BAILEYS_SEND_RETRY_BASE_DELAY_MS, 600, 100, 10_000);
|
|
7
|
+
const BAILEYS_SEND_MEDIA_UPLOAD_TIMEOUT_MS = parseEnvInt(process.env.BAILEYS_SEND_MEDIA_UPLOAD_TIMEOUT_MS, 0, 0, 120_000);
|
|
8
|
+
const BAILEYS_REPLY_PRESENCE_ENABLED = parseEnvBool(process.env.BAILEYS_REPLY_PRESENCE_ENABLED, true);
|
|
9
|
+
const BAILEYS_REPLY_PRESENCE_SUBSCRIBE = parseEnvBool(process.env.BAILEYS_REPLY_PRESENCE_SUBSCRIBE, true);
|
|
10
|
+
const BAILEYS_REPLY_PRESENCE_DELAY_MS = parseEnvInt(process.env.BAILEYS_REPLY_PRESENCE_DELAY_MS, 280, 0, 3_000);
|
|
11
|
+
const BAILEYS_REPLY_PRESENCE_BEFORE = normalizeWAPresence(process.env.BAILEYS_REPLY_PRESENCE_BEFORE, 'composing');
|
|
12
|
+
const BAILEYS_REPLY_PRESENCE_AFTER = normalizeWAPresence(process.env.BAILEYS_REPLY_PRESENCE_AFTER, 'paused');
|
|
13
|
+
|
|
14
|
+
const isPlainObject = (value) => Object.prototype.toString.call(value) === '[object Object]';
|
|
15
|
+
|
|
16
|
+
const ANY_MESSAGE_CONTENT_PRIMARY_KEYS = new Set(['text', 'image', 'video', 'audio', 'sticker', 'stickerPack', 'stickerPackMessage', 'document', 'event', 'poll', 'contacts', 'location', 'react', 'buttonReply', 'groupInvite', 'listReply', 'pin', 'product', 'sharePhoneNumber', 'requestPhoneNumber', 'forward', 'delete', 'disappearingMessagesInChat', 'limitSharing']);
|
|
17
|
+
const PRESENCE_NON_REPLY_CONTENT_KEYS = new Set(['react', 'delete', 'pin', 'disappearingMessagesInChat']);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Verifica se o payload se parece com AnyMessageContent do Baileys.
|
|
21
|
+
* @param {unknown} content
|
|
22
|
+
* @returns {boolean}
|
|
23
|
+
*/
|
|
24
|
+
const hasKnownAnyMessageContentShape = (content) => {
|
|
25
|
+
if (!isPlainObject(content)) return false;
|
|
26
|
+
return Object.keys(content).some((key) => ANY_MESSAGE_CONTENT_PRIMARY_KEYS.has(key));
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Normaliza opções de envio aceitas pelo Baileys (MiscMessageGenerationOptions).
|
|
31
|
+
* @param {unknown} options
|
|
32
|
+
* @returns {import('@whiskeysockets/baileys').MiscMessageGenerationOptions|undefined}
|
|
33
|
+
*/
|
|
34
|
+
const normalizeSendOptions = (options) => {
|
|
35
|
+
if (!isPlainObject(options)) return undefined;
|
|
36
|
+
|
|
37
|
+
const normalized = { ...options };
|
|
38
|
+
|
|
39
|
+
if (typeof normalized.messageId === 'string') {
|
|
40
|
+
const trimmedMessageId = normalized.messageId.trim();
|
|
41
|
+
if (trimmedMessageId) {
|
|
42
|
+
normalized.messageId = trimmedMessageId;
|
|
43
|
+
} else {
|
|
44
|
+
delete normalized.messageId;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (typeof normalized.mediaUploadTimeoutMs !== 'number' && BAILEYS_SEND_MEDIA_UPLOAD_TIMEOUT_MS > 0) {
|
|
49
|
+
normalized.mediaUploadTimeoutMs = BAILEYS_SEND_MEDIA_UPLOAD_TIMEOUT_MS;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (normalized.statusJidList !== undefined && !Array.isArray(normalized.statusJidList)) {
|
|
53
|
+
delete normalized.statusJidList;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return normalized;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Separa opções internas de presença das opções reais de envio do Baileys.
|
|
61
|
+
* @param {unknown} options
|
|
62
|
+
* @returns {{
|
|
63
|
+
* sendOptions: import('@whiskeysockets/baileys').MiscMessageGenerationOptions|undefined,
|
|
64
|
+
* skipPresenceUpdate: boolean,
|
|
65
|
+
* presenceBefore: import('@whiskeysockets/baileys').WAPresence,
|
|
66
|
+
* presenceAfter: import('@whiskeysockets/baileys').WAPresence,
|
|
67
|
+
* presenceDelayMs: number,
|
|
68
|
+
* presenceSubscribe: boolean
|
|
69
|
+
* }}
|
|
70
|
+
*/
|
|
71
|
+
const resolveRuntimeSendOptions = (options) => {
|
|
72
|
+
if (!isPlainObject(options)) {
|
|
73
|
+
return {
|
|
74
|
+
sendOptions: undefined,
|
|
75
|
+
skipPresenceUpdate: false,
|
|
76
|
+
presenceBefore: BAILEYS_REPLY_PRESENCE_BEFORE,
|
|
77
|
+
presenceAfter: BAILEYS_REPLY_PRESENCE_AFTER,
|
|
78
|
+
presenceDelayMs: BAILEYS_REPLY_PRESENCE_DELAY_MS,
|
|
79
|
+
presenceSubscribe: BAILEYS_REPLY_PRESENCE_SUBSCRIBE,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const { skipPresenceUpdate, presenceBefore, presenceAfter, presenceDelayMs, presenceSubscribe, ...sendOptions } = options;
|
|
84
|
+
const normalizedDelay = parseEnvInt(presenceDelayMs, BAILEYS_REPLY_PRESENCE_DELAY_MS, 0, 3_000);
|
|
85
|
+
return {
|
|
86
|
+
sendOptions: Object.keys(sendOptions).length > 0 ? sendOptions : undefined,
|
|
87
|
+
skipPresenceUpdate: Boolean(skipPresenceUpdate),
|
|
88
|
+
presenceBefore: normalizeWAPresence(presenceBefore, BAILEYS_REPLY_PRESENCE_BEFORE),
|
|
89
|
+
presenceAfter: normalizeWAPresence(presenceAfter, BAILEYS_REPLY_PRESENCE_AFTER),
|
|
90
|
+
presenceDelayMs: normalizedDelay,
|
|
91
|
+
presenceSubscribe: typeof presenceSubscribe === 'boolean' ? presenceSubscribe : BAILEYS_REPLY_PRESENCE_SUBSCRIBE,
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Indica se o conteúdo é uma resposta "normal" (texto/mídia) que merece presença.
|
|
97
|
+
* @param {unknown} content
|
|
98
|
+
* @returns {boolean}
|
|
99
|
+
*/
|
|
100
|
+
const shouldApplyPresenceByContent = (content) => {
|
|
101
|
+
if (!isPlainObject(content)) return false;
|
|
102
|
+
const keys = Object.keys(content);
|
|
103
|
+
if (keys.length === 0) return false;
|
|
104
|
+
return !keys.every((key) => PRESENCE_NON_REPLY_CONTENT_KEYS.has(key));
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Resolve se a presença deve ser enviada para este envio.
|
|
109
|
+
* @param {string} jid
|
|
110
|
+
* @param {unknown} content
|
|
111
|
+
* @param {{skipPresenceUpdate: boolean}} runtimeOptions
|
|
112
|
+
* @returns {boolean}
|
|
113
|
+
*/
|
|
114
|
+
const shouldSendReplyPresence = (jid, content, runtimeOptions) => {
|
|
115
|
+
if (!BAILEYS_REPLY_PRESENCE_ENABLED) return false;
|
|
116
|
+
if (runtimeOptions.skipPresenceUpdate) return false;
|
|
117
|
+
if (!shouldApplyPresenceByContent(content)) return false;
|
|
118
|
+
|
|
119
|
+
const normalizedJid = normalizeJid(jid) || String(jid || '').trim();
|
|
120
|
+
if (!normalizedJid) return false;
|
|
121
|
+
if (isGroupJid(normalizedJid)) return false;
|
|
122
|
+
if (isStatusJid(normalizedJid)) return false;
|
|
123
|
+
if (isBroadcastJid(normalizedJid)) return false;
|
|
124
|
+
if (isNewsletterJid(normalizedJid)) return false;
|
|
125
|
+
|
|
126
|
+
return true;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const sendPresenceSilently = async (sock, type, jid, subscribeFirst = false) => {
|
|
130
|
+
if (!sock || typeof sock.sendPresenceUpdate !== 'function') return;
|
|
131
|
+
try {
|
|
132
|
+
if (subscribeFirst && typeof sock.presenceSubscribe === 'function') {
|
|
133
|
+
await sock.presenceSubscribe(jid);
|
|
134
|
+
}
|
|
135
|
+
await sock.sendPresenceUpdate(type, jid);
|
|
136
|
+
} catch (error) {
|
|
137
|
+
logger.debug('Falha ao enviar atualização de presença no Baileys.', {
|
|
138
|
+
jid,
|
|
139
|
+
presence: type,
|
|
140
|
+
error: error?.message,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Converte um timestamp da mensagem para ms com fallback seguro.
|
|
147
|
+
* @param {import('@whiskeysockets/baileys').WAMessage} msg
|
|
148
|
+
* @returns {number}
|
|
149
|
+
*/
|
|
150
|
+
const resolveMessageTimestampMs = (msg) => {
|
|
151
|
+
const rawTimestamp = msg?.messageTimestamp;
|
|
152
|
+
if (rawTimestamp !== null && rawTimestamp !== undefined) {
|
|
153
|
+
const tsNumber = typeof rawTimestamp === 'number' ? rawTimestamp : Number(rawTimestamp);
|
|
154
|
+
if (Number.isFinite(tsNumber) && tsNumber > 0) {
|
|
155
|
+
return tsNumber * 1000;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return Date.now();
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Normaliza uma mensagem do Baileys para o formato persistido no banco.
|
|
163
|
+
* @param {import('@whiskeysockets/baileys').WAMessage} msg - Mensagem recebida/enviada.
|
|
164
|
+
* @param {string} [senderId] - ID do remetente (opcional).
|
|
165
|
+
* @returns {Object} Objeto com dados prontos para persistencia.
|
|
166
|
+
*/
|
|
167
|
+
export const buildMessageData = (msg, senderId) => ({
|
|
168
|
+
message_id: msg?.key?.id,
|
|
169
|
+
chat_id: msg?.key?.remoteJid,
|
|
170
|
+
sender_id: senderId || msg?.key?.participant || msg?.key?.remoteJid,
|
|
171
|
+
content: msg?.message?.conversation || msg?.message?.extendedTextMessage?.text || null,
|
|
172
|
+
raw_message: msg || {},
|
|
173
|
+
timestamp: new Date(resolveMessageTimestampMs(msg)),
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, Math.max(0, Number(ms) || 0)));
|
|
177
|
+
|
|
178
|
+
const isTransientSendError = (error) => {
|
|
179
|
+
const statusCode = Number(error?.output?.statusCode || error?.statusCode || 0);
|
|
180
|
+
if ([408, 409, 425, 429, 500, 502, 503, 504].includes(statusCode)) return true;
|
|
181
|
+
|
|
182
|
+
const code = String(error?.code || '')
|
|
183
|
+
.trim()
|
|
184
|
+
.toUpperCase();
|
|
185
|
+
if (['ETIMEDOUT', 'ECONNRESET', 'ECONNABORTED', 'EAI_AGAIN', 'ENOTFOUND', 'ERR_SOCKET_CLOSED', 'ERR_NETWORK'].includes(code)) {
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const rawMessage = `${error?.message || ''} ${error?.data?.message || ''}`.toLowerCase();
|
|
190
|
+
const transientFragments = ['timeout', 'timed out', 'connection closed', 'socket closed', 'media conn', 'media_conn', 'fetch failed', 'temporarily unavailable', 'network'];
|
|
191
|
+
return transientFragments.some((fragment) => rawMessage.includes(fragment));
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const shouldRefreshMediaConnection = (error) => {
|
|
195
|
+
const rawMessage = `${error?.message || ''} ${error?.data?.message || ''}`.toLowerCase();
|
|
196
|
+
return rawMessage.includes('media') || rawMessage.includes('directpath') || rawMessage.includes('upload');
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Envia uma mensagem via Baileys e persiste imediatamente o retorno.
|
|
201
|
+
* @param {import('@whiskeysockets/baileys').WASocket} sock
|
|
202
|
+
* @param {string} jid
|
|
203
|
+
* @param {import('@whiskeysockets/baileys').AnyMessageContent} content
|
|
204
|
+
* @param {import('@whiskeysockets/baileys').MiscMessageGenerationOptions & {
|
|
205
|
+
* skipPresenceUpdate?: boolean,
|
|
206
|
+
* presenceBefore?: import('@whiskeysockets/baileys').WAPresence,
|
|
207
|
+
* presenceAfter?: import('@whiskeysockets/baileys').WAPresence,
|
|
208
|
+
* presenceDelayMs?: number,
|
|
209
|
+
* presenceSubscribe?: boolean
|
|
210
|
+
* }} [options]
|
|
211
|
+
* @returns {Promise<import('@whiskeysockets/baileys').WAMessage|undefined>}
|
|
212
|
+
*/
|
|
213
|
+
export async function sendAndStore(sock, jid, content, options) {
|
|
214
|
+
if (!sock || typeof sock.sendMessage !== 'function') {
|
|
215
|
+
throw new TypeError('Socket Baileys inválido: sendMessage indisponível.');
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (!jid || typeof jid !== 'string') {
|
|
219
|
+
throw new TypeError('JID inválido para envio de mensagem.');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (!hasKnownAnyMessageContentShape(content)) {
|
|
223
|
+
const payloadKeys = isPlainObject(content) ? Object.keys(content).slice(0, 10) : [];
|
|
224
|
+
throw new TypeError(`Payload de mensagem inválido. Chaves recebidas: ${payloadKeys.join(', ') || 'nenhuma'}`);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const normalizedJid = normalizeJid(jid) || String(jid).trim();
|
|
228
|
+
const runtimeOptions = resolveRuntimeSendOptions(options);
|
|
229
|
+
const normalizedOptions = normalizeSendOptions(runtimeOptions.sendOptions);
|
|
230
|
+
const shouldSendPresence = shouldSendReplyPresence(normalizedJid, content, runtimeOptions);
|
|
231
|
+
|
|
232
|
+
if (shouldSendPresence) {
|
|
233
|
+
await sendPresenceSilently(sock, runtimeOptions.presenceBefore, normalizedJid, runtimeOptions.presenceSubscribe);
|
|
234
|
+
if (runtimeOptions.presenceDelayMs > 0) {
|
|
235
|
+
await wait(runtimeOptions.presenceDelayMs);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
let attempt = 0;
|
|
240
|
+
let sent;
|
|
241
|
+
let lastError;
|
|
242
|
+
|
|
243
|
+
try {
|
|
244
|
+
while (attempt < BAILEYS_SEND_RETRY_ATTEMPTS) {
|
|
245
|
+
attempt += 1;
|
|
246
|
+
try {
|
|
247
|
+
sent = await sock.sendMessage(normalizedJid, content, normalizedOptions);
|
|
248
|
+
break;
|
|
249
|
+
} catch (error) {
|
|
250
|
+
lastError = error;
|
|
251
|
+
const shouldRetry = attempt < BAILEYS_SEND_RETRY_ATTEMPTS && isTransientSendError(error);
|
|
252
|
+
if (!shouldRetry) {
|
|
253
|
+
throw error;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (shouldRefreshMediaConnection(error) && typeof sock?.refreshMediaConn === 'function') {
|
|
257
|
+
try {
|
|
258
|
+
await sock.refreshMediaConn(true);
|
|
259
|
+
} catch (refreshError) {
|
|
260
|
+
logger.debug('Falha ao forçar refresh de mediaConn antes do retry.', {
|
|
261
|
+
error: refreshError?.message,
|
|
262
|
+
attempt,
|
|
263
|
+
jid: normalizedJid,
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const delayMs = BAILEYS_SEND_RETRY_BASE_DELAY_MS * Math.pow(2, attempt - 1);
|
|
269
|
+
logger.warn('Falha transitória ao enviar mensagem; novo retry agendado.', {
|
|
270
|
+
attempt,
|
|
271
|
+
maxAttempts: BAILEYS_SEND_RETRY_ATTEMPTS,
|
|
272
|
+
delayMs,
|
|
273
|
+
jid: normalizedJid,
|
|
274
|
+
code: error?.code || null,
|
|
275
|
+
statusCode: error?.output?.statusCode || error?.statusCode || null,
|
|
276
|
+
error: error?.message,
|
|
277
|
+
});
|
|
278
|
+
await wait(delayMs);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
} finally {
|
|
282
|
+
if (shouldSendPresence) {
|
|
283
|
+
await sendPresenceSilently(sock, runtimeOptions.presenceAfter, normalizedJid, false);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (!sent) {
|
|
288
|
+
throw lastError || new Error('Falha ao enviar mensagem: resultado vazio.');
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const senderId = sock?.user?.id || sent?.key?.participant;
|
|
292
|
+
if (sent?.key?.id) {
|
|
293
|
+
try {
|
|
294
|
+
queueMessageInsert(buildMessageData(sent, senderId));
|
|
295
|
+
} catch (error) {
|
|
296
|
+
logger.warn('Falha ao enfileirar mensagem enviada para persistencia.', {
|
|
297
|
+
error: error.message,
|
|
298
|
+
messageId: sent?.key?.id,
|
|
299
|
+
remoteJid: sent?.key?.remoteJid,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return sent;
|
|
305
|
+
}
|