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