@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,399 @@
|
|
|
1
|
+
import logger from '#logger';
|
|
2
|
+
import { getSystemMetrics } from '../../utils/systemMetrics/systemMetricsModule.js';
|
|
3
|
+
import { sendAndStore } from '../../services/messaging/messagePersistenceService.js';
|
|
4
|
+
|
|
5
|
+
const METRICS_ENDPOINT = process.env.METRICS_ENDPOINT || `http://localhost:${process.env.METRICS_PORT || 9102}${process.env.METRICS_PATH || '/metrics'}`;
|
|
6
|
+
const METRICS_TOKEN = String(process.env.METRICS_TOKEN || process.env.METRICS_API_KEY || '').trim();
|
|
7
|
+
const METRICS_TIMEOUT_MS = Number(process.env.METRICS_PING_TIMEOUT_MS || 1500);
|
|
8
|
+
|
|
9
|
+
const formatLoadAverage = (values) => values.map((value) => value.toFixed(2)).join(' | ');
|
|
10
|
+
|
|
11
|
+
const formatBytes = (bytes) => {
|
|
12
|
+
if (!Number.isFinite(bytes)) return 'n/a';
|
|
13
|
+
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
14
|
+
let value = bytes;
|
|
15
|
+
let idx = 0;
|
|
16
|
+
while (value >= 1024 && idx < units.length - 1) {
|
|
17
|
+
value /= 1024;
|
|
18
|
+
idx += 1;
|
|
19
|
+
}
|
|
20
|
+
return `${value.toFixed(value >= 100 ? 0 : 2)}${units[idx]}`;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const formatSeconds = (seconds) => {
|
|
24
|
+
if (!Number.isFinite(seconds)) return 'n/a';
|
|
25
|
+
const total = Math.max(0, Math.floor(seconds));
|
|
26
|
+
const days = Math.floor(total / 86400);
|
|
27
|
+
const hours = Math.floor((total % 86400) / 3600);
|
|
28
|
+
const minutes = Math.floor((total % 3600) / 60);
|
|
29
|
+
const secs = total % 60;
|
|
30
|
+
const time = [hours, minutes, secs].map((value) => String(value).padStart(2, '0')).join(':');
|
|
31
|
+
return days > 0 ? `${days}d ${time}` : time;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const parseMetricNumber = (value) => {
|
|
35
|
+
if (typeof value === 'number') return Number.isFinite(value) ? value : null;
|
|
36
|
+
if (typeof value !== 'string') return null;
|
|
37
|
+
const parsed = Number(value.replace(',', '.').trim());
|
|
38
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const getStatusLevel = (value, warnAt, criticalAt) => {
|
|
42
|
+
const numericValue = parseMetricNumber(value);
|
|
43
|
+
if (numericValue === null) return { emoji: '⚪', label: 'sem dado' };
|
|
44
|
+
if (numericValue >= criticalAt) return { emoji: '🔴', label: 'crítico' };
|
|
45
|
+
if (numericValue >= warnAt) return { emoji: '🟡', label: 'atenção' };
|
|
46
|
+
return { emoji: '🟢', label: 'ok' };
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const formatStatusLevel = (status) => `${status.emoji} ${status.label}`;
|
|
50
|
+
|
|
51
|
+
const padNumber = (value) => String(value).padStart(2, '0');
|
|
52
|
+
|
|
53
|
+
const formatDateTime = (date = new Date()) => `${padNumber(date.getDate())}/${padNumber(date.getMonth() + 1)}/${date.getFullYear()} ${padNumber(date.getHours())}:${padNumber(date.getMinutes())}:${padNumber(date.getSeconds())}`;
|
|
54
|
+
|
|
55
|
+
const parseLabels = (raw) => {
|
|
56
|
+
if (!raw) return {};
|
|
57
|
+
const labels = {};
|
|
58
|
+
const regex = /(\w+)="((?:\\.|[^"\\])*)"/g;
|
|
59
|
+
let match;
|
|
60
|
+
while ((match = regex.exec(raw)) !== null) {
|
|
61
|
+
labels[match[1]] = match[2].replace(/\\"/g, '"');
|
|
62
|
+
}
|
|
63
|
+
return labels;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const parsePrometheusText = (text) => {
|
|
67
|
+
const series = new Map();
|
|
68
|
+
const lines = text.split('\n');
|
|
69
|
+
for (const line of lines) {
|
|
70
|
+
const trimmed = line.trim();
|
|
71
|
+
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
72
|
+
const [metricPart, valuePart] = trimmed.split(/\s+/, 2);
|
|
73
|
+
if (!metricPart || !valuePart) continue;
|
|
74
|
+
const value = Number(valuePart);
|
|
75
|
+
if (!Number.isFinite(value)) continue;
|
|
76
|
+
const labelStart = metricPart.indexOf('{');
|
|
77
|
+
let name = metricPart;
|
|
78
|
+
let labels = {};
|
|
79
|
+
if (labelStart !== -1) {
|
|
80
|
+
name = metricPart.slice(0, labelStart);
|
|
81
|
+
const labelBody = metricPart.slice(labelStart + 1, metricPart.lastIndexOf('}'));
|
|
82
|
+
labels = parseLabels(labelBody);
|
|
83
|
+
}
|
|
84
|
+
const list = series.get(name) || [];
|
|
85
|
+
list.push({ labels, value });
|
|
86
|
+
series.set(name, list);
|
|
87
|
+
}
|
|
88
|
+
return series;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const pickValue = (series, name, filter = null) => {
|
|
92
|
+
const list = series.get(name) || [];
|
|
93
|
+
if (!list.length) return null;
|
|
94
|
+
if (!filter) return list[0].value;
|
|
95
|
+
const hit = list.find((entry) => filter(entry.labels));
|
|
96
|
+
return hit ? hit.value : null;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const sumValues = (series, name, filter = null) => {
|
|
100
|
+
const list = series.get(name) || [];
|
|
101
|
+
return list.reduce((acc, entry) => {
|
|
102
|
+
if (filter && !filter(entry.labels)) return acc;
|
|
103
|
+
if (!Number.isFinite(entry.value)) return acc;
|
|
104
|
+
return acc + entry.value;
|
|
105
|
+
}, 0);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const getLabelValue = (series, name, labelKey) => {
|
|
109
|
+
const list = series.get(name) || [];
|
|
110
|
+
const entry = list.find((item) => item.labels && item.labels[labelKey]);
|
|
111
|
+
return entry ? entry.labels[labelKey] : null;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const buildPingMessage = ({ systemMetrics, metricsSummary, metricsOk, metricsError, latencyMs, generatedAt }) => {
|
|
115
|
+
const responseTime = Number.isFinite(latencyMs) ? `${Math.max(0, Math.round(latencyMs))}ms` : 'n/a';
|
|
116
|
+
|
|
117
|
+
const hostCpuStatus = getStatusLevel(systemMetrics.usoCpuPercentual, 65, 85);
|
|
118
|
+
const hostMemoryStatus = getStatusLevel(systemMetrics.usoMemoriaPercentual, 75, 90);
|
|
119
|
+
|
|
120
|
+
const load1 = Array.isArray(systemMetrics.cargaMedia) ? systemMetrics.cargaMedia[0] : null;
|
|
121
|
+
const loadPerCore = Number.isFinite(load1) && systemMetrics.totalCpus > 0 ? load1 / systemMetrics.totalCpus : null;
|
|
122
|
+
const loadStatus = getStatusLevel(loadPerCore, 0.9, 1.2);
|
|
123
|
+
const loadPerCoreText = loadPerCore === null ? 'n/a' : loadPerCore.toFixed(2);
|
|
124
|
+
|
|
125
|
+
const systemPart = `
|
|
126
|
+
🖥️ *Servidor (máquina)*
|
|
127
|
+
• Host: ${systemMetrics.hostname}
|
|
128
|
+
• SO: ${systemMetrics.plataforma} ${systemMetrics.release} (${systemMetrics.arquitetura})
|
|
129
|
+
• Uptime do sistema: ${systemMetrics.uptimeSistema}
|
|
130
|
+
• CPU da máquina: ${formatStatusLevel(hostCpuStatus)} • ${systemMetrics.usoCpuPercentual}% (uso geral)
|
|
131
|
+
• Carga (1m|5m|15m): ${formatLoadAverage(systemMetrics.cargaMedia)}
|
|
132
|
+
• Pressão por núcleo (1m): ${loadPerCoreText} • ${formatStatusLevel(loadStatus)}
|
|
133
|
+
• RAM: ${formatStatusLevel(hostMemoryStatus)} • ${systemMetrics.memoriaUsada} / ${systemMetrics.memoriaTotal} (${systemMetrics.usoMemoriaPercentual}%)
|
|
134
|
+
`.trim();
|
|
135
|
+
|
|
136
|
+
if (!metricsOk) {
|
|
137
|
+
return `
|
|
138
|
+
🏓 *Pong! Painel de saúde (modo básico)*
|
|
139
|
+
🕐 Atualizado em: ${formatDateTime(generatedAt)}
|
|
140
|
+
⚡ Tempo de resposta: ${responseTime}
|
|
141
|
+
🧭 Legenda: 🟢 ok • 🟡 atenção • 🔴 crítico • ⚪ sem dado
|
|
142
|
+
|
|
143
|
+
${systemPart}
|
|
144
|
+
|
|
145
|
+
⚠️ *Métricas avançadas indisponíveis*
|
|
146
|
+
• Motivo: ${metricsError || 'sem detalhes'}
|
|
147
|
+
• Endpoint: ${METRICS_ENDPOINT}
|
|
148
|
+
• Timeout: ${METRICS_TIMEOUT_MS}ms
|
|
149
|
+
|
|
150
|
+
💡 *Dica:* as métricas avançadas vêm do endpoint */metrics* (Prometheus).
|
|
151
|
+
`.trim();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const openFds = parseMetricNumber(metricsSummary.openFds);
|
|
155
|
+
const maxFds = parseMetricNumber(metricsSummary.maxFds);
|
|
156
|
+
const fdsUsage = openFds !== null && maxFds && maxFds > 0 ? (openFds / maxFds) * 100 : null;
|
|
157
|
+
const fdsStatus = getStatusLevel(fdsUsage, 60, 80);
|
|
158
|
+
const fdsUsageText = fdsUsage === null ? 'n/a' : `${fdsUsage.toFixed(1)}%`;
|
|
159
|
+
|
|
160
|
+
const lagP99 = parseMetricNumber(metricsSummary.lagP99);
|
|
161
|
+
const lagStatus = getStatusLevel(lagP99, 120, 300);
|
|
162
|
+
|
|
163
|
+
const dbTotal = parseMetricNumber(metricsSummary.dbTotal) || 0;
|
|
164
|
+
const dbSlow = parseMetricNumber(metricsSummary.dbSlow) || 0;
|
|
165
|
+
const slowRate = dbTotal > 0 ? (dbSlow / dbTotal) * 100 : null;
|
|
166
|
+
const dbStatus = getStatusLevel(slowRate, 5, 15);
|
|
167
|
+
const slowRateText = slowRate === null ? 'n/a' : `${slowRate.toFixed(2)}%`;
|
|
168
|
+
|
|
169
|
+
const queueValues = [metricsSummary.queues.messages, metricsSummary.queues.chats, metricsSummary.queues.lid_map].map((value) => parseMetricNumber(value)).filter((value) => value !== null);
|
|
170
|
+
const queuePeak = queueValues.length ? Math.max(...queueValues) : null;
|
|
171
|
+
const queueStatus = getStatusLevel(queuePeak, 30, 120);
|
|
172
|
+
const queuePeakText = queuePeak === null ? 'n/a' : String(Math.round(queuePeak));
|
|
173
|
+
|
|
174
|
+
const processPart = `
|
|
175
|
+
⚙️ *Processo do bot*
|
|
176
|
+
• Uptime do processo: ${metricsSummary.processUptime}
|
|
177
|
+
• Node.js: ${metricsSummary.nodeVersion}
|
|
178
|
+
• CPU acumulada: total ${metricsSummary.cpuTotalSec}s (user ${metricsSummary.cpuUserSec}s | sys ${metricsSummary.cpuSysSec}s)
|
|
179
|
+
• Memória do processo: RSS ${metricsSummary.rss} | Heap ${metricsSummary.heap} | VMem ${metricsSummary.vmem}
|
|
180
|
+
• FDs abertos: ${metricsSummary.openFds}/${metricsSummary.maxFds} (${fdsUsageText}) • ${formatStatusLevel(fdsStatus)}
|
|
181
|
+
`.trim();
|
|
182
|
+
|
|
183
|
+
const nodePart = `
|
|
184
|
+
🧠 *Event Loop (responsividade)*
|
|
185
|
+
• Lag p50: ${metricsSummary.lagP50}ms (comportamento normal)
|
|
186
|
+
• Lag p90: ${metricsSummary.lagP90}ms (picos frequentes)
|
|
187
|
+
• Lag p99: ${metricsSummary.lagP99}ms (pior caso recente)
|
|
188
|
+
• Status do loop: ${formatStatusLevel(lagStatus)} (quanto menor o lag, melhor)
|
|
189
|
+
`.trim();
|
|
190
|
+
|
|
191
|
+
const dbPart = `
|
|
192
|
+
🗄️ *Banco*
|
|
193
|
+
• Queries totais: ${metricsSummary.dbTotal}
|
|
194
|
+
• Queries lentas: ${metricsSummary.dbSlow} (${slowRateText}) • ${formatStatusLevel(dbStatus)}
|
|
195
|
+
• Writes: messages ${metricsSummary.writes.messages} | lid_map ${metricsSummary.writes.lid_map} | groups ${metricsSummary.writes.groups_metadata}
|
|
196
|
+
• Últimas latências (ms): messages ${metricsSummary.lastQuery.messages} | lid_map ${metricsSummary.lastQuery.lid_map} | groups ${metricsSummary.lastQuery.groups_metadata}
|
|
197
|
+
`.trim();
|
|
198
|
+
|
|
199
|
+
const queuePart = `
|
|
200
|
+
📦 *Filas internas (backlog)*
|
|
201
|
+
• messages ${metricsSummary.queues.messages} | chats ${metricsSummary.queues.chats} | lid_map ${metricsSummary.queues.lid_map}
|
|
202
|
+
• Pico atual: ${queuePeakText} • ${formatStatusLevel(queueStatus)} (quanto menor, melhor)
|
|
203
|
+
`.trim();
|
|
204
|
+
|
|
205
|
+
const upsertPart = `
|
|
206
|
+
📬 *messages.upsert (entrada de mensagens)*
|
|
207
|
+
• Eventos recebidos: append ${metricsSummary.upsertEvents.append} | notify ${metricsSummary.upsertEvents.notify}
|
|
208
|
+
• Mensagens processadas: append ${metricsSummary.upsertMessages.append} | notify ${metricsSummary.upsertMessages.notify}
|
|
209
|
+
`.trim();
|
|
210
|
+
|
|
211
|
+
const glossaryPart = `
|
|
212
|
+
📖 *Glossário rápido*
|
|
213
|
+
• RSS: memória real em RAM usada pelo processo
|
|
214
|
+
• Heap: memória JavaScript gerenciada pelo Node.js
|
|
215
|
+
• VMem: memória virtual reservada pelo processo
|
|
216
|
+
• Lag: atraso do Node para executar tarefas
|
|
217
|
+
`.trim();
|
|
218
|
+
|
|
219
|
+
return `
|
|
220
|
+
🏓 *Pong! Painel de saúde do Omnizap*
|
|
221
|
+
🕐 Atualizado em: ${formatDateTime(generatedAt)}
|
|
222
|
+
⚡ Tempo de resposta: ${responseTime}
|
|
223
|
+
🧭 Legenda: 🟢 ok • 🟡 atenção • 🔴 crítico • ⚪ sem dado
|
|
224
|
+
|
|
225
|
+
${systemPart}
|
|
226
|
+
|
|
227
|
+
${processPart}
|
|
228
|
+
|
|
229
|
+
${nodePart}
|
|
230
|
+
|
|
231
|
+
${dbPart}
|
|
232
|
+
|
|
233
|
+
${queuePart}
|
|
234
|
+
|
|
235
|
+
${upsertPart}
|
|
236
|
+
|
|
237
|
+
${glossaryPart}
|
|
238
|
+
`.trim();
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
const fetchMetricsSnapshot = async () => {
|
|
242
|
+
const controller = typeof globalThis.AbortController === 'function' ? new globalThis.AbortController() : null;
|
|
243
|
+
const timeout = setTimeout(() => controller?.abort(), METRICS_TIMEOUT_MS);
|
|
244
|
+
try {
|
|
245
|
+
if (typeof globalThis.fetch !== 'function') {
|
|
246
|
+
throw new Error('fetch indisponível');
|
|
247
|
+
}
|
|
248
|
+
const headers = {};
|
|
249
|
+
if (METRICS_TOKEN) {
|
|
250
|
+
headers.Authorization = `Bearer ${METRICS_TOKEN}`;
|
|
251
|
+
}
|
|
252
|
+
const response = await globalThis.fetch(METRICS_ENDPOINT, {
|
|
253
|
+
...(controller ? { signal: controller.signal } : {}),
|
|
254
|
+
...(Object.keys(headers).length ? { headers } : {}),
|
|
255
|
+
});
|
|
256
|
+
if (!response.ok) {
|
|
257
|
+
throw new Error(`HTTP ${response.status}`);
|
|
258
|
+
}
|
|
259
|
+
const text = await response.text();
|
|
260
|
+
const series = parsePrometheusText(text);
|
|
261
|
+
|
|
262
|
+
const processStart = pickValue(series, 'omnizap_process_start_time_seconds');
|
|
263
|
+
const nowSec = Date.now() / 1000;
|
|
264
|
+
const processUptime = processStart ? formatSeconds(nowSec - processStart) : 'n/a';
|
|
265
|
+
|
|
266
|
+
const cpuUserSec = pickValue(series, 'omnizap_process_cpu_user_seconds_total');
|
|
267
|
+
const cpuSysSec = pickValue(series, 'omnizap_process_cpu_system_seconds_total');
|
|
268
|
+
const cpuTotalSec = pickValue(series, 'omnizap_process_cpu_seconds_total');
|
|
269
|
+
|
|
270
|
+
const rss = pickValue(series, 'omnizap_process_resident_memory_bytes');
|
|
271
|
+
const vmem = pickValue(series, 'omnizap_process_virtual_memory_bytes');
|
|
272
|
+
const heap = pickValue(series, 'omnizap_process_heap_bytes');
|
|
273
|
+
|
|
274
|
+
const openFds = pickValue(series, 'omnizap_process_open_fds');
|
|
275
|
+
const maxFds = pickValue(series, 'omnizap_process_max_fds');
|
|
276
|
+
|
|
277
|
+
const lagP50 = pickValue(series, 'omnizap_nodejs_eventloop_lag_p50_seconds');
|
|
278
|
+
const lagP90 = pickValue(series, 'omnizap_nodejs_eventloop_lag_p90_seconds');
|
|
279
|
+
const lagP99 = pickValue(series, 'omnizap_nodejs_eventloop_lag_p99_seconds');
|
|
280
|
+
|
|
281
|
+
const nodeVersion = getLabelValue(series, 'omnizap_nodejs_version_info', 'version') || 'n/a';
|
|
282
|
+
|
|
283
|
+
const dbTotal = sumValues(series, 'omnizap_db_query_total');
|
|
284
|
+
const dbSlow = sumValues(series, 'omnizap_db_slow_queries_total');
|
|
285
|
+
|
|
286
|
+
const writesByTable = {};
|
|
287
|
+
const writeSeries = series.get('omnizap_db_write_total') || [];
|
|
288
|
+
writeSeries.forEach((entry) => {
|
|
289
|
+
const table = entry.labels?.table || 'unknown';
|
|
290
|
+
writesByTable[table] = (writesByTable[table] || 0) + entry.value;
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
const lastQuerySeries = series.get('omnizap_db_last_query_duration_ms') || [];
|
|
294
|
+
const lastQuery = {};
|
|
295
|
+
lastQuerySeries.forEach((entry) => {
|
|
296
|
+
const table = entry.labels?.table;
|
|
297
|
+
if (!table) return;
|
|
298
|
+
lastQuery[table] = entry.value;
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
const queueSeries = series.get('omnizap_queue_depth') || [];
|
|
302
|
+
const queues = {};
|
|
303
|
+
queueSeries.forEach((entry) => {
|
|
304
|
+
const queue = entry.labels?.queue;
|
|
305
|
+
if (!queue) return;
|
|
306
|
+
queues[queue] = entry.value;
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
const upsertEvents = {};
|
|
310
|
+
const upsertSeries = series.get('omnizap_messages_upsert_total') || [];
|
|
311
|
+
upsertSeries.forEach((entry) => {
|
|
312
|
+
const type = entry.labels?.type || 'unknown';
|
|
313
|
+
upsertEvents[type] = (upsertEvents[type] || 0) + entry.value;
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
const upsertMessages = {};
|
|
317
|
+
const upsertMsgSeries = series.get('omnizap_messages_upsert_messages_total') || [];
|
|
318
|
+
upsertMsgSeries.forEach((entry) => {
|
|
319
|
+
const type = entry.labels?.type || 'unknown';
|
|
320
|
+
upsertMessages[type] = (upsertMessages[type] || 0) + entry.value;
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
const formatNumber = (value, digits = 2) => (Number.isFinite(value) ? value.toFixed(digits) : 'n/a');
|
|
324
|
+
|
|
325
|
+
return {
|
|
326
|
+
processUptime,
|
|
327
|
+
cpuUserSec: formatNumber(cpuUserSec),
|
|
328
|
+
cpuSysSec: formatNumber(cpuSysSec),
|
|
329
|
+
cpuTotalSec: formatNumber(cpuTotalSec),
|
|
330
|
+
rss: formatBytes(rss),
|
|
331
|
+
heap: formatBytes(heap),
|
|
332
|
+
vmem: formatBytes(vmem),
|
|
333
|
+
openFds: Number.isFinite(openFds) ? Math.round(openFds) : 'n/a',
|
|
334
|
+
maxFds: Number.isFinite(maxFds) ? Math.round(maxFds) : 'n/a',
|
|
335
|
+
nodeVersion,
|
|
336
|
+
lagP50: Number.isFinite(lagP50) ? (lagP50 * 1000).toFixed(2) : 'n/a',
|
|
337
|
+
lagP90: Number.isFinite(lagP90) ? (lagP90 * 1000).toFixed(2) : 'n/a',
|
|
338
|
+
lagP99: Number.isFinite(lagP99) ? (lagP99 * 1000).toFixed(2) : 'n/a',
|
|
339
|
+
dbTotal: Math.round(dbTotal),
|
|
340
|
+
dbSlow: Math.round(dbSlow),
|
|
341
|
+
writes: {
|
|
342
|
+
messages: Math.round(writesByTable.messages || 0),
|
|
343
|
+
lid_map: Math.round(writesByTable.lid_map || 0),
|
|
344
|
+
groups_metadata: Math.round(writesByTable.groups_metadata || 0),
|
|
345
|
+
},
|
|
346
|
+
lastQuery: {
|
|
347
|
+
messages: Number.isFinite(lastQuery.messages) ? lastQuery.messages.toFixed(2) : 'n/a',
|
|
348
|
+
lid_map: Number.isFinite(lastQuery.lid_map) ? lastQuery.lid_map.toFixed(2) : 'n/a',
|
|
349
|
+
groups_metadata: Number.isFinite(lastQuery.groups_metadata) ? lastQuery.groups_metadata.toFixed(2) : 'n/a',
|
|
350
|
+
},
|
|
351
|
+
queues: {
|
|
352
|
+
messages: Math.round(queues.messages || 0),
|
|
353
|
+
chats: Math.round(queues.chats || 0),
|
|
354
|
+
lid_map: Math.round(queues.lid_map || 0),
|
|
355
|
+
},
|
|
356
|
+
upsertEvents: {
|
|
357
|
+
append: Math.round(upsertEvents.append || 0),
|
|
358
|
+
notify: Math.round(upsertEvents.notify || 0),
|
|
359
|
+
},
|
|
360
|
+
upsertMessages: {
|
|
361
|
+
append: Math.round(upsertMessages.append || 0),
|
|
362
|
+
notify: Math.round(upsertMessages.notify || 0),
|
|
363
|
+
},
|
|
364
|
+
};
|
|
365
|
+
} finally {
|
|
366
|
+
clearTimeout(timeout);
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
export async function handlePingCommand({ sock, remoteJid, messageInfo, expirationMessage }) {
|
|
371
|
+
try {
|
|
372
|
+
const startedAt = Date.now();
|
|
373
|
+
const systemMetrics = getSystemMetrics();
|
|
374
|
+
let metricsSummary = null;
|
|
375
|
+
let metricsOk = false;
|
|
376
|
+
let metricsError = null;
|
|
377
|
+
|
|
378
|
+
try {
|
|
379
|
+
metricsSummary = await fetchMetricsSnapshot();
|
|
380
|
+
metricsOk = true;
|
|
381
|
+
} catch (error) {
|
|
382
|
+
metricsError = error.message;
|
|
383
|
+
logger.warn('Falha ao buscar métricas Prometheus para /ping.', { error: error.message });
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const text = buildPingMessage({
|
|
387
|
+
systemMetrics,
|
|
388
|
+
metricsSummary,
|
|
389
|
+
metricsOk,
|
|
390
|
+
metricsError,
|
|
391
|
+
latencyMs: Date.now() - startedAt,
|
|
392
|
+
generatedAt: new Date(),
|
|
393
|
+
});
|
|
394
|
+
await sendAndStore(sock, remoteJid, { text }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
395
|
+
} catch (error) {
|
|
396
|
+
logger.error('Erro ao gerar status do sistema:', { error: error.message });
|
|
397
|
+
await sendAndStore(sock, remoteJid, { text: 'Erro ao obter informações do sistema.' }, { quoted: messageInfo, ephemeralExpiration: expirationMessage });
|
|
398
|
+
}
|
|
399
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { createModuleAiHelpWrapper } from '../../services/ai/moduleAiHelpWrapperFactory.js';
|
|
4
|
+
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
7
|
+
|
|
8
|
+
export const systemMetricsAiHelpWrapper = createModuleAiHelpWrapper({
|
|
9
|
+
moduleKey: 'system_metrics',
|
|
10
|
+
moduleLabel: 'comandos de metricas',
|
|
11
|
+
envPrefix: 'SYSTEM_METRICS_AI_HELP',
|
|
12
|
+
moduleDirPath: __dirname,
|
|
13
|
+
moduleNameFallback: 'systemMetricsModule',
|
|
14
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
|
|
4
|
+
import { createModuleCommandConfigRuntime } from '../../services/ai/moduleCommandConfigRuntimeService.js';
|
|
5
|
+
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = path.dirname(__filename);
|
|
8
|
+
const CONFIG_PATH = path.join(__dirname, 'commandConfig.json');
|
|
9
|
+
|
|
10
|
+
const DEFAULT_TEXTS = {
|
|
11
|
+
usage_header: '',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const runtime = createModuleCommandConfigRuntime({
|
|
15
|
+
configPath: CONFIG_PATH,
|
|
16
|
+
fallbackConfig: {
|
|
17
|
+
module: 'systemMetricsModule',
|
|
18
|
+
commands: [],
|
|
19
|
+
textos: DEFAULT_TEXTS,
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const renderUsageMethod = (method, commandPrefix) => String(method || '').replaceAll('<prefix>', String(commandPrefix || '/'));
|
|
24
|
+
|
|
25
|
+
const resolveUsageLines = (entry, variant) => {
|
|
26
|
+
if (!entry || typeof entry !== 'object') return [];
|
|
27
|
+
|
|
28
|
+
const usageMessages = entry?.mensagens_uso && typeof entry.mensagens_uso === 'object' ? entry.mensagens_uso : null;
|
|
29
|
+
|
|
30
|
+
if (usageMessages) {
|
|
31
|
+
const variantKey = typeof variant === 'string' ? variant.trim() : '';
|
|
32
|
+
const picked = (variantKey && usageMessages[variantKey]) || usageMessages.default || null;
|
|
33
|
+
if (Array.isArray(picked)) {
|
|
34
|
+
return picked.filter(Boolean).map((value) => String(value));
|
|
35
|
+
}
|
|
36
|
+
if (typeof picked === 'string' && picked.trim()) {
|
|
37
|
+
return [picked.trim()];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const methods = Array.isArray(entry?.metodos_de_uso) ? entry.metodos_de_uso : [];
|
|
42
|
+
return methods.filter(Boolean).map((value) => String(value));
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const getSystemMetricsModuleConfig = () => runtime.getModuleConfig();
|
|
46
|
+
|
|
47
|
+
export const resolveSystemMetricsCommandName = (command) => runtime.resolveCommandName(command);
|
|
48
|
+
export const getSystemMetricsCommandEntry = (command) => runtime.getCommandEntry(command);
|
|
49
|
+
export const listEnabledSystemMetricsCommands = () => runtime.listEnabledCommands();
|
|
50
|
+
|
|
51
|
+
export const getSystemMetricsTextConfig = () => {
|
|
52
|
+
const config = getSystemMetricsModuleConfig();
|
|
53
|
+
const raw = config?.textos && typeof config.textos === 'object' ? config.textos : {};
|
|
54
|
+
return {
|
|
55
|
+
...DEFAULT_TEXTS,
|
|
56
|
+
...raw,
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const getSystemMetricsUsageText = (command, { commandPrefix = '/', header, variant } = {}) => {
|
|
61
|
+
const entry = getSystemMetricsCommandEntry(command);
|
|
62
|
+
const methods = resolveUsageLines(entry, variant);
|
|
63
|
+
if (!methods.length) return '';
|
|
64
|
+
|
|
65
|
+
const prefixHeader = typeof header === 'string' ? header : getSystemMetricsTextConfig().usage_header || DEFAULT_TEXTS.usage_header;
|
|
66
|
+
const lines = methods.map((method) => renderUsageMethod(method, commandPrefix));
|
|
67
|
+
return prefixHeader ? [prefixHeader, ...lines].join('\n') : lines.join('\n');
|
|
68
|
+
};
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# TiktokModule Agent Guide
|
|
2
|
+
|
|
3
|
+
Este arquivo e destinado a agentes de IA para gerar respostas no contexto dos comandos deste modulo.
|
|
4
|
+
|
|
5
|
+
## Fonte de Verdade
|
|
6
|
+
|
|
7
|
+
- arquivo_base: `app/modules/tiktokModule/commandConfig.json`
|
|
8
|
+
- schema_version: `2.0.0`
|
|
9
|
+
- module_enabled: `true`
|
|
10
|
+
- generated_at: `2026-03-11T02:35:17.177Z`
|
|
11
|
+
|
|
12
|
+
## Escopo do Modulo
|
|
13
|
+
|
|
14
|
+
- module: `tiktokModule`
|
|
15
|
+
- source_files:
|
|
16
|
+
- tiktokCommand.js
|
|
17
|
+
- total_commands: `1`
|
|
18
|
+
- total_enabled_commands: `1`
|
|
19
|
+
|
|
20
|
+
## Defaults Schema v2
|
|
21
|
+
|
|
22
|
+
- inheritance_mode: deep_merge_with_command_overrides
|
|
23
|
+
- compatibility_mode: legacy_and_v2_fields
|
|
24
|
+
- legacy_field_aliases:
|
|
25
|
+
- descricao: description
|
|
26
|
+
- metodos_de_uso: usage
|
|
27
|
+
- permissao_necessaria: permission
|
|
28
|
+
- local_de_uso: contexts
|
|
29
|
+
- informacoes_coletadas: collected_data
|
|
30
|
+
- pre_condicoes: requirements
|
|
31
|
+
- dependencias_externas: dependencies
|
|
32
|
+
- efeitos_colaterais: side_effects
|
|
33
|
+
- observabilidade: observability
|
|
34
|
+
- privacidade: privacy
|
|
35
|
+
- limite_uso_por_plano: plan_limits
|
|
36
|
+
- argumentos: arguments
|
|
37
|
+
- acesso: access
|
|
38
|
+
- defaults.command:
|
|
39
|
+
- enabled: true
|
|
40
|
+
- category: midia
|
|
41
|
+
- version: 1.0.0
|
|
42
|
+
- stability: stable
|
|
43
|
+
- deprecated: false
|
|
44
|
+
- replaced_by: null
|
|
45
|
+
- risk_level: medium
|
|
46
|
+
- defaults.requirements (legacy view):
|
|
47
|
+
- requer_grupo: nao
|
|
48
|
+
- requer_admin: nao
|
|
49
|
+
- requer_admin_principal: nao
|
|
50
|
+
- requer_google_login: sim
|
|
51
|
+
- requer_nsfw: nao
|
|
52
|
+
- requer_midia: nao
|
|
53
|
+
- requer_mensagem_respondida: nao
|
|
54
|
+
|
|
55
|
+
## Protocolo de Resposta para IA
|
|
56
|
+
|
|
57
|
+
- Passo 1: identificar comando pelo token apos o prefixo.
|
|
58
|
+
- Passo 2: resolver alias para nome canonico usando campo `aliases`.
|
|
59
|
+
- Passo 3: validar `enabled`, `pre_condicoes`, permissao e local de uso.
|
|
60
|
+
- Passo 4: se houver erro de uso, responder com `mensagens_uso` (quando existir) ou `metodos_de_uso`.
|
|
61
|
+
- Passo 5: seguir `respostas_padrao` como fallback de texto.
|
|
62
|
+
- Passo 6: considerar `informacoes_coletadas`, `privacidade` e `observabilidade` ao elaborar resposta.
|
|
63
|
+
|
|
64
|
+
## Regras de Seguranca para IA
|
|
65
|
+
|
|
66
|
+
- A IA orienta, mas nao executa acao administrativa automaticamente.
|
|
67
|
+
- Nao inventar comandos, subcomandos ou permissao fora do JSON.
|
|
68
|
+
- Sempre informar onde pode usar (grupo/privado) e quem pode usar.
|
|
69
|
+
- Em duvida de permissao, responder com orientacao conservadora.
|
|
70
|
+
|
|
71
|
+
## Catalogo de Comandos
|
|
72
|
+
|
|
73
|
+
### baixartiktok
|
|
74
|
+
|
|
75
|
+
- id: tiktok.baixartiktok
|
|
76
|
+
- aliases: tt, tiktok
|
|
77
|
+
- enabled: true
|
|
78
|
+
- categoria: midia
|
|
79
|
+
- descricao: Baixa midia do TikTok sem marca d'agua.
|
|
80
|
+
- permissao_necessaria: usuario comum
|
|
81
|
+
- version: 1.0.0
|
|
82
|
+
- stability: stable
|
|
83
|
+
- deprecated: nao
|
|
84
|
+
- risk_level: low
|
|
85
|
+
- local_de_uso:
|
|
86
|
+
- privado
|
|
87
|
+
- grupo
|
|
88
|
+
- metodos_de_uso:
|
|
89
|
+
- <prefix>baixartiktok <url>
|
|
90
|
+
- <prefix>tt <url1> <url2>
|
|
91
|
+
- mensagens_uso (variantes):
|
|
92
|
+
- default:
|
|
93
|
+
- 🎬 _Baixartiktok Downloader_
|
|
94
|
+
- Uso: _<prefix>baixartiktok <link1> [link2 ...]_
|
|
95
|
+
- Exemplo: _<prefix>baixartiktok https://www.baixartiktok.com/@usuario/video/123_
|
|
96
|
+
- subcomandos:
|
|
97
|
+
- (nenhum)
|
|
98
|
+
- argumentos:
|
|
99
|
+
- urls | tipo: array | obrigatorio | validacao: 1 a 5 URLs do TikTok | default: null | posicao: 0
|
|
100
|
+
- pre_condicoes:
|
|
101
|
+
- requer_grupo: nao
|
|
102
|
+
- requer_admin: nao
|
|
103
|
+
- requer_admin_principal: nao
|
|
104
|
+
- requer_google_login: sim
|
|
105
|
+
- requer_nsfw: nao
|
|
106
|
+
- requer_midia: nao
|
|
107
|
+
- requer_mensagem_respondida: nao
|
|
108
|
+
- rate_limit:
|
|
109
|
+
- max: 5
|
|
110
|
+
- janela_ms: null
|
|
111
|
+
- escopo: por_execucao
|
|
112
|
+
- acesso:
|
|
113
|
+
- somente_premium: nao
|
|
114
|
+
- planos_permitidos: comum, premium
|
|
115
|
+
- limite_uso_por_plano:
|
|
116
|
+
- comum: max=4, janela_ms=600000, escopo=usuario
|
|
117
|
+
- premium: max=15, janela_ms=600000, escopo=usuario
|
|
118
|
+
- informacoes_coletadas:
|
|
119
|
+
- identificador do chat (remoteJid)
|
|
120
|
+
- identificador do remetente (senderJid)
|
|
121
|
+
- texto do comando e argumentos
|
|
122
|
+
- contexto da mensagem (citacao e mencoes, quando existir)
|
|
123
|
+
- URLs do TikTok extraidas do texto
|
|
124
|
+
- metadados do post (autor, descricao, estatisticas)
|
|
125
|
+
- tamanho dos arquivos para enforce de limite
|
|
126
|
+
- dependencias_externas:
|
|
127
|
+
- serviço extractor de TikTok
|
|
128
|
+
- efeitos_colaterais:
|
|
129
|
+
- baixa mídia temporária
|
|
130
|
+
- envia vídeo/imagens no chat
|
|
131
|
+
- respostas_padrao:
|
|
132
|
+
- success: Comando executado com sucesso.
|
|
133
|
+
- usage_error: Formato de uso inválido. Consulte metodos_de_uso.
|
|
134
|
+
- permission_error: Permissão insuficiente para executar este comando.
|
|
135
|
+
- sucesso: Comando executado com sucesso.
|
|
136
|
+
- erro_uso: Formato de uso inválido. Consulte metodos_de_uso.
|
|
137
|
+
- erro_permissao: Permissão insuficiente para executar este comando.
|
|
138
|
+
- mensagens_sistema:
|
|
139
|
+
- (nao informado)
|
|
140
|
+
- limites_operacionais:
|
|
141
|
+
- (nao informado)
|
|
142
|
+
- opcoes:
|
|
143
|
+
- toggle_on_off_status.type: toggle
|
|
144
|
+
- toggle_on_off_status.allowed_actions: on, off, status
|
|
145
|
+
- toggle_on_off_status.action_argument: acao
|
|
146
|
+
- add_remove_list.type: list_management
|
|
147
|
+
- add_remove_list.allowed_actions: add, remove, list
|
|
148
|
+
- add_remove_list.action_argument: acao
|
|
149
|
+
- approve_reject.type: moderation_decision
|
|
150
|
+
- approve_reject.allowed_actions: approve, reject
|
|
151
|
+
- approve_reject.action_argument: acao
|
|
152
|
+
- approve_reject.requires_targets: true
|
|
153
|
+
- set_status_reset.type: configuration_window
|
|
154
|
+
- set_status_reset.allowed_actions: set, status, reset
|
|
155
|
+
- set_status_reset.action_argument: valor
|
|
156
|
+
- observabilidade:
|
|
157
|
+
- event_name: command.executed
|
|
158
|
+
- analytics_event: whatsapp_command_tiktok
|
|
159
|
+
- tags_log: whatsapp, command, tiktokModule, tiktok
|
|
160
|
+
- nivel_log: info
|
|
161
|
+
- privacidade:
|
|
162
|
+
- dados_sensiveis:
|
|
163
|
+
- chat_identifier
|
|
164
|
+
- sender_identifier
|
|
165
|
+
- command_content
|
|
166
|
+
- retencao: standard_app_logs
|
|
167
|
+
- base_legal: service_execution_and_legitimate_interest
|
|
168
|
+
- docs:
|
|
169
|
+
- summary: Baixa midia do TikTok sem marca d'agua.
|
|
170
|
+
- usage_examples: <prefix>baixartiktok <url>, <prefix>tt <url1> <url2>
|
|
171
|
+
- usage*variants.default: 🎬 \_Baixartiktok Downloader*, , Uso: _<prefix>baixartiktok <link1> [link2 ...]_, , Exemplo: _<prefix>baixartiktok https://www.baixartiktok.com/@usuario/video/123_
|
|
172
|
+
- behavior:
|
|
173
|
+
- type: argument_driven
|
|
174
|
+
- allowed_actions: (nenhum)
|
|
175
|
+
- limits:
|
|
176
|
+
- usage_description: ate 5 URLs por comando e ate 80 MB por arquivo (padrao)
|
|
177
|
+
- rate_limit.max: 5
|
|
178
|
+
- rate_limit.janela_ms: null
|
|
179
|
+
- rate_limit.escopo: por_execucao
|
|
180
|
+
- access.somente_premium: false
|
|
181
|
+
- access.planos_permitidos: comum, premium
|
|
182
|
+
- plan_limits.comum.max: 4
|
|
183
|
+
- plan_limits.comum.janela_ms: 600000
|
|
184
|
+
- plan_limits.comum.escopo: usuario
|
|
185
|
+
- plan_limits.premium.max: 15
|
|
186
|
+
- plan_limits.premium.janela_ms: 600000
|
|
187
|
+
- plan_limits.premium.escopo: usuario
|
|
188
|
+
- discovery:
|
|
189
|
+
- keywords: baixartiktok, tt, midia, privado, grupo
|
|
190
|
+
- faq_queries: como usar baixartiktok, o que faz baixartiktok, comando baixartiktok
|
|
191
|
+
- user_phrasings: quero usar baixartiktok, me ajuda com baixartiktok, baixa midia do baixartiktok
|
|
192
|
+
- suggestion_priority: 100
|
|
193
|
+
- handler:
|
|
194
|
+
- file: tiktokCommand.js
|
|
195
|
+
- method: handleTikTokCommand
|
|
196
|
+
- command_case: baixartiktok
|