import { builder, type Handler } from '@netlify/functions'; import type { SSRManifest } from 'astro'; import { App } from 'astro/app'; import { applyPolyfills } from 'astro/app/node'; import { ASTRO_LOCALS_HEADER } from './integration-functions.js'; applyPolyfills(); export interface Args { builders?: boolean; binaryMediaTypes?: string[]; edgeMiddleware: boolean; functionPerRoute: boolean; } function parseContentType(header?: string) { return header?.split(';')[0] ?? ''; } const clientAddressSymbol = Symbol.for('astro.clientAddress'); export const createExports = (manifest: SSRManifest, args: Args) => { const app = new App(manifest); const builders = args.builders ?? false; 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/heif', '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 myHandler: Handler = async (event) => { const { httpMethod, headers, rawUrl, body: requestBody, isBase64Encoded } = event; const init: RequestInit = { method: httpMethod, headers: new Headers(headers as any), }; // Attach the event body the request, with proper encoding. if (httpMethod !== 'GET' && httpMethod !== 'HEAD') { const encoding = isBase64Encoded ? 'base64' : 'utf-8'; init.body = typeof requestBody === 'string' ? Buffer.from(requestBody, encoding) : requestBody; } const request = new Request(rawUrl, init); const routeData = app.match(request); const ip = headers['x-nf-client-connection-ip']; Reflect.set(request, clientAddressSymbol, ip); let locals = {}; if (request.headers.has(ASTRO_LOCALS_HEADER)) { let localsAsString = request.headers.get(ASTRO_LOCALS_HEADER); if (localsAsString) { locals = JSON.parse(localsAsString); } } const response: Response = await app.render(request, routeData, locals); const responseHeaders = Object.fromEntries(response.headers.entries()); const responseContentType = parseContentType(responseHeaders['content-type']); const responseIsBase64Encoded = knownBinaryMediaTypes.has(responseContentType); let responseBody: string; if (responseIsBase64Encoded) { const ab = await response.arrayBuffer(); responseBody = Buffer.from(ab).toString('base64'); } else { responseBody = await response.text(); } const fnResponse: any = { statusCode: response.status, headers: responseHeaders, body: responseBody, isBase64Encoded: responseIsBase64Encoded, }; const cookies = response.headers.get('set-cookie'); if (cookies) { fnResponse.multiValueHeaders = { 'set-cookie': Array.isArray(cookies) ? cookies : splitCookiesString(cookies), }; } // Apply cookies set via Astro.cookies.set/delete if (app.setCookieHeaders) { const setCookieHeaders = Array.from(app.setCookieHeaders(response)); fnResponse.multiValueHeaders = fnResponse.multiValueHeaders || {}; if (!fnResponse.multiValueHeaders['set-cookie']) { fnResponse.multiValueHeaders['set-cookie'] = []; } fnResponse.multiValueHeaders['set-cookie'].push(...setCookieHeaders); } return fnResponse; }; const handler = builders ? builder(myHandler) : myHandler; return { handler }; }; /* From: https://github.com/nfriedly/set-cookie-parser/blob/5cae030d8ef0f80eec58459e3583d43a07b984cb/lib/set-cookie.js#L144 Set-Cookie header field-values are sometimes comma joined in one string. This splits them without choking on commas that are within a single set-cookie field-value, such as in the Expires portion. This is uncommon, but explicitly allowed - see https://tools.ietf.org/html/rfc2616#section-4.2 Node.js does this for every header *except* set-cookie - see https://github.com/nodejs/node/blob/d5e363b77ebaf1caf67cd7528224b651c86815c1/lib/_http_incoming.js#L128 React Native's fetch does this for *every* header, including set-cookie. Based on: https://github.com/google/j2objc/commit/16820fdbc8f76ca0c33472810ce0cb03d20efe25 Credits to: https://github.com/tomball for original and https://github.com/chrusart for JavaScript implementation */ function splitCookiesString(cookiesString: string): string[] { if (Array.isArray(cookiesString)) { return cookiesString; } if (typeof cookiesString !== 'string') { return []; } let cookiesStrings = []; let pos = 0; let start; let ch; let lastComma; let nextStart; let cookiesSeparatorFound; function skipWhitespace() { while (pos < cookiesString.length && /\s/.test(cookiesString.charAt(pos))) { pos += 1; } return pos < cookiesString.length; } function notSpecialChar() { ch = cookiesString.charAt(pos); return ch !== '=' && ch !== ';' && ch !== ','; } while (pos < cookiesString.length) { start = pos; cookiesSeparatorFound = false; while (skipWhitespace()) { ch = cookiesString.charAt(pos); if (ch === ',') { // ',' is a cookie separator if we have later first '=', not ';' or ',' lastComma = pos; pos += 1; skipWhitespace(); nextStart = pos; while (pos < cookiesString.length && notSpecialChar()) { pos += 1; } // currently special character if (pos < cookiesString.length && cookiesString.charAt(pos) === '=') { // we found cookies separator cookiesSeparatorFound = true; // pos is inside the next cookie, so back up and return it. pos = nextStart; cookiesStrings.push(cookiesString.substring(start, lastComma)); start = pos; } else { // in param ',' or param separator ';', // we continue from that comma pos = lastComma + 1; } } else { pos += 1; } } if (!cookiesSeparatorFound || pos >= cookiesString.length) { cookiesStrings.push(cookiesString.substring(start, cookiesString.length)); } } return cookiesStrings; } on value='feat/ci-next'>feat/ci-next Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src/compiler/optimize/module-scripts.ts (unfollow)
AgeCommit message (Expand)AuthorFilesLines
2021-04-06Blog Support 1/3: Data fetching (#62)Gravatar Drew Powers 36-34/+2359
2021-04-06[ci] npm run formatGravatar matthewp 2-2/+2
2021-04-06Compiler cleanup (#64)Gravatar Matthew Phillips 7-83/+129
2021-04-06Create a astro/components/ folder (#63)Gravatar Matthew Phillips 10-11/+61
2021-04-05Allow no config (#61)Gravatar Drew Powers 10-52/+86
2021-04-05[ci] npm run formatGravatar matthewp 4-29/+32
2021-04-05Improve searching for pages (#60)Gravatar Matthew Phillips 10-81/+217
2021-04-02Add type declarations (#59)Gravatar Drew Powers 7-30/+46
2021-04-02Fix scoping issues (#58)Gravatar Drew Powers 6-108/+159
2021-04-02Add Tailwind support (#57)Gravatar Drew Powers 4-18/+96
2021-04-02Fix body from being scoped (#56)Gravatar Drew Powers 4-35/+44
2021-04-02Fix React import (#55)Gravatar Drew Powers 4-7/+7
2021-04-02Move devDeps to deps (#54)Gravatar Drew Powers 2-138/+6
2021-04-02Get CSS Modules working in Vue (#53)Gravatar Drew Powers 15-92/+251
2021-04-01Remove errant console.log (#51)Gravatar Matthew Phillips 1-1/+0
2021-04-01[ci] npm run formatGravatar matthewp 3-10/+8
2021-04-01Fix complex MDX parsing (#50)Gravatar Matthew Phillips 16-36/+136
2021-04-01Add prism and skeleton www page (#49)Gravatar Matthew Phillips 12-0/+4518
2021-04-01Annoying Lint PR #2 (#47)Gravatar Drew Powers 32-49/+156
2021-04-01Add runtime mode (#48)Gravatar Drew Powers 10-32/+48
2021-03-31Implements import.meta.request (#46)Gravatar Matthew Phillips 4-4/+37
2021-03-31Support for custom elements (#45)Gravatar Matthew Phillips 9-13/+144
2021-03-31Implement fallback capability (#44)Gravatar Matthew Phillips 14-28/+135
2021-03-31Extract Astro styles to external stylesheets (#43)Gravatar Drew Powers 54-165/+202
2021-03-30remove unused fnGravatar Fred K. Schott 1-13/+0
2021-03-30[ci] npm run formatGravatar matthewp 1-1/+1
2021-03-30Add minification (#42)Gravatar Matthew Phillips 3-1/+101
2021-03-30simplify svg animation, slow it downGravatar Fred K. Schott 1-54/+13
2021-03-30[ci] npm run formatGravatar matthewp 1-2/+2
2021-03-30Resolve component URLs during compilation (#40)Gravatar Matthew Phillips 6-16/+28
2021-03-30Fix nested parens bug (#39)Gravatar Drew Powers 4-5/+12
2021-03-30Convert CSS Modules to scoped styles (#38)Gravatar Drew Powers 9-84/+238
2021-03-30[ci] npm run formatGravatar matthewp 9-29/+24
2021-03-30Add support for doctype (#37)Gravatar Matthew Phillips 22-28/+162
2021-03-30[ci] npm run formatGravatar matthewp 4-41/+43
2021-03-30Bundling! 🤘 (#36)Gravatar Matthew Phillips 12-48/+373
2021-03-29revert bad snowpack example changesGravatar Fred K. Schott 1-8/+146
2021-03-29update landing pageGravatar Fred K. Schott 2-2/+3
2021-03-29update site titleGravatar Fred K. Schott 1-1/+1
2021-03-29clean up landing pageGravatar Fred K. Schott 4-224/+120
2021-03-29add example www siteGravatar Fred K. Schott 10-0/+5088
2021-03-26New hydration methods (#29)Gravatar Nate Moore 10-144/+219