import { getDb } from '../db/client.js' import * as valkey from '../plugins/valkey.js' import { VK_MITRAS_DEACTIVATED } from './mitra-status.service.js' import { revokeAllSessionsForUser } from './token.service.js' import { UserType } from '../constants.js' const sql = getDb() export const getMitraByPhone = async (phone) => { const [mitra] = await sql` SELECT id, display_name, phone, is_active, created_at FROM mitras WHERE phone = ${phone} ` return mitra } export const getMitraById = async (id) => { const [mitra] = await sql` SELECT id, display_name, phone, is_active, created_at FROM mitras WHERE id = ${id} ` return mitra } export const createMitra = async ({ phone, display_name }) => { const [mitra] = await sql` INSERT INTO mitras (phone, display_name, is_active) VALUES (${phone}, ${display_name}, false) RETURNING id, phone, display_name, is_active, created_at ` return mitra } export const updateMitraStatus = async (id, is_active) => { const [mitra] = await sql` UPDATE mitras SET is_active = ${is_active} WHERE id = ${id} RETURNING id, is_active ` if (!mitra) throw Object.assign(new Error('Mitra not found'), { code: 'NOT_FOUND', statusCode: 404 }) // Deactivation also revokes all auth_sessions so the next token refresh fails // (bounds the "ghost online" window to access-token TTL across all routes, // not just heartbeat). See requirement/valkey-online-mirror-plan.md. if (!is_active) { await revokeAllSessionsForUser({ userType: UserType.MITRA, userId: id }) } try { if (is_active) { await valkey.srem(VK_MITRAS_DEACTIVATED, id) } else { await valkey.sadd(VK_MITRAS_DEACTIVATED, id) } } catch (err) { console.error(`[valkey-mirror] updateMitraStatus ${id} failed:`, err) } return mitra } export const updateMitraDisplayName = async (id, display_name) => { const [mitra] = await sql` UPDATE mitras SET display_name = ${display_name} WHERE id = ${id} RETURNING id, phone, display_name, is_active, created_at ` if (!mitra) throw Object.assign(new Error('Mitra not found'), { code: 'NOT_FOUND', statusCode: 404 }) return mitra } export const listMitras = async ({ page = 1, limit = 20, is_active }) => { const offset = (page - 1) * limit const conditions = is_active !== undefined ? sql`WHERE is_active = ${is_active}` : sql`` const items = await sql` SELECT id, phone, display_name, is_active, created_at FROM mitras ${conditions} ORDER BY created_at DESC LIMIT ${limit} OFFSET ${offset} ` const [{ count }] = await sql`SELECT COUNT(*) FROM mitras ${conditions}` return { items, total: Number(count), page, limit } }