@@ -16,21 +16,23 @@ const logger = createLogger('WorkspaceFileStyleAPI')
1616
1717/**
1818 * GET /api/workspaces/[id]/files/[fileId]/style
19- * Extract a compact JSON style summary from an uploaded .docx or .pptx file.
20- * Uses OOXML theme XML to return theme colors, font pair, and named styles.
21- * Only works on binary OOXML files (ZIP format) — not on JS source files .
19+ * Extract a compact JSON style summary from an uploaded .docx, .pptx, or .pdf file.
20+ * OOXML files return theme colors, font pair, and named styles.
21+ * PDF files return page dimensions and embedded font names .
2222 */
23+ const MAX_STYLE_FILE_BYTES = 100 * 1024 * 1024 // 100 MB
24+
2325export const GET = withRouteHandler (
2426 async ( request : NextRequest , context : { params : Promise < { id : string ; fileId : string } > } ) => {
25- const parsed = await parseRequest ( workspaceFileStyleContract , request , context )
26- if ( ! parsed . success ) return parsed . response
27- const { id : workspaceId , fileId } = parsed . data . params
28-
2927 const session = await getSession ( )
3028 if ( ! session ?. user ?. id ) {
3129 return NextResponse . json ( { error : 'Unauthorized' } , { status : 401 } )
3230 }
3331
32+ const parsed = await parseRequest ( workspaceFileStyleContract , request , context )
33+ if ( ! parsed . success ) return parsed . response
34+ const { id : workspaceId , fileId } = parsed . data . params
35+
3436 const membership = await verifyWorkspaceMembership ( session . user . id , workspaceId )
3537 if ( ! membership ) {
3638 return NextResponse . json ( { error : 'Insufficient permissions' } , { status : 403 } )
@@ -42,13 +44,20 @@ export const GET = withRouteHandler(
4244 }
4345
4446 const rawExt = fileRecord . name . split ( '.' ) . pop ( ) ?. toLowerCase ( )
45- if ( rawExt !== 'docx' && rawExt !== 'pptx' ) {
47+ if ( rawExt !== 'docx' && rawExt !== 'pptx' && rawExt !== 'pdf' ) {
4648 return NextResponse . json (
47- { error : 'Style extraction only supports .docx and .pptx files' } ,
49+ { error : 'Style extraction supports .docx, .pptx, and .pdf files' } ,
50+ { status : 422 }
51+ )
52+ }
53+ const ext : 'docx' | 'pptx' | 'pdf' = rawExt
54+
55+ if ( fileRecord . size > MAX_STYLE_FILE_BYTES ) {
56+ return NextResponse . json (
57+ { error : 'File is too large for style extraction (limit: 100 MB)' } ,
4858 { status : 422 }
4959 )
5060 }
51- const ext : 'docx' | 'pptx' = rawExt
5261
5362 let buffer : Buffer
5463 try {
@@ -66,17 +75,13 @@ export const GET = withRouteHandler(
6675 return NextResponse . json (
6776 {
6877 error :
69- 'File is not a compiled binary document — style extraction requires an uploaded or compiled .docx/.pptx file ' ,
78+ 'Could not extract style — file may be encrypted, corrupt, image-only, or contain no parseable style information ' ,
7079 } ,
7180 { status : 422 }
7281 )
7382 }
7483
75- logger . info ( 'Extracted style summary via API' , {
76- fileId,
77- format : ext ,
78- themeName : summary . theme . name ,
79- } )
84+ logger . info ( 'Extracted style summary via API' , { fileId, format : ext } )
8085
8186 return NextResponse . json ( summary , {
8287 headers : { 'Cache-Control' : 'private, max-age=300' } ,
0 commit comments