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 {ReactClientValue} from 'react-server/src/ReactFlightServer';
    
  11. import type {ServerContextJSONValue, Thenable} from 'shared/ReactTypes';
    
  12. import type {ClientManifest} from './ReactFlightServerConfigTurbopackBundler';
    
  13. import type {ServerManifest} from 'react-client/src/ReactFlightClientConfig';
    
  14. 
    
  15. import {
    
  16.   createRequest,
    
  17.   startWork,
    
  18.   startFlowing,
    
  19.   abort,
    
  20. } from 'react-server/src/ReactFlightServer';
    
  21. 
    
  22. import {
    
  23.   createResponse,
    
  24.   close,
    
  25.   getRoot,
    
  26. } from 'react-server/src/ReactFlightReplyServer';
    
  27. 
    
  28. import {decodeAction} from 'react-server/src/ReactFlightActionServer';
    
  29. 
    
  30. export {
    
  31.   registerServerReference,
    
  32.   registerClientReference,
    
  33.   createClientModuleProxy,
    
  34. } from './ReactFlightTurbopackReferences';
    
  35. 
    
  36. type Options = {
    
  37.   identifierPrefix?: string,
    
  38.   signal?: AbortSignal,
    
  39.   context?: Array<[string, ServerContextJSONValue]>,
    
  40.   onError?: (error: mixed) => void,
    
  41.   onPostpone?: (reason: string) => void,
    
  42. };
    
  43. 
    
  44. function renderToReadableStream(
    
  45.   model: ReactClientValue,
    
  46.   turbopackMap: ClientManifest,
    
  47.   options?: Options,
    
  48. ): ReadableStream {
    
  49.   const request = createRequest(
    
  50.     model,
    
  51.     turbopackMap,
    
  52.     options ? options.onError : undefined,
    
  53.     options ? options.context : undefined,
    
  54.     options ? options.identifierPrefix : undefined,
    
  55.     options ? options.onPostpone : undefined,
    
  56.   );
    
  57.   if (options && options.signal) {
    
  58.     const signal = options.signal;
    
  59.     if (signal.aborted) {
    
  60.       abort(request, (signal: any).reason);
    
  61.     } else {
    
  62.       const listener = () => {
    
  63.         abort(request, (signal: any).reason);
    
  64.         signal.removeEventListener('abort', listener);
    
  65.       };
    
  66.       signal.addEventListener('abort', listener);
    
  67.     }
    
  68.   }
    
  69.   const stream = new ReadableStream(
    
  70.     {
    
  71.       type: 'bytes',
    
  72.       start: (controller): ?Promise<void> => {
    
  73.         startWork(request);
    
  74.       },
    
  75.       pull: (controller): ?Promise<void> => {
    
  76.         startFlowing(request, controller);
    
  77.       },
    
  78.       cancel: (reason): ?Promise<void> => {},
    
  79.     },
    
  80.     // $FlowFixMe[prop-missing] size() methods are not allowed on byte streams.
    
  81.     {highWaterMark: 0},
    
  82.   );
    
  83.   return stream;
    
  84. }
    
  85. 
    
  86. function decodeReply<T>(
    
  87.   body: string | FormData,
    
  88.   turbopackMap: ServerManifest,
    
  89. ): Thenable<T> {
    
  90.   if (typeof body === 'string') {
    
  91.     const form = new FormData();
    
  92.     form.append('0', body);
    
  93.     body = form;
    
  94.   }
    
  95.   const response = createResponse(turbopackMap, '', body);
    
  96.   const root = getRoot<T>(response);
    
  97.   close(response);
    
  98.   return root;
    
  99. }
    
  100. 
    
  101. export {renderToReadableStream, decodeReply, decodeAction};