@@ -7,17 +7,20 @@ import { Elysia, t } from 'elysia';
77import { type ExportRequest , processExport } from '../lib/export' ;
88import { logger } from '../lib/logger' ;
99
10- // import { createRateLimitMiddleware } from '../middleware/rate-limit';
10+ import { createRateLimitMiddleware } from '../middleware/rate-limit' ;
1111
1212dayjs . extend ( utc ) ;
1313
14- // Rate limiting for exports - use expensive rate limit (stricter limits)
15- // const exportRateLimit = createRateLimitMiddleware({
16- // type: 'expensive',
17- // skipAuth: false,
18- // });
14+ const exportRateLimit = createRateLimitMiddleware ( {
15+ type : 'expensive' ,
16+ identifier : 'export' ,
17+ customConfig : {
18+ requests : 10 ,
19+ window : '1m' ,
20+ } ,
21+ skipAuth : false ,
22+ } ) ;
1923
20- // Cached website lookup (same as in RPC utils)
2124const getWebsiteById = cacheable (
2225 async ( id : string ) => {
2326 try {
@@ -59,20 +62,17 @@ async function authorizeWebsiteAccess(
5962 return website ;
6063 }
6164
62- // Get user session
6365 const session = await auth . api . getSession ( { headers } ) ;
6466 const user = session ?. user ;
6567
6668 if ( ! user ) {
6769 throw new Error ( 'Authentication is required for this action' ) ;
6870 }
6971
70- // Admin users have full access
7172 if ( user . role === 'ADMIN' ) {
7273 return website ;
7374 }
7475
75- // Check organization permissions
7676 if ( website . organizationId ) {
7777 const { success } = await websitesApi . hasPermission ( {
7878 headers,
@@ -90,7 +90,7 @@ async function authorizeWebsiteAccess(
9090}
9191
9292export const exportRoute = new Elysia ( { prefix : '/v1/export' } )
93- // .use(exportRateLimit)
93+ . use ( exportRateLimit )
9494 . post (
9595 '/data' ,
9696 async ( { body, request } ) => {
@@ -114,14 +114,22 @@ export const exportRoute = new Elysia({ prefix: '/v1/export' })
114114 'read'
115115 ) ;
116116
117- // Validate and sanitize date inputs
117+ if ( ! _website ) {
118+ return createErrorResponse (
119+ 403 ,
120+ 'ACCESS_DENIED' ,
121+ 'Access denied. You may not have permission to export data for this website.'
122+ ) ;
123+ }
124+
118125 const { validatedDates, error : dateError } = validateDateRange (
119126 body . start_date ,
120127 body . end_date
121128 ) ;
122129
123130 if ( dateError ) {
124- await logger . warn ( 'Export request with invalid dates' , {
131+ logger . warn ( {
132+ message : 'Export request with invalid dates' ,
125133 requestId,
126134 websiteId,
127135 startDate : body . start_date ,
@@ -131,10 +139,10 @@ export const exportRoute = new Elysia({ prefix: '/v1/export' })
131139 return createErrorResponse ( 400 , 'INVALID_DATE_RANGE' , dateError ) ;
132140 }
133141
134- // Validate export format
135142 const format = body . format || 'json' ;
136143 if ( ! [ 'csv' , 'json' , 'txt' , 'proto' ] . includes ( format ) ) {
137- await logger . warn ( 'Export request with invalid format' , {
144+ logger . warn ( {
145+ message : 'Export request with invalid format' ,
138146 requestId,
139147 websiteId,
140148 format,
@@ -146,8 +154,8 @@ export const exportRoute = new Elysia({ prefix: '/v1/export' })
146154 ) ;
147155 }
148156
149- // Log export initiation for audit trail
150- await logger . info ( 'Data export initiated' , {
157+ logger . info ( {
158+ message : 'Data export initiated' ,
151159 requestId,
152160 websiteId,
153161 startDate : validatedDates . startDate ,
@@ -160,7 +168,6 @@ export const exportRoute = new Elysia({ prefix: '/v1/export' })
160168 timestamp : new Date ( ) . toISOString ( ) ,
161169 } ) ;
162170
163- // Process the export with validated data
164171 const exportRequest : ExportRequest = {
165172 website_id : websiteId ,
166173 start_date : validatedDates . startDate ,
@@ -170,8 +177,8 @@ export const exportRoute = new Elysia({ prefix: '/v1/export' })
170177
171178 const result = await processExport ( exportRequest ) ;
172179
173- // Log successful export for audit trail
174- logger . info ( 'Data export completed successfully' , {
180+ logger . info ( {
181+ message : 'Data export completed successfully' ,
175182 requestId,
176183 websiteId,
177184 filename : result . filename ,
@@ -189,8 +196,8 @@ export const exportRoute = new Elysia({ prefix: '/v1/export' })
189196 } ,
190197 } ) ;
191198 } catch ( error ) {
192- // Log export failure for audit trail
193- logger . error ( 'Data export failed' , {
199+ logger . error ( {
200+ message : 'Data export failed' ,
194201 requestId,
195202 websiteId : body . website_id ,
196203 error : error instanceof Error ? error . message : String ( error ) ,
@@ -203,7 +210,6 @@ export const exportRoute = new Elysia({ prefix: '/v1/export' })
203210 timestamp : new Date ( ) . toISOString ( ) ,
204211 } ) ;
205212
206- // Handle authorization errors specifically
207213 if ( error instanceof Error ) {
208214 if ( error . message . includes ( 'not found' ) ) {
209215 return createErrorResponse (
@@ -317,15 +323,13 @@ function validateDateRange(
317323 const maxHistoryDays = 365 * 2 ; // 2 years max
318324 const maxRangeDays = 365 ; // 1 year max range
319325
320- // If no dates provided, allow (will default to reasonable limits in query)
321326 if ( ! ( startDate || endDate ) ) {
322327 return { validatedDates : { } } ;
323328 }
324329
325330 let validatedStartDate : string | undefined ;
326331 let validatedEndDate : string | undefined ;
327332
328- // Validate start date
329333 if ( startDate ) {
330334 const start = dayjs . utc ( startDate , 'YYYY-MM-DD' , true ) ;
331335 if ( ! start . isValid ( ) ) {
0 commit comments