@@ -6,6 +6,7 @@ import { getRequestBundleFilePath } from '../shared/utils';
66export type IncrementalRenderSink = {
77 /** Called for every subsequent NDJSON object after the first one */
88 add : ( chunk : unknown ) => void ;
9+ handleRequestClosed : ( ) => void ;
910} ;
1011
1112export type UpdateChunk = {
@@ -27,11 +28,33 @@ function assertIsUpdateChunk(value: unknown): asserts value is UpdateChunk {
2728}
2829
2930export type IncrementalRenderInitialRequest = {
30- renderingRequest : string ;
31+ firstRequestChunk : unknown ;
3132 bundleTimestamp : string | number ;
3233 dependencyBundleTimestamps ?: string [ ] | number [ ] ;
3334} ;
3435
36+ export type FirstIncrementalRenderRequestChunk = {
37+ renderingRequest : string ;
38+ onRequestClosedUpdateChunk ?: string ;
39+ } ;
40+
41+ function assertFirstIncrementalRenderRequestChunk (
42+ chunk : unknown ,
43+ ) : asserts chunk is FirstIncrementalRenderRequestChunk {
44+ if (
45+ typeof chunk !== 'object' ||
46+ chunk === null ||
47+ ! ( 'renderingRequest' in chunk ) ||
48+ typeof chunk . renderingRequest !== 'string' ||
49+ // onRequestClosedUpdateChunk is an optional field
50+ ( 'onRequestClosedUpdateChunk' in chunk &&
51+ chunk . onRequestClosedUpdateChunk &&
52+ typeof chunk . onRequestClosedUpdateChunk !== 'object' )
53+ ) {
54+ throw new Error ( 'Invalid first incremental render request chunk received, missing properties' ) ;
55+ }
56+ }
57+
3558export type IncrementalRenderResult = {
3659 response : ResponseResult ;
3760 sink ?: IncrementalRenderSink ;
@@ -46,7 +69,9 @@ export type IncrementalRenderResult = {
4669export async function handleIncrementalRenderRequest (
4770 initial : IncrementalRenderInitialRequest ,
4871) : Promise < IncrementalRenderResult > {
49- const { renderingRequest, bundleTimestamp, dependencyBundleTimestamps } = initial ;
72+ const { firstRequestChunk, bundleTimestamp, dependencyBundleTimestamps } = initial ;
73+ assertFirstIncrementalRenderRequestChunk ( firstRequestChunk ) ;
74+ const { renderingRequest, onRequestClosedUpdateChunk } = firstRequestChunk ;
5075
5176 try {
5277 // Call handleRenderRequest internally to handle all validation and VM execution
@@ -79,6 +104,27 @@ export async function handleIncrementalRenderRequest(
79104 log . error ( { msg : 'Invalid incremental render chunk' , err, chunk } ) ;
80105 }
81106 } ,
107+ handleRequestClosed : ( ) => {
108+ if ( ! onRequestClosedUpdateChunk ) {
109+ return ;
110+ }
111+
112+ try {
113+ assertIsUpdateChunk ( onRequestClosedUpdateChunk ) ;
114+ const bundlePath = getRequestBundleFilePath ( onRequestClosedUpdateChunk . bundleTimestamp ) ;
115+ executionContext
116+ . runInVM ( onRequestClosedUpdateChunk . updateChunk , bundlePath )
117+ . catch ( ( err : unknown ) => {
118+ log . error ( {
119+ msg : 'Error running onRequestClosedUpdateChunk' ,
120+ err,
121+ onRequestClosedUpdateChunk,
122+ } ) ;
123+ } ) ;
124+ } catch ( err ) {
125+ log . error ( { msg : 'Invalid onRequestClosedUpdateChunk' , err, onRequestClosedUpdateChunk } ) ;
126+ }
127+ } ,
82128 } ,
83129 } ;
84130 } catch ( error ) {
0 commit comments