1import db from '$lib/db/db.server';
2import { users } from '$lib/db/schema';
3import { eq } from 'drizzle-orm/sql';
4import { validateSessionToken, generateSessionToken, createSession } from '$lib/api/session.server';
5import { setSessionTokenCookie } from '$lib/api/session.cookie';
6import { createSafeUser } from '$lib/types/chat';
7import { createLogger } from '$lib/utils/logger.server';
8import { buddyListCache } from '$lib/buddyListCache';
9import type { RequestHandler } from './$types';
10
11const log = createLogger('status-server');
12
13export const POST: RequestHandler = async ({ request, cookies, locals }) => {
14 if (!locals.user) {
15 log.warn('Authentication required');
16 return new Response(JSON.stringify({ success: false, error: 'Unauthorized' }), {
17 status: 401,
18 headers: { 'Content-Type': 'application/json' }
19 });
20 }
21
22 try {
23 const { status } = await request.json();
24 const validStatuses = ['online', 'away', 'busy', 'offline'];
25 if (!validStatuses.includes(status)) {
26 log.warn('Invalid status received', { status });
27 return new Response(JSON.stringify({ success: false, error: 'Invalid status' }), {
28 status: 400,
29 headers: { 'Content-Type': 'application/json' }
30 });
31 }
32
33 const userId = locals.user.id;
34 const maskedUserId = `${userId.slice(0, 4)}...${userId.slice(-4)}`;
35 log.debug('Updating user status', { userId: maskedUserId, status });
36
37 const now = Date.now();
38
39 // Update the user status in the database
40 // Always update lastSeen to support timeout detection
41 const updatedUser = await db.update(users)
42 .set({
43 status,
44 lastSeen: now // Always update lastSeen for proper timeout detection
45 })
46 .where(eq(users.id, userId))
47 .returning()
48 .get();
49 log.debug('Database updated successfully', { userId: maskedUserId, status });
50
51 // Invalidate buddy list cache when status changes
52 buddyListCache.invalidate();
53
54 // Renew session if status is online and session expires in less than 1 day
55 if (status === 'online') {
56 const token = cookies.get('session');
57 if (token) {
58 const result = await validateSessionToken(token);
59 if (result.session) {
60 const remaining = result.session.expiresAt - now;
61 const threshold = 24 * 60 * 60 * 1000; // 1 day in milliseconds
62 if (remaining < threshold) {
63 const newToken = generateSessionToken();
64 const newSession = await createSession(newToken, userId);
65 setSessionTokenCookie({ cookies }, newToken, newSession.expiresAt);
66 log.info('Session renewed', {
67 userId: maskedUserId,
68 expiresAt: new Date(newSession.expiresAt).toISOString()
69 });
70 }
71 }
72 }
73 }
74
75 return new Response(JSON.stringify({
76 success: true,
77 user: createSafeUser(updatedUser)
78 }), {
79 status: 200,
80 headers: { 'Content-Type': 'application/json' }
81 });
82 } catch (error) {
83 return new Response(
84 JSON.stringify({ success: false, error: error instanceof Error ? error.message : 'Unknown error' }),
85 {
86 status: 500,
87 headers: { 'Content-Type': 'application/json' }
88 }
89 );
90 }
91};