@@ -20,6 +20,8 @@ const SERVER_HANDLER_NAME = '___netlify-server-handler'
20
20
* @property {string } [url] TThe relative path that should be requested. Defaults to '/'
21
21
* @property {Record<string, string> } [headers] The headers used for the invocation
22
22
* @property {Record<string, unknown> } [flags] Feature flags that should be set during the invocation
23
+ *
24
+ * @typedef {Pick<FunctionInvocationOptions, 'env'> } LoadFunctionOptions
23
25
*/
24
26
25
27
/**
@@ -109,73 +111,84 @@ const DEFAULT_FLAGS = {}
109
111
110
112
/**
111
113
* @param {FixtureTestContext } ctx
112
- * @param {FunctionInvocationOptions } options
114
+ * @param {LoadFunctionOptions } options
113
115
*/
114
- export async function loadAndInvokeFunctionImpl (
115
- ctx ,
116
- { headers, httpMethod, flags, url, env } = { } ,
117
- ) {
116
+ export async function loadFunction ( ctx , { env } = { } ) {
118
117
const restoreEnvironment = temporarilySetEnv ( ctx , env )
119
118
120
119
const { handler } = await import (
121
120
'file:///' + join ( ctx . functionDist , SERVER_HANDLER_NAME , '___netlify-entry-point.mjs' )
122
121
)
123
122
124
- let resolveInvocation , rejectInvocation
125
- const invocationPromise = new Promise ( ( resolve , reject ) => {
126
- resolveInvocation = resolve
127
- rejectInvocation = reject
128
- } )
123
+ /**
124
+ * @param {FunctionInvocationOptions } options
125
+ */
126
+ async function invokeFunction ( { headers, httpMethod, flags, url, env : invokeEnv } = { } ) {
127
+ const restoreEnvironment = temporarilySetEnv ( ctx , {
128
+ ...env ,
129
+ ...invokeEnv ,
130
+ } )
129
131
130
- const response = await execute ( {
131
- event : {
132
- headers : headers || { } ,
133
- httpMethod : httpMethod || 'GET' ,
134
- rawUrl : new URL ( url || '/' , 'https://example.netlify' ) . href ,
135
- flags : flags ?? DEFAULT_FLAGS ,
136
- } ,
137
- lambdaFunc : { handler } ,
138
- timeoutMs : 4_000 ,
139
- onInvocationEnd : ( error ) => {
140
- // lambda-local resolve promise return from execute when response is closed
141
- // but we should wait for tracked background work to finish
142
- // before resolving the promise to allow background work to finish
143
- if ( error ) {
144
- rejectInvocation ( error )
145
- } else {
146
- resolveInvocation ( )
147
- }
148
- } ,
149
- } )
132
+ let resolveInvocation , rejectInvocation
133
+ const invocationPromise = new Promise ( ( resolve , reject ) => {
134
+ resolveInvocation = resolve
135
+ rejectInvocation = reject
136
+ } )
137
+
138
+ const response = await execute ( {
139
+ event : {
140
+ headers : headers || { } ,
141
+ httpMethod : httpMethod || 'GET' ,
142
+ rawUrl : new URL ( url || '/' , 'https://example.netlify' ) . href ,
143
+ flags : flags ?? DEFAULT_FLAGS ,
144
+ } ,
145
+ lambdaFunc : { handler } ,
146
+ timeoutMs : 4_000 ,
147
+ onInvocationEnd : ( error ) => {
148
+ // lambda-local resolve promise return from execute when response is closed
149
+ // but we should wait for tracked background work to finish
150
+ // before resolving the promise to allow background work to finish
151
+ if ( error ) {
152
+ rejectInvocation ( error )
153
+ } else {
154
+ resolveInvocation ( )
155
+ }
156
+ } ,
157
+ } )
150
158
151
- await invocationPromise
159
+ await invocationPromise
152
160
153
- if ( ! response ) {
154
- throw new Error ( 'No response from lambda-local' )
155
- }
161
+ if ( ! response ) {
162
+ throw new Error ( 'No response from lambda-local' )
163
+ }
156
164
157
- const responseHeaders = Object . entries ( response . multiValueHeaders || { } ) . reduce (
158
- ( prev , [ key , value ] ) => ( {
159
- ...prev ,
160
- [ key ] : value . length === 1 ? `${ value } ` : value . join ( ', ' ) ,
161
- } ) ,
162
- response . headers || { } ,
163
- )
165
+ const responseHeaders = Object . entries ( response . multiValueHeaders || { } ) . reduce (
166
+ ( prev , [ key , value ] ) => ( {
167
+ ...prev ,
168
+ [ key ] : value . length === 1 ? `${ value } ` : value . join ( ', ' ) ,
169
+ } ) ,
170
+ response . headers || { } ,
171
+ )
164
172
165
- const bodyBuffer = await streamToBuffer ( response . body )
173
+ const bodyBuffer = await streamToBuffer ( response . body )
166
174
167
- restoreEnvironment ( )
175
+ restoreEnvironment ( )
168
176
169
- return {
170
- statusCode : response . statusCode ,
171
- bodyBuffer,
172
- body : bodyBuffer . toString ( 'utf-8' ) ,
173
- headers : responseHeaders ,
174
- isBase64Encoded : response . isBase64Encoded ,
177
+ return {
178
+ statusCode : response . statusCode ,
179
+ bodyBuffer,
180
+ body : bodyBuffer . toString ( 'utf-8' ) ,
181
+ headers : responseHeaders ,
182
+ isBase64Encoded : response . isBase64Encoded ,
183
+ }
175
184
}
185
+
186
+ restoreEnvironment ( )
187
+
188
+ return invokeFunction
176
189
}
177
190
178
191
/**
179
- * @typedef {typeof loadAndInvokeFunctionImpl } InvokeFunction
192
+ * @typedef {Awaited<ReturnType< typeof loadFunction>> } InvokeFunction
180
193
* @typedef {Promise<Awaited<ReturnType<InvokeFunction>>> } InvokeFunctionResult
181
194
*/
0 commit comments