1- import { joinURL } from 'ufo'
21import { consola } from 'consola'
3- import { createError , defineEventHandler , getRouterParam , readBody } from 'h3'
2+ import { createError , defineEventHandler , getRouterParam , readBody , send , setResponseHeader , setResponseStatus , splitCookiesString } from 'h3'
43import type { ModuleOptions } from '../../module'
54import { createAuthHeader } from '../utils'
65import type { ServerFetchOptions } from '../types'
7- import type { NuxtError } from '#app'
86
97// @ts -expect-error: Will be resolved by Nitro
108import { defineCachedFunction } from '#internal/nitro'
@@ -22,52 +20,40 @@ async function fetcher({
2220} : { key : string } & ServerFetchOptions ) {
2321 const isQueryRequest = key . startsWith ( '$kql' )
2422
25- try {
26- const result = await globalThis . $fetch < any > ( isQueryRequest ? kql . prefix : path ! , {
27- baseURL : kql . url ,
28- ...( isQueryRequest
29- ? {
30- method : 'POST' ,
31- body : query ,
32- }
33- : {
34- query,
35- method,
36- body,
37- } ) ,
38- headers : {
39- ...headers ,
40- ...createAuthHeader ( kql ) ,
41- } ,
42- } )
23+ const response = await globalThis . $fetch . raw < ArrayBuffer > ( isQueryRequest ? kql . prefix : path ! , {
24+ responseType : 'arrayBuffer' ,
25+ ignoreResponseError : true ,
26+ baseURL : kql . url ,
27+ ...( isQueryRequest
28+ ? {
29+ method : 'POST' ,
30+ body : query ,
31+ }
32+ : {
33+ query,
34+ method,
35+ body,
36+ } ) ,
37+ headers : {
38+ ...headers ,
39+ ...createAuthHeader ( kql ) ,
40+ } ,
41+ } )
4342
44- return result
45- }
46- catch ( error ) {
47- if ( isQueryRequest ) {
48- consola . error (
49- `KQL query failed with status code ${ ( error as NuxtError ) . statusCode } :\n` ,
50- JSON . stringify ( ( error as NuxtError ) . data , undefined , 2 ) ,
51- )
52- if ( kql . server . verboseErrors )
53- consola . log ( 'KQL query request:' , query )
54- }
55- else {
56- consola . error ( `Failed ${ ( method || 'get' ) ?. toUpperCase ( ) } request to ${ joinURL ( kql . url , path ! ) } with options:` , { headers, query, body } )
57- }
43+ // Serialize the response data
44+ const buffer = Buffer . from ( response . _data ?? ( [ ] as unknown as ArrayBuffer ) )
45+ const data = buffer . toString ( 'base64' )
5846
59- throw createError ( {
60- statusCode : 500 ,
61- statusMessage : isQueryRequest
62- ? 'Failed to execute KQL query'
63- : `Failed to fetch "${ path } "` ,
64- data : ( error as NuxtError ) . statusMessage ,
65- } )
47+ return {
48+ status : response . status ,
49+ statusText : response . statusText ,
50+ headers : [ ...response . headers . entries ( ) ] ,
51+ data,
6652 }
6753}
6854
6955const cachedFetcher = defineCachedFunction ( fetcher , {
70- name : 'kql-fetcher ' ,
56+ name : 'kirby ' ,
7157 base : kql . server . storage ,
7258 swr : kql . server . swr ,
7359 maxAge : kql . server . maxAge ,
@@ -77,12 +63,13 @@ const cachedFetcher = defineCachedFunction(fetcher, {
7763export default defineEventHandler ( async ( event ) => {
7864 const body = await readBody < ServerFetchOptions > ( event )
7965 const key = decodeURIComponent ( getRouterParam ( event , 'key' ) ! )
66+ const isQueryRequest = key . startsWith ( '$kql' )
8067
81- if ( key . startsWith ( '$kql' ) ) {
68+ if ( isQueryRequest ) {
8269 if ( ! body . query ?. query ) {
8370 throw createError ( {
8471 statusCode : 400 ,
85- statusMessage : 'Empty KQL query' ,
72+ statusMessage : 'KQL query is empty ' ,
8673 } )
8774 }
8875 }
@@ -96,8 +83,75 @@ export default defineEventHandler(async (event) => {
9683 }
9784 }
9885
99- if ( kql . server . cache && body . cache )
100- return await cachedFetcher ( { key, ...body } )
86+ let response : Awaited < ReturnType < typeof fetcher > >
87+ const queryErrorMessage = `Failed KQL query "${ body . query ?. query } " (...)`
88+ const fetchErrorMessage = `Failed ${ ( body . method || 'get' ) ?. toUpperCase ( ) } request to "${ body . path ! } "`
89+
90+ try {
91+ response = kql . server . cache && body . cache
92+ ? await cachedFetcher ( { key, ...body } )
93+ : await fetcher ( { key, ...body } )
94+ }
95+ catch ( error ) {
96+ consola . error ( error )
97+
98+ throw createError ( {
99+ statusCode : 500 ,
100+ statusMessage : isQueryRequest
101+ ? queryErrorMessage
102+ : fetchErrorMessage ,
103+ } )
104+ }
101105
102- return await fetcher ( { key, ...body } )
106+ if ( response . status >= 400 && response . status < 600 ) {
107+ if ( isQueryRequest ) {
108+ consola . error ( `${ queryErrorMessage } with status code ${ response . status } :\n` , tryParseJSON ( response . data ) )
109+ if ( kql . server . verboseErrors )
110+ consola . log ( 'Full KQL query request:' , body . query )
111+ }
112+ else {
113+ consola . error ( fetchErrorMessage )
114+ }
115+
116+ throw createError ( {
117+ statusCode : 500 ,
118+ statusMessage : isQueryRequest
119+ ? queryErrorMessage
120+ : fetchErrorMessage ,
121+ data : tryParseJSON ( response . data ) ,
122+ } )
123+ }
124+
125+ const cookies : string [ ] = [ ]
126+
127+ for ( const [ key , value ] of response . headers ) {
128+ if ( key === 'content-encoding' )
129+ continue
130+
131+ if ( key === 'content-length' )
132+ continue
133+
134+ if ( key === 'set-cookie' ) {
135+ cookies . push ( ...splitCookiesString ( value ) )
136+ continue
137+ }
138+
139+ setResponseHeader ( event , key , value )
140+ }
141+
142+ if ( cookies . length > 0 )
143+ setResponseHeader ( event , 'set-cookie' , cookies )
144+
145+ const buffer = Buffer . from ( response . data , 'base64' )
146+ setResponseStatus ( event , response . status , response . statusText )
147+ return send ( event , buffer )
103148} )
149+
150+ function tryParseJSON ( data : string ) {
151+ try {
152+ return JSON . parse ( data )
153+ }
154+ catch ( e ) {
155+ return data
156+ }
157+ }
0 commit comments