diff options
Diffstat (limited to 'packages/integrations/netlify/src')
-rw-r--r-- | packages/integrations/netlify/src/integration-functions.ts | 10 | ||||
-rw-r--r-- | packages/integrations/netlify/src/netlify-functions.ts | 51 |
2 files changed, 54 insertions, 7 deletions
diff --git a/packages/integrations/netlify/src/integration-functions.ts b/packages/integrations/netlify/src/integration-functions.ts index 8f9b291fa..4242a7b00 100644 --- a/packages/integrations/netlify/src/integration-functions.ts +++ b/packages/integrations/netlify/src/integration-functions.ts @@ -1,20 +1,22 @@ import type { AstroAdapter, AstroConfig, AstroIntegration } from 'astro'; import { createRedirects } from './shared.js'; +import type { Args } from './netlify-functions.js'; -export function getAdapter(): AstroAdapter { +export function getAdapter(args: Args = {}): AstroAdapter { return { name: '@astrojs/netlify/functions', serverEntrypoint: '@astrojs/netlify/netlify-functions.js', exports: ['handler'], - args: {}, + args, }; } interface NetlifyFunctionsOptions { dist?: URL; + binaryMediaTypes?: string[]; } -function netlifyFunctions({ dist }: NetlifyFunctionsOptions = {}): AstroIntegration { +function netlifyFunctions({ dist, binaryMediaTypes }: NetlifyFunctionsOptions = {}): AstroIntegration { let _config: AstroConfig; let entryFile: string; return { @@ -28,7 +30,7 @@ function netlifyFunctions({ dist }: NetlifyFunctionsOptions = {}): AstroIntegrat } }, 'astro:config:done': ({ config, setAdapter }) => { - setAdapter(getAdapter()); + setAdapter(getAdapter({ binaryMediaTypes })); _config = config; }, 'astro:build:start': async ({ buildConfig }) => { diff --git a/packages/integrations/netlify/src/netlify-functions.ts b/packages/integrations/netlify/src/netlify-functions.ts index 66e5271f5..f8b3ab21b 100644 --- a/packages/integrations/netlify/src/netlify-functions.ts +++ b/packages/integrations/netlify/src/netlify-functions.ts @@ -7,11 +7,49 @@ polyfill(globalThis, { exclude: 'window document', }); -interface Args {} +export interface Args { + binaryMediaTypes?: string[]; +} + +function parseContentType(header?: string) { + return header?.split(';')[0] ?? ''; +} export const createExports = (manifest: SSRManifest, args: Args) => { const app = new App(manifest); + const binaryMediaTypes = args.binaryMediaTypes ?? []; + const knownBinaryMediaTypes = new Set([ + 'audio/3gpp', + 'audio/3gpp2', + 'audio/aac', + 'audio/midi', + 'audio/mpeg', + 'audio/ogg', + 'audio/opus', + 'audio/wav', + 'audio/webm', + 'audio/x-midi', + 'image/avif', + 'image/bmp', + 'image/gif', + 'image/vnd.microsoft.icon', + 'image/jpeg', + 'image/png', + 'image/svg+xml', + 'image/tiff', + 'image/webp', + 'video/3gpp', + 'video/3gpp2', + 'video/mp2t', + 'video/mp4', + 'video/mpeg', + 'video/ogg', + 'video/x-msvideo', + 'video/webm', + ...binaryMediaTypes, + ]); + const handler: Handler = async (event) => { const { httpMethod, headers, rawUrl, body: requestBody, isBase64Encoded } = event; const init: RequestInit = { @@ -34,13 +72,20 @@ export const createExports = (manifest: SSRManifest, args: Args) => { } const response: Response = await app.render(request); - const responseBody = await response.text(); - const responseHeaders = Object.fromEntries(response.headers.entries()); + + const responseContentType = parseContentType(responseHeaders['content-type']); + const responseIsBase64Encoded = knownBinaryMediaTypes.has(responseContentType); + + const responseBody = responseIsBase64Encoded + ? Buffer.from(await response.text(), 'binary').toString('base64') + : await response.text(); + const fnResponse: any = { statusCode: response.status, headers: responseHeaders, body: responseBody, + isBase64Encoded: responseIsBase64Encoded, }; // Special-case set-cookie which has to be set an different way :/ |