@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,432 @@
|
|
|
1
|
+
import { executeQuery, TABLES } from '../../../database/index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Faz parse resiliente de JSON vindo do banco.
|
|
5
|
+
*
|
|
6
|
+
* @param {unknown} value Valor bruto.
|
|
7
|
+
* @param {unknown} [fallback=null] Valor fallback em caso de erro.
|
|
8
|
+
* @returns {unknown} Valor convertido ou fallback.
|
|
9
|
+
*/
|
|
10
|
+
const parseJson = (value, fallback = null) => {
|
|
11
|
+
if (value === null || value === undefined) return fallback;
|
|
12
|
+
if (typeof value === 'object') return value;
|
|
13
|
+
if (Buffer.isBuffer(value)) {
|
|
14
|
+
try {
|
|
15
|
+
return JSON.parse(value.toString('utf8'));
|
|
16
|
+
} catch {
|
|
17
|
+
return fallback;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (typeof value === 'string') {
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(value);
|
|
24
|
+
} catch {
|
|
25
|
+
return fallback;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return fallback;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Normaliza um item do pack com dados opcionais de asset.
|
|
34
|
+
*
|
|
35
|
+
* @param {Record<string, unknown>|null|undefined} row Linha crua retornada da query.
|
|
36
|
+
* @returns {object|null} Item normalizado.
|
|
37
|
+
*/
|
|
38
|
+
const normalizeItemRow = (row) => {
|
|
39
|
+
if (!row) return null;
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
id: row.id,
|
|
43
|
+
pack_id: row.pack_id,
|
|
44
|
+
sticker_id: row.sticker_id,
|
|
45
|
+
position: Number(row.position || 0),
|
|
46
|
+
emojis: parseJson(row.emojis, []),
|
|
47
|
+
accessibility_label: row.accessibility_label || null,
|
|
48
|
+
created_at: row.created_at,
|
|
49
|
+
asset: row.asset_id
|
|
50
|
+
? {
|
|
51
|
+
id: row.asset_id,
|
|
52
|
+
owner_jid: row.asset_owner_jid,
|
|
53
|
+
sha256: row.asset_sha256,
|
|
54
|
+
mimetype: row.asset_mimetype,
|
|
55
|
+
is_animated: row.asset_is_animated === 1 || row.asset_is_animated === true,
|
|
56
|
+
width: row.asset_width !== null && row.asset_width !== undefined ? Number(row.asset_width) : null,
|
|
57
|
+
height: row.asset_height !== null && row.asset_height !== undefined ? Number(row.asset_height) : null,
|
|
58
|
+
size_bytes: row.asset_size_bytes !== null && row.asset_size_bytes !== undefined ? Number(row.asset_size_bytes) : 0,
|
|
59
|
+
storage_path: row.asset_storage_path,
|
|
60
|
+
created_at: row.asset_created_at,
|
|
61
|
+
}
|
|
62
|
+
: null,
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Lista itens de um pack em ordem de posição.
|
|
68
|
+
*
|
|
69
|
+
* @param {string} packId ID do pack.
|
|
70
|
+
* @param {import('mysql2/promise').PoolConnection|null} [connection=null] Conexão transacional opcional.
|
|
71
|
+
* @returns {Promise<object[]>} Itens do pack.
|
|
72
|
+
*/
|
|
73
|
+
export async function listStickerPackItems(packId, connection = null) {
|
|
74
|
+
const rows = await executeQuery(
|
|
75
|
+
`SELECT
|
|
76
|
+
i.*,
|
|
77
|
+
a.id AS asset_id,
|
|
78
|
+
a.owner_jid AS asset_owner_jid,
|
|
79
|
+
a.sha256 AS asset_sha256,
|
|
80
|
+
a.mimetype AS asset_mimetype,
|
|
81
|
+
a.is_animated AS asset_is_animated,
|
|
82
|
+
a.width AS asset_width,
|
|
83
|
+
a.height AS asset_height,
|
|
84
|
+
a.size_bytes AS asset_size_bytes,
|
|
85
|
+
a.storage_path AS asset_storage_path,
|
|
86
|
+
a.created_at AS asset_created_at
|
|
87
|
+
FROM ${TABLES.STICKER_PACK_ITEM} i
|
|
88
|
+
LEFT JOIN ${TABLES.STICKER_ASSET} a ON a.id = i.sticker_id
|
|
89
|
+
WHERE i.pack_id = ?
|
|
90
|
+
ORDER BY i.position ASC`,
|
|
91
|
+
[packId],
|
|
92
|
+
connection,
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
return rows.map((row) => normalizeItemRow(row));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Lista itens de múltiplos packs em uma única consulta.
|
|
100
|
+
*
|
|
101
|
+
* @param {string[]} packIds IDs dos packs.
|
|
102
|
+
* @param {import('mysql2/promise').PoolConnection|null} [connection=null]
|
|
103
|
+
* @returns {Promise<object[]>}
|
|
104
|
+
*/
|
|
105
|
+
export async function listStickerPackItemsByPackIds(packIds, connection = null) {
|
|
106
|
+
if (!Array.isArray(packIds) || packIds.length === 0) return [];
|
|
107
|
+
const uniquePackIds = Array.from(new Set(packIds.filter(Boolean)));
|
|
108
|
+
if (!uniquePackIds.length) return [];
|
|
109
|
+
|
|
110
|
+
const placeholders = uniquePackIds.map(() => '?').join(', ');
|
|
111
|
+
const rows = await executeQuery(
|
|
112
|
+
`SELECT
|
|
113
|
+
i.*,
|
|
114
|
+
a.id AS asset_id,
|
|
115
|
+
a.owner_jid AS asset_owner_jid,
|
|
116
|
+
a.sha256 AS asset_sha256,
|
|
117
|
+
a.mimetype AS asset_mimetype,
|
|
118
|
+
a.is_animated AS asset_is_animated,
|
|
119
|
+
a.width AS asset_width,
|
|
120
|
+
a.height AS asset_height,
|
|
121
|
+
a.size_bytes AS asset_size_bytes,
|
|
122
|
+
a.storage_path AS asset_storage_path,
|
|
123
|
+
a.created_at AS asset_created_at
|
|
124
|
+
FROM ${TABLES.STICKER_PACK_ITEM} i
|
|
125
|
+
LEFT JOIN ${TABLES.STICKER_ASSET} a ON a.id = i.sticker_id
|
|
126
|
+
WHERE i.pack_id IN (${placeholders})
|
|
127
|
+
ORDER BY i.pack_id ASC, i.position ASC`,
|
|
128
|
+
uniquePackIds,
|
|
129
|
+
connection,
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
return rows.map((row) => normalizeItemRow(row));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Busca item do pack pelo sticker_id.
|
|
137
|
+
*
|
|
138
|
+
* @param {string} packId ID do pack.
|
|
139
|
+
* @param {string} stickerId ID do asset/sticker.
|
|
140
|
+
* @param {import('mysql2/promise').PoolConnection|null} [connection=null] Conexão transacional opcional.
|
|
141
|
+
* @returns {Promise<object|null>} Item encontrado.
|
|
142
|
+
*/
|
|
143
|
+
export async function getStickerPackItemByStickerId(packId, stickerId, connection = null) {
|
|
144
|
+
const rows = await executeQuery(
|
|
145
|
+
`SELECT i.* FROM ${TABLES.STICKER_PACK_ITEM} i
|
|
146
|
+
WHERE i.pack_id = ? AND i.sticker_id = ?
|
|
147
|
+
LIMIT 1`,
|
|
148
|
+
[packId, stickerId],
|
|
149
|
+
connection,
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
return normalizeItemRow(rows?.[0] || null);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Busca item pela posição ordinal no pack.
|
|
157
|
+
*
|
|
158
|
+
* @param {string} packId ID do pack.
|
|
159
|
+
* @param {number} position Posição do item.
|
|
160
|
+
* @param {import('mysql2/promise').PoolConnection|null} [connection=null] Conexão transacional opcional.
|
|
161
|
+
* @returns {Promise<object|null>} Item encontrado.
|
|
162
|
+
*/
|
|
163
|
+
export async function getStickerPackItemByPosition(packId, position, connection = null) {
|
|
164
|
+
const rows = await executeQuery(
|
|
165
|
+
`SELECT i.* FROM ${TABLES.STICKER_PACK_ITEM} i
|
|
166
|
+
WHERE i.pack_id = ? AND i.position = ?
|
|
167
|
+
LIMIT 1`,
|
|
168
|
+
[packId, position],
|
|
169
|
+
connection,
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
return normalizeItemRow(rows?.[0] || null);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Conta quantos itens existem em um pack.
|
|
177
|
+
*
|
|
178
|
+
* @param {string} packId ID do pack.
|
|
179
|
+
* @param {import('mysql2/promise').PoolConnection|null} [connection=null] Conexão transacional opcional.
|
|
180
|
+
* @returns {Promise<number>} Total de itens.
|
|
181
|
+
*/
|
|
182
|
+
export async function countStickerPackItems(packId, connection = null) {
|
|
183
|
+
const rows = await executeQuery(`SELECT COUNT(*) AS total FROM ${TABLES.STICKER_PACK_ITEM} WHERE pack_id = ?`, [packId], connection);
|
|
184
|
+
|
|
185
|
+
return Number(rows?.[0]?.total || 0);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Conta quantas referências um sticker possui em todos os packs.
|
|
190
|
+
*
|
|
191
|
+
* @param {string} stickerId ID do sticker/asset.
|
|
192
|
+
* @param {import('mysql2/promise').PoolConnection|null} [connection=null] Conexão transacional opcional.
|
|
193
|
+
* @returns {Promise<number>} Total de referências em packs.
|
|
194
|
+
*/
|
|
195
|
+
export async function countStickerPackItemRefsByStickerId(stickerId, connection = null) {
|
|
196
|
+
const rows = await executeQuery(`SELECT COUNT(*) AS total FROM ${TABLES.STICKER_PACK_ITEM} WHERE sticker_id = ?`, [stickerId], connection);
|
|
197
|
+
|
|
198
|
+
return Number(rows?.[0]?.total || 0);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Lista IDs de packs que referenciam um sticker.
|
|
203
|
+
*
|
|
204
|
+
* @param {string} stickerId ID do sticker/asset.
|
|
205
|
+
* @param {import('mysql2/promise').PoolConnection|null} [connection=null]
|
|
206
|
+
* @returns {Promise<string[]>}
|
|
207
|
+
*/
|
|
208
|
+
export async function listPackIdsByStickerId(stickerId, connection = null) {
|
|
209
|
+
const rows = await executeQuery(
|
|
210
|
+
`SELECT DISTINCT pack_id
|
|
211
|
+
FROM ${TABLES.STICKER_PACK_ITEM}
|
|
212
|
+
WHERE sticker_id = ?`,
|
|
213
|
+
[stickerId],
|
|
214
|
+
connection,
|
|
215
|
+
);
|
|
216
|
+
return (Array.isArray(rows) ? rows : []).map((row) => String(row?.pack_id || '')).filter(Boolean);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Obtém a maior posição atualmente usada no pack.
|
|
221
|
+
*
|
|
222
|
+
* @param {string} packId ID do pack.
|
|
223
|
+
* @param {import('mysql2/promise').PoolConnection|null} [connection=null] Conexão transacional opcional.
|
|
224
|
+
* @returns {Promise<number>} Maior posição encontrada.
|
|
225
|
+
*/
|
|
226
|
+
export async function getMaxStickerPackPosition(packId, connection = null) {
|
|
227
|
+
const rows = await executeQuery(`SELECT MAX(position) AS max_position FROM ${TABLES.STICKER_PACK_ITEM} WHERE pack_id = ?`, [packId], connection);
|
|
228
|
+
|
|
229
|
+
const maxValue = rows?.[0]?.max_position;
|
|
230
|
+
return maxValue !== null && maxValue !== undefined ? Number(maxValue) : 0;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Cria um novo item dentro de um pack.
|
|
235
|
+
*
|
|
236
|
+
* @param {object} item Dados do item.
|
|
237
|
+
* @param {import('mysql2/promise').PoolConnection|null} [connection=null] Conexão transacional opcional.
|
|
238
|
+
* @returns {Promise<object|null>} Item criado.
|
|
239
|
+
*/
|
|
240
|
+
export async function createStickerPackItem(item, connection = null) {
|
|
241
|
+
await executeQuery(
|
|
242
|
+
`INSERT INTO ${TABLES.STICKER_PACK_ITEM}
|
|
243
|
+
(id, pack_id, sticker_id, position, emojis, accessibility_label)
|
|
244
|
+
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
245
|
+
[item.id, item.pack_id, item.sticker_id, item.position, item.emojis ? JSON.stringify(item.emojis) : JSON.stringify([]), item.accessibility_label ?? null],
|
|
246
|
+
connection,
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
return getStickerPackItemByStickerId(item.pack_id, item.sticker_id, connection);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Atualiza metadados do item (emojis/acessibilidade).
|
|
254
|
+
*
|
|
255
|
+
* @param {string} packId ID do pack.
|
|
256
|
+
* @param {string} stickerId ID do sticker.
|
|
257
|
+
* @param {Record<string, unknown>} fields Campos alteráveis.
|
|
258
|
+
* @param {import('mysql2/promise').PoolConnection|null} [connection=null] Conexão transacional opcional.
|
|
259
|
+
* @returns {Promise<object|null>} Item atualizado.
|
|
260
|
+
*/
|
|
261
|
+
export async function updateStickerPackItemMetadata(packId, stickerId, fields, connection = null) {
|
|
262
|
+
const clauses = [];
|
|
263
|
+
const params = [];
|
|
264
|
+
|
|
265
|
+
if ('emojis' in fields) {
|
|
266
|
+
clauses.push('emojis = ?');
|
|
267
|
+
params.push(fields.emojis ? JSON.stringify(fields.emojis) : JSON.stringify([]));
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if ('accessibility_label' in fields) {
|
|
271
|
+
clauses.push('accessibility_label = ?');
|
|
272
|
+
params.push(fields.accessibility_label ?? null);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (!clauses.length) {
|
|
276
|
+
return getStickerPackItemByStickerId(packId, stickerId, connection);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
await executeQuery(
|
|
280
|
+
`UPDATE ${TABLES.STICKER_PACK_ITEM}
|
|
281
|
+
SET ${clauses.join(', ')}
|
|
282
|
+
WHERE pack_id = ? AND sticker_id = ?`,
|
|
283
|
+
[...params, packId, stickerId],
|
|
284
|
+
connection,
|
|
285
|
+
);
|
|
286
|
+
|
|
287
|
+
return getStickerPackItemByStickerId(packId, stickerId, connection);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Remove item por sticker_id e retorna o item removido.
|
|
292
|
+
*
|
|
293
|
+
* @param {string} packId ID do pack.
|
|
294
|
+
* @param {string} stickerId ID do sticker.
|
|
295
|
+
* @param {import('mysql2/promise').PoolConnection|null} [connection=null] Conexão transacional opcional.
|
|
296
|
+
* @returns {Promise<object|null>} Item removido.
|
|
297
|
+
*/
|
|
298
|
+
export async function removeStickerPackItemByStickerId(packId, stickerId, connection = null) {
|
|
299
|
+
const item = await getStickerPackItemByStickerId(packId, stickerId, connection);
|
|
300
|
+
if (!item) return null;
|
|
301
|
+
|
|
302
|
+
await executeQuery(
|
|
303
|
+
`DELETE FROM ${TABLES.STICKER_PACK_ITEM}
|
|
304
|
+
WHERE pack_id = ? AND sticker_id = ?`,
|
|
305
|
+
[packId, stickerId],
|
|
306
|
+
connection,
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
return item;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Remove item por posição e retorna o item removido.
|
|
314
|
+
*
|
|
315
|
+
* @param {string} packId ID do pack.
|
|
316
|
+
* @param {number} position Posição do item.
|
|
317
|
+
* @param {import('mysql2/promise').PoolConnection|null} [connection=null] Conexão transacional opcional.
|
|
318
|
+
* @returns {Promise<object|null>} Item removido.
|
|
319
|
+
*/
|
|
320
|
+
export async function removeStickerPackItemByPosition(packId, position, connection = null) {
|
|
321
|
+
const item = await getStickerPackItemByPosition(packId, position, connection);
|
|
322
|
+
if (!item) return null;
|
|
323
|
+
|
|
324
|
+
await executeQuery(
|
|
325
|
+
`DELETE FROM ${TABLES.STICKER_PACK_ITEM}
|
|
326
|
+
WHERE pack_id = ? AND position = ?`,
|
|
327
|
+
[packId, position],
|
|
328
|
+
connection,
|
|
329
|
+
);
|
|
330
|
+
|
|
331
|
+
return item;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Remove todos os itens de um pack.
|
|
336
|
+
*
|
|
337
|
+
* @param {string} packId ID do pack.
|
|
338
|
+
* @param {import('mysql2/promise').PoolConnection|null} [connection=null] Conexão transacional opcional.
|
|
339
|
+
* @returns {Promise<number>} Quantidade de linhas removidas.
|
|
340
|
+
*/
|
|
341
|
+
export async function removeStickerPackItemsByPackId(packId, connection = null) {
|
|
342
|
+
const result = await executeQuery(
|
|
343
|
+
`DELETE FROM ${TABLES.STICKER_PACK_ITEM}
|
|
344
|
+
WHERE pack_id = ?`,
|
|
345
|
+
[packId],
|
|
346
|
+
connection,
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
return Number(result?.affectedRows || 0);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Reordena automaticamente os itens após remover uma posição.
|
|
354
|
+
*
|
|
355
|
+
* @param {string} packId ID do pack.
|
|
356
|
+
* @param {number} removedPosition Posição removida.
|
|
357
|
+
* @param {import('mysql2/promise').PoolConnection|null} [connection=null] Conexão transacional opcional.
|
|
358
|
+
* @returns {Promise<void>}
|
|
359
|
+
*/
|
|
360
|
+
export async function shiftStickerPackPositionsAfter(packId, removedPosition, connection = null) {
|
|
361
|
+
const SHIFT_OFFSET = 10000;
|
|
362
|
+
|
|
363
|
+
// Fase 1: move posições para uma faixa temporária, evitando colisão no índice único (pack_id, position).
|
|
364
|
+
await executeQuery(
|
|
365
|
+
`UPDATE ${TABLES.STICKER_PACK_ITEM}
|
|
366
|
+
SET position = position + ?
|
|
367
|
+
WHERE pack_id = ? AND position > ?`,
|
|
368
|
+
[SHIFT_OFFSET, packId, removedPosition],
|
|
369
|
+
connection,
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
// Fase 2: normaliza removendo o offset e deslocando 1 posição para preencher o "gap" do item removido.
|
|
373
|
+
await executeQuery(
|
|
374
|
+
`UPDATE ${TABLES.STICKER_PACK_ITEM}
|
|
375
|
+
SET position = position - ?
|
|
376
|
+
WHERE pack_id = ? AND position > ?`,
|
|
377
|
+
[SHIFT_OFFSET + 1, packId, removedPosition + SHIFT_OFFSET],
|
|
378
|
+
connection,
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Aplica uma nova ordem explícita para os stickers do pack.
|
|
384
|
+
*
|
|
385
|
+
* @param {string} packId ID do pack.
|
|
386
|
+
* @param {string[]} orderedStickerIds IDs na ordem desejada.
|
|
387
|
+
* @param {import('mysql2/promise').PoolConnection|null} [connection=null] Conexão transacional opcional.
|
|
388
|
+
* @returns {Promise<void>}
|
|
389
|
+
*/
|
|
390
|
+
export async function bulkUpdateStickerPackPositions(packId, orderedStickerIds, connection = null) {
|
|
391
|
+
if (!Array.isArray(orderedStickerIds) || orderedStickerIds.length === 0) return;
|
|
392
|
+
|
|
393
|
+
await executeQuery(
|
|
394
|
+
`UPDATE ${TABLES.STICKER_PACK_ITEM}
|
|
395
|
+
SET position = position + 10000
|
|
396
|
+
WHERE pack_id = ?`,
|
|
397
|
+
[packId],
|
|
398
|
+
connection,
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
for (let index = 0; index < orderedStickerIds.length; index += 1) {
|
|
402
|
+
const stickerId = orderedStickerIds[index];
|
|
403
|
+
await executeQuery(
|
|
404
|
+
`UPDATE ${TABLES.STICKER_PACK_ITEM}
|
|
405
|
+
SET position = ?
|
|
406
|
+
WHERE pack_id = ? AND sticker_id = ?`,
|
|
407
|
+
[index + 1, packId, stickerId],
|
|
408
|
+
connection,
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Clona todos os itens de um pack para outro.
|
|
415
|
+
*
|
|
416
|
+
* @param {string} sourcePackId Pack de origem.
|
|
417
|
+
* @param {string} targetPackId Pack de destino.
|
|
418
|
+
* @param {import('mysql2/promise').PoolConnection|null} [connection=null] Conexão transacional opcional.
|
|
419
|
+
* @returns {Promise<void>}
|
|
420
|
+
*/
|
|
421
|
+
export async function cloneStickerPackItems(sourcePackId, targetPackId, connection = null) {
|
|
422
|
+
const items = await listStickerPackItems(sourcePackId, connection);
|
|
423
|
+
for (const item of items) {
|
|
424
|
+
await executeQuery(
|
|
425
|
+
`INSERT INTO ${TABLES.STICKER_PACK_ITEM}
|
|
426
|
+
(id, pack_id, sticker_id, position, emojis, accessibility_label)
|
|
427
|
+
VALUES (UUID(), ?, ?, ?, ?, ?)`,
|
|
428
|
+
[targetPackId, item.sticker_id, item.position, item.emojis ? JSON.stringify(item.emojis) : JSON.stringify([]), item.accessibility_label ?? null],
|
|
429
|
+
connection,
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
}
|