1- import { handlers , startServerAndCreateLambdaHandler } from '@as-integrations/aws-lambda '
1+ import { HeaderMap } from '@apollo/server '
22
33import config from './utils/config.js'
44import connect from './utils/connect.js'
55import createApolloServer from './utils/createApolloServer.js'
66import { createServerlessContext } from './utils/createContext.js'
7- import fullyQualifiedDomainNames from './utils/fullyQualifiedDomainNames .js'
7+ import findMatchingOrigin from './utils/findMatchingOrigin .js'
88
99if ( config . dbUrl == null ) {
1010 throw new Error ( 'MongoDB connection URI missing in environment' )
@@ -13,53 +13,88 @@ if (config.dbUrl == null) {
1313connect ( config . dbUrl )
1414
1515const apolloServer = createApolloServer ( )
16+ await apolloServer . start ( )
1617
17- const resolveAllowedOrigin = async ( requestOrigin ) => {
18- if ( config . autoOrigin === true ) {
19- const names = await fullyQualifiedDomainNames ( )
20- const origins = names . flatMap ( ( name ) => [ `http://${ name } ` , `https://${ name } ` , name ] )
21- return origins . includes ( requestOrigin ) ? requestOrigin : null
18+ const buildCorsHeaders = ( allowedOrigin ) => {
19+ if ( allowedOrigin == null ) return { }
20+
21+ return {
22+ 'access-control-allow-origin' : allowedOrigin ,
23+ 'access-control-allow-methods' : 'GET, POST, PATCH, OPTIONS' ,
24+ 'access-control-allow-headers' : 'Content-Type, Authorization, Time-Zone' ,
25+ 'access-control-allow-credentials' : 'true' ,
26+ 'access-control-max-age' : '3600' ,
2227 }
28+ }
2329
24- if ( config . allowOrigin === '*' ) {
25- return '*'
30+ /**
31+ * Handles incoming requests using the Web API (Request/Response).
32+ * Manages CORS, delegates GraphQL operations to Apollo Server, and returns a Web Response.
33+ * Used by both Vercel and Netlify serverless entry points.
34+ *
35+ * @param {Request } request - The incoming web request.
36+ * @returns {Promise<Response> } - The web response to send back.
37+ */
38+ export const handler = async ( request ) => {
39+ const requestOrigin = request . headers . get ( 'origin' )
40+ const allowedOrigin = await findMatchingOrigin ( requestOrigin , config . allowOrigin , config . autoOrigin )
41+ const corsHeaders = buildCorsHeaders ( allowedOrigin )
42+
43+ if ( request . method === 'OPTIONS' ) {
44+ return new Response ( null , {
45+ status : 204 ,
46+ headers : corsHeaders ,
47+ } )
2648 }
2749
28- if ( config . allowOrigin != null ) {
29- const origins = config . allowOrigin . split ( ',' )
30- return origins . includes ( requestOrigin ) ? requestOrigin : null
50+ const url = new URL ( request . url )
51+
52+ const headers = new HeaderMap ( )
53+ for ( const [ key , value ] of request . headers ) {
54+ headers . set ( key , value )
3155 }
3256
33- return null
34- }
57+ const body = request . method === 'POST' ? await request . json ( ) : undefined
58+
59+ const result = await apolloServer . executeHTTPGraphQLRequest ( {
60+ httpGraphQLRequest : {
61+ method : request . method ,
62+ headers,
63+ body,
64+ search : url . search ?? '' ,
65+ } ,
66+ context : ( ) => createServerlessContext ( request ) ,
67+ } )
68+
69+ const responseHeaders = new Headers ( )
70+
71+ for ( const [ key , value ] of result . headers ) {
72+ responseHeaders . set ( key , value )
73+ }
74+
75+ for ( const [ key , value ] of Object . entries ( corsHeaders ) ) {
76+ responseHeaders . set ( key , value )
77+ }
78+
79+ if ( result . body . kind === 'complete' ) {
80+ return new Response ( result . body . string , {
81+ status : result . status ?? 200 ,
82+ headers : responseHeaders ,
83+ } )
84+ }
85+
86+ const stream = new ReadableStream ( {
87+ async start ( controller ) {
88+ for await ( const chunk of result . body . asyncIterator ) {
89+ controller . enqueue ( new TextEncoder ( ) . encode ( chunk ) )
90+ }
3591
36- export const handler = startServerAndCreateLambdaHandler (
37- apolloServer ,
38- handlers . createAPIGatewayProxyEventRequestHandler ( ) ,
39- {
40- context : createServerlessContext ,
41- middleware : [
42- async ( event ) => {
43- // Set request context which is missing on Vercel:
44- // https://stackoverflow.com/questions/71360059/apollo-server-lambda-unable-to-determine-event-source-based-on-event
45- if ( event . requestContext == null ) event . requestContext = { }
46-
47- const requestOrigin = event . headers ?. origin || event . headers ?. Origin
48- const allowedOrigin = await resolveAllowedOrigin ( requestOrigin )
49-
50- return ( result ) => {
51- if ( allowedOrigin != null ) {
52- result . headers = {
53- ...result . headers ,
54- 'access-control-allow-origin' : allowedOrigin ,
55- 'access-control-allow-methods' : 'GET, POST, PATCH, OPTIONS' ,
56- 'access-control-allow-headers' : 'Content-Type, Authorization, Time-Zone' ,
57- 'access-control-allow-credentials' : 'true' ,
58- 'access-control-max-age' : '3600' ,
59- }
60- }
61- }
62- } ,
63- ] ,
64- } ,
65- )
92+ controller . close ( )
93+ } ,
94+ } )
95+
96+ return new Response ( stream , {
97+ status : result . status ?? 200 ,
98+ headers : responseHeaders ,
99+ } )
100+ }
0 commit comments