Skip to content

Commit 742dd59

Browse files
fix: Fix issues with the KV sessions
1 parent f01698c commit 742dd59

File tree

2 files changed

+57
-30
lines changed

2 files changed

+57
-30
lines changed

src/server/team-roles.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import "server-only";
22
import { getDB } from "@/db";
3-
import { TEAM_PERMISSIONS, teamRoleTable } from "@/db/schema";
3+
import { TEAM_PERMISSIONS, teamRoleTable, teamMembershipTable } from "@/db/schema";
44
import { ZSAError } from "zsa";
55
import { eq, and, not } from "drizzle-orm";
66
import { requireTeamPermission } from "@/utils/team-auth";
7+
import { updateAllSessionsOfUser } from "@/utils/kv-session";
78

89
/**
910
* Get all custom roles for a team
@@ -157,6 +158,19 @@ export async function updateTeamRole({
157158
})
158159
.where(eq(teamRoleTable.id, roleId));
159160

161+
// Update sessions for all users with this role
162+
const membersWithRole = await db.query.teamMembershipTable.findMany({
163+
where: and(
164+
eq(teamMembershipTable.teamId, teamId),
165+
eq(teamMembershipTable.roleId, roleId),
166+
eq(teamMembershipTable.isSystemRole, 0)
167+
),
168+
});
169+
170+
for (const member of membersWithRole) {
171+
await updateAllSessionsOfUser(member.userId);
172+
}
173+
160174
return {
161175
id: roleId,
162176
name: data.name || role.name,
@@ -199,9 +213,23 @@ export async function deleteTeamRole({
199213
throw new ZSAError("FORBIDDEN", "This role cannot be deleted");
200214
}
201215

216+
// Get all users with this role before deleting it
217+
const membersWithRole = await db.query.teamMembershipTable.findMany({
218+
where: and(
219+
eq(teamMembershipTable.teamId, teamId),
220+
eq(teamMembershipTable.roleId, roleId),
221+
eq(teamMembershipTable.isSystemRole, 0)
222+
),
223+
});
224+
202225
// Delete the role
203226
await db.delete(teamRoleTable)
204227
.where(eq(teamRoleTable.id, roleId));
205228

229+
// Update sessions for all users who had this role
230+
for (const member of membersWithRole) {
231+
await updateAllSessionsOfUser(member.userId);
232+
}
233+
206234
return { success: true };
207235
}

src/utils/kv-session.ts

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,11 @@ export async function createKVSession({
119119
// Check if user has reached the session limit
120120
const existingSessions = await getAllSessionIdsOfUser(userId);
121121

122-
// If user has MAX_SESSIONS_PER_USER or more sessions, delete the oldest one
122+
// Calculate how many sessions we need to delete to make room for the new one
123123
if (existingSessions.length >= MAX_SESSIONS_PER_USER) {
124+
// We need to delete enough sessions to get below the limit after adding the new one
125+
const sessionsToDelete = existingSessions.length - MAX_SESSIONS_PER_USER + 1;
126+
124127
// Sort sessions by expiration time (oldest first)
125128
const sortedSessions = [...existingSessions].sort((a, b) => {
126129
// If a session has no expiration, treat it as oldest
@@ -129,11 +132,16 @@ export async function createKVSession({
129132
return a.absoluteExpiration.getTime() - b.absoluteExpiration.getTime();
130133
});
131134

132-
// Delete the oldest session
133-
const oldestSessionKey = sortedSessions?.[0]?.key;
134-
const oldestSessionId = oldestSessionKey?.split(':')?.[2]; // Extract sessionId from key
135+
// Delete the oldest sessions
136+
for (let i = 0; i < sessionsToDelete; i++) {
137+
const sessionKey = sortedSessions[i]?.key;
138+
if (!sessionKey) continue;
139+
140+
const sessionId = sessionKey.split(':')[2];
141+
if (!sessionId) continue;
135142

136-
await deleteKVSession(oldestSessionId, userId);
143+
await deleteKVSession(sessionId, userId);
144+
}
137145
}
138146

139147
await kv.put(
@@ -178,18 +186,25 @@ export async function getKVSession(sessionId: string, userId: string): Promise<K
178186
return session;
179187
}
180188

181-
export async function updateKVSession(sessionId: string, userId: string, expiresAt: Date): Promise<KVSession | null> {
189+
export async function updateKVSession(
190+
sessionId: string,
191+
userId: string,
192+
expiresAt: Date,
193+
userData?: KVSessionUser,
194+
teams?: KVSession['teams']
195+
): Promise<KVSession | null> {
182196
const session = await getKVSession(sessionId, userId);
183197
if (!session) return null;
184198

185-
const updatedUser = await getUserFromDB(userId);
199+
// Only fetch user data if not provided
200+
const updatedUser = userData ?? await getUserFromDB(userId);
186201

187202
if (!updatedUser) {
188203
throw new Error("User not found");
189204
}
190205

191-
// Get updated teams data with permissions
192-
const teamsWithPermissions = await getUserTeamsWithPermissions(userId);
206+
// Only fetch teams data if not provided
207+
const teamsWithPermissions = teams ?? await getUserTeamsWithPermissions(userId);
193208

194209
const updatedSession: KVSession = {
195210
...session,
@@ -285,11 +300,6 @@ export async function getAllSessionIdsOfUser(userId: string) {
285300
*/
286301
export async function updateAllSessionsOfUser(userId: string) {
287302
const sessions = await getAllSessionIdsOfUser(userId);
288-
const kv = await getKV();
289-
290-
if (!kv) {
291-
throw new Error("Can't connect to KV store");
292-
}
293303

294304
const newUserData = await getUserFromDB(userId);
295305

@@ -299,24 +309,13 @@ export async function updateAllSessionsOfUser(userId: string) {
299309
const teamsWithPermissions = await getUserTeamsWithPermissions(userId);
300310

301311
for (const sessionObj of sessions) {
302-
const session = await kv.get(sessionObj.key);
303-
if (!session) continue;
304-
305-
const sessionData = JSON.parse(session) as KVSession;
312+
// Extract sessionId from key (format: "session:userId:sessionId")
313+
const sessionId = sessionObj.key.split(':')[2];
314+
if (!sessionId) continue;
306315

307316
// Only update non-expired sessions
308317
if (sessionObj.absoluteExpiration && sessionObj.absoluteExpiration.getTime() > Date.now()) {
309-
const ttlInSeconds = Math.floor((sessionObj.absoluteExpiration.getTime() - Date.now()) / 1000);
310-
311-
await kv.put(
312-
sessionObj.key,
313-
JSON.stringify({
314-
...sessionData,
315-
user: newUserData,
316-
teams: teamsWithPermissions,
317-
}),
318-
{ expirationTtl: ttlInSeconds }
319-
);
318+
await updateKVSession(sessionId, userId, sessionObj.absoluteExpiration, newUserData, teamsWithPermissions);
320319
}
321320
}
322321
}

0 commit comments

Comments
 (0)