@omnizap-system/omnizap 2.6.0 → 2.6.2
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/.env.example +58 -13
- package/.github/workflows/ci.yml +5 -5
- package/.github/workflows/codeql.yml +1 -1
- package/.github/workflows/db-migration-check.yml +2 -2
- package/.github/workflows/dependency-review.yml +1 -1
- package/.github/workflows/deploy.yml +2 -2
- package/.github/workflows/release.yml +2 -2
- package/.github/workflows/security-attest-provenance.yml +2 -2
- package/.github/workflows/security-gitleaks.yml +13 -4
- package/.github/workflows/security-runner-hardening.yml +2 -2
- package/.github/workflows/security-scorecard.yml +1 -1
- package/.github/workflows/security-zap-baseline.yml +1 -1
- package/.github/workflows/security-zap-full-scan.yml +2 -1
- package/.github/workflows/security-zizmor.yml +1 -1
- package/.github/workflows/wiki-sync.yml +1 -1
- package/.gitleaksignore +9 -0
- package/CODE_OF_CONDUCT.md +2 -2
- package/GEMINI.md +64 -0
- package/README.md +52 -82
- package/SECURITY.md +1 -1
- package/app/config/index.js +2 -0
- package/app/configParts/adminIdentity.js +5 -5
- package/app/configParts/baileysConfig.js +230 -58
- package/app/configParts/groupUtils.js +5 -0
- package/app/configParts/messagePersistenceService.js +145 -4
- package/app/configParts/sessionConfig.js +157 -0
- package/app/connection/baileysCompatibility.test.js +1 -1
- package/app/connection/groupOwnerWriteStateResolver.js +109 -0
- package/app/connection/socketController.js +660 -158
- package/app/connection/socketController.multiSession.test.js +108 -0
- package/app/controllers/messageController.js +1 -1
- package/app/controllers/messagePipeline/commandMiddleware.js +12 -10
- package/app/controllers/messagePipeline/conversationMiddleware.js +2 -1
- package/app/controllers/messagePipeline/messagePipelineMiddlewares.test.js +104 -0
- package/app/controllers/messagePipeline/preProcessingMiddlewares.js +80 -2
- package/app/controllers/messageProcessingPipeline.js +93 -13
- package/app/controllers/messageProcessingPipeline.test.js +200 -0
- package/app/modules/adminModule/AGENT.md +1 -1
- package/app/modules/adminModule/commandConfig.json +3318 -1347
- package/app/modules/adminModule/groupCommandHandlers.js +858 -15
- package/app/modules/adminModule/groupCommandHandlers.test.js +378 -11
- package/app/modules/adminModule/groupWarningRepository.js +152 -0
- package/app/modules/aiModule/AGENT.md +47 -30
- package/app/modules/aiModule/aiConfigRuntime.js +1 -0
- package/app/modules/aiModule/catCommand.js +135 -27
- package/app/modules/aiModule/commandConfig.json +114 -28
- package/app/modules/analyticsModule/messageAnalysisEventRepository.js +54 -6
- package/app/modules/gameModule/AGENT.md +1 -1
- package/app/modules/gameModule/commandConfig.json +29 -0
- package/app/modules/menuModule/AGENT.md +1 -1
- package/app/modules/menuModule/commandConfig.json +45 -10
- package/app/modules/menuModule/menuCatalogService.js +190 -0
- package/app/modules/menuModule/menuCommandUsageRepository.js +109 -0
- package/app/modules/menuModule/menuDynamicService.js +511 -0
- package/app/modules/menuModule/menuDynamicService.test.js +141 -0
- package/app/modules/menuModule/menus.js +36 -5
- package/app/modules/playModule/AGENT.md +10 -5
- package/app/modules/playModule/commandConfig.json +140 -12
- package/app/modules/playModule/playCommand.js +1 -1417
- package/app/modules/playModule/playCommandConstants.js +80 -0
- package/app/modules/playModule/playCommandCore.js +361 -0
- package/app/modules/playModule/playCommandHandlers.js +41 -0
- package/app/modules/playModule/playCommandMediaClient.js +1872 -0
- package/app/modules/playModule/playConfigRuntime.js +245 -4
- package/app/modules/playModule/playModuleCriticalFlows.test.js +152 -0
- package/app/modules/quoteModule/AGENT.md +1 -1
- package/app/modules/quoteModule/commandConfig.json +29 -0
- package/app/modules/quoteModule/quoteCommand.js +3 -2
- package/app/modules/rpgPokemonModule/AGENT.md +1 -1
- package/app/modules/rpgPokemonModule/commandConfig.json +29 -0
- package/app/modules/rpgPokemonModule/rpgBattleCanvasRenderer.js +5 -4
- package/app/modules/rpgPokemonModule/rpgBattleService.test.js +2 -1
- package/app/modules/rpgPokemonModule/rpgPokemonDomain.js +2 -1
- package/app/modules/rpgPokemonModule/rpgPokemonService.js +38 -37
- package/app/modules/rpgPokemonModule/rpgProfileCanvasRenderer.js +4 -3
- package/app/modules/statsModule/AGENT.md +1 -1
- package/app/modules/statsModule/commandConfig.json +58 -0
- package/app/modules/statsModule/rankingCommon.js +5 -4
- package/app/modules/stickerModule/AGENT.md +1 -1
- package/app/modules/stickerModule/addStickerMetadata.js +4 -3
- package/app/modules/stickerModule/commandConfig.json +145 -0
- package/app/modules/stickerModule/stickerCommand.js +1 -1
- package/app/modules/stickerPackModule/AGENT.md +1 -1
- package/app/modules/stickerPackModule/autoPackCollectorService.js +5 -1
- package/app/modules/stickerPackModule/commandConfig.json +29 -0
- package/app/modules/stickerPackModule/semanticThemeClusterService.js +7 -6
- package/app/modules/stickerPackModule/stickerAutoPackByTagsRuntime.js +10 -9
- package/app/modules/stickerPackModule/stickerClassificationBackgroundRuntime.js +9 -8
- package/app/modules/stickerPackModule/stickerDomainEventConsumerRuntime.js +3 -2
- package/app/modules/stickerPackModule/stickerMarketplaceDriftService.js +2 -1
- package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +80 -58
- package/app/modules/stickerPackModule/stickerPackMarketplaceService.js +2 -1
- package/app/modules/stickerPackModule/stickerPackRepository.js +2 -1
- package/app/modules/stickerPackModule/stickerPackScoreSnapshotRuntime.js +5 -4
- package/app/modules/stickerPackModule/stickerPackService.js +13 -6
- package/app/modules/stickerPackModule/stickerStorageService.js +3 -2
- package/app/modules/stickerPackModule/stickerWorkerPipelineRuntime.js +2 -1
- package/app/modules/systemMetricsModule/AGENT.md +1 -1
- package/app/modules/systemMetricsModule/commandConfig.json +29 -0
- package/app/modules/systemMetricsModule/pingCommand.js +6 -5
- package/app/modules/tiktokModule/AGENT.md +1 -1
- package/app/modules/tiktokModule/commandConfig.json +29 -0
- package/app/modules/tiktokModule/tiktokCommand.js +2 -1
- package/app/modules/userModule/AGENT.md +1 -1
- package/app/modules/userModule/commandConfig.json +29 -0
- package/app/modules/userModule/userCommand.js +72 -23
- package/app/modules/waifuPicsModule/AGENT.md +57 -27
- package/app/modules/waifuPicsModule/commandConfig.json +87 -0
- package/app/modules/waifuPicsModule/waifuPicsCommand.js +3 -2
- package/app/observability/metrics.js +136 -0
- package/app/services/ai/commandConfigEnrichmentService.js +229 -47
- package/app/services/ai/conversationRouterService.js +4 -3
- package/app/services/ai/geminiService.js +132 -7
- package/app/services/ai/geminiService.test.js +59 -2
- package/app/services/ai/globalModuleAiHelpService.js +3 -2
- package/app/services/ai/messageCommandExecutionService.js +2 -1
- package/app/services/ai/moduleAiHelpCoreService.js +45 -14
- package/app/services/ai/moduleToolExecutorService.js +3 -2
- package/app/services/ai/moduleToolRegistryService.js +2 -1
- package/app/services/ai/toolCandidateSelectorService.js +6 -5
- package/app/services/auth/googleWebLinkService.js +3 -2
- package/app/services/auth/whatsappLoginLinkService.js +3 -2
- package/app/services/external/pokeApiService.js +4 -3
- package/app/services/group/groupMetadataService.js +24 -1
- package/app/services/infra/dbWriteQueue.js +57 -26
- package/app/services/infra/featureFlagService.js +2 -1
- package/app/services/messaging/captchaService.js +3 -2
- package/app/services/messaging/newsBroadcastService.js +846 -29
- package/app/services/multiSession/assignmentBalancerService.js +457 -0
- package/app/services/multiSession/groupOwnershipRepository.js +381 -0
- package/app/services/multiSession/groupOwnershipService.js +890 -0
- package/app/services/multiSession/groupOwnershipService.test.js +309 -0
- package/app/services/multiSession/sessionRegistryService.js +293 -0
- package/app/services/sticker/stickerFocusService.js +11 -10
- package/app/store/aiPromptStore.js +36 -19
- package/app/store/conversationSessionStore.js +7 -6
- package/app/store/groupConfigStore.js +41 -5
- package/app/store/premiumUserStore.js +21 -7
- package/app/utils/antiLink/antiLinkModule.js +352 -16
- package/app/workers/aiHelperContinuousLearningWorker.js +512 -0
- package/app/workers/aiLearningWorker.js +6 -5
- package/app/workers/commandConfigEnrichmentWorker.js +4 -3
- package/database/index.js +14 -8
- package/database/migrations/20260307_d0_hardening_down.sql +1 -1
- package/database/migrations/20260314_d7_canonical_sender_down.sql +1 -1
- package/database/migrations/20260406_d30_security_analytics_down.sql +1 -1
- package/database/migrations/20260411_d35_group_community_metadata_down.sql +59 -0
- package/database/migrations/20260411_d35_group_community_metadata_up.sql +62 -0
- package/database/migrations/20260412_d36_system_config_tables_down.sql +32 -0
- package/database/migrations/20260412_d36_system_config_tables_up.sql +66 -0
- package/database/migrations/20260413_d37_group_user_warnings_down.sql +11 -0
- package/database/migrations/20260413_d37_group_user_warnings_up.sql +24 -0
- package/database/migrations/20260414_d38_multi_session_foundation_down.sql +72 -0
- package/database/migrations/20260414_d38_multi_session_foundation_up.sql +125 -0
- package/database/migrations/20260414_d39_multi_session_cutover_down.sql +103 -0
- package/database/migrations/20260414_d39_multi_session_cutover_up.sql +83 -0
- package/database/schema.sql +102 -1
- package/docker-compose.yml +4 -1
- package/docs/compliance/acceptable-use-policy-2026-03-07.md +1 -1
- package/docs/compliance/dpa-b2b-standard-2026-03-07.md +1 -1
- package/docs/compliance/privacy-policy-2026-03-07.md +4 -4
- package/docs/security/dsar-lgpd-runbook-2026-03-07.md +1 -1
- package/docs/security/incident-response-lgpd-anpd-runbook-2026-03-07.md +1 -1
- package/docs/security/network-hardening-runbook-2026-03-07.md +53 -0
- package/docs/security/omnizap-static-security-headers.conf +25 -0
- package/docs/wiki/Home.md +1 -1
- package/ecosystem.prod.config.cjs +32 -12
- package/index.js +57 -23
- package/observability/alert-rules.yml +20 -0
- package/observability/grafana/dashboards/omnizap-system-admin.json +229 -0
- package/observability/mysql-setup.sql +4 -4
- package/observability/system-admin-observability.md +26 -0
- package/package.json +20 -6
- package/public/apple-touch-icon.png +0 -0
- package/public/comandos/commands-catalog.json +2853 -3326
- 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 +3 -2
- package/public/js/apps/commandsReactApp.js +280 -99
- package/public/js/apps/createPackApp.js +11 -10
- package/public/js/apps/homeReactApp.js +181 -130
- package/public/js/apps/loginReactApp.js +1 -1
- package/public/js/apps/stickersApp.js +263 -110
- package/public/js/apps/termsReactApp.js +73 -24
- package/public/js/apps/userApp.js +4 -3
- package/public/js/apps/userPasswordResetReactApp.js +406 -0
- package/public/js/apps/userReactApp.js +355 -280
- package/public/js/apps/userSystemAdmReactApp.js +1506 -0
- package/public/pages/api-docs.html +1 -1
- package/public/pages/aup.html +2 -2
- package/public/pages/dpa.html +3 -3
- package/public/pages/licenca.html +4 -4
- package/public/pages/login.html +1 -1
- package/public/pages/notice-and-takedown.html +2 -2
- package/public/pages/politica-de-privacidade.html +6 -6
- package/public/pages/seo-bot-whatsapp-para-grupo.html +3 -3
- package/public/pages/seo-bot-whatsapp-sem-programar.html +3 -3
- package/public/pages/seo-como-automatizar-avisos-no-whatsapp.html +3 -3
- package/public/pages/seo-como-criar-comandos-whatsapp.html +3 -3
- package/public/pages/seo-como-evitar-spam-no-whatsapp.html +3 -3
- package/public/pages/seo-como-moderar-grupo-whatsapp.html +3 -3
- package/public/pages/seo-como-organizar-comunidade-whatsapp.html +3 -3
- package/public/pages/seo-melhor-bot-whatsapp-para-grupos.html +3 -3
- package/public/pages/stickers-admin.html +1 -1
- package/public/pages/stickers-create.html +1 -1
- package/public/pages/stickers.html +6 -6
- package/public/pages/suboperadores.html +2 -2
- package/public/pages/termos-de-uso-texto-integral.html +6 -6
- package/public/pages/termos-de-uso.html +3 -3
- package/public/pages/user-password-reset.html +4 -5
- package/public/pages/user-systemadm.html +9 -463
- package/public/pages/user.html +2 -2
- package/scripts/clear-whatsapp-session.sh +123 -0
- package/scripts/core-ai-mode.mjs +163 -0
- package/scripts/deploy.sh +11 -1
- package/scripts/email-broadcast-terms-update.mjs +2 -1
- package/scripts/enrich-command-config-ux-openai.mjs +492 -0
- package/scripts/generate-commands-catalog.mjs +166 -2
- package/scripts/generate-module-agents.mjs +2 -1
- package/scripts/generate-seo-satellite-pages.mjs +5 -4
- package/scripts/github-deploy-notify.mjs +2 -1
- package/scripts/github-release-notify.mjs +25 -10
- package/scripts/new-whatsapp-session.sh +317 -0
- package/scripts/release.sh +2 -19
- package/scripts/security-smoketest.mjs +6 -5
- package/scripts/security-web-surface-check.mjs +218 -0
- package/scripts/sticker-catalog-loadtest.mjs +5 -4
- package/server/auth/googleWebAuth/googleWebAuthService.js +8 -7
- package/server/auth/jwt/webJwtService.js +1 -1
- package/server/auth/stickerCatalogAuthContext.js +2 -1
- package/server/auth/termsAcceptance/termsAcceptanceHandler.js +2 -1
- package/server/auth/userPassword/userPasswordAuthService.js +2 -1
- package/server/auth/userPassword/userPasswordRecoveryService.js +4 -3
- package/server/auth/webAccount/webAccountHandlers.js +9 -10
- package/server/controllers/admin/adminPanelHandlers.js +267 -16
- package/server/controllers/admin/systemAdminController.js +267 -0
- package/server/controllers/seo/stickerCatalogSeoContext.js +10 -9
- package/server/controllers/sticker/nonCatalogHandlers.js +2 -1
- package/server/controllers/sticker/stickerCatalogController.js +23 -36
- package/server/controllers/system/contactController.js +9 -17
- package/server/controllers/system/githubController.js +3 -2
- package/server/controllers/system/stickerCatalogSystemContext.js +41 -19
- package/server/controllers/system/systemController.js +254 -1
- package/server/controllers/system/systemMetricsController.js +2 -1
- package/server/controllers/userController.js +6 -0
- package/server/email/emailTemplateService.js +5 -3
- package/server/http/httpServer.js +11 -6
- package/server/middleware/rateLimit.js +2 -1
- package/server/middleware/securityHeaders.js +20 -1
- package/server/routes/admin/systemAdminRouter.js +6 -0
- package/server/routes/indexRouter.js +30 -6
- package/server/routes/observability/grafanaProxyRouter.js +254 -0
- package/server/routes/static/staticPageRouter.js +27 -1
- package/server/utils/publicContact.js +31 -0
- package/utils/time/timeModule.js +135 -0
- package/utils/time/timeModule.test.js +65 -0
- package/utils/whatsapp/contactEnv.js +39 -0
- package/vite.config.mjs +7 -1
- package/public/assets/images/brand-icon-192.png +0 -0
- package/scripts/sync-readme-snapshot.mjs +0 -133
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { now as __timeNow, nowIso as __timeNowIso, toUnixMs as __timeNowMs } from '#time';
|
|
1
2
|
import { pool } from '../../../database/index.js';
|
|
2
3
|
import { getJidUser, isGroupJid, normalizeJid } from '../../config/index.js';
|
|
3
4
|
import logger from '#logger';
|
|
@@ -504,7 +505,7 @@ const loadPocketItems = async (pocketName) => {
|
|
|
504
505
|
};
|
|
505
506
|
|
|
506
507
|
const getShopCatalog = async ({ forceRefresh = false } = {}) => {
|
|
507
|
-
const now =
|
|
508
|
+
const now = __timeNowMs();
|
|
508
509
|
if (!forceRefresh && dynamicShopCache.items && dynamicShopCache.expiresAt > now) {
|
|
509
510
|
return {
|
|
510
511
|
items: dynamicShopCache.items,
|
|
@@ -544,7 +545,7 @@ const getShopCatalog = async ({ forceRefresh = false } = {}) => {
|
|
|
544
545
|
dynamicShopCache.items = fallbackItems;
|
|
545
546
|
dynamicShopCache.index = fallbackIndex;
|
|
546
547
|
dynamicShopCache.aliasMap = aliasMap;
|
|
547
|
-
dynamicShopCache.expiresAt =
|
|
548
|
+
dynamicShopCache.expiresAt = __timeNowMs() + Math.min(SHOP_REFRESH_MS, 10 * 60 * 1000);
|
|
548
549
|
|
|
549
550
|
return { items: fallbackItems, index: fallbackIndex, aliasMap };
|
|
550
551
|
}
|
|
@@ -616,7 +617,7 @@ const resolveTravelEncounterPool = async (locationAreaKey) => {
|
|
|
616
617
|
if (!key) return [];
|
|
617
618
|
|
|
618
619
|
const cached = areaEncounterCache.get(key);
|
|
619
|
-
if (cached && cached.expiresAt >
|
|
620
|
+
if (cached && cached.expiresAt > __timeNowMs()) {
|
|
620
621
|
return cached.pool;
|
|
621
622
|
}
|
|
622
623
|
|
|
@@ -628,7 +629,7 @@ const resolveTravelEncounterPool = async (locationAreaKey) => {
|
|
|
628
629
|
.slice(0, 40);
|
|
629
630
|
areaEncounterCache.set(key, {
|
|
630
631
|
pool,
|
|
631
|
-
expiresAt:
|
|
632
|
+
expiresAt: __timeNowMs() + SHOP_REFRESH_MS,
|
|
632
633
|
});
|
|
633
634
|
return pool;
|
|
634
635
|
} catch (error) {
|
|
@@ -690,7 +691,7 @@ const formatMissionRewardSummary = (reward, label) => {
|
|
|
690
691
|
};
|
|
691
692
|
|
|
692
693
|
const ensureMissionStateForUpdate = async ({ ownerJid, connection }) => {
|
|
693
|
-
const refs = resolveMissionRefs(
|
|
694
|
+
const refs = resolveMissionRefs(__timeNow());
|
|
694
695
|
let row = await getMissionProgressByOwnerForUpdate(ownerJid, connection);
|
|
695
696
|
|
|
696
697
|
if (!row) {
|
|
@@ -792,7 +793,7 @@ const applyMissionEvent = async ({ ownerJid, eventKey, connection }) => {
|
|
|
792
793
|
reward: DAILY_MISSION_REWARD,
|
|
793
794
|
connection,
|
|
794
795
|
});
|
|
795
|
-
dailyClaimedAt =
|
|
796
|
+
dailyClaimedAt = __timeNow();
|
|
796
797
|
notices.push(formatMissionRewardSummary(DAILY_MISSION_REWARD, 'diária'));
|
|
797
798
|
}
|
|
798
799
|
|
|
@@ -803,7 +804,7 @@ const applyMissionEvent = async ({ ownerJid, eventKey, connection }) => {
|
|
|
803
804
|
reward: WEEKLY_MISSION_REWARD,
|
|
804
805
|
connection,
|
|
805
806
|
});
|
|
806
|
-
weeklyClaimedAt =
|
|
807
|
+
weeklyClaimedAt = __timeNow();
|
|
807
808
|
notices.push(formatMissionRewardSummary(WEEKLY_MISSION_REWARD, 'semanal'));
|
|
808
809
|
}
|
|
809
810
|
|
|
@@ -826,9 +827,9 @@ const applyMissionEvent = async ({ ownerJid, eventKey, connection }) => {
|
|
|
826
827
|
const buildBattleChatKey = (chatJid, ownerJid) => `${chatJid}::${ownerJid}`;
|
|
827
828
|
const extractSourceChatFromBattleKey = (battleChatKey) => String(battleChatKey || '').split('::')[0] || null;
|
|
828
829
|
|
|
829
|
-
const nowPlusTtlDate = () => new Date(
|
|
830
|
-
const nowPlusRaidTtlDate = () => new Date(
|
|
831
|
-
const nowPlusPvpTtlDate = () => new Date(
|
|
830
|
+
const nowPlusTtlDate = () => new Date(__timeNowMs() + BATTLE_TTL_MS);
|
|
831
|
+
const nowPlusRaidTtlDate = () => new Date(__timeNowMs() + RAID_TTL_MS);
|
|
832
|
+
const nowPlusPvpTtlDate = () => new Date(__timeNowMs() + PVP_TTL_MS);
|
|
832
833
|
|
|
833
834
|
const parseBattleSnapshot = (battleState) => {
|
|
834
835
|
const snapshot = battleState?.enemy_snapshot_json;
|
|
@@ -844,9 +845,9 @@ const toDateSafe = (value) => {
|
|
|
844
845
|
return date;
|
|
845
846
|
};
|
|
846
847
|
|
|
847
|
-
const toDurationSeconds = (startedAt, endedAt =
|
|
848
|
+
const toDurationSeconds = (startedAt, endedAt = __timeNow()) => {
|
|
848
849
|
const start = toDateSafe(startedAt);
|
|
849
|
-
const end = toDateSafe(endedAt) ||
|
|
850
|
+
const end = toDateSafe(endedAt) || __timeNow();
|
|
850
851
|
if (!start) return 0;
|
|
851
852
|
const delta = (end.getTime() - start.getTime()) / 1000;
|
|
852
853
|
if (!Number.isFinite(delta) || delta < 0) return 0;
|
|
@@ -864,7 +865,7 @@ const recordBattleDurationFromSnapshot = ({ snapshot, outcome }) => {
|
|
|
864
865
|
};
|
|
865
866
|
|
|
866
867
|
const markSessionSample = (ownerJid) => {
|
|
867
|
-
const now =
|
|
868
|
+
const now = __timeNowMs();
|
|
868
869
|
const tracker = sessionTrackerMap.get(ownerJid);
|
|
869
870
|
if (!tracker || now - tracker.lastAt > SESSION_IDLE_MS) {
|
|
870
871
|
sessionTrackerMap.set(ownerJid, {
|
|
@@ -879,14 +880,14 @@ const markSessionSample = (ownerJid) => {
|
|
|
879
880
|
recordRpgSessionDuration(durationSec);
|
|
880
881
|
};
|
|
881
882
|
|
|
882
|
-
const toUtcDateOnly = (value =
|
|
883
|
+
const toUtcDateOnly = (value = __timeNow()) => {
|
|
883
884
|
const date = value instanceof Date ? value : new Date(value);
|
|
884
885
|
if (Number.isNaN(date.getTime())) return null;
|
|
885
886
|
return date.toISOString().slice(0, 10);
|
|
886
887
|
};
|
|
887
888
|
|
|
888
889
|
const getDateOnlyOffset = (days = 0) => {
|
|
889
|
-
const now =
|
|
890
|
+
const now = __timeNow();
|
|
890
891
|
const atMidnightUtc = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
|
|
891
892
|
atMidnightUtc.setUTCDate(atMidnightUtc.getUTCDate() + days);
|
|
892
893
|
return toUtcDateOnly(atMidnightUtc);
|
|
@@ -894,14 +895,14 @@ const getDateOnlyOffset = (days = 0) => {
|
|
|
894
895
|
|
|
895
896
|
const toDateFromDateOnly = (dateOnly, plusDays = 0) => {
|
|
896
897
|
const source = String(dateOnly || '').trim();
|
|
897
|
-
if (!source) return
|
|
898
|
+
if (!source) return __timeNow();
|
|
898
899
|
const date = new Date(`${source}T00:00:00.000Z`);
|
|
899
|
-
if (Number.isNaN(date.getTime())) return
|
|
900
|
+
if (Number.isNaN(date.getTime())) return __timeNow();
|
|
900
901
|
date.setUTCDate(date.getUTCDate() + plusDays);
|
|
901
902
|
return date;
|
|
902
903
|
};
|
|
903
904
|
|
|
904
|
-
const getCurrentMissionRefs = () => resolveMissionRefs(
|
|
905
|
+
const getCurrentMissionRefs = () => resolveMissionRefs(__timeNow());
|
|
905
906
|
|
|
906
907
|
const getCurrentWeekRefDate = () => getCurrentMissionRefs().weeklyRefDate;
|
|
907
908
|
|
|
@@ -1245,7 +1246,7 @@ const resolveOpponentJidFromArgs = async ({ actionArgs = [], mentionedJids = []
|
|
|
1245
1246
|
const getCooldownSecondsLeft = (ownerJid) => {
|
|
1246
1247
|
const lastAt = playerCooldownMap.get(ownerJid);
|
|
1247
1248
|
if (!lastAt) return 0;
|
|
1248
|
-
const diff =
|
|
1249
|
+
const diff = __timeNowMs() - lastAt;
|
|
1249
1250
|
if (diff >= COOLDOWN_MS) return 0;
|
|
1250
1251
|
return Math.max(1, Math.ceil((COOLDOWN_MS - diff) / 1000));
|
|
1251
1252
|
};
|
|
@@ -1253,7 +1254,7 @@ const getCooldownSecondsLeft = (ownerJid) => {
|
|
|
1253
1254
|
const getPvpCooldownSecondsLeft = (ownerJid) => {
|
|
1254
1255
|
const lastAt = pvpCooldownMap.get(ownerJid);
|
|
1255
1256
|
if (!lastAt) return 0;
|
|
1256
|
-
const diff =
|
|
1257
|
+
const diff = __timeNowMs() - lastAt;
|
|
1257
1258
|
if (diff >= PVP_CHALLENGE_COOLDOWN_MS) return 0;
|
|
1258
1259
|
return Math.max(1, Math.ceil((PVP_CHALLENGE_COOLDOWN_MS - diff) / 1000));
|
|
1259
1260
|
};
|
|
@@ -1263,11 +1264,11 @@ const shouldApplyCooldown = (action) => {
|
|
|
1263
1264
|
};
|
|
1264
1265
|
|
|
1265
1266
|
const touchCooldown = (ownerJid) => {
|
|
1266
|
-
playerCooldownMap.set(ownerJid,
|
|
1267
|
+
playerCooldownMap.set(ownerJid, __timeNowMs());
|
|
1267
1268
|
};
|
|
1268
1269
|
|
|
1269
1270
|
const touchPvpCooldown = (ownerJid) => {
|
|
1270
|
-
pvpCooldownMap.set(ownerJid,
|
|
1271
|
+
pvpCooldownMap.set(ownerJid, __timeNowMs());
|
|
1271
1272
|
};
|
|
1272
1273
|
|
|
1273
1274
|
const loadPokemonDisplayData = async (pokemonRow) => {
|
|
@@ -2077,7 +2078,7 @@ const handleProfile = async ({ ownerJid, chatJid, commandPrefix }) => {
|
|
|
2077
2078
|
text,
|
|
2078
2079
|
profileCanvas: {
|
|
2079
2080
|
trainerLabel: toMentionLabel(ownerJid),
|
|
2080
|
-
generatedAtLabel: toDateLabel(
|
|
2081
|
+
generatedAtLabel: toDateLabel(__timeNowMs()),
|
|
2081
2082
|
activePokemon: {
|
|
2082
2083
|
displayName: activeDisplay?.displayName || activeDisplay?.name || null,
|
|
2083
2084
|
name: activeDisplay?.name || null,
|
|
@@ -2273,7 +2274,7 @@ const handleExplore = async ({ ownerJid, chatJid, commandPrefix }) => {
|
|
|
2273
2274
|
|
|
2274
2275
|
const battleSnapshot = {
|
|
2275
2276
|
turn: 1,
|
|
2276
|
-
startedAt:
|
|
2277
|
+
startedAt: __timeNowIso(),
|
|
2277
2278
|
mode: 'wild',
|
|
2278
2279
|
biome: biome
|
|
2279
2280
|
? {
|
|
@@ -2397,7 +2398,7 @@ const handleGym = async ({ ownerJid, chatJid, commandPrefix }) => {
|
|
|
2397
2398
|
|
|
2398
2399
|
const battleSnapshot = {
|
|
2399
2400
|
turn: 1,
|
|
2400
|
-
startedAt:
|
|
2401
|
+
startedAt: __timeNowIso(),
|
|
2401
2402
|
mode: 'gym',
|
|
2402
2403
|
biome: biome
|
|
2403
2404
|
? {
|
|
@@ -2786,7 +2787,7 @@ const requireInventoryItem = async ({ ownerJid, itemKey, connection }) => {
|
|
|
2786
2787
|
const getEconomyRescueSecondsLeft = (ownerJid) => {
|
|
2787
2788
|
const lastAt = economyRescueMap.get(ownerJid);
|
|
2788
2789
|
if (!lastAt) return 0;
|
|
2789
|
-
const diff =
|
|
2790
|
+
const diff = __timeNowMs() - lastAt;
|
|
2790
2791
|
if (diff >= ECONOMY_RESCUE_COOLDOWN_MS) return 0;
|
|
2791
2792
|
return Math.max(1, Math.ceil((ECONOMY_RESCUE_COOLDOWN_MS - diff) / 1000));
|
|
2792
2793
|
};
|
|
@@ -2813,7 +2814,7 @@ const tryApplyEconomyRescue = async ({ ownerJid, player, activePokemon = null, c
|
|
|
2813
2814
|
const nextGold = currentGold + ECONOMY_RESCUE_GOLD;
|
|
2814
2815
|
await updatePlayerGoldOnly({ jid: ownerJid, gold: nextGold }, connection);
|
|
2815
2816
|
await addInventoryItem({ ownerJid, itemKey: 'potion', quantity: ECONOMY_RESCUE_POTION_QTY }, connection);
|
|
2816
|
-
economyRescueMap.set(ownerJid,
|
|
2817
|
+
economyRescueMap.set(ownerJid, __timeNowMs());
|
|
2817
2818
|
|
|
2818
2819
|
logger.info('Auxílio econômico aplicado para evitar travamento no início.', {
|
|
2819
2820
|
ownerJid,
|
|
@@ -4421,7 +4422,7 @@ const toRaidView = (raidRow) => {
|
|
|
4421
4422
|
const isDateExpired = (value) => {
|
|
4422
4423
|
const date = toDateSafe(value);
|
|
4423
4424
|
if (!date) return false;
|
|
4424
|
-
return date.getTime() <=
|
|
4425
|
+
return date.getTime() <= __timeNowMs();
|
|
4425
4426
|
};
|
|
4426
4427
|
|
|
4427
4428
|
const formatParticipantRows = (participants = []) =>
|
|
@@ -4441,7 +4442,7 @@ const resolveRaidRewards = ({ bossLevel, totalDamage, participantDamage }) => {
|
|
|
4441
4442
|
|
|
4442
4443
|
const buildPvpSnapshotState = ({ challengerJid, challengerPokemonId, challengerSnapshot, opponentJid, opponentPokemonId, opponentSnapshot, turnJid }) => {
|
|
4443
4444
|
return {
|
|
4444
|
-
startedAt:
|
|
4445
|
+
startedAt: __timeNowIso(),
|
|
4445
4446
|
turn: 1,
|
|
4446
4447
|
players: {
|
|
4447
4448
|
[challengerJid]: {
|
|
@@ -4919,7 +4920,7 @@ const handleRaid = async ({ ownerJid, chatJid, commandPrefix, actionArgs = [] })
|
|
|
4919
4920
|
currentHp: bossMaxHp,
|
|
4920
4921
|
};
|
|
4921
4922
|
|
|
4922
|
-
const startedAt =
|
|
4923
|
+
const startedAt = __timeNow();
|
|
4923
4924
|
const endsAt = nowPlusRaidTtlDate();
|
|
4924
4925
|
await upsertRaidState(
|
|
4925
4926
|
{
|
|
@@ -5435,7 +5436,7 @@ const handlePvpQueue = async ({ ownerJid, chatJid, commandPrefix, actionArgs = [
|
|
|
5435
5436
|
{
|
|
5436
5437
|
chatJid,
|
|
5437
5438
|
ownerJid: canonicalOwnerJid,
|
|
5438
|
-
expiresAt: new Date(
|
|
5439
|
+
expiresAt: new Date(__timeNowMs() + PVP_QUEUE_TTL_MS),
|
|
5439
5440
|
},
|
|
5440
5441
|
connection,
|
|
5441
5442
|
);
|
|
@@ -5661,7 +5662,7 @@ const handlePvp = async ({ ownerJid, chatJid, commandPrefix, actionArgs = [], me
|
|
|
5661
5662
|
{
|
|
5662
5663
|
id: challenge.id,
|
|
5663
5664
|
status: 'active',
|
|
5664
|
-
startedAt:
|
|
5665
|
+
startedAt: __timeNow(),
|
|
5665
5666
|
expiresAt: nowPlusPvpTtlDate(),
|
|
5666
5667
|
},
|
|
5667
5668
|
connection,
|
|
@@ -5721,7 +5722,7 @@ const handlePvp = async ({ ownerJid, chatJid, commandPrefix, actionArgs = [], me
|
|
|
5721
5722
|
status: 'finished',
|
|
5722
5723
|
winnerJid: opponentJid,
|
|
5723
5724
|
turnJid: null,
|
|
5724
|
-
expiresAt:
|
|
5725
|
+
expiresAt: __timeNow(),
|
|
5725
5726
|
},
|
|
5726
5727
|
connection,
|
|
5727
5728
|
);
|
|
@@ -5797,7 +5798,7 @@ const handlePvp = async ({ ownerJid, chatJid, commandPrefix, actionArgs = [], me
|
|
|
5797
5798
|
status: 'finished',
|
|
5798
5799
|
winnerJid: toInt(me?.pokemon?.currentHp, 0) > 0 ? canonicalOwnerJid : opponentJid,
|
|
5799
5800
|
turnJid: null,
|
|
5800
|
-
expiresAt:
|
|
5801
|
+
expiresAt: __timeNow(),
|
|
5801
5802
|
},
|
|
5802
5803
|
connection,
|
|
5803
5804
|
);
|
|
@@ -5951,7 +5952,7 @@ const handlePvp = async ({ ownerJid, chatJid, commandPrefix, actionArgs = [], me
|
|
|
5951
5952
|
winnerJid,
|
|
5952
5953
|
turnJid: null,
|
|
5953
5954
|
battleSnapshot: nextSnapshot,
|
|
5954
|
-
expiresAt:
|
|
5955
|
+
expiresAt: __timeNow(),
|
|
5955
5956
|
},
|
|
5956
5957
|
connection,
|
|
5957
5958
|
);
|
|
@@ -6207,7 +6208,7 @@ const handleTrade = async ({ ownerJid, chatJid, commandPrefix, actionArgs = [],
|
|
|
6207
6208
|
receiverJid,
|
|
6208
6209
|
proposerOffer,
|
|
6209
6210
|
receiverOffer,
|
|
6210
|
-
expiresAt: new Date(
|
|
6211
|
+
expiresAt: new Date(__timeNowMs() + TRADE_TTL_MS),
|
|
6211
6212
|
},
|
|
6212
6213
|
connection,
|
|
6213
6214
|
);
|
|
@@ -6284,7 +6285,7 @@ const handleTrade = async ({ ownerJid, chatJid, commandPrefix, actionArgs = [],
|
|
|
6284
6285
|
{
|
|
6285
6286
|
id: offer.id,
|
|
6286
6287
|
status: 'accepted',
|
|
6287
|
-
acceptedAt:
|
|
6288
|
+
acceptedAt: __timeNow(),
|
|
6288
6289
|
},
|
|
6289
6290
|
connection,
|
|
6290
6291
|
);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { now as __timeNow, nowIso as __timeNowIso, toUnixMs as __timeNowMs } from '#time';
|
|
1
2
|
import axios from 'axios';
|
|
2
3
|
import { createCanvas, loadImage } from 'canvas';
|
|
3
4
|
import logger from '#logger';
|
|
@@ -75,7 +76,7 @@ const drawRoundRect = (ctx, x, y, width, height, radius, fillStyle) => {
|
|
|
75
76
|
|
|
76
77
|
const cleanupImageCache = () => {
|
|
77
78
|
if (imageCache.size <= IMAGE_CACHE_LIMIT) return;
|
|
78
|
-
const now =
|
|
79
|
+
const now = __timeNowMs();
|
|
79
80
|
for (const [key, value] of imageCache.entries()) {
|
|
80
81
|
if (!value || value.expiresAt <= now) imageCache.delete(key);
|
|
81
82
|
}
|
|
@@ -90,7 +91,7 @@ const resolveImage = async (url) => {
|
|
|
90
91
|
if (!normalized) return null;
|
|
91
92
|
|
|
92
93
|
const cached = imageCache.get(normalized);
|
|
93
|
-
if (cached && cached.expiresAt >
|
|
94
|
+
if (cached && cached.expiresAt > __timeNowMs()) return cached.image;
|
|
94
95
|
|
|
95
96
|
try {
|
|
96
97
|
const response = await axios.get(normalized, {
|
|
@@ -101,7 +102,7 @@ const resolveImage = async (url) => {
|
|
|
101
102
|
const image = await loadImage(Buffer.from(response.data));
|
|
102
103
|
imageCache.set(normalized, {
|
|
103
104
|
image,
|
|
104
|
-
expiresAt:
|
|
105
|
+
expiresAt: __timeNowMs() + IMAGE_CACHE_TTL_MS,
|
|
105
106
|
});
|
|
106
107
|
cleanupImageCache();
|
|
107
108
|
return image;
|
|
@@ -7,7 +7,7 @@ Este arquivo e destinado a agentes de IA para gerar respostas no contexto dos co
|
|
|
7
7
|
- arquivo_base: `app/modules/statsModule/commandConfig.json`
|
|
8
8
|
- schema_version: `2.0.0`
|
|
9
9
|
- module_enabled: `true`
|
|
10
|
-
- generated_at: `2026-03-
|
|
10
|
+
- generated_at: `2026-03-17T04:04:14.195Z`
|
|
11
11
|
|
|
12
12
|
## Escopo do Modulo
|
|
13
13
|
|
|
@@ -335,6 +335,35 @@
|
|
|
335
335
|
"schema": "legacy_v1_and_v2",
|
|
336
336
|
"legacy_name": "classificacao",
|
|
337
337
|
"legacy_fields_present": ["descricao", "metodos_de_uso", "permissao_necessaria", "local_de_uso", "informacoes_coletadas", "argumentos", "pre_condicoes", "dependencias_externas", "efeitos_colaterais", "observabilidade", "privacidade", "acesso", "limite_uso_por_plano"]
|
|
338
|
+
},
|
|
339
|
+
"user_experience": {
|
|
340
|
+
"resumo_usuario": "Mostra os 5 membros mais ativos do grupo. Não requer Premium.",
|
|
341
|
+
"quando_usar": ["Quando quiser ver quem participa mais no grupo.", "Antes de uma discussão ou decisão, para identificar os participantes mais ativos.", "Para comparar participação entre diferentes períodos."],
|
|
342
|
+
"exemplos_reais": [
|
|
343
|
+
{
|
|
344
|
+
"situacao": "Quero ver quem são os 5 membros mais ativos no grupo agora.",
|
|
345
|
+
"comando": "<prefix>classificacao",
|
|
346
|
+
"resposta_esperada": "Top 5 ativos no grupo: 1) @usuario1, 2) @usuario2, 3) @usuario3, 4) @usuario4, 5) @usuario5.",
|
|
347
|
+
"variacao": "<prefix>rank."
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
"situacao": "Quero o mesmo resultado usando outro atalho.",
|
|
351
|
+
"comando": "<prefix>rank",
|
|
352
|
+
"resposta_esperada": "Top 5 ativos no grupo: 1) @usuario1, 2) @usuario2, 3) @usuario3, 4) @usuario4, 5) @usuario5.",
|
|
353
|
+
"variacao": "<prefix>classificacao."
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
"situacao": "Outra forma rápida de ver o top 5.",
|
|
357
|
+
"comando": "<prefix>top5",
|
|
358
|
+
"resposta_esperada": "Top 5 ativos no grupo: 1) @usuario1, 2) @usuario2, 3) @usuario3, 4) @usuario4, 5) @usuario5.",
|
|
359
|
+
"variacao": "<prefix>classificacao."
|
|
360
|
+
}
|
|
361
|
+
],
|
|
362
|
+
"resposta_esperada": ["A lista com os 5 membros mais ativos no grupo é exibida."],
|
|
363
|
+
"erros_comuns_usuario": ["Não está em um grupo ao enviar o comando.", "Ainda não fez login com Google no app.", "Formato do comando incorreto; use um dos métodos de uso: <prefix>classificacao, <prefix>rank, <prefix>top5.", "O grupo não possui participantes ativos suficientes."],
|
|
364
|
+
"passos_se_der_erro": ["Confira se você está dentro de um grupo.", "Verifique se você está logado com Google.", "Envie o comando correto: <prefix>classificacao, <prefix>rank ou <prefix>top5.", "Tente novamente em poucos segundos.", "Se o erro persistir, peça para o admin revisar as permissões."],
|
|
365
|
+
"resumo_usuario_origem": "auto_ia_assistida",
|
|
366
|
+
"resumo_usuario_revisao_pendente": true
|
|
338
367
|
}
|
|
339
368
|
},
|
|
340
369
|
{
|
|
@@ -531,6 +560,35 @@
|
|
|
531
560
|
"schema": "legacy_v1_and_v2",
|
|
532
561
|
"legacy_name": "classificacaoglobal",
|
|
533
562
|
"legacy_fields_present": ["descricao", "metodos_de_uso", "permissao_necessaria", "local_de_uso", "informacoes_coletadas", "argumentos", "pre_condicoes", "dependencias_externas", "efeitos_colaterais", "observabilidade", "privacidade", "acesso", "limite_uso_por_plano"]
|
|
563
|
+
},
|
|
564
|
+
"user_experience": {
|
|
565
|
+
"resumo_usuario": "Mostra o top 5 global de atividade. Use para ver quem lidera a atividade mundial e comparar com seu desempenho.",
|
|
566
|
+
"quando_usar": ["Quero saber quem está no topo da atividade global agora.", "Quero comparar meu desempenho com o ranking global.", "Preciso de uma visão rápida do ranking mundial sem dados locais."],
|
|
567
|
+
"exemplos_reais": [
|
|
568
|
+
{
|
|
569
|
+
"situacao": "Quero ver o ranking global rapidamente.",
|
|
570
|
+
"comando": "<prefix>classificacaoglobal",
|
|
571
|
+
"resposta_esperada": "Top 5 global de atividade exibidos com nomes e pontos. Ex.: 1) Nome - 980 pts, 2) Nome2 - 950 pts, ...",
|
|
572
|
+
"variacao": "<prefix>globalrank."
|
|
573
|
+
},
|
|
574
|
+
{
|
|
575
|
+
"situacao": "Quero usar a outra forma de comando para o ranking.",
|
|
576
|
+
"comando": "<prefix>globalrank",
|
|
577
|
+
"resposta_esperada": "Top 5 global de atividade exibidos com nomes e pontos.",
|
|
578
|
+
"variacao": "<prefix>classificacaoglobal."
|
|
579
|
+
},
|
|
580
|
+
{
|
|
581
|
+
"situacao": "Não estou logado com Google e tento ver o ranking.",
|
|
582
|
+
"comando": "<prefix>classificacaoglobal",
|
|
583
|
+
"resposta_esperada": "Você precisa estar logado com sua conta Google para ver o ranking global.",
|
|
584
|
+
"variacao": "Sem login Google."
|
|
585
|
+
}
|
|
586
|
+
],
|
|
587
|
+
"resposta_esperada": ["Top 5 global de atividade exibidos com nomes e pontos.", "Se não houver dados, será exibida mensagem informando a ausência de resultados para o ranking global."],
|
|
588
|
+
"erros_comuns_usuario": ["Esquecer o prefixo no início do comando.", "Digitar o comando com espaços extras ou caracteres não reconhecidos.", "Tentar usar sem estar logado com Google (googleLogin requerido).", "Usar uma forma de comando incorreta ou digitá-lo com erro de grafia."],
|
|
589
|
+
"passos_se_der_erro": ["Confira se está logado com a conta Google ligada.", "Digite novamente um dos comandos válidos: <prefix>classificacaoglobal ou <prefix>globalrank.", "Verifique se não há espaço extra ou caracteres estranhos no comando.", "Se o problema persistir, peça ajuda e informe a mensagem de erro e o comando utilizado."],
|
|
590
|
+
"resumo_usuario_origem": "auto_ia_assistida",
|
|
591
|
+
"resumo_usuario_revisao_pendente": true
|
|
534
592
|
}
|
|
535
593
|
}
|
|
536
594
|
],
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { now as __timeNow, nowIso as __timeNowIso, toUnixMs as __timeNowMs } from '#time';
|
|
1
2
|
import { createCanvas, loadImage } from 'canvas';
|
|
2
3
|
import { executeQuery } from '../../../database/index.js';
|
|
3
4
|
import { getJidUser, getProfilePicBuffer, normalizeJid } from '../../config/index.js';
|
|
@@ -179,17 +180,17 @@ const getCachedProfilePic = (jid) => {
|
|
|
179
180
|
const entry = PROFILE_PIC_CACHE.get(jid);
|
|
180
181
|
if (!entry) return null;
|
|
181
182
|
const lastAccess = entry.lastAccess || entry.createdAt || 0;
|
|
182
|
-
if (
|
|
183
|
+
if (__timeNowMs() - lastAccess > PROFILE_CACHE_TTL_MS) {
|
|
183
184
|
PROFILE_PIC_CACHE.delete(jid);
|
|
184
185
|
return null;
|
|
185
186
|
}
|
|
186
|
-
entry.lastAccess =
|
|
187
|
+
entry.lastAccess = __timeNowMs();
|
|
187
188
|
return entry.buffer || null;
|
|
188
189
|
};
|
|
189
190
|
|
|
190
191
|
const setCachedProfilePic = (jid, buffer) => {
|
|
191
192
|
if (!jid || !buffer) return;
|
|
192
|
-
PROFILE_PIC_CACHE.set(jid, { buffer, createdAt:
|
|
193
|
+
PROFILE_PIC_CACHE.set(jid, { buffer, createdAt: __timeNowMs(), lastAccess: __timeNowMs() });
|
|
193
194
|
if (PROFILE_PIC_CACHE.size > PROFILE_CACHE_LIMIT) {
|
|
194
195
|
const oldestKey = Array.from(PROFILE_PIC_CACHE.entries()).sort((a, b) => (a[1].lastAccess || a[1].createdAt || 0) - (b[1].lastAccess || b[1].createdAt || 0))[0]?.[0];
|
|
195
196
|
if (oldestKey) PROFILE_PIC_CACHE.delete(oldestKey);
|
|
@@ -1292,7 +1293,7 @@ export const renderRankingImage = async ({ sock, remoteJid, rows, totalMessages,
|
|
|
1292
1293
|
}
|
|
1293
1294
|
|
|
1294
1295
|
const footerY = height - 36;
|
|
1295
|
-
const updatedAt = formatDate(
|
|
1296
|
+
const updatedAt = formatDate(__timeNow());
|
|
1296
1297
|
ctx.fillStyle = 'rgba(148, 163, 184, 0.7)';
|
|
1297
1298
|
ctx.font = uiFont(15, 500);
|
|
1298
1299
|
ctx.textAlign = 'left';
|
|
@@ -7,7 +7,7 @@ Este arquivo e destinado a agentes de IA para gerar respostas no contexto dos co
|
|
|
7
7
|
- arquivo_base: `app/modules/stickerModule/commandConfig.json`
|
|
8
8
|
- schema_version: `2.0.0`
|
|
9
9
|
- module_enabled: `true`
|
|
10
|
-
- generated_at: `2026-03-
|
|
10
|
+
- generated_at: `2026-03-17T04:04:14.195Z`
|
|
11
11
|
|
|
12
12
|
## Escopo do Modulo
|
|
13
13
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { now as __timeNow, nowIso as __timeNowIso, toUnixMs as __timeNowMs } from '#time';
|
|
1
2
|
import fs from 'node:fs/promises';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import { spawn } from 'node:child_process';
|
|
@@ -154,11 +155,11 @@ function normalizeMetadataText(value, fallback = '') {
|
|
|
154
155
|
*/
|
|
155
156
|
export async function addStickerMetadata(stickerPath, packName, packAuthor, replaceContext = {}) {
|
|
156
157
|
const { senderName = '', userId = '' } = replaceContext;
|
|
157
|
-
const now =
|
|
158
|
+
const now = __timeNow();
|
|
158
159
|
const pad = (n) => n.toString().padStart(2, '0');
|
|
159
160
|
const dataAtual = `${pad(now.getDate())}/${pad(now.getMonth() + 1)}/${now.getFullYear()}`;
|
|
160
161
|
const horaAtual = `${pad(now.getHours())}:${pad(now.getMinutes())}`;
|
|
161
|
-
const baseSenderName = normalizeMetadataText(senderName, '
|
|
162
|
+
const baseSenderName = normalizeMetadataText(senderName, 'Omnizap');
|
|
162
163
|
const resolvedUserId = String(getJidUser(userId) || userId || '').trim();
|
|
163
164
|
|
|
164
165
|
function doReplaces(str) {
|
|
@@ -169,7 +170,7 @@ export async function addStickerMetadata(stickerPath, packName, packAuthor, repl
|
|
|
169
170
|
.replace(/#id/gi, resolvedUserId);
|
|
170
171
|
}
|
|
171
172
|
|
|
172
|
-
const finalPackName = normalizeMetadataText(doReplaces(packName), '
|
|
173
|
+
const finalPackName = normalizeMetadataText(doReplaces(packName), 'Omnizap');
|
|
173
174
|
const finalPackAuthor = normalizeMetadataText(doReplaces(packAuthor), baseSenderName);
|
|
174
175
|
|
|
175
176
|
logger.info(`addStickerMetadata Adicionando metadados ao sticker. Nome: "${finalPackName}", Autor: "${finalPackAuthor}"`);
|