diff --git a/src/db.ts b/src/db.ts index 3f5d2d2..0c7ab68 100644 --- a/src/db.ts +++ b/src/db.ts @@ -29,7 +29,8 @@ export function getDb(filename: string = 'tasks.db'): Database { try { mkdirSync(dirname(absolutePath), { recursive: true }); } catch (err) { - if ((err as any)?.code !== 'EEXIST') throw err; // Solo ignorar "ya existe" + const code = (err && typeof err === 'object') ? (err as { code?: string }).code : undefined; + if (code !== 'EEXIST') throw err; // Solo ignorar "ya existe" } const instance = new Database(absolutePath); applyDefaultPragmas(instance); @@ -45,7 +46,8 @@ export function getDb(filename: string = 'tasks.db'): Database { try { mkdirSync(dirPath, { recursive: true }); } catch (err) { - if ((err as any)?.code !== 'EEXIST') throw err; // Only ignore "already exists" errors + const code = (err && typeof err === 'object') ? (err as { code?: string }).code : undefined; + if (code !== 'EEXIST') throw err; // Only ignore "already exists" errors } const instance = new Database(join(dirPath, filename)); @@ -75,7 +77,7 @@ export function initializeDatabase(instance: Database) { try { const row = instance .query(`SELECT name FROM sqlite_master WHERE type='table' AND name = ?`) - .get(name) as any; + .get(name) as { name?: string } | undefined; return Boolean(row && row.name === name); } catch { return false; diff --git a/src/db/migrations/index.ts b/src/db/migrations/index.ts index 6eab0a5..9724f32 100644 --- a/src/db/migrations/index.ts +++ b/src/db/migrations/index.ts @@ -8,7 +8,7 @@ export type Migration = { }; function tableHasColumn(db: Database, table: string, column: string): boolean { - const cols = db.query(`PRAGMA table_info(${table})`).all() as any[]; + const cols = db.query(`PRAGMA table_info(${table})`).all() as Array<{ name?: string }>; return Array.isArray(cols) && cols.some((c: any) => c.name === column); } @@ -250,7 +250,7 @@ export const migrations: Migration[] = [ up: (db: Database) => { // Añadir columna display_code si no existe try { - const cols = db.query(`PRAGMA table_info(tasks)`).all() as any[]; + const cols = db.query(`PRAGMA table_info(tasks)`).all() as Array<{ name?: string }>; const hasDisplay = Array.isArray(cols) && cols.some((c: any) => String(c.name) === 'display_code'); if (!hasDisplay) { db.exec(`ALTER TABLE tasks ADD COLUMN display_code INTEGER NULL;`); @@ -368,7 +368,7 @@ export const migrations: Migration[] = [ // Añadir columna para poder mostrar siempre la URL (guardando el token en claro). // Nota: mantenemos token_hash para validación; token_plain se usa solo para construir la URL en UI. try { - const cols = db.query(`PRAGMA table_info(calendar_tokens)`).all() as any[]; + const cols = db.query(`PRAGMA table_info(calendar_tokens)`).all() as Array<{ name?: string }>; const hasPlain = Array.isArray(cols) && cols.some((c: any) => String(c.name) === 'token_plain'); if (!hasPlain) { db.exec(`ALTER TABLE calendar_tokens ADD COLUMN token_plain TEXT NULL;`); @@ -382,7 +382,7 @@ export const migrations: Migration[] = [ checksum: 'v13-groups-onboarding-2025-10-17', up: (db: Database) => { try { - const cols = db.query(`PRAGMA table_info(groups)`).all() as any[]; + const cols = db.query(`PRAGMA table_info(groups)`).all() as Array<{ name?: string }>; const hasCol = Array.isArray(cols) && cols.some((c: any) => String(c.name) === 'onboarding_prompted_at'); if (!hasCol) { db.exec(`ALTER TABLE groups ADD COLUMN onboarding_prompted_at TEXT NULL;`); @@ -396,7 +396,7 @@ export const migrations: Migration[] = [ checksum: 'v14-groups-archived-2025-10-19', up: (db: Database) => { try { - const cols = db.query(`PRAGMA table_info(groups)`).all() as any[]; + const cols = db.query(`PRAGMA table_info(groups)`).all() as Array<{ name?: string }>; const hasArchived = Array.isArray(cols) && cols.some((c: any) => String(c.name) === 'archived'); if (!hasArchived) { db.exec(`ALTER TABLE groups ADD COLUMN archived BOOLEAN NOT NULL DEFAULT 0;`); @@ -443,7 +443,7 @@ export const migrations: Migration[] = [ checksum: 'v16-groups-is-community-2025-10-19', up: (db: Database) => { try { - const cols = db.query(`PRAGMA table_info(groups)`).all() as any[]; + const cols = db.query(`PRAGMA table_info(groups)`).all() as Array<{ name?: string }>; const hasCol = Array.isArray(cols) && cols.some((c: any) => String(c.name) === 'is_community'); if (!hasCol) { db.exec(`ALTER TABLE groups ADD COLUMN is_community BOOLEAN NOT NULL DEFAULT 0;`); @@ -479,7 +479,7 @@ export const migrations: Migration[] = [ checksum: 'v18-task-origins-participant-fromme-2025-10-21', up: (db: Database) => { try { - const cols = db.query(`PRAGMA table_info(task_origins)`).all() as any[]; + const cols = db.query(`PRAGMA table_info(task_origins)`).all() as Array<{ name?: string }>; const hasParticipant = Array.isArray(cols) && cols.some((c: any) => String(c.name) === 'participant'); if (!hasParticipant) { db.exec(`ALTER TABLE task_origins ADD COLUMN participant TEXT NULL;`); @@ -497,7 +497,7 @@ export const migrations: Migration[] = [ checksum: 'v19-users-last-command-at-2025-10-25', up: (db: Database) => { try { - const cols = db.query(`PRAGMA table_info(users)`).all() as any[]; + const cols = db.query(`PRAGMA table_info(users)`).all() as Array<{ name?: string }>; const hasCol = Array.isArray(cols) && cols.some((c: any) => String(c.name) === 'last_command_at'); if (!hasCol) { db.exec(`ALTER TABLE users ADD COLUMN last_command_at TEXT NULL;`); diff --git a/src/db/migrator.ts b/src/db/migrator.ts index 513aabc..209ebb4 100644 --- a/src/db/migrator.ts +++ b/src/db/migrator.ts @@ -35,7 +35,7 @@ function ensureMigrationsTable(db: Database) { } function getAppliedVersions(db: Database): Map { - const rows = db.query(`SELECT version, name, checksum, applied_at FROM schema_migrations ORDER BY version`).all() as any[]; + const rows = db.query(`SELECT version, name, checksum, applied_at FROM schema_migrations ORDER BY version`).all() as Array<{ version: number; name: string; checksum: string; applied_at: string }>; const map = new Map(); for (const r of rows) { map.set(Number(r.version), { name: String(r.name), checksum: String(r.checksum), applied_at: String(r.applied_at) }); @@ -44,7 +44,7 @@ function getAppliedVersions(db: Database): Map | undefined; + const journalMode = jmRow ? String((jmRow['journal_mode'] ?? jmRow['value'] ?? jmRow['mode'] ?? 'unknown')) : 'unknown'; const currentVersion = applied.size ? Math.max(...Array.from(applied.keys())) : 0; if (!MIGRATIONS_QUIET) console.log(`ℹ️ Migrador — journal_mode=${journalMode}, versión_actual=${currentVersion}, pendientes=${pending.length}`); try { logEvent('info', 'startup_summary', { journal_mode: journalMode, current_version: currentVersion, pending: pending.length }); } catch {} diff --git a/src/server.ts b/src/server.ts index 795d229..90719a2 100644 --- a/src/server.ts +++ b/src/server.ts @@ -354,16 +354,16 @@ export class WebhookServer { // Etapa 2: Descubrimiento seguro de grupos (modo 'discover') if (isGroupId(remoteJid)) { - try { (AllowedGroups as any).dbInstance = WebhookServer.dbInstance; } catch {} + try { AllowedGroups.dbInstance = WebhookServer.dbInstance; } catch {} const gatingMode = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase(); if (gatingMode === 'discover') { try { const exists = WebhookServer.dbInstance .prepare(`SELECT 1 FROM allowed_groups WHERE group_id = ? LIMIT 1`) - .get(remoteJid) as any; + .get(remoteJid); if (!exists) { try { await GroupSyncService.ensureGroupLabelAndName(remoteJid); } catch {} - try { (AllowedGroups as any).dbInstance = WebhookServer.dbInstance; } catch {} + try { AllowedGroups.dbInstance = WebhookServer.dbInstance; } catch {} try { AllowedGroups.upsertPending(remoteJid, (GroupSyncService.activeGroupsCache.get(remoteJid) || null), normalizedSenderId); } catch {} try { Metrics.inc('unknown_groups_discovered_total'); } catch {} try { @@ -382,7 +382,7 @@ export class WebhookServer { } catch { // Si la tabla no existe por alguna razón, intentar upsert y retornar igualmente try { await GroupSyncService.ensureGroupLabelAndName(remoteJid); } catch {} - try { (AllowedGroups as any).dbInstance = WebhookServer.dbInstance; } catch {} + try { AllowedGroups.dbInstance = WebhookServer.dbInstance; } catch {} try { AllowedGroups.upsertPending(remoteJid, (GroupSyncService.activeGroupsCache.get(remoteJid) || null), normalizedSenderId); } catch {} try { Metrics.inc('unknown_groups_discovered_total'); } catch {} try { @@ -403,7 +403,7 @@ export class WebhookServer { // Etapa 3: Gating en modo 'enforce' — ignorar mensajes de grupos no permitidos if (isGroupId(remoteJid)) { - try { (AllowedGroups as any).dbInstance = WebhookServer.dbInstance; } catch {} + try { AllowedGroups.dbInstance = WebhookServer.dbInstance; } catch {} const gatingMode2 = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase(); if (gatingMode2 === 'enforce') { try { @@ -420,8 +420,8 @@ export class WebhookServer { // Manejo de comandos de administración (/admin) antes de cualquier otra lógica de grupo if (messageTextTrimmed.startsWith('/admin')) { - try { (AdminService as any).dbInstance = WebhookServer.dbInstance; } catch {} - try { (AllowedGroups as any).dbInstance = WebhookServer.dbInstance; } catch {} + try { AdminService.dbInstance = WebhookServer.dbInstance; } catch {} + try { AllowedGroups.dbInstance = WebhookServer.dbInstance; } catch {} const adminResponses = await AdminService.handle({ sender: normalizedSenderId, groupId: remoteJid, @@ -477,8 +477,8 @@ export class WebhookServer { || []; // Asegurar que CommandService y TaskService usen la misma DB (tests/producción) - (CommandService as any).dbInstance = WebhookServer.dbInstance; - (TaskService as any).dbInstance = WebhookServer.dbInstance; + CommandService.dbInstance = WebhookServer.dbInstance; + TaskService.dbInstance = WebhookServer.dbInstance; // Delegar el manejo del comando const messageId = typeof data?.key?.id === 'string' ? data.key.id : null; @@ -514,7 +514,7 @@ export class WebhookServer { if (scope !== 'all' && !isGroup) return; // Respetar gating 'enforce' - try { (AllowedGroups as any).dbInstance = WebhookServer.dbInstance; } catch {} + try { AllowedGroups.dbInstance = WebhookServer.dbInstance; } catch {} const mode = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase(); if (mode === 'enforce' && isGroup) { try { diff --git a/src/services/admin.ts b/src/services/admin.ts index 24c1cd8..eba6e40 100644 --- a/src/services/admin.ts +++ b/src/services/admin.ts @@ -61,7 +61,7 @@ export class AdminService { } // Asegurar acceso a la misma DB para AllowedGroups - try { (AllowedGroups as any).dbInstance = this.dbInstance; } catch {} + try { AllowedGroups.dbInstance = this.dbInstance; } catch {} const raw = String(ctx.message || '').trim(); const lower = raw.toLowerCase(); @@ -251,7 +251,7 @@ export class AdminService { rest.startsWith('list-all ') ) { // Asegurar acceso a la misma DB para TaskService - try { (TaskService as any).dbInstance = this.dbInstance; } catch {} + try { TaskService.dbInstance = this.dbInstance; } catch {} const DEFAULT_LIMIT = 50; let limit = DEFAULT_LIMIT; diff --git a/src/services/command.ts b/src/services/command.ts index d169151..b583c5f 100644 --- a/src/services/command.ts +++ b/src/services/command.ts @@ -49,7 +49,7 @@ export class CommandService { try { let usersTableExists = false; try { - const row = this.dbInstance.query(`SELECT name FROM sqlite_master WHERE type='table' AND name='users'`).get() as any; + const row = this.dbInstance.query(`SELECT name FROM sqlite_master WHERE type='table' AND name='users'`).get() as { name?: string } | undefined; usersTableExists = !!row; } catch {} if (usersTableExists) { @@ -64,7 +64,7 @@ export class CommandService { // Gating de grupos en modo 'enforce' (cuando CommandService se invoca directamente) if (isGroupId(context.groupId)) { - try { (AllowedGroups as any).dbInstance = this.dbInstance; } catch { } + try { AllowedGroups.dbInstance = this.dbInstance; } catch { } const mode = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase(); if (mode === 'enforce') { try { diff --git a/src/services/commands/index.ts b/src/services/commands/index.ts index e90aa2d..d1cda22 100644 --- a/src/services/commands/index.ts +++ b/src/services/commands/index.ts @@ -12,6 +12,13 @@ import { handleCompletar } from './handlers/completar'; import { handleTomar } from './handlers/tomar'; import { handleSoltar } from './handlers/soltar'; import { handleNueva } from './handlers/nueva'; +type NuevaCtx = Parameters[0]; +type VerCtx = Parameters[0]; +type CompletarCtx = Parameters[0]; +type TomarCtx = Parameters[0]; +type SoltarCtx = Parameters[0]; +type ConfigurarCtx = Parameters[0]; +type WebCtx = Parameters[0]; import { ResponseQueue } from '../response-queue'; import { isGroupId } from '../../utils/whatsapp'; import { Metrics } from '../metrics'; @@ -105,7 +112,7 @@ export async function route(context: RouteContext, deps?: { db: Database }): Pro if (action === 'nueva') { try { ResponseQueue.setOnboardingAggregatesMetrics(); } catch {} - return await handleNueva(context as any, { db: database }); + return await handleNueva(context as unknown as NuevaCtx, { db: database }); } if (action === 'ver') { @@ -129,32 +136,32 @@ export async function route(context: RouteContext, deps?: { db: Database }): Pro }]; } - return await handleVer(context as any); + return await handleVer(context as unknown as VerCtx); } if (action === 'completar') { try { ResponseQueue.setOnboardingAggregatesMetrics(); } catch {} - return await handleCompletar(context as any); + return await handleCompletar(context as unknown as CompletarCtx); } if (action === 'tomar') { try { ResponseQueue.setOnboardingAggregatesMetrics(); } catch {} - return await handleTomar(context as any); + return await handleTomar(context as unknown as TomarCtx); } if (action === 'soltar') { try { ResponseQueue.setOnboardingAggregatesMetrics(); } catch {} - return await handleSoltar(context as any); + return await handleSoltar(context as unknown as SoltarCtx); } if (action === 'configurar') { try { ResponseQueue.setOnboardingAggregatesMetrics(); } catch {} - return handleConfigurar(context as any, { db: database }); + return handleConfigurar(context as unknown as ConfigurarCtx, { db: database }); } if (action === 'web') { try { ResponseQueue.setOnboardingAggregatesMetrics(); } catch {} - return await handleWeb(context as any, { db: database }); + return await handleWeb(context as unknown as WebCtx, { db: database }); } // Desconocido → ayuda rápida diff --git a/src/services/contacts.ts b/src/services/contacts.ts index d13bacd..7515d6b 100644 --- a/src/services/contacts.ts +++ b/src/services/contacts.ts @@ -104,7 +104,7 @@ export class ContactsService { return null; } - const data = await res.json().catch(() => null as any); + const data = await res.json().catch(() => null); const arrayCandidates: any[] = Array.isArray(data) ? data : Array.isArray((data as any)?.contacts) diff --git a/src/services/group-sync.ts b/src/services/group-sync.ts index 18b094c..013e40d 100644 --- a/src/services/group-sync.ts +++ b/src/services/group-sync.ts @@ -91,30 +91,30 @@ export class GroupSyncService { console.log('ℹ️ Grupos crudos de la API:', JSON.stringify(groups, null, 2)); console.log('ℹ️ Sin filtrar por comunidad (modo multicomunidad). Total grupos:', groups.length); - const dbGroupsBefore = this.dbInstance.prepare('SELECT id, active, COALESCE(archived,0) AS archived, COALESCE(is_community,0) AS is_community, name FROM groups').all(); + const dbGroupsBefore = this.dbInstance.prepare('SELECT id, active, COALESCE(archived,0) AS archived, COALESCE(is_community,0) AS is_community, name FROM groups').all() as Array<{ id: string; active: number; archived: number; is_community: number; name?: string | null }>; console.log('ℹ️ Grupos en DB antes de upsert:', dbGroupsBefore); const result = await this.upsertGroups(groups); - const dbGroupsAfter = this.dbInstance.prepare('SELECT id, active, COALESCE(archived,0) AS archived, COALESCE(is_community,0) AS is_community, name FROM groups').all(); + const dbGroupsAfter = this.dbInstance.prepare('SELECT id, active, COALESCE(archived,0) AS archived, COALESCE(is_community,0) AS is_community, name FROM groups').all() as Array<{ id: string; active: number; archived: number; is_community: number; name?: string | null }>; console.log('ℹ️ Grupos en DB después de upsert:', dbGroupsAfter); // Detectar grupos que pasaron de activos a inactivos (y no están archivados) en este sync try { const beforeMap = new Map(); - for (const r of dbGroupsBefore as any[]) { - beforeMap.set(String(r.id), { active: Number(r.active || 0), archived: Number(r.archived || 0), is_community: Number((r as any).is_community || 0), name: r.name ? String(r.name) : null }); + for (const r of dbGroupsBefore) { + beforeMap.set(String(r.id), { active: Number(r.active || 0), archived: Number(r.archived || 0), is_community: Number(r.is_community || 0), name: r.name ? String(r.name) : null }); } const afterMap = new Map(); - for (const r of dbGroupsAfter as any[]) { - afterMap.set(String(r.id), { active: Number(r.active || 0), archived: Number(r.archived || 0), is_community: Number((r as any).is_community || 0), name: r.name ? String(r.name) : null }); + for (const r of dbGroupsAfter) { + afterMap.set(String(r.id), { active: Number(r.active || 0), archived: Number(r.archived || 0), is_community: Number(r.is_community || 0), name: r.name ? String(r.name) : null }); } // Determinar grupos que pasaron a estar activos (nuevos o reactivados) const newlyActivatedLocal: string[] = []; for (const [id, a] of afterMap.entries()) { const b = beforeMap.get(id); - const becameActive = Number(a.active) === 1 && Number(a.archived) === 0 && Number((a as any).is_community || 0) === 0; + const becameActive = Number(a.active) === 1 && Number(a.archived) === 0 && Number(a.is_community || 0) === 0; if (becameActive && (!b || Number(b.active) !== 1)) { newlyActivatedLocal.push(id); } @@ -179,12 +179,12 @@ export class GroupSyncService { } // Completar labels faltantes en allowed_groups usando todos los grupos devueltos por la API - try { (AllowedGroups as any).dbInstance = this.dbInstance; this.fillMissingAllowedGroupLabels(groups); } catch {} + try { AllowedGroups.dbInstance = this.dbInstance; this.fillMissingAllowedGroupLabels(groups); } catch {} // Actualizar métricas this.cacheActiveGroups(); Metrics.set('active_groups', this.activeGroupsCache.size); - const rowM = this.dbInstance.prepare(`SELECT COUNT(*) AS c FROM group_members WHERE is_active = 1`).get() as any; + const rowM = this.dbInstance.prepare(`SELECT COUNT(*) AS c FROM group_members WHERE is_active = 1`).get() as { c?: number } | undefined; Metrics.set('active_members', Number(rowM?.c || 0)); Metrics.set('last_sync_timestamp_seconds', Math.floor(Date.now() / 1000)); Metrics.set('last_sync_ok', 1); @@ -321,7 +321,7 @@ export class GroupSyncService { SELECT group_id AS id FROM allowed_groups WHERE label IS NULL OR TRIM(label) = '' - `).all() as any[]; + `).all() as Array<{ id: string }>; if (!rows || rows.length === 0) return 0; let filled = 0; @@ -453,7 +453,7 @@ export class GroupSyncService { // - Si es grupo "comunidad/announce", bloquearlo. // - En caso contrario, upsert pending y label. try { - (AllowedGroups as any).dbInstance = this.dbInstance; + AllowedGroups.dbInstance = this.dbInstance; if (isCommunityFlag) { AllowedGroups.setStatus(group.id, 'blocked', group.subject); } else { @@ -844,7 +844,7 @@ export class GroupSyncService { try { const mode = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase(); if (mode === 'enforce') { - try { (AllowedGroups as any).dbInstance = this.dbInstance; } catch {} + try { AllowedGroups.dbInstance = this.dbInstance; } catch {} if (!AllowedGroups.isAllowed(groupId)) { try { Metrics.inc('onboarding_prompts_skipped_total', 1, { group_id: groupId, reason: 'not_allowed' }); } catch {} return; @@ -941,7 +941,7 @@ export class GroupSyncService { const mode = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase(); const enforce = mode === 'enforce'; if (enforce) { - try { (AllowedGroups as any).dbInstance = this.dbInstance; } catch {} + try { AllowedGroups.dbInstance = this.dbInstance; } catch {} } let groups = 0, added = 0, updated = 0, deactivated = 0; @@ -984,7 +984,7 @@ export class GroupSyncService { const mode = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase(); const enforce = mode === 'enforce'; if (enforce) { - try { (AllowedGroups as any).dbInstance = this.dbInstance; } catch {} + try { AllowedGroups.dbInstance = this.dbInstance; } catch {} } let groups = 0, added = 0, updated = 0, deactivated = 0; @@ -1106,7 +1106,7 @@ export class GroupSyncService { */ public static isSnapshotFresh(groupId: string, nowMs: number = Date.now()): boolean { try { - const row = this.dbInstance.prepare(`SELECT last_verified FROM groups WHERE id = ?`).get(groupId) as any; + const row = this.dbInstance.prepare(`SELECT last_verified FROM groups WHERE id = ?`).get(groupId) as { last_verified?: string | null } | undefined; const lv = row?.last_verified ? String(row.last_verified) : null; if (!lv) return false; // Persistimos 'YYYY-MM-DD HH:MM:SS[.mmm]'. Convertimos a ISO-like para Date.parse @@ -1146,7 +1146,7 @@ export class GroupSyncService { WHERE gm.user_id = ? AND gm.is_active = 1 AND g.active = 1 AND COALESCE(g.is_community,0) = 0 AND COALESCE(g.archived,0) = 0 - `).all(userId) as any[]; + `).all(userId) as Array<{ id: string }>; const set = new Set(); for (const r of rows) { if (r?.id) set.add(String(r.id)); @@ -1216,18 +1216,18 @@ export class GroupSyncService { const cached = this.activeGroupsCache.get(groupId); if (cached && cached.trim()) { try { this.ensureGroupExists(groupId, cached); } catch {} - try { (AllowedGroups as any).dbInstance = this.dbInstance; AllowedGroups.upsertPending(groupId, cached, null); } catch {} + try { AllowedGroups.dbInstance = this.dbInstance; AllowedGroups.upsertPending(groupId, cached, null); } catch {} this.cacheActiveGroups(); return cached; } // 2) DB (tabla groups) try { - const row = this.dbInstance.prepare('SELECT name FROM groups WHERE id = ?').get(groupId) as any; + const row = this.dbInstance.prepare('SELECT name FROM groups WHERE id = ?').get(groupId) as { name?: string | null } | undefined; const name = row?.name ? String(row.name).trim() : ''; if (name) { try { this.ensureGroupExists(groupId, name); } catch {} - try { (AllowedGroups as any).dbInstance = this.dbInstance; AllowedGroups.upsertPending(groupId, name, null); } catch {} + try { AllowedGroups.dbInstance = this.dbInstance; AllowedGroups.upsertPending(groupId, name, null); } catch {} this.cacheActiveGroups(); return name; } @@ -1240,7 +1240,7 @@ export class GroupSyncService { const subject = g?.subject ? String(g.subject).trim() : ''; if (subject) { try { this.ensureGroupExists(groupId, subject); } catch {} - try { (AllowedGroups as any).dbInstance = this.dbInstance; AllowedGroups.upsertPending(groupId, subject, null); } catch {} + try { AllowedGroups.dbInstance = this.dbInstance; AllowedGroups.upsertPending(groupId, subject, null); } catch {} this.cacheActiveGroups(); return subject; } @@ -1275,7 +1275,7 @@ export class GroupSyncService { try { // Asegurar existencia del grupo en DB (FKs) antes de reconciliar this.ensureGroupExists(groupId); - const snapshot = await (this as any).fetchGroupMembersFromAPI(groupId); + const snapshot = await this.fetchGroupMembersFromAPI(groupId); return this.reconcileGroupMembers(groupId, snapshot); } catch (e) { console.error(`❌ Failed to sync members for group ${groupId}:`, e instanceof Error ? e.message : String(e)); diff --git a/src/services/response-queue.ts b/src/services/response-queue.ts index 975b140..d6acee9 100644 --- a/src/services/response-queue.ts +++ b/src/services/response-queue.ts @@ -226,7 +226,7 @@ export const ResponseQueue = { AND status IN ('queued','processing','sent') AND (updated_at > ? OR created_at > ?) LIMIT 1 - `).get(metadata, cutoff, cutoff) as any; + `).get(metadata, cutoff, cutoff); if (exists) { return; diff --git a/src/tasks/service.ts b/src/tasks/service.ts index 4ee9342..953f0c4 100644 --- a/src/tasks/service.ts +++ b/src/tasks/service.ts @@ -96,7 +96,7 @@ export class TaskService { ensuredCreator, displayCode ); - const taskId = Number((runResult as any).lastInsertRowid); + const taskId = Number((runResult as { lastInsertRowid?: number | bigint }).lastInsertRowid); if (assignments.length > 0) { const insertAssignment = this.dbInstance.prepare(` @@ -252,7 +252,7 @@ export class TaskService { FROM tasks WHERE id = ? `) - .get(taskId) as any; + .get(taskId) as { id?: number; description?: string; due_date?: string | null; completed?: number; completed_at?: string | null; display_code?: number | null; group_id?: string | null } | undefined; if (!existing) { return { status: 'not_found' }; @@ -291,13 +291,13 @@ export class TaskService { SELECT chat_id, message_id, created_at, participant, from_me FROM task_origins WHERE task_id = ? - `).get(taskId) as any; + `).get(taskId) as { chat_id?: string; message_id?: string; created_at?: string } | undefined; } catch { origin = this.dbInstance.prepare(` SELECT chat_id, message_id, created_at FROM task_origins WHERE task_id = ? - `).get(taskId) as any; + `).get(taskId) as { id?: number; description?: string; due_date?: string | null; group_id?: string | null; completed?: number; completed_at?: string | null; display_code?: number | null } | undefined; } if (origin && origin.chat_id && origin.message_id) { @@ -515,7 +515,7 @@ export class TaskService { SUM(CASE WHEN user_id = ? THEN 1 ELSE 0 END) AS mine FROM task_assignments WHERE task_id = ? - `).get(ensuredUser, taskId) as any; + `).get(ensuredUser, taskId) as { cnt?: number; mine?: number } | undefined; const cnt = Number(stats?.cnt || 0); const mine = Number(stats?.mine || 0) > 0; if (existing.group_id == null && cnt === 1 && mine) { @@ -537,7 +537,7 @@ export class TaskService { WHERE task_id = ? AND user_id = ? `); - const result = deleteStmt.run(taskId, ensuredUser) as any; + const result = deleteStmt.run(taskId, ensuredUser) as { changes?: number }; const cntRow = this.dbInstance .prepare(`SELECT COUNT(*) as cnt FROM task_assignments WHERE task_id = ?`) @@ -592,7 +592,7 @@ export class TaskService { completed_at FROM tasks WHERE id = ? - `).get(taskId) as any; + `).get(taskId) as { id?: number; description?: string; due_date?: string | null; group_id?: string | null; completed?: number; completed_at?: string | null; display_code?: number | null } | undefined; if (!row) return null; return { id: Number(row.id),