@@ -7,18 +7,20 @@ import type {
77 APIGatewayProxyStructuredResultV2 ,
88} from 'aws-lambda' ;
99import type {
10- CompressionOptions ,
1110 ExtendedAPIGatewayProxyResult ,
1211 ExtendedAPIGatewayProxyResultBody ,
1312 HandlerResponse ,
13+ HttpStatusCode ,
1414 ResponseType ,
1515 ResponseTypeMap ,
1616 V1Headers ,
17+ WebResponseToProxyResultOptions ,
1718} from '../types/rest.js' ;
18- import { COMPRESSION_ENCODING_TYPES } from './constants.js' ;
19+ import { HttpStatusCodes } from './constants.js' ;
1920import { InvalidHttpMethodError } from './errors.js' ;
2021import {
2122 isAPIGatewayProxyEventV2 ,
23+ isBinaryResult ,
2224 isExtendedAPIGatewayProxyResult ,
2325 isHttpMethod ,
2426 isNodeReadableStream ,
@@ -213,41 +215,29 @@ const webHeadersToApiGatewayHeaders = <T extends ResponseType>(
213215 : { headers : Record < string , string > } ;
214216} ;
215217
218+ const responseBodyToBase64 = async ( response : Response ) => {
219+ const buffer = await response . arrayBuffer ( ) ;
220+ return Buffer . from ( buffer ) . toString ( 'base64' ) ;
221+ } ;
222+
216223/**
217224 * Converts a Web API Response object to an API Gateway V1 proxy result.
218225 *
219226 * @param response - The Web API Response object
227+ * @param isBase64Encoded - Whether the response body should be base64 encoded (e.g., for binary or compressed content)
220228 * @returns An API Gateway V1 proxy result
221229 */
222230const webResponseToProxyResultV1 = async (
223- response : Response
231+ response : Response ,
232+ isBase64Encoded ?: boolean
224233) : Promise < APIGatewayProxyResult > => {
225234 const { headers, multiValueHeaders } = webHeadersToApiGatewayV1Headers (
226235 response . headers
227236 ) ;
228237
229- // Check if response contains compressed/binary content
230- const contentEncoding = response . headers . get (
231- 'content-encoding'
232- ) as CompressionOptions [ 'encoding' ] ;
233- let body : string ;
234- let isBase64Encoded = false ;
235-
236- if (
237- contentEncoding &&
238- [
239- COMPRESSION_ENCODING_TYPES . GZIP ,
240- COMPRESSION_ENCODING_TYPES . DEFLATE ,
241- ] . includes ( contentEncoding )
242- ) {
243- // For compressed content, get as buffer and encode to base64
244- const buffer = await response . arrayBuffer ( ) ;
245- body = Buffer . from ( buffer ) . toString ( 'base64' ) ;
246- isBase64Encoded = true ;
247- } else {
248- // For text content, use text()
249- body = await response . text ( ) ;
250- }
238+ const body = isBase64Encoded
239+ ? await responseBodyToBase64 ( response )
240+ : await response . text ( ) ;
251241
252242 const result : APIGatewayProxyResult = {
253243 statusCode : response . status ,
@@ -267,10 +257,12 @@ const webResponseToProxyResultV1 = async (
267257 * Converts a Web API Response object to an API Gateway V2 proxy result.
268258 *
269259 * @param response - The Web API Response object
260+ * @param isBase64Encoded - Whether the response body should be base64 encoded (e.g., for binary or compressed content)
270261 * @returns An API Gateway V2 proxy result
271262 */
272263const webResponseToProxyResultV2 = async (
273- response : Response
264+ response : Response ,
265+ isBase64Encoded ?: boolean
274266) : Promise < APIGatewayProxyStructuredResultV2 > => {
275267 const headers : Record < string , string > = { } ;
276268 const cookies : string [ ] = [ ] ;
@@ -283,25 +275,9 @@ const webResponseToProxyResultV2 = async (
283275 }
284276 }
285277
286- const contentEncoding = response . headers . get (
287- 'content-encoding'
288- ) as CompressionOptions [ 'encoding' ] ;
289- let body : string ;
290- let isBase64Encoded = false ;
291-
292- if (
293- contentEncoding &&
294- [
295- COMPRESSION_ENCODING_TYPES . GZIP ,
296- COMPRESSION_ENCODING_TYPES . DEFLATE ,
297- ] . includes ( contentEncoding )
298- ) {
299- const buffer = await response . arrayBuffer ( ) ;
300- body = Buffer . from ( buffer ) . toString ( 'base64' ) ;
301- isBase64Encoded = true ;
302- } else {
303- body = await response . text ( ) ;
304- }
278+ const body = isBase64Encoded
279+ ? await responseBodyToBase64 ( response )
280+ : await response . text ( ) ;
305281
306282 const result : APIGatewayProxyStructuredResultV2 = {
307283 statusCode : response . status ,
@@ -319,12 +295,18 @@ const webResponseToProxyResultV2 = async (
319295
320296const webResponseToProxyResult = < T extends ResponseType > (
321297 response : Response ,
322- responseType : T
298+ responseType : T ,
299+ options ?: WebResponseToProxyResultOptions
323300) : Promise < ResponseTypeMap [ T ] > => {
301+ const isBase64Encoded = options ?. isBase64Encoded ?? false ;
324302 if ( responseType === 'ApiGatewayV1' ) {
325- return webResponseToProxyResultV1 ( response ) as Promise < ResponseTypeMap [ T ] > ;
303+ return webResponseToProxyResultV1 ( response , isBase64Encoded ) as Promise <
304+ ResponseTypeMap [ T ]
305+ > ;
326306 }
327- return webResponseToProxyResultV2 ( response ) as Promise < ResponseTypeMap [ T ] > ;
307+ return webResponseToProxyResultV2 ( response , isBase64Encoded ) as Promise <
308+ ResponseTypeMap [ T ]
309+ > ;
328310} ;
329311
330312/**
@@ -365,13 +347,15 @@ function addProxyEventHeaders(
365347 * Handles APIGatewayProxyResult, Response objects, and plain objects.
366348 *
367349 * @param response - The handler response (APIGatewayProxyResult, Response, or plain object)
368- * @param resHeaders - Optional headers to be included in the response
350+ * @param options - Optional configuration with statusCode and resHeaders
369351 * @returns A Web API Response object
370352 */
371353const handlerResultToWebResponse = (
372354 response : HandlerResponse ,
373- resHeaders ?: Headers
355+ options ?: { statusCode ?: HttpStatusCode ; resHeaders ?: Headers }
374356) : Response => {
357+ const statusCode = options ?. statusCode ?? HttpStatusCodes . OK ;
358+ const resHeaders = options ?. resHeaders ;
375359 if ( response instanceof Response ) {
376360 if ( resHeaders === undefined ) return response ;
377361 const headers = new Headers ( resHeaders ) ;
@@ -385,6 +369,19 @@ const handlerResultToWebResponse = (
385369 }
386370
387371 const headers = new Headers ( resHeaders ) ;
372+
373+ if ( isBinaryResult ( response ) ) {
374+ const body =
375+ response instanceof Readable
376+ ? ( Readable . toWeb ( response ) as ReadableStream )
377+ : response ;
378+
379+ return new Response ( body , {
380+ status : statusCode ,
381+ headers,
382+ } ) ;
383+ }
384+
388385 headers . set ( 'Content-Type' , 'application/json' ) ;
389386
390387 if ( isExtendedAPIGatewayProxyResult ( response ) ) {
@@ -400,7 +397,7 @@ const handlerResultToWebResponse = (
400397 headers,
401398 } ) ;
402399 }
403- return Response . json ( response , { headers } ) ;
400+ return Response . json ( response , { headers, status : statusCode } ) ;
404401} ;
405402
406403/**
0 commit comments