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
@@ -14,12 +13,19 @@ import {
1413} from '../headers.js'
1514import { nextResponseProxy } from '../revalidate.js'
1615
17- import { createRequestContext , getLogger , getRequestContext } from './request-context.cjs'
16+ import {
17+ createRequestContext ,
18+ FutureContext ,
19+ getLogger ,
20+ getRequestContext ,
21+ } from './request-context.cjs'
1822import { getTracer } from './tracer.cjs'
19- import { setWaitUntil } from './wait-until.cjs'
23+ import { setupWaitUntil } from './wait-until.cjs'
2024
2125const nextImportPromise = import ( '../next.cjs' )
2226
27+ setupWaitUntil ( )
28+
2329let nextHandler : WorkerRequestHandler , nextConfig : NextConfigComplete
2430
2531/**
@@ -45,15 +51,9 @@ const disableFaultyTransferEncodingHandling = (res: ComputeJsOutgoingMessage) =>
4551 }
4652}
4753
48- // TODO: remove once https://github.com/netlify/serverless-functions-api/pull/219
49- // is released and public types are updated
50- interface FutureContext extends Context {
51- waitUntil ?: ( promise : Promise < unknown > ) => void
52- }
53-
5454export default async ( request : Request , context : FutureContext ) => {
5555 const tracer = getTracer ( )
56- setWaitUntil ( context )
56+
5757 if ( ! nextHandler ) {
5858 await tracer . withActiveSpan ( 'initialize next server' , async ( ) => {
5959 // set the server config
@@ -129,19 +129,19 @@ export default async (request: Request, context: FutureContext) => {
129129 return new Response ( body || null , response )
130130 }
131131
132- if ( context . waitUntil ) {
133- context . waitUntil ( requestContext . backgroundWorkPromise )
134- }
135-
136132 const keepOpenUntilNextFullyRendered = new TransformStream ( {
137133 async flush ( ) {
138134 // it's important to keep the stream open until the next handler has finished
139135 await nextHandlerPromise
140- if ( ! context . waitUntil ) {
141- // if waitUntil is not available, we have to keep response stream open until background promises are resolved
142- // to ensure that all background work executes
143- await requestContext . backgroundWorkPromise
144- }
136+
137+ // Next.js relies on `close` event emitted by response to trigger running callback variant of `next/after`
138+ // however @fastly /http-compute-js never actually emits that event - so we have to emit it ourselves, otherwise
139+ // Next would never run the callback variant of `next/after`
140+ res . emit ( 'close' )
141+
142+ // if waitUntil is not available, we have to keep response stream open until background promises are resolved
143+ // to ensure that all background work executes
144+ await requestContext . backgroundWorkPromise
145145 } ,
146146 } )
147147
0 commit comments