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 {Thenable} from 'shared/ReactTypes.js';
    
  11. 
    
  12. import type {Response as FlightResponse} from 'react-client/src/ReactFlightClient';
    
  13. 
    
  14. import type {ReactServerValue} from 'react-client/src/ReactFlightReplyClient';
    
  15. 
    
  16. import type {
    
  17.   SSRModuleMap,
    
  18.   ModuleLoading,
    
  19. } from 'react-client/src/ReactFlightClientConfig';
    
  20. 
    
  21. type SSRManifest = {
    
  22.   moduleMap: SSRModuleMap,
    
  23.   moduleLoading: ModuleLoading,
    
  24. };
    
  25. 
    
  26. import {
    
  27.   createResponse,
    
  28.   getRoot,
    
  29.   reportGlobalError,
    
  30.   processBinaryChunk,
    
  31.   close,
    
  32. } from 'react-client/src/ReactFlightClient';
    
  33. 
    
  34. import {
    
  35.   processReply,
    
  36.   createServerReference as createServerReferenceImpl,
    
  37. } from 'react-client/src/ReactFlightReplyClient';
    
  38. 
    
  39. function noServerCall() {
    
  40.   throw new Error(
    
  41.     'Server Functions cannot be called during initial render. ' +
    
  42.       'This would create a fetch waterfall. Try to use a Server Component ' +
    
  43.       'to pass data to Client Components instead.',
    
  44.   );
    
  45. }
    
  46. 
    
  47. export function createServerReference<A: Iterable<any>, T>(
    
  48.   id: any,
    
  49.   callServer: any,
    
  50. ): (...A) => Promise<T> {
    
  51.   return createServerReferenceImpl(id, noServerCall);
    
  52. }
    
  53. 
    
  54. export type Options = {
    
  55.   ssrManifest: SSRManifest,
    
  56.   nonce?: string,
    
  57. };
    
  58. 
    
  59. function createResponseFromOptions(options: Options) {
    
  60.   return createResponse(
    
  61.     options.ssrManifest.moduleMap,
    
  62.     options.ssrManifest.moduleLoading,
    
  63.     noServerCall,
    
  64.     typeof options.nonce === 'string' ? options.nonce : undefined,
    
  65.   );
    
  66. }
    
  67. 
    
  68. function startReadingFromStream(
    
  69.   response: FlightResponse,
    
  70.   stream: ReadableStream,
    
  71. ): void {
    
  72.   const reader = stream.getReader();
    
  73.   function progress({
    
  74.     done,
    
  75.     value,
    
  76.   }: {
    
  77.     done: boolean,
    
  78.     value: ?any,
    
  79.     ...
    
  80.   }): void | Promise<void> {
    
  81.     if (done) {
    
  82.       close(response);
    
  83.       return;
    
  84.     }
    
  85.     const buffer: Uint8Array = (value: any);
    
  86.     processBinaryChunk(response, buffer);
    
  87.     return reader.read().then(progress).catch(error);
    
  88.   }
    
  89.   function error(e: any) {
    
  90.     reportGlobalError(response, e);
    
  91.   }
    
  92.   reader.read().then(progress).catch(error);
    
  93. }
    
  94. 
    
  95. function createFromReadableStream<T>(
    
  96.   stream: ReadableStream,
    
  97.   options: Options,
    
  98. ): Thenable<T> {
    
  99.   const response: FlightResponse = createResponseFromOptions(options);
    
  100.   startReadingFromStream(response, stream);
    
  101.   return getRoot(response);
    
  102. }
    
  103. 
    
  104. function createFromFetch<T>(
    
  105.   promiseForResponse: Promise<Response>,
    
  106.   options: Options,
    
  107. ): Thenable<T> {
    
  108.   const response: FlightResponse = createResponseFromOptions(options);
    
  109.   promiseForResponse.then(
    
  110.     function (r) {
    
  111.       startReadingFromStream(response, (r.body: any));
    
  112.     },
    
  113.     function (e) {
    
  114.       reportGlobalError(response, e);
    
  115.     },
    
  116.   );
    
  117.   return getRoot(response);
    
  118. }
    
  119. 
    
  120. function encodeReply(
    
  121.   value: ReactServerValue,
    
  122. ): Promise<
    
  123.   string | URLSearchParams | FormData,
    
  124. > /* We don't use URLSearchParams yet but maybe */ {
    
  125.   return new Promise((resolve, reject) => {
    
  126.     processReply(value, '', resolve, reject);
    
  127.   });
    
  128. }
    
  129. 
    
  130. export {createFromFetch, createFromReadableStream, encodeReply};