@@ -192,38 +192,70 @@ export async function handleGet(request, reply) {
192192 return reply . code ( 500 ) . send ( { error : 'Read error' } ) ;
193193 }
194194
195- // Content negotiation for RDF resources
196- if ( connegEnabled && isRdfContentType ( storedContentType ) ) {
197- try {
198- // Parse stored content as JSON-LD
199- const jsonLd = JSON . parse ( content . toString ( ) ) ;
200-
201- // Select output format based on Accept header
202- const acceptHeader = request . headers . accept ;
203- const targetType = selectContentType ( acceptHeader , connegEnabled ) ;
204-
205- // Convert to requested format
206- const { content : outputContent , contentType : outputType } = await fromJsonLd (
207- jsonLd ,
208- targetType ,
209- resourceUrl ,
210- connegEnabled
211- ) ;
195+ // Content negotiation for RDF resources (including HTML with JSON-LD data islands)
196+ if ( connegEnabled ) {
197+ const contentStr = content . toString ( ) ;
198+ const acceptHeader = request . headers . accept || '' ;
199+ const wantsTurtle = acceptHeader . includes ( 'text/turtle' ) ||
200+ acceptHeader . includes ( 'text/n3' ) ||
201+ acceptHeader . includes ( 'application/n-triples' ) ;
202+
203+ // Check if this is HTML with JSON-LD data island
204+ const isHtmlWithDataIsland = contentStr . trimStart ( ) . startsWith ( '<!DOCTYPE' ) ||
205+ contentStr . trimStart ( ) . startsWith ( '<html' ) ;
206+
207+ if ( isHtmlWithDataIsland && wantsTurtle ) {
208+ // Extract JSON-LD from HTML data island and convert to Turtle
209+ try {
210+ const jsonLdMatch = contentStr . match ( / < s c r i p t \s + t y p e = [ " ' ] a p p l i c a t i o n \/ l d \+ j s o n [ " ' ] \s * > ( [ \s \S ] * ?) < \/ s c r i p t > / i) ;
211+ if ( jsonLdMatch ) {
212+ const jsonLd = JSON . parse ( jsonLdMatch [ 1 ] ) ;
213+ const { content : turtleContent } = await fromJsonLd ( jsonLd , 'text/turtle' , resourceUrl , true ) ;
214+
215+ const headers = getAllHeaders ( {
216+ isContainer : false ,
217+ etag : stats . etag ,
218+ contentType : 'text/turtle' ,
219+ origin,
220+ resourceUrl,
221+ connegEnabled
222+ } ) ;
223+ headers [ 'Vary' ] = getVaryHeader ( connegEnabled , request . mashlibEnabled ) ;
212224
213- const headers = getAllHeaders ( {
214- isContainer : false ,
215- etag : stats . etag ,
216- contentType : outputType ,
217- origin,
218- resourceUrl,
219- connegEnabled
220- } ) ;
221- headers [ 'Vary' ] = getVaryHeader ( connegEnabled , request . mashlibEnabled ) ;
225+ Object . entries ( headers ) . forEach ( ( [ k , v ] ) => reply . header ( k , v ) ) ;
226+ return reply . send ( turtleContent ) ;
227+ }
228+ } catch ( err ) {
229+ // Fall through to serve HTML if conversion fails
230+ console . error ( 'Failed to convert HTML data island to Turtle:' , err . message ) ;
231+ }
232+ } else if ( isRdfContentType ( storedContentType ) ) {
233+ // Plain JSON-LD file
234+ try {
235+ const jsonLd = JSON . parse ( contentStr ) ;
236+ const targetType = selectContentType ( acceptHeader , connegEnabled ) ;
237+ const { content : outputContent , contentType : outputType } = await fromJsonLd (
238+ jsonLd ,
239+ targetType ,
240+ resourceUrl ,
241+ connegEnabled
242+ ) ;
243+
244+ const headers = getAllHeaders ( {
245+ isContainer : false ,
246+ etag : stats . etag ,
247+ contentType : outputType ,
248+ origin,
249+ resourceUrl,
250+ connegEnabled
251+ } ) ;
252+ headers [ 'Vary' ] = getVaryHeader ( connegEnabled , request . mashlibEnabled ) ;
222253
223- Object . entries ( headers ) . forEach ( ( [ k , v ] ) => reply . header ( k , v ) ) ;
224- return reply . send ( outputContent ) ;
225- } catch ( e ) {
226- // If not valid JSON-LD, serve as-is
254+ Object . entries ( headers ) . forEach ( ( [ k , v ] ) => reply . header ( k , v ) ) ;
255+ return reply . send ( outputContent ) ;
256+ } catch ( e ) {
257+ // If not valid JSON-LD, serve as-is
258+ }
227259 }
228260 }
229261
0 commit comments