11import type { OutgoingHttpHeaders } from 'http'
22
33import { ComputeJsOutgoingMessage , toComputeResponse , toReqRes } from '@fastly/http-compute-js'
4- import { Context } from '@netlify/functions'
54import type { NextConfigComplete } from 'next/dist/server/config-shared.js'
65import type { WorkerRequestHandler } from 'next/dist/server/lib/types.js'
76
@@ -16,9 +15,12 @@ import { nextResponseProxy } from '../revalidate.js'
1615
1716import { createRequestContext , getLogger , getRequestContext } from './request-context.cjs'
1817import { getTracer } from './tracer.cjs'
18+ import { setupWaitUntil } from './wait-until.cjs'
1919
2020const nextImportPromise = import ( '../next.cjs' )
2121
22+ setupWaitUntil ( )
23+
2224let nextHandler : WorkerRequestHandler , nextConfig : NextConfigComplete
2325
2426/**
@@ -44,13 +46,7 @@ const disableFaultyTransferEncodingHandling = (res: ComputeJsOutgoingMessage) =>
4446 }
4547}
4648
47- // TODO: remove once https://github.com/netlify/serverless-functions-api/pull/219
48- // is released and public types are updated
49- interface FutureContext extends Context {
50- waitUntil ?: ( promise : Promise < unknown > ) => void
51- }
52-
53- export default async ( request : Request , context : FutureContext ) => {
49+ export default async ( request : Request ) => {
5450 const tracer = getTracer ( )
5551
5652 if ( ! nextHandler ) {
@@ -60,10 +56,10 @@ export default async (request: Request, context: FutureContext) => {
6056 nextConfig = await getRunConfig ( )
6157 setRunConfig ( nextConfig )
6258
63- const { getMockedRequestHandlers } = await nextImportPromise
59+ const { getMockedRequestHandler } = await nextImportPromise
6460 const url = new URL ( request . url )
6561
66- ; [ nextHandler ] = await getMockedRequestHandlers ( {
62+ nextHandler = await getMockedRequestHandler ( {
6763 port : Number ( url . port ) || 443 ,
6864 hostname : url . hostname ,
6965 dir : process . cwd ( ) ,
@@ -128,19 +124,20 @@ export default async (request: Request, context: FutureContext) => {
128124 return new Response ( body || null , response )
129125 }
130126
131- if ( context . waitUntil ) {
132- context . waitUntil ( requestContext . backgroundWorkPromise )
133- }
134-
135127 const keepOpenUntilNextFullyRendered = new TransformStream ( {
136128 async flush ( ) {
137129 // it's important to keep the stream open until the next handler has finished
138130 await nextHandlerPromise
139- if ( ! context . waitUntil ) {
140- // if waitUntil is not available, we have to keep response stream open until background promises are resolved
141- // to ensure that all background work executes
142- await requestContext . backgroundWorkPromise
143- }
131+
132+ // Next.js relies on `close` event emitted by response to trigger running callback variant of `next/after`
133+ // however @fastly /http-compute-js never actually emits that event - so we have to emit it ourselves,
134+ // otherwise Next would never run the callback variant of `next/after`
135+ res . emit ( 'close' )
136+
137+ // We have to keep response stream open until tracked background promises that are don't use `context.waitUntil`
138+ // are resolved. If `context.waitUntil` is available, `requestContext.backgroundWorkPromise` will be empty
139+ // resolved promised and so awaiting it is no-op
140+ await requestContext . backgroundWorkPromise
144141 } ,
145142 } )
146143
0 commit comments