refactor: eliminar dbInstance y añadir resetDb/clearDb, usar getDb()

Co-authored-by: aider (openrouter/openai/gpt-5) <aider@aider.chat>
main
brobert 1 month ago
parent 5c6ca072e4
commit e415a26442

@ -28,6 +28,20 @@ export function getDb(): Database {
throw new DbNotConfiguredError('Database has not been configured. Call setDb(db) before using getDb().'); throw new DbNotConfiguredError('Database has not been configured. Call setDb(db) before using getDb().');
} }
/**
* Resetea la instancia global de DB. Útil en tests para detectar fugas entre suites.
*/
export function resetDb(): void {
currentDb = null;
}
/**
* Alias de resetDb() por ergonomía en tests.
*/
export function clearDb(): void {
currentDb = null;
}
/** /**
* Ejecuta una función con la DB actual (sync o async) y devuelve su resultado. * Ejecuta una función con la DB actual (sync o async) y devuelve su resultado.
*/ */

@ -140,7 +140,6 @@ export async function handleMessageUpsert(data: any, db: Database): Promise<void
// Etapa 2: Descubrimiento seguro de grupos (modo 'discover') // Etapa 2: Descubrimiento seguro de grupos (modo 'discover')
if (isGroupId(remoteJid)) { if (isGroupId(remoteJid)) {
try { AllowedGroups.dbInstance = db; } catch {}
const gatingMode = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase(); const gatingMode = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase();
if (gatingMode === 'discover') { if (gatingMode === 'discover') {
try { try {
@ -149,7 +148,6 @@ export async function handleMessageUpsert(data: any, db: Database): Promise<void
.get(remoteJid); .get(remoteJid);
if (!exists) { if (!exists) {
try { await GroupSyncService.ensureGroupLabelAndName(remoteJid); } catch {} try { await GroupSyncService.ensureGroupLabelAndName(remoteJid); } catch {}
try { AllowedGroups.dbInstance = db; } catch {}
try { AllowedGroups.upsertPending(remoteJid, (GroupSyncService.activeGroupsCache.get(remoteJid) || null), normalizedSenderId); } catch {} try { AllowedGroups.upsertPending(remoteJid, (GroupSyncService.activeGroupsCache.get(remoteJid) || null), normalizedSenderId); } catch {}
try { Metrics.inc('unknown_groups_discovered_total'); } catch {} try { Metrics.inc('unknown_groups_discovered_total'); } catch {}
try { try {
@ -168,7 +166,6 @@ export async function handleMessageUpsert(data: any, db: Database): Promise<void
} catch { } catch {
// Si la tabla no existe por alguna razón, intentar upsert y retornar igualmente // Si la tabla no existe por alguna razón, intentar upsert y retornar igualmente
try { await GroupSyncService.ensureGroupLabelAndName(remoteJid); } catch {} try { await GroupSyncService.ensureGroupLabelAndName(remoteJid); } catch {}
try { AllowedGroups.dbInstance = db; } catch {}
try { AllowedGroups.upsertPending(remoteJid, (GroupSyncService.activeGroupsCache.get(remoteJid) || null), normalizedSenderId); } catch {} try { AllowedGroups.upsertPending(remoteJid, (GroupSyncService.activeGroupsCache.get(remoteJid) || null), normalizedSenderId); } catch {}
try { Metrics.inc('unknown_groups_discovered_total'); } catch {} try { Metrics.inc('unknown_groups_discovered_total'); } catch {}
try { try {
@ -189,7 +186,6 @@ export async function handleMessageUpsert(data: any, db: Database): Promise<void
// Etapa 3: Gating en modo 'enforce' — ignorar mensajes de grupos no permitidos // Etapa 3: Gating en modo 'enforce' — ignorar mensajes de grupos no permitidos
if (isGroupId(remoteJid)) { if (isGroupId(remoteJid)) {
try { AllowedGroups.dbInstance = db; } catch {}
const gatingMode2 = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase(); const gatingMode2 = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase();
if (gatingMode2 === 'enforce') { if (gatingMode2 === 'enforce') {
try { try {
@ -206,8 +202,6 @@ export async function handleMessageUpsert(data: any, db: Database): Promise<void
// Manejo de comandos de administración (/admin) antes de cualquier otra lógica de grupo // Manejo de comandos de administración (/admin) antes de cualquier otra lógica de grupo
if (messageTextTrimmed.startsWith('/admin')) { if (messageTextTrimmed.startsWith('/admin')) {
try { AdminService.dbInstance = db; } catch {}
try { AllowedGroups.dbInstance = db; } catch {}
const adminResponses = await AdminService.handle({ const adminResponses = await AdminService.handle({
sender: normalizedSenderId, sender: normalizedSenderId,
groupId: remoteJid, groupId: remoteJid,
@ -262,8 +256,6 @@ export async function handleMessageUpsert(data: any, db: Database): Promise<void
|| []; || [];
// Asegurar que CommandService y TaskService usen la misma DB (tests/producción) // Asegurar que CommandService y TaskService usen la misma DB (tests/producción)
CommandService.dbInstance = db;
TaskService.dbInstance = db;
// Delegar el manejo del comando // Delegar el manejo del comando
const messageId = typeof data?.key?.id === 'string' ? data.key.id : null; const messageId = typeof data?.key?.id === 'string' ? data.key.id : null;
@ -299,7 +291,6 @@ export async function handleMessageUpsert(data: any, db: Database): Promise<void
if (scope !== 'all' && !isGroup) return; if (scope !== 'all' && !isGroup) return;
// Respetar gating 'enforce' // Respetar gating 'enforce'
try { AllowedGroups.dbInstance = db; } catch {}
const mode = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase(); const mode = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase();
if (mode === 'enforce' && isGroup) { if (mode === 'enforce' && isGroup) {
try { try {

@ -189,7 +189,6 @@ export class WebhookServer {
await Migrator.migrateToLatest(this.dbInstance); await Migrator.migrateToLatest(this.dbInstance);
// Etapa 7: seed inicial de grupos permitidos desde ALLOWED_GROUPS (best-effort) // Etapa 7: seed inicial de grupos permitidos desde ALLOWED_GROUPS (best-effort)
try { (AllowedGroups as any).dbInstance = this.dbInstance; } catch {}
try { AllowedGroups.seedFromEnv(); } catch {} try { AllowedGroups.seedFromEnv(); } catch {}
const PORT = process.env.PORT || '3007'; const PORT = process.env.PORT || '3007';

@ -1,5 +1,4 @@
import type { Database } from 'bun:sqlite'; import type { Database } from 'bun:sqlite';
import { db } from '../db';
import { AllowedGroups } from './allowed-groups'; import { AllowedGroups } from './allowed-groups';
import { GroupSyncService } from './group-sync'; import { GroupSyncService } from './group-sync';
import { normalizeWhatsAppId, isGroupId } from '../utils/whatsapp'; import { normalizeWhatsAppId, isGroupId } from '../utils/whatsapp';
@ -17,7 +16,7 @@ type AdminContext = {
type AdminResponse = { recipient: string; message: string }; type AdminResponse = { recipient: string; message: string };
export class AdminService { export class AdminService {
static dbInstance: Database = db;
private static admins(): Set<string> { private static admins(): Set<string> {
const raw = String(process.env.ADMIN_USERS || ''); const raw = String(process.env.ADMIN_USERS || '');
@ -61,9 +60,8 @@ export class AdminService {
return [{ recipient: sender, message: '🚫 No estás autorizado para usar /admin.' }]; return [{ recipient: sender, message: '🚫 No estás autorizado para usar /admin.' }];
} }
const instanceDb = ((this as any).dbInstance ?? getDb()) as Database; const instanceDb = getDb() as Database;
// Asegurar acceso a la misma DB para AllowedGroups // Asegurar acceso a la misma DB para AllowedGroups
try { AllowedGroups.dbInstance = instanceDb; } catch {}
const raw = String(ctx.message || '').trim(); const raw = String(ctx.message || '').trim();
const lower = raw.toLowerCase(); const lower = raw.toLowerCase();
@ -231,7 +229,6 @@ export class AdminService {
// /admin sync-grupos // /admin sync-grupos
if (rest === 'sync-grupos' || rest === 'group-sync' || rest === 'syncgroups') { if (rest === 'sync-grupos' || rest === 'group-sync' || rest === 'syncgroups') {
try { (GroupSyncService as any).dbInstance = instanceDb; } catch {}
try { try {
const r = await GroupSyncService.syncGroups(true); const r = await GroupSyncService.syncGroups(true);
return [{ recipient: sender, message: `✅ Sync de grupos ejecutado: ${r.added} añadidos, ${r.updated} actualizados.` }]; return [{ recipient: sender, message: `✅ Sync de grupos ejecutado: ${r.added} añadidos, ${r.updated} actualizados.` }];
@ -253,7 +250,6 @@ export class AdminService {
rest.startsWith('list-all ') rest.startsWith('list-all ')
) { ) {
// Asegurar acceso a la misma DB para TaskService // Asegurar acceso a la misma DB para TaskService
try { TaskService.dbInstance = instanceDb; } catch {}
const DEFAULT_LIMIT = 50; const DEFAULT_LIMIT = 50;
let limit = DEFAULT_LIMIT; let limit = DEFAULT_LIMIT;

@ -1,5 +1,4 @@
import type { Database } from 'bun:sqlite'; import { getDb } from '../db/locator';
import { db } from '../db';
type GroupStatus = 'pending' | 'allowed' | 'blocked'; type GroupStatus = 'pending' | 'allowed' | 'blocked';
@ -9,7 +8,6 @@ type CacheEntry = {
}; };
export class AllowedGroups { export class AllowedGroups {
static dbInstance: Database = db;
// Caché en memoria: group_id (JID completo) -> { status, label } // Caché en memoria: group_id (JID completo) -> { status, label }
private static cache = new Map<string, CacheEntry>(); private static cache = new Map<string, CacheEntry>();
@ -26,7 +24,7 @@ export class AllowedGroups {
private static getRow(groupId: string): { group_id: string; label: string | null; status: GroupStatus } | null { private static getRow(groupId: string): { group_id: string; label: string | null; status: GroupStatus } | null {
try { try {
const row = this.dbInstance const row = getDb()
.prepare(`SELECT group_id, label, status FROM allowed_groups WHERE group_id = ?`) .prepare(`SELECT group_id, label, status FROM allowed_groups WHERE group_id = ?`)
.get(groupId) as { group_id?: string; label?: string | null; status?: string } | undefined; .get(groupId) as { group_id?: string; label?: string | null; status?: string } | undefined;
if (!row) return null; if (!row) return null;
@ -66,7 +64,7 @@ export class AllowedGroups {
const row = this.getRow(gid); const row = this.getRow(gid);
if (!row) { if (!row) {
// Insertar como pending // Insertar como pending
this.dbInstance getDb()
.prepare(` .prepare(`
INSERT INTO allowed_groups (group_id, label, status, discovered_at, updated_at, discovered_by) INSERT INTO allowed_groups (group_id, label, status, discovered_at, updated_at, discovered_by)
VALUES (?, ?, 'pending', ${this.nowExpr}, ${this.nowExpr}, ?) VALUES (?, ?, 'pending', ${this.nowExpr}, ${this.nowExpr}, ?)
@ -79,7 +77,7 @@ export class AllowedGroups {
// No cambiar status existente. Solo actualizar label si se aporta y cambió. // No cambiar status existente. Solo actualizar label si se aporta y cambió.
const newLabel = label ?? row.label; const newLabel = label ?? row.label;
if (label != null && String(row.label ?? '') !== String(label)) { if (label != null && String(row.label ?? '') !== String(label)) {
this.dbInstance getDb()
.prepare(` .prepare(`
UPDATE allowed_groups UPDATE allowed_groups
SET label = ?, updated_at = ${this.nowExpr} SET label = ?, updated_at = ${this.nowExpr}
@ -98,7 +96,7 @@ export class AllowedGroups {
if (!gid) return false; if (!gid) return false;
const before = this.getRow(gid); const before = this.getRow(gid);
this.dbInstance getDb()
.prepare(` .prepare(`
INSERT INTO allowed_groups (group_id, label, status, discovered_at, updated_at) INSERT INTO allowed_groups (group_id, label, status, discovered_at, updated_at)
VALUES (?, ?, ?, ${this.nowExpr}, ${this.nowExpr}) VALUES (?, ?, ?, ${this.nowExpr}, ${this.nowExpr})
@ -120,7 +118,7 @@ export class AllowedGroups {
} }
static listByStatus(status: GroupStatus): Array<{ group_id: string; label: string | null }> { static listByStatus(status: GroupStatus): Array<{ group_id: string; label: string | null }> {
const rows = this.dbInstance const rows = getDb()
.prepare( .prepare(
`SELECT group_id, label FROM allowed_groups WHERE status = ? ORDER BY group_id` `SELECT group_id, label FROM allowed_groups WHERE status = ? ORDER BY group_id`
) )

@ -1,5 +1,5 @@
import type { Database } from 'bun:sqlite'; import type { Database } from 'bun:sqlite';
import { db, ensureUserExists } from '../db'; import { ensureUserExists } from '../db';
import { isGroupId } from '../utils/whatsapp'; import { isGroupId } from '../utils/whatsapp';
import { AllowedGroups } from './allowed-groups'; import { AllowedGroups } from './allowed-groups';
import { Metrics } from './metrics'; import { Metrics } from './metrics';
@ -30,10 +30,6 @@ export type CommandOutcome = {
}; };
export class CommandService { export class CommandService {
static dbInstance: Database = db;
static async handle(context: CommandContext): Promise<CommandResponse[]> { static async handle(context: CommandContext): Promise<CommandResponse[]> {
const outcome = await this.handleWithOutcome(context); const outcome = await this.handleWithOutcome(context);
@ -42,7 +38,7 @@ export class CommandService {
static async handleWithOutcome(context: CommandContext): Promise<CommandOutcome> { static async handleWithOutcome(context: CommandContext): Promise<CommandOutcome> {
const msg = (context.message || '').trim(); const msg = (context.message || '').trim();
const instanceDb = ((this as any).dbInstance ?? getDb()) as Database; const instanceDb = getDb() as Database;
if (!/^\/(tarea|t)\b/i.test(msg)) { if (!/^\/(tarea|t)\b/i.test(msg)) {
return { responses: [], ok: true }; return { responses: [], ok: true };
} }
@ -66,7 +62,6 @@ export class CommandService {
// Gating de grupos en modo 'enforce' (cuando CommandService se invoca directamente) // Gating de grupos en modo 'enforce' (cuando CommandService se invoca directamente)
if (isGroupId(context.groupId)) { if (isGroupId(context.groupId)) {
try { AllowedGroups.dbInstance = instanceDb; } catch { }
const mode = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase(); const mode = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase();
if (mode === 'enforce') { if (mode === 'enforce') {
try { try {

@ -48,7 +48,6 @@ export async function upsertGroups(
// Propagar sujeto a allowed_groups // Propagar sujeto a allowed_groups
try { try {
(AllowedGroups as any).dbInstance = db;
if (isCommunityFlag) { if (isCommunityFlag) {
AllowedGroups.setStatus(group.id, 'blocked', group.subject); AllowedGroups.setStatus(group.id, 'blocked', group.subject);
} else { } else {

@ -1,10 +1,9 @@
import type { Database } from 'bun:sqlite'; import { ensureUserExists } from '../db';
import { db, ensureUserExists } from '../db'; import { getDb } from '../db/locator';
import { normalizeWhatsAppId } from '../utils/whatsapp'; import { normalizeWhatsAppId } from '../utils/whatsapp';
import { Metrics } from './metrics'; import { Metrics } from './metrics';
export class IdentityService { export class IdentityService {
static dbInstance: Database = db;
// Caché en memoria como respaldo si la tabla user_aliases no está disponible (tests o migraciones incompletas) // Caché en memoria como respaldo si la tabla user_aliases no está disponible (tests o migraciones incompletas)
private static readonly inMemoryAliases = new Map<string, string>(); private static readonly inMemoryAliases = new Map<string, string>();
@ -19,7 +18,7 @@ export class IdentityService {
// Asegurar que el user_id numérico exista para no violar la FK (user_aliases.user_id -> users.id) // Asegurar que el user_id numérico exista para no violar la FK (user_aliases.user_id -> users.id)
try { ensureUserExists(u, this.dbInstance); } catch {} try { ensureUserExists(u, this.dbInstance); } catch {}
try { try {
this.dbInstance.prepare(` getDb().prepare(`
INSERT INTO user_aliases (alias, user_id, source, created_at, updated_at) INSERT INTO user_aliases (alias, user_id, source, created_at, updated_at)
VALUES (?, ?, ?, strftime('%Y-%m-%d %H:%M:%f', 'now'), strftime('%Y-%m-%d %H:%M:%f', 'now')) VALUES (?, ?, ?, strftime('%Y-%m-%d %H:%M:%f', 'now'), strftime('%Y-%m-%d %H:%M:%f', 'now'))
ON CONFLICT(alias) DO UPDATE SET ON CONFLICT(alias) DO UPDATE SET
@ -58,7 +57,7 @@ export class IdentityService {
// Después, intentar en la base de datos // Después, intentar en la base de datos
try { try {
const row = this.dbInstance.prepare(`SELECT user_id FROM user_aliases WHERE alias = ?`).get(n) as { user_id?: string } | undefined; const row = getDb().prepare(`SELECT user_id FROM user_aliases WHERE alias = ?`).get(n) as { user_id?: string } | undefined;
if (row?.user_id) { if (row?.user_id) {
const v = String(row.user_id); const v = String(row.user_id);
// Mantener caché en memoria para futuras resoluciones rápidas // Mantener caché en memoria para futuras resoluciones rápidas

@ -67,7 +67,7 @@ export class MaintenanceService {
static async cleanupInactiveMembersOnce(instance?: Database, retentionDays: number = this.retentionDays): Promise<number> { static async cleanupInactiveMembersOnce(instance?: Database, retentionDays: number = this.retentionDays): Promise<number> {
if (retentionDays <= 0) return 0; if (retentionDays <= 0) return 0;
const threshold = toIsoSqlUTC(new Date(Date.now() - retentionDays * 24 * 60 * 60 * 1000)); const threshold = toIsoSqlUTC(new Date(Date.now() - retentionDays * 24 * 60 * 60 * 1000));
const dbi = ((instance ?? (this as any).dbInstance ?? getDb()) as Database); const dbi = ((instance ?? getDb()) as Database);
const res = dbi.prepare(` const res = dbi.prepare(`
DELETE FROM group_members DELETE FROM group_members
WHERE is_active = 0 WHERE is_active = 0
@ -84,7 +84,7 @@ export class MaintenanceService {
*/ */
static async reconcileAliasUsersOnce(instance?: Database): Promise<number> { static async reconcileAliasUsersOnce(instance?: Database): Promise<number> {
try { try {
const dbi = ((instance ?? (this as any).dbInstance ?? getDb()) as Database); const dbi = ((instance ?? getDb()) as Database);
const rows = dbi.prepare(`SELECT alias, user_id FROM user_aliases WHERE alias != user_id`).all() as any[]; const rows = dbi.prepare(`SELECT alias, user_id FROM user_aliases WHERE alias != user_id`).all() as any[];
let merged = 0; let merged = 0;

@ -85,7 +85,6 @@ export function maybeEnqueueOnboardingBundle(db: Database, params: {
try { try {
const mode = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase(); const mode = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase();
if (mode === 'enforce') { if (mode === 'enforce') {
try { (AllowedGroups as any).dbInstance = db; } catch {}
allowed = AllowedGroups.isAllowed(gid); allowed = AllowedGroups.isAllowed(gid);
} }
} catch {} } catch {}
@ -235,7 +234,6 @@ export function publishGroupCoveragePrompt(db: Database, groupId: string, ratio:
try { try {
const mode = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase(); const mode = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase();
if (mode === 'enforce') { if (mode === 'enforce') {
try { (AllowedGroups as any).dbInstance = db; } catch {}
if (!AllowedGroups.isAllowed(groupId)) { if (!AllowedGroups.isAllowed(groupId)) {
try { Metrics.inc('onboarding_prompts_skipped_total', 1, { group_id: groupId, reason: 'not_allowed' }); } catch {} try { Metrics.inc('onboarding_prompts_skipped_total', 1, { group_id: groupId, reason: 'not_allowed' }); } catch {}
return; return;

@ -1,5 +1,4 @@
import type { Database } from 'bun:sqlite'; import type { Database } from 'bun:sqlite';
import { db } from '../db';
import { TaskService } from '../tasks/service'; import { TaskService } from '../tasks/service';
import { ResponseQueue } from './response-queue'; import { ResponseQueue } from './response-queue';
import { ContactsService } from './contacts'; import { ContactsService } from './contacts';
@ -18,7 +17,7 @@ type UserPreference = {
}; };
export class RemindersService { export class RemindersService {
static dbInstance: Database = db;
private static _running = false; private static _running = false;
private static _timer: any = null; private static _timer: any = null;
@ -81,7 +80,7 @@ export class RemindersService {
} }
static async runOnce(now: Date = new Date()): Promise<void> { static async runOnce(now: Date = new Date()): Promise<void> {
const instanceDb = ((this as any).dbInstance ?? getDb()) as Database; const instanceDb = getDb() as Database;
const todayYMD = this.ymdInTZ(now); const todayYMD = this.ymdInTZ(now);
const nowHM = this.hmInTZ(now); const nowHM = this.hmInTZ(now);
const weekday = this.weekdayShortInTZ(now); // 'Mon'..'Sun' const weekday = this.weekdayShortInTZ(now); // 'Mon'..'Sun'
@ -98,7 +97,6 @@ export class RemindersService {
const enforce = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase() === 'enforce'; const enforce = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase() === 'enforce';
if (enforce) { if (enforce) {
try { try {
(AllowedGroups as any).dbInstance = instanceDb;
// Evitar falsos positivos por caché obsoleta entre operaciones previas del test // Evitar falsos positivos por caché obsoleta entre operaciones previas del test
AllowedGroups.clearCache?.(); AllowedGroups.clearCache?.();
} catch {} } catch {}

@ -1,5 +1,4 @@
import type { Database } from 'bun:sqlite'; import type { Database } from 'bun:sqlite';
import { db } from '../db';
import { getDb } from '../db/locator'; import { getDb } from '../db/locator';
import { IdentityService } from './identity'; import { IdentityService } from './identity';
import { normalizeWhatsAppId } from '../utils/whatsapp'; import { normalizeWhatsAppId } from '../utils/whatsapp';
@ -32,8 +31,7 @@ type ClaimedItem = {
}; };
export const ResponseQueue = { export const ResponseQueue = {
// Permite inyectar una DB distinta en tests si se necesita
dbInstance: db as Database,
// Conservamos la cola en memoria por compatibilidad, aunque no se usa para persistencia // Conservamos la cola en memoria por compatibilidad, aunque no se usa para persistencia
queue: [] as QueuedResponse[], queue: [] as QueuedResponse[],
@ -65,12 +63,7 @@ export const ResponseQueue = {
_cleanupRunCount: 0, _cleanupRunCount: 0,
getDbInstance(): Database { getDbInstance(): Database {
const anyThis = this as any; return getDb();
try {
return (anyThis.dbInstance as Database) ?? getDb();
} catch {
return anyThis.dbInstance as Database;
}
}, },
nowIso(): string { nowIso(): string {

@ -55,7 +55,6 @@ export function enqueueCompletionReactionIfEligible(db: Database, taskId: number
const mode = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase(); const mode = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase();
if (mode === 'enforce') { if (mode === 'enforce') {
let allowed = true; let allowed = true;
try { (AllowedGroups as any).dbInstance = db; } catch {}
try { allowed = AllowedGroups.isAllowed(chatId); } catch { allowed = true; } try { allowed = AllowedGroups.isAllowed(chatId); } catch { allowed = true; }
if (!allowed) return; if (!allowed) return;
} }

@ -1,5 +1,5 @@
import type { Database } from 'bun:sqlite'; import type { Database } from 'bun:sqlite';
import { db, ensureUserExists } from '../db'; import { ensureUserExists } from '../db';
import { getDb as getGlobalDb } from '../db/locator'; import { getDb as getGlobalDb } from '../db/locator';
import { AllowedGroups } from '../services/allowed-groups'; import { AllowedGroups } from '../services/allowed-groups';
import { isGroupId } from '../utils/whatsapp'; import { isGroupId } from '../utils/whatsapp';
@ -20,10 +20,9 @@ type CreateAssignmentInput = {
}; };
export class TaskService { export class TaskService {
static dbInstance: Database = db;
private static getDb(): Database { private static getDb(): Database {
return ((this as any).dbInstance as Database) ?? getGlobalDb(); return getGlobalDb();
} }
static createTask(task: CreateTaskInput, assignments: CreateAssignmentInput[] = []): number { static createTask(task: CreateTaskInput, assignments: CreateAssignmentInput[] = []): number {
@ -46,7 +45,6 @@ export class TaskService {
try { try {
const mode = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase(); const mode = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase();
if (groupIdToInsert && isGroupId(groupIdToInsert) && mode === 'enforce') { if (groupIdToInsert && isGroupId(groupIdToInsert) && mode === 'enforce') {
try { (AllowedGroups as any).dbInstance = this.dbInstance; } catch {}
if (!AllowedGroups.isAllowed(groupIdToInsert)) { if (!AllowedGroups.isAllowed(groupIdToInsert)) {
groupIdToInsert = null; groupIdToInsert = null;
} }

Loading…
Cancel
Save