1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and affiliates.
    
  3.  *
    
  4.  * This source code is licensed under the MIT license found in the
    
  5.  * LICENSE file in the root directory of this source tree.
    
  6.  *
    
  7.  * @flow
    
  8.  */
    
  9. 
    
  10. import type {ReactNodeList} from 'shared/ReactTypes';
    
  11. 
    
  12. import type {Request} from 'react-server/src/ReactFizzServer';
    
  13. 
    
  14. import type {Destination} from 'react-server/src/ReactServerStreamConfig';
    
  15. import type {BootstrapScriptDescriptor} from 'react-dom-bindings/src/server/ReactFizzConfigDOM';
    
  16. 
    
  17. import {
    
  18.   createRequest,
    
  19.   startWork,
    
  20.   performWork,
    
  21.   startFlowing,
    
  22.   abort,
    
  23. } from 'react-server/src/ReactFizzServer';
    
  24. 
    
  25. import {
    
  26.   createResumableState,
    
  27.   createRenderState,
    
  28.   createRootFormatContext,
    
  29. } from 'react-server/src/ReactFizzConfig';
    
  30. 
    
  31. type Options = {
    
  32.   identifierPrefix?: string,
    
  33.   bootstrapScriptContent?: string,
    
  34.   bootstrapScripts: Array<string>,
    
  35.   bootstrapModules: Array<string>,
    
  36.   progressiveChunkSize?: number,
    
  37.   onError: (error: mixed) => void,
    
  38.   unstable_externalRuntimeSrc?: string | BootstrapScriptDescriptor,
    
  39. };
    
  40. 
    
  41. opaque type Stream = {
    
  42.   destination: Destination,
    
  43.   request: Request,
    
  44. };
    
  45. 
    
  46. function renderToStream(children: ReactNodeList, options: Options): Stream {
    
  47.   const destination = {
    
  48.     buffer: '',
    
  49.     done: false,
    
  50.     fatal: false,
    
  51.     error: null,
    
  52.   };
    
  53.   const resumableState = createResumableState(
    
  54.     options ? options.identifierPrefix : undefined,
    
  55.     options ? options.unstable_externalRuntimeSrc : undefined,
    
  56.   );
    
  57.   const request = createRequest(
    
  58.     children,
    
  59.     resumableState,
    
  60.     createRenderState(
    
  61.       resumableState,
    
  62.       undefined,
    
  63.       options ? options.bootstrapScriptContent : undefined,
    
  64.       options ? options.bootstrapScripts : undefined,
    
  65.       options ? options.bootstrapModules : undefined,
    
  66.       options ? options.unstable_externalRuntimeSrc : undefined,
    
  67.     ),
    
  68.     createRootFormatContext(undefined),
    
  69.     options ? options.progressiveChunkSize : undefined,
    
  70.     options.onError,
    
  71.     undefined,
    
  72.     undefined,
    
  73.   );
    
  74.   startWork(request);
    
  75.   if (destination.fatal) {
    
  76.     throw destination.error;
    
  77.   }
    
  78.   return {
    
  79.     destination,
    
  80.     request,
    
  81.   };
    
  82. }
    
  83. 
    
  84. function abortStream(stream: Stream, reason: mixed): void {
    
  85.   abort(stream.request, reason);
    
  86. }
    
  87. 
    
  88. function renderNextChunk(stream: Stream): string {
    
  89.   const {request, destination} = stream;
    
  90.   performWork(request);
    
  91.   startFlowing(request, destination);
    
  92.   if (destination.fatal) {
    
  93.     throw destination.error;
    
  94.   }
    
  95.   const chunk = destination.buffer;
    
  96.   destination.buffer = '';
    
  97.   return chunk;
    
  98. }
    
  99. 
    
  100. function hasFinished(stream: Stream): boolean {
    
  101.   return stream.destination.done;
    
  102. }
    
  103. 
    
  104. function debug(stream: Stream): any {
    
  105.   // convert to any to silence flow errors from opaque type
    
  106.   const request = (stream.request: any);
    
  107.   return {
    
  108.     pendingRootTasks: request.pendingRootTasks,
    
  109.     clientRenderedBoundaries: request.clientRenderedBoundaries.length,
    
  110.     completedBoundaries: request.completedBoundaries.length,
    
  111.     partialBoundaries: request.partialBoundaries.length,
    
  112.     allPendingTasks: request.allPendingTasks,
    
  113.     pingedTasks: request.pingedTasks.length,
    
  114.   };
    
  115. }
    
  116. 
    
  117. export {renderToStream, renderNextChunk, hasFinished, abortStream, debug};