1- import { getPrismaClientForTenancy , getPrismaSchemaForTenancy , globalPrismaClient , sqlQuoteIdent } from "@/prisma-client" ;
1+ import { globalPrismaClient } from "@/prisma-client" ;
22import { createCrudHandlers } from "@/route-handlers/crud-handler" ;
33import { SmartRequestAuth } from "@/route-handlers/smart-request" ;
4- import { Prisma } from "@/generated/prisma/client" ;
54import { KnownErrors } from "@stackframe/stack-shared" ;
65import { sessionsCrud } from "@stackframe/stack-shared/dist/interface/crud/sessions" ;
76import { userIdOrMeSchema , yupObject , yupString } from "@stackframe/stack-shared/dist/schema-fields" ;
87import { StatusError , throwErr } from "@stackframe/stack-shared/dist/utils/errors" ;
9- import { GeoInfo } from "@stackframe/stack-shared/dist/utils/geo" ;
8+ import { geoInfoSchema } from "@stackframe/stack-shared/dist/utils/geo" ;
109import { createLazyProxy } from "@stackframe/stack-shared/dist/utils/proxies" ;
1110
1211export const sessionsCrudHandlers = createLazyProxy ( ( ) => createCrudHandlers ( sessionsCrud , {
@@ -17,8 +16,6 @@ export const sessionsCrudHandlers = createLazyProxy(() => createCrudHandlers(ses
1716 user_id : userIdOrMeSchema . defined ( ) ,
1817 } ) . defined ( ) ,
1918 onList : async ( { auth, query } ) => {
20- const prisma = await getPrismaClientForTenancy ( auth . tenancy ) ;
21- const schema = await getPrismaSchemaForTenancy ( auth . tenancy ) ;
2219 const listImpersonations = auth . type === 'admin' ;
2320
2421 if ( auth . type === 'client' ) {
@@ -39,60 +36,25 @@ export const sessionsCrudHandlers = createLazyProxy(() => createCrudHandlers(ses
3936 } ,
4037 } ) ;
4138
42- // Get the latest event for each session
43- const events = await prisma . $queryRaw < Array < { sessionId : string , lastActiveAt : Date , geo : GeoInfo | null , isEndUserIpInfoGuessTrusted : boolean } > > `
44- WITH latest_events AS (
45- SELECT data->>'sessionId' as "sessionId",
46- MAX("eventStartedAt") as "lastActiveAt"
47- FROM ${ sqlQuoteIdent ( schema ) } ."Event"
48- WHERE ${ refreshTokenObjs . length > 0
49- ? Prisma . sql `data->>'sessionId' = ANY(${ Prisma . sql `ARRAY[${ Prisma . join ( refreshTokenObjs . map ( s => s . id ) ) } ]` } )`
50- : Prisma . sql `FALSE` }
51- AND "systemEventTypeIds" @> '{"$session-activity"}'
52- AND data->>'userId' = ${ query . user_id }
53- AND data->>'projectId' = ${ auth . tenancy . project . id }
54- AND COALESCE(data->>'branchId', 'main') = ${ auth . tenancy . branchId }
55- GROUP BY data->>'sessionId'
56- )
57- SELECT e.data->>'sessionId' as "sessionId",
58- le."lastActiveAt",
59- row_to_json(geo.*) as "geo",
60- e.data->>'isEndUserIpInfoGuessTrusted' as "isEndUserIpInfoGuessTrusted"
61- FROM ${ sqlQuoteIdent ( schema ) } ."Event" e
62- JOIN latest_events le ON e.data->>'sessionId' = le."sessionId" AND e."eventStartedAt" = le."lastActiveAt"
63- LEFT JOIN ${ sqlQuoteIdent ( schema ) } ."EventIpInfo" geo ON geo.id = e."endUserIpInfoGuessId"
64- WHERE e."systemEventTypeIds" @> '{"$session-activity"}'
65- AND e.data->>'userId' = ${ query . user_id }
66- AND e.data->>'projectId' = ${ auth . tenancy . project . id }
67- AND COALESCE(e.data->>'branchId', 'main') = ${ auth . tenancy . branchId }
68- ` ;
69-
70- const sessionsWithLastActiveAt = refreshTokenObjs . map ( s => {
71- const event = events . find ( e => e . sessionId === s . id ) ;
72- return {
73- ...s ,
74- last_active_at : event ?. lastActiveAt . getTime ( ) ,
75- last_active_at_end_user_ip_info : event ?. geo ,
76- } ;
77- } ) ;
78-
7939 const result = {
80- items : sessionsWithLastActiveAt . map ( s => ( {
81- id : s . id ,
82- user_id : s . projectUserId ,
83- created_at : s . createdAt . getTime ( ) ,
84- last_used_at : s . last_active_at ,
85- is_impersonation : s . isImpersonation ,
86- last_used_at_end_user_ip_info : s . last_active_at_end_user_ip_info ?? undefined ,
87- is_current_session : s . id === auth . refreshTokenId ,
88- } ) ) ,
40+ items : refreshTokenObjs . map ( s => {
41+ const ipInfo = s . lastActiveAtIpInfo ? geoInfoSchema . validateSync ( s . lastActiveAtIpInfo ) : undefined ;
42+ return {
43+ id : s . id ,
44+ user_id : s . projectUserId ,
45+ created_at : s . createdAt . getTime ( ) ,
46+ last_used_at : s . lastActiveAt . getTime ( ) ,
47+ is_impersonation : s . isImpersonation ,
48+ is_current_session : s . id === auth . refreshTokenId ,
49+ last_used_at_end_user_ip_info : ipInfo ,
50+ } ;
51+ } ) ,
8952 is_paginated : false ,
9053 } ;
9154
9255 return result ;
9356 } ,
9457 onDelete : async ( { auth, params } : { auth : SmartRequestAuth , params : { id : string } , query : { user_id ?: string } } ) => {
95- const prisma = await getPrismaClientForTenancy ( auth . tenancy ) ;
9658 const session = await globalPrismaClient . projectUserRefreshToken . findFirst ( {
9759 where : {
9860 tenancyId : auth . tenancy . id ,
0 commit comments