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