@@ -2,6 +2,116 @@ import { defineConfig, loadEnv } from 'vite';
22import tsConfigPaths from 'vite-tsconfig-paths' ;
33import { tanstackStart } from '@tanstack/react-start/plugin/vite' ;
44import viteReact from '@vitejs/plugin-react' ;
5+ import { unsealData } from 'iron-session' ;
6+ import { decodeJwt } from 'jose' ;
7+ import type { Plugin } from 'vite' ;
8+
9+ // Request logging utilities
10+ async function extractUserInfoFromRequest ( req : any ) : Promise < { userId : string ; orgId : string } > {
11+ try {
12+ const cookieName = process . env . WORKOS_COOKIE_NAME || 'wos-session' ;
13+ const cookiePassword = process . env . WORKOS_COOKIE_PASSWORD ;
14+
15+ if ( ! cookiePassword ) {
16+ return { userId : 'anonymous' , orgId : 'anonymous' } ;
17+ }
18+
19+ const cookieHeader = req . headers ?. cookie || req . getHeader ?.( 'cookie' ) ;
20+ if ( ! cookieHeader ) {
21+ return { userId : 'anonymous' , orgId : 'anonymous' } ;
22+ }
23+
24+ const cookies = cookieHeader . split ( ';' ) . reduce ( ( acc : Record < string , string > , cookie : string ) => {
25+ const [ key , value ] = cookie . trim ( ) . split ( '=' ) ;
26+ acc [ key ] = decodeURIComponent ( value ) ;
27+ return acc ;
28+ } , { } ) ;
29+
30+ const sessionCookie = cookies [ cookieName ] ;
31+ if ( ! sessionCookie ) {
32+ return { userId : 'anonymous' , orgId : 'anonymous' } ;
33+ }
34+
35+ const session = await unsealData ( sessionCookie , {
36+ password : cookiePassword ,
37+ } ) as { user ?: { id ?: string } ; accessToken ?: string } ;
38+
39+ if ( ! session ?. user ?. id || ! session ?. accessToken ) {
40+ return { userId : 'anonymous' , orgId : 'anonymous' } ;
41+ }
42+
43+ // Decode JWT to get organization ID
44+ let orgId = 'anonymous' ;
45+ try {
46+ const decoded = decodeJwt < { org_id ?: string } > ( session . accessToken ) ;
47+ orgId = decoded . org_id || 'anonymous' ;
48+ } catch ( error ) {
49+ // If JWT decode fails, just use anonymous
50+ }
51+
52+ return { userId : session . user . id , orgId } ;
53+ } catch ( error ) {
54+ return { userId : 'anonymous' , orgId : 'anonymous' } ;
55+ }
56+ }
57+
58+ function logRequestInit ( method : string , path : string , requestId : string , userId : string , orgId : string ) {
59+ console . log ( JSON . stringify ( {
60+ event : 'request_initialized' ,
61+ method,
62+ path,
63+ requestId,
64+ userId,
65+ orgId,
66+ } ) ) ;
67+ }
68+
69+ function logResponse ( method : string , path : string , requestId : string , latency : number , statusCode : number ) {
70+ console . log ( JSON . stringify ( {
71+ event : 'response_sent' ,
72+ method,
73+ path,
74+ requestId,
75+ latency,
76+ statusCode,
77+ } ) ) ;
78+ }
79+
80+ // Logging middleware plugin
81+ function requestLoggingPlugin ( ) : Plugin {
82+ return {
83+ name : 'request-logging' ,
84+ configureServer ( server ) {
85+ server . middlewares . use ( async ( req , res , next ) => {
86+ const existingRequestId = req . headers [ 'x-request-id' ] ;
87+ const requestId = Array . isArray ( existingRequestId )
88+ ? existingRequestId [ 0 ]
89+ : existingRequestId || `ssr-${ Math . random ( ) . toString ( 36 ) . slice ( 2 , 10 ) } ` ;
90+ const requestStart = Date . now ( ) ;
91+
92+ const pathname = req . url ?. split ( '?' ) [ 0 ] || '/' ;
93+ const method = req . method || 'GET' ;
94+
95+ // Extract user ID and org ID and log request initialization
96+ const { userId, orgId } = await extractUserInfoFromRequest ( req ) ;
97+ logRequestInit ( method , pathname , requestId , userId , orgId ) ;
98+
99+ // Set request ID header
100+ req . headers [ 'x-request-id' ] = requestId ;
101+
102+ // Capture original end function to log response
103+ const originalEnd = res . end . bind ( res ) ;
104+ res . end = function ( ...args : any [ ] ) {
105+ const latency = Date . now ( ) - requestStart ;
106+ logResponse ( method , pathname , requestId , latency , res . statusCode || 200 ) ;
107+ return originalEnd ( ...args ) ;
108+ } ;
109+
110+ next ( ) ;
111+ } ) ;
112+ } ,
113+ } ;
114+ }
5115
6116export default defineConfig ( ( { mode } ) => {
7117
@@ -25,6 +135,7 @@ export default defineConfig(({ mode }) => {
25135 tsConfigPaths ( {
26136 projects : [ './tsconfig.json' ] ,
27137 } ) ,
138+ requestLoggingPlugin ( ) ,
28139 tanstackStart ( ) ,
29140 viteReact ( ) ,
30141 // cloudflare({ viteEnvironment: { name: 'ssr' } }),
0 commit comments