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 {Chunk, BinaryChunk, Destination} from './ReactServerStreamConfig';
    
  11. 
    
  12. import type {Postpone} from 'react/src/ReactPostpone';
    
  13. 
    
  14. import {
    
  15.   enableBinaryFlight,
    
  16.   enablePostpone,
    
  17.   enableTaint,
    
  18.   enableServerContext,
    
  19. } from 'shared/ReactFeatureFlags';
    
  20. 
    
  21. import {
    
  22.   scheduleWork,
    
  23.   flushBuffered,
    
  24.   beginWriting,
    
  25.   writeChunkAndReturn,
    
  26.   stringToChunk,
    
  27.   typedArrayToBinaryChunk,
    
  28.   byteLengthOfChunk,
    
  29.   byteLengthOfBinaryChunk,
    
  30.   completeWriting,
    
  31.   close,
    
  32.   closeWithError,
    
  33. } from './ReactServerStreamConfig';
    
  34. 
    
  35. export type {Destination, Chunk} from './ReactServerStreamConfig';
    
  36. 
    
  37. import type {
    
  38.   ClientManifest,
    
  39.   ClientReferenceMetadata,
    
  40.   ClientReference,
    
  41.   ClientReferenceKey,
    
  42.   ServerReference,
    
  43.   ServerReferenceId,
    
  44.   Hints,
    
  45.   HintCode,
    
  46.   HintModel,
    
  47. } from './ReactFlightServerConfig';
    
  48. import type {ContextSnapshot} from './ReactFlightNewContext';
    
  49. import type {ThenableState} from './ReactFlightThenable';
    
  50. import type {
    
  51.   ReactProviderType,
    
  52.   ServerContextJSONValue,
    
  53.   Wakeable,
    
  54.   Thenable,
    
  55.   PendingThenable,
    
  56.   FulfilledThenable,
    
  57.   RejectedThenable,
    
  58.   ReactServerContext,
    
  59. } from 'shared/ReactTypes';
    
  60. import type {LazyComponent} from 'react/src/ReactLazy';
    
  61. 
    
  62. import {
    
  63.   resolveClientReferenceMetadata,
    
  64.   getServerReferenceId,
    
  65.   getServerReferenceBoundArguments,
    
  66.   getClientReferenceKey,
    
  67.   isClientReference,
    
  68.   isServerReference,
    
  69.   supportsRequestStorage,
    
  70.   requestStorage,
    
  71.   prepareHostDispatcher,
    
  72.   createHints,
    
  73. } from './ReactFlightServerConfig';
    
  74. 
    
  75. import {
    
  76.   HooksDispatcher,
    
  77.   prepareToUseHooksForRequest,
    
  78.   prepareToUseHooksForComponent,
    
  79.   getThenableStateAfterSuspending,
    
  80.   resetHooksForRequest,
    
  81. } from './ReactFlightHooks';
    
  82. import {DefaultCacheDispatcher} from './flight/ReactFlightServerCache';
    
  83. import {
    
  84.   pushProvider,
    
  85.   popProvider,
    
  86.   switchContext,
    
  87.   getActiveContext,
    
  88.   rootContextSnapshot,
    
  89. } from './ReactFlightNewContext';
    
  90. 
    
  91. import {
    
  92.   getIteratorFn,
    
  93.   REACT_ELEMENT_TYPE,
    
  94.   REACT_FORWARD_REF_TYPE,
    
  95.   REACT_FRAGMENT_TYPE,
    
  96.   REACT_LAZY_TYPE,
    
  97.   REACT_MEMO_TYPE,
    
  98.   REACT_POSTPONE_TYPE,
    
  99.   REACT_PROVIDER_TYPE,
    
  100. } from 'shared/ReactSymbols';
    
  101. 
    
  102. import {
    
  103.   describeValueForErrorMessage,
    
  104.   describeObjectForErrorMessage,
    
  105.   isSimpleObject,
    
  106.   jsxPropsParents,
    
  107.   jsxChildrenParents,
    
  108.   objectName,
    
  109. } from 'shared/ReactSerializationErrors';
    
  110. 
    
  111. import {getOrCreateServerContext} from 'shared/ReactServerContextRegistry';
    
  112. import ReactSharedInternals from 'shared/ReactSharedInternals';
    
  113. import ReactServerSharedInternals from './ReactServerSharedInternals';
    
  114. import isArray from 'shared/isArray';
    
  115. import getPrototypeOf from 'shared/getPrototypeOf';
    
  116. import binaryToComparableString from 'shared/binaryToComparableString';
    
  117. 
    
  118. import {SuspenseException, getSuspendedThenable} from './ReactFlightThenable';
    
  119. 
    
  120. const ObjectPrototype = Object.prototype;
    
  121. 
    
  122. type JSONValue =
    
  123.   | string
    
  124.   | boolean
    
  125.   | number
    
  126.   | null
    
  127.   | {+[key: string]: JSONValue}
    
  128.   | $ReadOnlyArray<JSONValue>;
    
  129. 
    
  130. const stringify = JSON.stringify;
    
  131. 
    
  132. type ReactJSONValue =
    
  133.   | string
    
  134.   | boolean
    
  135.   | number
    
  136.   | null
    
  137.   | $ReadOnlyArray<ReactJSONValue>
    
  138.   | ReactClientObject;
    
  139. 
    
  140. // Serializable values
    
  141. export type ReactClientValue =
    
  142.   // Server Elements and Lazy Components are unwrapped on the Server
    
  143.   | React$Element<React$AbstractComponent<any, any>>
    
  144.   | LazyComponent<ReactClientValue, any>
    
  145.   // References are passed by their value
    
  146.   | ClientReference<any>
    
  147.   | ServerReference<any>
    
  148.   // The rest are passed as is. Sub-types can be passed in but lose their
    
  149.   // subtype, so the receiver can only accept once of these.
    
  150.   | React$Element<string>
    
  151.   | React$Element<ClientReference<any> & any>
    
  152.   | ReactServerContext<any>
    
  153.   | string
    
  154.   | boolean
    
  155.   | number
    
  156.   | symbol
    
  157.   | null
    
  158.   | void
    
  159.   | bigint
    
  160.   | Iterable<ReactClientValue>
    
  161.   | Array<ReactClientValue>
    
  162.   | Map<ReactClientValue, ReactClientValue>
    
  163.   | Set<ReactClientValue>
    
  164.   | Date
    
  165.   | ReactClientObject
    
  166.   | Promise<ReactClientValue>; // Thenable<ReactClientValue>
    
  167. 
    
  168. type ReactClientObject = {+[key: string]: ReactClientValue};
    
  169. 
    
  170. const PENDING = 0;
    
  171. const COMPLETED = 1;
    
  172. const ABORTED = 3;
    
  173. const ERRORED = 4;
    
  174. 
    
  175. type Task = {
    
  176.   id: number,
    
  177.   status: 0 | 1 | 3 | 4,
    
  178.   model: ReactClientValue,
    
  179.   ping: () => void,
    
  180.   context: ContextSnapshot,
    
  181.   thenableState: ThenableState | null,
    
  182. };
    
  183. 
    
  184. interface Reference {}
    
  185. 
    
  186. export type Request = {
    
  187.   status: 0 | 1 | 2,
    
  188.   flushScheduled: boolean,
    
  189.   fatalError: mixed,
    
  190.   destination: null | Destination,
    
  191.   bundlerConfig: ClientManifest,
    
  192.   cache: Map<Function, mixed>,
    
  193.   nextChunkId: number,
    
  194.   pendingChunks: number,
    
  195.   hints: Hints,
    
  196.   abortableTasks: Set<Task>,
    
  197.   pingedTasks: Array<Task>,
    
  198.   completedImportChunks: Array<Chunk>,
    
  199.   completedHintChunks: Array<Chunk>,
    
  200.   completedRegularChunks: Array<Chunk | BinaryChunk>,
    
  201.   completedErrorChunks: Array<Chunk>,
    
  202.   writtenSymbols: Map<symbol, number>,
    
  203.   writtenClientReferences: Map<ClientReferenceKey, number>,
    
  204.   writtenServerReferences: Map<ServerReference<any>, number>,
    
  205.   writtenProviders: Map<string, number>,
    
  206.   writtenObjects: WeakMap<Reference, number>, // -1 means "seen" but not outlined.
    
  207.   identifierPrefix: string,
    
  208.   identifierCount: number,
    
  209.   taintCleanupQueue: Array<string | bigint>,
    
  210.   onError: (error: mixed) => ?string,
    
  211.   onPostpone: (reason: string) => void,
    
  212.   toJSON: (key: string, value: ReactClientValue) => ReactJSONValue,
    
  213. };
    
  214. 
    
  215. const {
    
  216.   TaintRegistryObjects,
    
  217.   TaintRegistryValues,
    
  218.   TaintRegistryByteLengths,
    
  219.   TaintRegistryPendingRequests,
    
  220.   ReactCurrentCache,
    
  221. } = ReactServerSharedInternals;
    
  222. const ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
    
  223. 
    
  224. function throwTaintViolation(message: string) {
    
  225.   // eslint-disable-next-line react-internal/prod-error-codes
    
  226.   throw new Error(message);
    
  227. }
    
  228. 
    
  229. function cleanupTaintQueue(request: Request): void {
    
  230.   const cleanupQueue = request.taintCleanupQueue;
    
  231.   TaintRegistryPendingRequests.delete(cleanupQueue);
    
  232.   for (let i = 0; i < cleanupQueue.length; i++) {
    
  233.     const entryValue = cleanupQueue[i];
    
  234.     const entry = TaintRegistryValues.get(entryValue);
    
  235.     if (entry !== undefined) {
    
  236.       if (entry.count === 1) {
    
  237.         TaintRegistryValues.delete(entryValue);
    
  238.       } else {
    
  239.         entry.count--;
    
  240.       }
    
  241.     }
    
  242.   }
    
  243.   cleanupQueue.length = 0;
    
  244. }
    
  245. 
    
  246. function defaultErrorHandler(error: mixed) {
    
  247.   console['error'](error);
    
  248.   // Don't transform to our wrapper
    
  249. }
    
  250. 
    
  251. function defaultPostponeHandler(reason: string) {
    
  252.   // Noop
    
  253. }
    
  254. 
    
  255. const OPEN = 0;
    
  256. const CLOSING = 1;
    
  257. const CLOSED = 2;
    
  258. 
    
  259. export function createRequest(
    
  260.   model: ReactClientValue,
    
  261.   bundlerConfig: ClientManifest,
    
  262.   onError: void | ((error: mixed) => ?string),
    
  263.   context?: Array<[string, ServerContextJSONValue]>,
    
  264.   identifierPrefix?: string,
    
  265.   onPostpone: void | ((reason: string) => void),
    
  266. ): Request {
    
  267.   if (
    
  268.     ReactCurrentCache.current !== null &&
    
  269.     ReactCurrentCache.current !== DefaultCacheDispatcher
    
  270.   ) {
    
  271.     throw new Error(
    
  272.       'Currently React only supports one RSC renderer at a time.',
    
  273.     );
    
  274.   }
    
  275.   prepareHostDispatcher();
    
  276.   ReactCurrentCache.current = DefaultCacheDispatcher;
    
  277. 
    
  278.   const abortSet: Set<Task> = new Set();
    
  279.   const pingedTasks: Array<Task> = [];
    
  280.   const cleanupQueue: Array<string | bigint> = [];
    
  281.   if (enableTaint) {
    
  282.     TaintRegistryPendingRequests.add(cleanupQueue);
    
  283.   }
    
  284.   const hints = createHints();
    
  285.   const request: Request = {
    
  286.     status: OPEN,
    
  287.     flushScheduled: false,
    
  288.     fatalError: null,
    
  289.     destination: null,
    
  290.     bundlerConfig,
    
  291.     cache: new Map(),
    
  292.     nextChunkId: 0,
    
  293.     pendingChunks: 0,
    
  294.     hints,
    
  295.     abortableTasks: abortSet,
    
  296.     pingedTasks: pingedTasks,
    
  297.     completedImportChunks: ([]: Array<Chunk>),
    
  298.     completedHintChunks: ([]: Array<Chunk>),
    
  299.     completedRegularChunks: ([]: Array<Chunk | BinaryChunk>),
    
  300.     completedErrorChunks: ([]: Array<Chunk>),
    
  301.     writtenSymbols: new Map(),
    
  302.     writtenClientReferences: new Map(),
    
  303.     writtenServerReferences: new Map(),
    
  304.     writtenProviders: new Map(),
    
  305.     writtenObjects: new WeakMap(),
    
  306.     identifierPrefix: identifierPrefix || '',
    
  307.     identifierCount: 1,
    
  308.     taintCleanupQueue: cleanupQueue,
    
  309.     onError: onError === undefined ? defaultErrorHandler : onError,
    
  310.     onPostpone: onPostpone === undefined ? defaultPostponeHandler : onPostpone,
    
  311.     // $FlowFixMe[missing-this-annot]
    
  312.     toJSON: function (key: string, value: ReactClientValue): ReactJSONValue {
    
  313.       return resolveModelToJSON(request, this, key, value);
    
  314.     },
    
  315.   };
    
  316.   request.pendingChunks++;
    
  317.   const rootContext = createRootContext(context);
    
  318.   const rootTask = createTask(request, model, rootContext, abortSet);
    
  319.   pingedTasks.push(rootTask);
    
  320.   return request;
    
  321. }
    
  322. 
    
  323. let currentRequest: null | Request = null;
    
  324. 
    
  325. export function resolveRequest(): null | Request {
    
  326.   if (currentRequest) return currentRequest;
    
  327.   if (supportsRequestStorage) {
    
  328.     const store = requestStorage.getStore();
    
  329.     if (store) return store;
    
  330.   }
    
  331.   return null;
    
  332. }
    
  333. 
    
  334. function createRootContext(
    
  335.   reqContext?: Array<[string, ServerContextJSONValue]>,
    
  336. ) {
    
  337.   return importServerContexts(reqContext);
    
  338. }
    
  339. 
    
  340. const POP = {};
    
  341. 
    
  342. function serializeThenable(request: Request, thenable: Thenable<any>): number {
    
  343.   request.pendingChunks++;
    
  344.   const newTask = createTask(
    
  345.     request,
    
  346.     null,
    
  347.     getActiveContext(),
    
  348.     request.abortableTasks,
    
  349.   );
    
  350. 
    
  351.   switch (thenable.status) {
    
  352.     case 'fulfilled': {
    
  353.       // We have the resolved value, we can go ahead and schedule it for serialization.
    
  354.       newTask.model = thenable.value;
    
  355.       pingTask(request, newTask);
    
  356.       return newTask.id;
    
  357.     }
    
  358.     case 'rejected': {
    
  359.       const x = thenable.reason;
    
  360.       if (
    
  361.         enablePostpone &&
    
  362.         typeof x === 'object' &&
    
  363.         x !== null &&
    
  364.         (x: any).$$typeof === REACT_POSTPONE_TYPE
    
  365.       ) {
    
  366.         const postponeInstance: Postpone = (x: any);
    
  367.         logPostpone(request, postponeInstance.message);
    
  368.         emitPostponeChunk(request, newTask.id, postponeInstance);
    
  369.       } else {
    
  370.         const digest = logRecoverableError(request, x);
    
  371.         emitErrorChunk(request, newTask.id, digest, x);
    
  372.       }
    
  373.       return newTask.id;
    
  374.     }
    
  375.     default: {
    
  376.       if (typeof thenable.status === 'string') {
    
  377.         // Only instrument the thenable if the status if not defined. If
    
  378.         // it's defined, but an unknown value, assume it's been instrumented by
    
  379.         // some custom userspace implementation. We treat it as "pending".
    
  380.         break;
    
  381.       }
    
  382.       const pendingThenable: PendingThenable<mixed> = (thenable: any);
    
  383.       pendingThenable.status = 'pending';
    
  384.       pendingThenable.then(
    
  385.         fulfilledValue => {
    
  386.           if (thenable.status === 'pending') {
    
  387.             const fulfilledThenable: FulfilledThenable<mixed> = (thenable: any);
    
  388.             fulfilledThenable.status = 'fulfilled';
    
  389.             fulfilledThenable.value = fulfilledValue;
    
  390.           }
    
  391.         },
    
  392.         (error: mixed) => {
    
  393.           if (thenable.status === 'pending') {
    
  394.             const rejectedThenable: RejectedThenable<mixed> = (thenable: any);
    
  395.             rejectedThenable.status = 'rejected';
    
  396.             rejectedThenable.reason = error;
    
  397.           }
    
  398.         },
    
  399.       );
    
  400.       break;
    
  401.     }
    
  402.   }
    
  403. 
    
  404.   thenable.then(
    
  405.     value => {
    
  406.       newTask.model = value;
    
  407.       pingTask(request, newTask);
    
  408.     },
    
  409.     reason => {
    
  410.       newTask.status = ERRORED;
    
  411.       request.abortableTasks.delete(newTask);
    
  412.       // TODO: We should ideally do this inside performWork so it's scheduled
    
  413.       const digest = logRecoverableError(request, reason);
    
  414.       emitErrorChunk(request, newTask.id, digest, reason);
    
  415.       if (request.destination !== null) {
    
  416.         flushCompletedChunks(request, request.destination);
    
  417.       }
    
  418.     },
    
  419.   );
    
  420. 
    
  421.   return newTask.id;
    
  422. }
    
  423. 
    
  424. export function emitHint<Code: HintCode>(
    
  425.   request: Request,
    
  426.   code: Code,
    
  427.   model: HintModel<Code>,
    
  428. ): void {
    
  429.   emitHintChunk(request, code, model);
    
  430.   enqueueFlush(request);
    
  431. }
    
  432. 
    
  433. export function getHints(request: Request): Hints {
    
  434.   return request.hints;
    
  435. }
    
  436. 
    
  437. export function getCache(request: Request): Map<Function, mixed> {
    
  438.   return request.cache;
    
  439. }
    
  440. 
    
  441. function readThenable<T>(thenable: Thenable<T>): T {
    
  442.   if (thenable.status === 'fulfilled') {
    
  443.     return thenable.value;
    
  444.   } else if (thenable.status === 'rejected') {
    
  445.     throw thenable.reason;
    
  446.   }
    
  447.   throw thenable;
    
  448. }
    
  449. 
    
  450. function createLazyWrapperAroundWakeable(wakeable: Wakeable) {
    
  451.   // This is a temporary fork of the `use` implementation until we accept
    
  452.   // promises everywhere.
    
  453.   const thenable: Thenable<mixed> = (wakeable: any);
    
  454.   switch (thenable.status) {
    
  455.     case 'fulfilled':
    
  456.     case 'rejected':
    
  457.       break;
    
  458.     default: {
    
  459.       if (typeof thenable.status === 'string') {
    
  460.         // Only instrument the thenable if the status if not defined. If
    
  461.         // it's defined, but an unknown value, assume it's been instrumented by
    
  462.         // some custom userspace implementation. We treat it as "pending".
    
  463.         break;
    
  464.       }
    
  465.       const pendingThenable: PendingThenable<mixed> = (thenable: any);
    
  466.       pendingThenable.status = 'pending';
    
  467.       pendingThenable.then(
    
  468.         fulfilledValue => {
    
  469.           if (thenable.status === 'pending') {
    
  470.             const fulfilledThenable: FulfilledThenable<mixed> = (thenable: any);
    
  471.             fulfilledThenable.status = 'fulfilled';
    
  472.             fulfilledThenable.value = fulfilledValue;
    
  473.           }
    
  474.         },
    
  475.         (error: mixed) => {
    
  476.           if (thenable.status === 'pending') {
    
  477.             const rejectedThenable: RejectedThenable<mixed> = (thenable: any);
    
  478.             rejectedThenable.status = 'rejected';
    
  479.             rejectedThenable.reason = error;
    
  480.           }
    
  481.         },
    
  482.       );
    
  483.       break;
    
  484.     }
    
  485.   }
    
  486.   const lazyType: LazyComponent<any, Thenable<any>> = {
    
  487.     $$typeof: REACT_LAZY_TYPE,
    
  488.     _payload: thenable,
    
  489.     _init: readThenable,
    
  490.   };
    
  491.   return lazyType;
    
  492. }
    
  493. 
    
  494. function attemptResolveElement(
    
  495.   request: Request,
    
  496.   type: any,
    
  497.   key: null | React$Key,
    
  498.   ref: mixed,
    
  499.   props: any,
    
  500.   prevThenableState: ThenableState | null,
    
  501. ): ReactClientValue {
    
  502.   if (ref !== null && ref !== undefined) {
    
  503.     // When the ref moves to the regular props object this will implicitly
    
  504.     // throw for functions. We could probably relax it to a DEV warning for other
    
  505.     // cases.
    
  506.     throw new Error(
    
  507.       'Refs cannot be used in Server Components, nor passed to Client Components.',
    
  508.     );
    
  509.   }
    
  510.   if (__DEV__) {
    
  511.     jsxPropsParents.set(props, type);
    
  512.     if (typeof props.children === 'object' && props.children !== null) {
    
  513.       jsxChildrenParents.set(props.children, type);
    
  514.     }
    
  515.   }
    
  516.   if (typeof type === 'function') {
    
  517.     if (isClientReference(type)) {
    
  518.       // This is a reference to a Client Component.
    
  519.       return [REACT_ELEMENT_TYPE, type, key, props];
    
  520.     }
    
  521.     // This is a server-side component.
    
  522.     prepareToUseHooksForComponent(prevThenableState);
    
  523.     const result = type(props);
    
  524.     if (
    
  525.       typeof result === 'object' &&
    
  526.       result !== null &&
    
  527.       typeof result.then === 'function'
    
  528.     ) {
    
  529.       // When the return value is in children position we can resolve it immediately,
    
  530.       // to its value without a wrapper if it's synchronously available.
    
  531.       const thenable: Thenable<any> = result;
    
  532.       if (thenable.status === 'fulfilled') {
    
  533.         return thenable.value;
    
  534.       }
    
  535.       // TODO: Once we accept Promises as children on the client, we can just return
    
  536.       // the thenable here.
    
  537.       return createLazyWrapperAroundWakeable(result);
    
  538.     }
    
  539.     return result;
    
  540.   } else if (typeof type === 'string') {
    
  541.     // This is a host element. E.g. HTML.
    
  542.     return [REACT_ELEMENT_TYPE, type, key, props];
    
  543.   } else if (typeof type === 'symbol') {
    
  544.     if (type === REACT_FRAGMENT_TYPE) {
    
  545.       // For key-less fragments, we add a small optimization to avoid serializing
    
  546.       // it as a wrapper.
    
  547.       // TODO: If a key is specified, we should propagate its key to any children.
    
  548.       // Same as if a Server Component has a key.
    
  549.       return props.children;
    
  550.     }
    
  551.     // This might be a built-in React component. We'll let the client decide.
    
  552.     // Any built-in works as long as its props are serializable.
    
  553.     return [REACT_ELEMENT_TYPE, type, key, props];
    
  554.   } else if (type != null && typeof type === 'object') {
    
  555.     if (isClientReference(type)) {
    
  556.       // This is a reference to a Client Component.
    
  557.       return [REACT_ELEMENT_TYPE, type, key, props];
    
  558.     }
    
  559.     switch (type.$$typeof) {
    
  560.       case REACT_LAZY_TYPE: {
    
  561.         const payload = type._payload;
    
  562.         const init = type._init;
    
  563.         const wrappedType = init(payload);
    
  564.         return attemptResolveElement(
    
  565.           request,
    
  566.           wrappedType,
    
  567.           key,
    
  568.           ref,
    
  569.           props,
    
  570.           prevThenableState,
    
  571.         );
    
  572.       }
    
  573.       case REACT_FORWARD_REF_TYPE: {
    
  574.         const render = type.render;
    
  575.         prepareToUseHooksForComponent(prevThenableState);
    
  576.         return render(props, undefined);
    
  577.       }
    
  578.       case REACT_MEMO_TYPE: {
    
  579.         return attemptResolveElement(
    
  580.           request,
    
  581.           type.type,
    
  582.           key,
    
  583.           ref,
    
  584.           props,
    
  585.           prevThenableState,
    
  586.         );
    
  587.       }
    
  588.       case REACT_PROVIDER_TYPE: {
    
  589.         if (enableServerContext) {
    
  590.           pushProvider(type._context, props.value);
    
  591.           if (__DEV__) {
    
  592.             const extraKeys = Object.keys(props).filter(value => {
    
  593.               if (value === 'children' || value === 'value') {
    
  594.                 return false;
    
  595.               }
    
  596.               return true;
    
  597.             });
    
  598.             if (extraKeys.length !== 0) {
    
  599.               console.error(
    
  600.                 'ServerContext can only have a value prop and children. Found: %s',
    
  601.                 JSON.stringify(extraKeys),
    
  602.               );
    
  603.             }
    
  604.           }
    
  605.           return [
    
  606.             REACT_ELEMENT_TYPE,
    
  607.             type,
    
  608.             key,
    
  609.             // Rely on __popProvider being serialized last to pop the provider.
    
  610.             {value: props.value, children: props.children, __pop: POP},
    
  611.           ];
    
  612.         }
    
  613.         // Fallthrough
    
  614.       }
    
  615.     }
    
  616.   }
    
  617.   throw new Error(
    
  618.     `Unsupported Server Component type: ${describeValueForErrorMessage(type)}`,
    
  619.   );
    
  620. }
    
  621. 
    
  622. function pingTask(request: Request, task: Task): void {
    
  623.   const pingedTasks = request.pingedTasks;
    
  624.   pingedTasks.push(task);
    
  625.   if (pingedTasks.length === 1) {
    
  626.     request.flushScheduled = request.destination !== null;
    
  627.     scheduleWork(() => performWork(request));
    
  628.   }
    
  629. }
    
  630. 
    
  631. function createTask(
    
  632.   request: Request,
    
  633.   model: ReactClientValue,
    
  634.   context: ContextSnapshot,
    
  635.   abortSet: Set<Task>,
    
  636. ): Task {
    
  637.   const id = request.nextChunkId++;
    
  638.   const task: Task = {
    
  639.     id,
    
  640.     status: PENDING,
    
  641.     model,
    
  642.     context,
    
  643.     ping: () => pingTask(request, task),
    
  644.     thenableState: null,
    
  645.   };
    
  646.   abortSet.add(task);
    
  647.   return task;
    
  648. }
    
  649. 
    
  650. function serializeByValueID(id: number): string {
    
  651.   return '$' + id.toString(16);
    
  652. }
    
  653. 
    
  654. function serializeLazyID(id: number): string {
    
  655.   return '$L' + id.toString(16);
    
  656. }
    
  657. 
    
  658. function serializePromiseID(id: number): string {
    
  659.   return '$@' + id.toString(16);
    
  660. }
    
  661. 
    
  662. function serializeServerReferenceID(id: number): string {
    
  663.   return '$F' + id.toString(16);
    
  664. }
    
  665. 
    
  666. function serializeSymbolReference(name: string): string {
    
  667.   return '$S' + name;
    
  668. }
    
  669. 
    
  670. function serializeProviderReference(name: string): string {
    
  671.   return '$P' + name;
    
  672. }
    
  673. 
    
  674. function serializeNumber(number: number): string | number {
    
  675.   if (Number.isFinite(number)) {
    
  676.     if (number === 0 && 1 / number === -Infinity) {
    
  677.       return '$-0';
    
  678.     } else {
    
  679.       return number;
    
  680.     }
    
  681.   } else {
    
  682.     if (number === Infinity) {
    
  683.       return '$Infinity';
    
  684.     } else if (number === -Infinity) {
    
  685.       return '$-Infinity';
    
  686.     } else {
    
  687.       return '$NaN';
    
  688.     }
    
  689.   }
    
  690. }
    
  691. 
    
  692. function serializeUndefined(): string {
    
  693.   return '$undefined';
    
  694. }
    
  695. 
    
  696. function serializeDateFromDateJSON(dateJSON: string): string {
    
  697.   // JSON.stringify automatically calls Date.prototype.toJSON which calls toISOString.
    
  698.   // We need only tack on a $D prefix.
    
  699.   return '$D' + dateJSON;
    
  700. }
    
  701. 
    
  702. function serializeBigInt(n: bigint): string {
    
  703.   return '$n' + n.toString(10);
    
  704. }
    
  705. 
    
  706. function serializeRowHeader(tag: string, id: number) {
    
  707.   return id.toString(16) + ':' + tag;
    
  708. }
    
  709. 
    
  710. function encodeReferenceChunk(
    
  711.   request: Request,
    
  712.   id: number,
    
  713.   reference: string,
    
  714. ): Chunk {
    
  715.   const json = stringify(reference);
    
  716.   const row = id.toString(16) + ':' + json + '\n';
    
  717.   return stringToChunk(row);
    
  718. }
    
  719. 
    
  720. function serializeClientReference(
    
  721.   request: Request,
    
  722.   parent:
    
  723.     | {+[key: string | number]: ReactClientValue}
    
  724.     | $ReadOnlyArray<ReactClientValue>,
    
  725.   key: string,
    
  726.   clientReference: ClientReference<any>,
    
  727. ): string {
    
  728.   const clientReferenceKey: ClientReferenceKey =
    
  729.     getClientReferenceKey(clientReference);
    
  730.   const writtenClientReferences = request.writtenClientReferences;
    
  731.   const existingId = writtenClientReferences.get(clientReferenceKey);
    
  732.   if (existingId !== undefined) {
    
  733.     if (parent[0] === REACT_ELEMENT_TYPE && key === '1') {
    
  734.       // If we're encoding the "type" of an element, we can refer
    
  735.       // to that by a lazy reference instead of directly since React
    
  736.       // knows how to deal with lazy values. This lets us suspend
    
  737.       // on this component rather than its parent until the code has
    
  738.       // loaded.
    
  739.       return serializeLazyID(existingId);
    
  740.     }
    
  741.     return serializeByValueID(existingId);
    
  742.   }
    
  743.   try {
    
  744.     const clientReferenceMetadata: ClientReferenceMetadata =
    
  745.       resolveClientReferenceMetadata(request.bundlerConfig, clientReference);
    
  746.     request.pendingChunks++;
    
  747.     const importId = request.nextChunkId++;
    
  748.     emitImportChunk(request, importId, clientReferenceMetadata);
    
  749.     writtenClientReferences.set(clientReferenceKey, importId);
    
  750.     if (parent[0] === REACT_ELEMENT_TYPE && key === '1') {
    
  751.       // If we're encoding the "type" of an element, we can refer
    
  752.       // to that by a lazy reference instead of directly since React
    
  753.       // knows how to deal with lazy values. This lets us suspend
    
  754.       // on this component rather than its parent until the code has
    
  755.       // loaded.
    
  756.       return serializeLazyID(importId);
    
  757.     }
    
  758.     return serializeByValueID(importId);
    
  759.   } catch (x) {
    
  760.     request.pendingChunks++;
    
  761.     const errorId = request.nextChunkId++;
    
  762.     const digest = logRecoverableError(request, x);
    
  763.     emitErrorChunk(request, errorId, digest, x);
    
  764.     return serializeByValueID(errorId);
    
  765.   }
    
  766. }
    
  767. 
    
  768. function outlineModel(request: Request, value: any): number {
    
  769.   request.pendingChunks++;
    
  770.   const newTask = createTask(
    
  771.     request,
    
  772.     value,
    
  773.     getActiveContext(),
    
  774.     request.abortableTasks,
    
  775.   );
    
  776.   retryTask(request, newTask);
    
  777.   return newTask.id;
    
  778. }
    
  779. 
    
  780. function serializeServerReference(
    
  781.   request: Request,
    
  782.   parent:
    
  783.     | {+[key: string | number]: ReactClientValue}
    
  784.     | $ReadOnlyArray<ReactClientValue>,
    
  785.   key: string,
    
  786.   serverReference: ServerReference<any>,
    
  787. ): string {
    
  788.   const writtenServerReferences = request.writtenServerReferences;
    
  789.   const existingId = writtenServerReferences.get(serverReference);
    
  790.   if (existingId !== undefined) {
    
  791.     return serializeServerReferenceID(existingId);
    
  792.   }
    
  793. 
    
  794.   const bound: null | Array<any> = getServerReferenceBoundArguments(
    
  795.     request.bundlerConfig,
    
  796.     serverReference,
    
  797.   );
    
  798.   const serverReferenceMetadata: {
    
  799.     id: ServerReferenceId,
    
  800.     bound: null | Promise<Array<any>>,
    
  801.   } = {
    
  802.     id: getServerReferenceId(request.bundlerConfig, serverReference),
    
  803.     bound: bound ? Promise.resolve(bound) : null,
    
  804.   };
    
  805.   const metadataId = outlineModel(request, serverReferenceMetadata);
    
  806.   writtenServerReferences.set(serverReference, metadataId);
    
  807.   return serializeServerReferenceID(metadataId);
    
  808. }
    
  809. 
    
  810. function serializeLargeTextString(request: Request, text: string): string {
    
  811.   request.pendingChunks += 2;
    
  812.   const textId = request.nextChunkId++;
    
  813.   const textChunk = stringToChunk(text);
    
  814.   const binaryLength = byteLengthOfChunk(textChunk);
    
  815.   const row = textId.toString(16) + ':T' + binaryLength.toString(16) + ',';
    
  816.   const headerChunk = stringToChunk(row);
    
  817.   request.completedRegularChunks.push(headerChunk, textChunk);
    
  818.   return serializeByValueID(textId);
    
  819. }
    
  820. 
    
  821. function serializeMap(
    
  822.   request: Request,
    
  823.   map: Map<ReactClientValue, ReactClientValue>,
    
  824. ): string {
    
  825.   const entries = Array.from(map);
    
  826.   for (let i = 0; i < entries.length; i++) {
    
  827.     const key = entries[i][0];
    
  828.     if (typeof key === 'object' && key !== null) {
    
  829.       const writtenObjects = request.writtenObjects;
    
  830.       const existingId = writtenObjects.get(key);
    
  831.       if (existingId === undefined) {
    
  832.         // Mark all object keys as seen so that they're always outlined.
    
  833.         writtenObjects.set(key, -1);
    
  834.       }
    
  835.     }
    
  836.   }
    
  837.   const id = outlineModel(request, entries);
    
  838.   return '$Q' + id.toString(16);
    
  839. }
    
  840. 
    
  841. function serializeSet(request: Request, set: Set<ReactClientValue>): string {
    
  842.   const entries = Array.from(set);
    
  843.   for (let i = 0; i < entries.length; i++) {
    
  844.     const key = entries[i];
    
  845.     if (typeof key === 'object' && key !== null) {
    
  846.       const writtenObjects = request.writtenObjects;
    
  847.       const existingId = writtenObjects.get(key);
    
  848.       if (existingId === undefined) {
    
  849.         // Mark all object keys as seen so that they're always outlined.
    
  850.         writtenObjects.set(key, -1);
    
  851.       }
    
  852.     }
    
  853.   }
    
  854.   const id = outlineModel(request, entries);
    
  855.   return '$W' + id.toString(16);
    
  856. }
    
  857. 
    
  858. function serializeTypedArray(
    
  859.   request: Request,
    
  860.   tag: string,
    
  861.   typedArray: $ArrayBufferView,
    
  862. ): string {
    
  863.   if (enableTaint) {
    
  864.     if (TaintRegistryByteLengths.has(typedArray.byteLength)) {
    
  865.       // If we have had any tainted values of this length, we check
    
  866.       // to see if these bytes matches any entries in the registry.
    
  867.       const tainted = TaintRegistryValues.get(
    
  868.         binaryToComparableString(typedArray),
    
  869.       );
    
  870.       if (tainted !== undefined) {
    
  871.         throwTaintViolation(tainted.message);
    
  872.       }
    
  873.     }
    
  874.   }
    
  875.   request.pendingChunks += 2;
    
  876.   const bufferId = request.nextChunkId++;
    
  877.   // TODO: Convert to little endian if that's not the server default.
    
  878.   const binaryChunk = typedArrayToBinaryChunk(typedArray);
    
  879.   const binaryLength = byteLengthOfBinaryChunk(binaryChunk);
    
  880.   const row =
    
  881.     bufferId.toString(16) + ':' + tag + binaryLength.toString(16) + ',';
    
  882.   const headerChunk = stringToChunk(row);
    
  883.   request.completedRegularChunks.push(headerChunk, binaryChunk);
    
  884.   return serializeByValueID(bufferId);
    
  885. }
    
  886. 
    
  887. function escapeStringValue(value: string): string {
    
  888.   if (value[0] === '$') {
    
  889.     // We need to escape $ prefixed strings since we use those to encode
    
  890.     // references to IDs and as special symbol values.
    
  891.     return '$' + value;
    
  892.   } else {
    
  893.     return value;
    
  894.   }
    
  895. }
    
  896. 
    
  897. let insideContextProps = null;
    
  898. let isInsideContextValue = false;
    
  899. let modelRoot: null | ReactClientValue = false;
    
  900. 
    
  901. function resolveModelToJSON(
    
  902.   request: Request,
    
  903.   parent:
    
  904.     | {+[key: string | number]: ReactClientValue}
    
  905.     | $ReadOnlyArray<ReactClientValue>,
    
  906.   key: string,
    
  907.   value: ReactClientValue,
    
  908. ): ReactJSONValue {
    
  909.   // Make sure that `parent[key]` wasn't JSONified before `value` was passed to us
    
  910.   if (__DEV__) {
    
  911.     // $FlowFixMe[incompatible-use]
    
  912.     const originalValue = parent[key];
    
  913.     if (
    
  914.       typeof originalValue === 'object' &&
    
  915.       originalValue !== value &&
    
  916.       !(originalValue instanceof Date)
    
  917.     ) {
    
  918.       if (objectName(originalValue) !== 'Object') {
    
  919.         const jsxParentType = jsxChildrenParents.get(parent);
    
  920.         if (typeof jsxParentType === 'string') {
    
  921.           console.error(
    
  922.             '%s objects cannot be rendered as text children. Try formatting it using toString().%s',
    
  923.             objectName(originalValue),
    
  924.             describeObjectForErrorMessage(parent, key),
    
  925.           );
    
  926.         } else {
    
  927.           console.error(
    
  928.             'Only plain objects can be passed to Client Components from Server Components. ' +
    
  929.               '%s objects are not supported.%s',
    
  930.             objectName(originalValue),
    
  931.             describeObjectForErrorMessage(parent, key),
    
  932.           );
    
  933.         }
    
  934.       } else {
    
  935.         console.error(
    
  936.           'Only plain objects can be passed to Client Components from Server Components. ' +
    
  937.             'Objects with toJSON methods are not supported. Convert it manually ' +
    
  938.             'to a simple value before passing it to props.%s',
    
  939.           describeObjectForErrorMessage(parent, key),
    
  940.         );
    
  941.       }
    
  942.     }
    
  943.   }
    
  944. 
    
  945.   // Special Symbols
    
  946.   switch (value) {
    
  947.     case REACT_ELEMENT_TYPE:
    
  948.       return '$';
    
  949.   }
    
  950. 
    
  951.   if (__DEV__) {
    
  952.     if (
    
  953.       enableServerContext &&
    
  954.       parent[0] === REACT_ELEMENT_TYPE &&
    
  955.       parent[1] &&
    
  956.       (parent[1]: any).$$typeof === REACT_PROVIDER_TYPE &&
    
  957.       key === '3'
    
  958.     ) {
    
  959.       insideContextProps = value;
    
  960.     } else if (insideContextProps === parent && key === 'value') {
    
  961.       isInsideContextValue = true;
    
  962.     } else if (insideContextProps === parent && key === 'children') {
    
  963.       isInsideContextValue = false;
    
  964.     }
    
  965.   }
    
  966. 
    
  967.   // Resolve Server Components.
    
  968.   while (
    
  969.     typeof value === 'object' &&
    
  970.     value !== null &&
    
  971.     ((value: any).$$typeof === REACT_ELEMENT_TYPE ||
    
  972.       (value: any).$$typeof === REACT_LAZY_TYPE)
    
  973.   ) {
    
  974.     if (__DEV__) {
    
  975.       if (enableServerContext && isInsideContextValue) {
    
  976.         console.error('React elements are not allowed in ServerContext');
    
  977.       }
    
  978.     }
    
  979. 
    
  980.     try {
    
  981.       switch ((value: any).$$typeof) {
    
  982.         case REACT_ELEMENT_TYPE: {
    
  983.           const writtenObjects = request.writtenObjects;
    
  984.           const existingId = writtenObjects.get(value);
    
  985.           if (existingId !== undefined) {
    
  986.             if (existingId === -1) {
    
  987.               // Seen but not yet outlined.
    
  988.               const newId = outlineModel(request, value);
    
  989.               return serializeByValueID(newId);
    
  990.             } else if (modelRoot === value) {
    
  991.               // This is the ID we're currently emitting so we need to write it
    
  992.               // once but if we discover it again, we refer to it by id.
    
  993.               modelRoot = null;
    
  994.             } else {
    
  995.               // We've already emitted this as an outlined object, so we can
    
  996.               // just refer to that by its existing ID.
    
  997.               return serializeByValueID(existingId);
    
  998.             }
    
  999.           } else {
    
  1000.             // This is the first time we've seen this object. We may never see it again
    
  1001.             // so we'll inline it. Mark it as seen. If we see it again, we'll outline.
    
  1002.             writtenObjects.set(value, -1);
    
  1003.           }
    
  1004. 
    
  1005.           // TODO: Concatenate keys of parents onto children.
    
  1006.           const element: React$Element<any> = (value: any);
    
  1007.           // Attempt to render the Server Component.
    
  1008.           value = attemptResolveElement(
    
  1009.             request,
    
  1010.             element.type,
    
  1011.             element.key,
    
  1012.             element.ref,
    
  1013.             element.props,
    
  1014.             null,
    
  1015.           );
    
  1016.           break;
    
  1017.         }
    
  1018.         case REACT_LAZY_TYPE: {
    
  1019.           const payload = (value: any)._payload;
    
  1020.           const init = (value: any)._init;
    
  1021.           value = init(payload);
    
  1022.           break;
    
  1023.         }
    
  1024.       }
    
  1025.     } catch (thrownValue) {
    
  1026.       const x =
    
  1027.         thrownValue === SuspenseException
    
  1028.           ? // This is a special type of exception used for Suspense. For historical
    
  1029.             // reasons, the rest of the Suspense implementation expects the thrown
    
  1030.             // value to be a thenable, because before `use` existed that was the
    
  1031.             // (unstable) API for suspending. This implementation detail can change
    
  1032.             // later, once we deprecate the old API in favor of `use`.
    
  1033.             getSuspendedThenable()
    
  1034.           : thrownValue;
    
  1035.       if (typeof x === 'object' && x !== null) {
    
  1036.         // $FlowFixMe[method-unbinding]
    
  1037.         if (typeof x.then === 'function') {
    
  1038.           // Something suspended, we'll need to create a new task and resolve it later.
    
  1039.           request.pendingChunks++;
    
  1040.           const newTask = createTask(
    
  1041.             request,
    
  1042.             value,
    
  1043.             getActiveContext(),
    
  1044.             request.abortableTasks,
    
  1045.           );
    
  1046.           const ping = newTask.ping;
    
  1047.           x.then(ping, ping);
    
  1048.           newTask.thenableState = getThenableStateAfterSuspending();
    
  1049.           return serializeLazyID(newTask.id);
    
  1050.         } else if (enablePostpone && x.$$typeof === REACT_POSTPONE_TYPE) {
    
  1051.           // Something postponed. We'll still send everything we have up until this point.
    
  1052.           // We'll replace this element with a lazy reference that postpones on the client.
    
  1053.           const postponeInstance: Postpone = (x: any);
    
  1054.           request.pendingChunks++;
    
  1055.           const postponeId = request.nextChunkId++;
    
  1056.           logPostpone(request, postponeInstance.message);
    
  1057.           emitPostponeChunk(request, postponeId, postponeInstance);
    
  1058.           return serializeLazyID(postponeId);
    
  1059.         }
    
  1060.       }
    
  1061.       // Something errored. We'll still send everything we have up until this point.
    
  1062.       // We'll replace this element with a lazy reference that throws on the client
    
  1063.       // once it gets rendered.
    
  1064.       request.pendingChunks++;
    
  1065.       const errorId = request.nextChunkId++;
    
  1066.       const digest = logRecoverableError(request, x);
    
  1067.       emitErrorChunk(request, errorId, digest, x);
    
  1068.       return serializeLazyID(errorId);
    
  1069.     }
    
  1070.   }
    
  1071. 
    
  1072.   if (value === null) {
    
  1073.     return null;
    
  1074.   }
    
  1075. 
    
  1076.   if (typeof value === 'object') {
    
  1077.     if (enableTaint) {
    
  1078.       const tainted = TaintRegistryObjects.get(value);
    
  1079.       if (tainted !== undefined) {
    
  1080.         throwTaintViolation(tainted);
    
  1081.       }
    
  1082.     }
    
  1083.     if (isClientReference(value)) {
    
  1084.       return serializeClientReference(request, parent, key, (value: any));
    
  1085.     }
    
  1086. 
    
  1087.     const writtenObjects = request.writtenObjects;
    
  1088.     const existingId = writtenObjects.get(value);
    
  1089.     // $FlowFixMe[method-unbinding]
    
  1090.     if (typeof value.then === 'function') {
    
  1091.       if (existingId !== undefined) {
    
  1092.         if (modelRoot === value) {
    
  1093.           // This is the ID we're currently emitting so we need to write it
    
  1094.           // once but if we discover it again, we refer to it by id.
    
  1095.           modelRoot = null;
    
  1096.         } else {
    
  1097.           // We've seen this promise before, so we can just refer to the same result.
    
  1098.           return serializePromiseID(existingId);
    
  1099.         }
    
  1100.       }
    
  1101.       // We assume that any object with a .then property is a "Thenable" type,
    
  1102.       // or a Promise type. Either of which can be represented by a Promise.
    
  1103.       const promiseId = serializeThenable(request, (value: any));
    
  1104.       writtenObjects.set(value, promiseId);
    
  1105.       return serializePromiseID(promiseId);
    
  1106.     }
    
  1107. 
    
  1108.     if (enableServerContext) {
    
  1109.       if ((value: any).$$typeof === REACT_PROVIDER_TYPE) {
    
  1110.         const providerKey = ((value: any): ReactProviderType<any>)._context
    
  1111.           ._globalName;
    
  1112.         const writtenProviders = request.writtenProviders;
    
  1113.         let providerId = writtenProviders.get(key);
    
  1114.         if (providerId === undefined) {
    
  1115.           request.pendingChunks++;
    
  1116.           providerId = request.nextChunkId++;
    
  1117.           writtenProviders.set(providerKey, providerId);
    
  1118.           emitProviderChunk(request, providerId, providerKey);
    
  1119.         }
    
  1120.         return serializeByValueID(providerId);
    
  1121.       } else if (value === POP) {
    
  1122.         popProvider();
    
  1123.         if (__DEV__) {
    
  1124.           insideContextProps = null;
    
  1125.           isInsideContextValue = false;
    
  1126.         }
    
  1127.         return (undefined: any);
    
  1128.       }
    
  1129.     }
    
  1130. 
    
  1131.     if (existingId !== undefined) {
    
  1132.       if (existingId === -1) {
    
  1133.         // Seen but not yet outlined.
    
  1134.         const newId = outlineModel(request, value);
    
  1135.         return serializeByValueID(newId);
    
  1136.       } else if (modelRoot === value) {
    
  1137.         // This is the ID we're currently emitting so we need to write it
    
  1138.         // once but if we discover it again, we refer to it by id.
    
  1139.         modelRoot = null;
    
  1140.       } else {
    
  1141.         // We've already emitted this as an outlined object, so we can
    
  1142.         // just refer to that by its existing ID.
    
  1143.         return serializeByValueID(existingId);
    
  1144.       }
    
  1145.     } else {
    
  1146.       // This is the first time we've seen this object. We may never see it again
    
  1147.       // so we'll inline it. Mark it as seen. If we see it again, we'll outline.
    
  1148.       writtenObjects.set(value, -1);
    
  1149.     }
    
  1150. 
    
  1151.     if (isArray(value)) {
    
  1152.       // $FlowFixMe[incompatible-return]
    
  1153.       return value;
    
  1154.     }
    
  1155. 
    
  1156.     if (value instanceof Map) {
    
  1157.       return serializeMap(request, value);
    
  1158.     }
    
  1159.     if (value instanceof Set) {
    
  1160.       return serializeSet(request, value);
    
  1161.     }
    
  1162. 
    
  1163.     if (enableBinaryFlight) {
    
  1164.       if (value instanceof ArrayBuffer) {
    
  1165.         return serializeTypedArray(request, 'A', new Uint8Array(value));
    
  1166.       }
    
  1167.       if (value instanceof Int8Array) {
    
  1168.         // char
    
  1169.         return serializeTypedArray(request, 'C', value);
    
  1170.       }
    
  1171.       if (value instanceof Uint8Array) {
    
  1172.         // unsigned char
    
  1173.         return serializeTypedArray(request, 'c', value);
    
  1174.       }
    
  1175.       if (value instanceof Uint8ClampedArray) {
    
  1176.         // unsigned clamped char
    
  1177.         return serializeTypedArray(request, 'U', value);
    
  1178.       }
    
  1179.       if (value instanceof Int16Array) {
    
  1180.         // sort
    
  1181.         return serializeTypedArray(request, 'S', value);
    
  1182.       }
    
  1183.       if (value instanceof Uint16Array) {
    
  1184.         // unsigned short
    
  1185.         return serializeTypedArray(request, 's', value);
    
  1186.       }
    
  1187.       if (value instanceof Int32Array) {
    
  1188.         // long
    
  1189.         return serializeTypedArray(request, 'L', value);
    
  1190.       }
    
  1191.       if (value instanceof Uint32Array) {
    
  1192.         // unsigned long
    
  1193.         return serializeTypedArray(request, 'l', value);
    
  1194.       }
    
  1195.       if (value instanceof Float32Array) {
    
  1196.         // float
    
  1197.         return serializeTypedArray(request, 'F', value);
    
  1198.       }
    
  1199.       if (value instanceof Float64Array) {
    
  1200.         // double
    
  1201.         return serializeTypedArray(request, 'D', value);
    
  1202.       }
    
  1203.       if (value instanceof BigInt64Array) {
    
  1204.         // number
    
  1205.         return serializeTypedArray(request, 'N', value);
    
  1206.       }
    
  1207.       if (value instanceof BigUint64Array) {
    
  1208.         // unsigned number
    
  1209.         // We use "m" instead of "n" since JSON can start with "null"
    
  1210.         return serializeTypedArray(request, 'm', value);
    
  1211.       }
    
  1212.       if (value instanceof DataView) {
    
  1213.         return serializeTypedArray(request, 'V', value);
    
  1214.       }
    
  1215.     }
    
  1216. 
    
  1217.     const iteratorFn = getIteratorFn(value);
    
  1218.     if (iteratorFn) {
    
  1219.       return Array.from((value: any));
    
  1220.     }
    
  1221. 
    
  1222.     // Verify that this is a simple plain object.
    
  1223.     const proto = getPrototypeOf(value);
    
  1224.     if (
    
  1225.       proto !== ObjectPrototype &&
    
  1226.       (proto === null || getPrototypeOf(proto) !== null)
    
  1227.     ) {
    
  1228.       throw new Error(
    
  1229.         'Only plain objects, and a few built-ins, can be passed to Client Components ' +
    
  1230.           'from Server Components. Classes or null prototypes are not supported.',
    
  1231.       );
    
  1232.     }
    
  1233.     if (__DEV__) {
    
  1234.       if (objectName(value) !== 'Object') {
    
  1235.         console.error(
    
  1236.           'Only plain objects can be passed to Client Components from Server Components. ' +
    
  1237.             '%s objects are not supported.%s',
    
  1238.           objectName(value),
    
  1239.           describeObjectForErrorMessage(parent, key),
    
  1240.         );
    
  1241.       } else if (!isSimpleObject(value)) {
    
  1242.         console.error(
    
  1243.           'Only plain objects can be passed to Client Components from Server Components. ' +
    
  1244.             'Classes or other objects with methods are not supported.%s',
    
  1245.           describeObjectForErrorMessage(parent, key),
    
  1246.         );
    
  1247.       } else if (Object.getOwnPropertySymbols) {
    
  1248.         const symbols = Object.getOwnPropertySymbols(value);
    
  1249.         if (symbols.length > 0) {
    
  1250.           console.error(
    
  1251.             'Only plain objects can be passed to Client Components from Server Components. ' +
    
  1252.               'Objects with symbol properties like %s are not supported.%s',
    
  1253.             symbols[0].description,
    
  1254.             describeObjectForErrorMessage(parent, key),
    
  1255.           );
    
  1256.         }
    
  1257.       }
    
  1258.     }
    
  1259. 
    
  1260.     // $FlowFixMe[incompatible-return]
    
  1261.     return value;
    
  1262.   }
    
  1263. 
    
  1264.   if (typeof value === 'string') {
    
  1265.     if (enableTaint) {
    
  1266.       const tainted = TaintRegistryValues.get(value);
    
  1267.       if (tainted !== undefined) {
    
  1268.         throwTaintViolation(tainted.message);
    
  1269.       }
    
  1270.     }
    
  1271.     // TODO: Maybe too clever. If we support URL there's no similar trick.
    
  1272.     if (value[value.length - 1] === 'Z') {
    
  1273.       // Possibly a Date, whose toJSON automatically calls toISOString
    
  1274.       // $FlowFixMe[incompatible-use]
    
  1275.       const originalValue = parent[key];
    
  1276.       if (originalValue instanceof Date) {
    
  1277.         return serializeDateFromDateJSON(value);
    
  1278.       }
    
  1279.     }
    
  1280.     if (value.length >= 1024) {
    
  1281.       // For large strings, we encode them outside the JSON payload so that we
    
  1282.       // don't have to double encode and double parse the strings. This can also
    
  1283.       // be more compact in case the string has a lot of escaped characters.
    
  1284.       return serializeLargeTextString(request, value);
    
  1285.     }
    
  1286.     return escapeStringValue(value);
    
  1287.   }
    
  1288. 
    
  1289.   if (typeof value === 'boolean') {
    
  1290.     return value;
    
  1291.   }
    
  1292. 
    
  1293.   if (typeof value === 'number') {
    
  1294.     return serializeNumber(value);
    
  1295.   }
    
  1296. 
    
  1297.   if (typeof value === 'undefined') {
    
  1298.     return serializeUndefined();
    
  1299.   }
    
  1300. 
    
  1301.   if (typeof value === 'function') {
    
  1302.     if (enableTaint) {
    
  1303.       const tainted = TaintRegistryObjects.get(value);
    
  1304.       if (tainted !== undefined) {
    
  1305.         throwTaintViolation(tainted);
    
  1306.       }
    
  1307.     }
    
  1308.     if (isClientReference(value)) {
    
  1309.       return serializeClientReference(request, parent, key, (value: any));
    
  1310.     }
    
  1311.     if (isServerReference(value)) {
    
  1312.       return serializeServerReference(request, parent, key, (value: any));
    
  1313.     }
    
  1314.     if (/^on[A-Z]/.test(key)) {
    
  1315.       throw new Error(
    
  1316.         'Event handlers cannot be passed to Client Component props.' +
    
  1317.           describeObjectForErrorMessage(parent, key) +
    
  1318.           '\nIf you need interactivity, consider converting part of this to a Client Component.',
    
  1319.       );
    
  1320.     } else {
    
  1321.       throw new Error(
    
  1322.         'Functions cannot be passed directly to Client Components ' +
    
  1323.           'unless you explicitly expose it by marking it with "use server".' +
    
  1324.           describeObjectForErrorMessage(parent, key),
    
  1325.       );
    
  1326.     }
    
  1327.   }
    
  1328. 
    
  1329.   if (typeof value === 'symbol') {
    
  1330.     const writtenSymbols = request.writtenSymbols;
    
  1331.     const existingId = writtenSymbols.get(value);
    
  1332.     if (existingId !== undefined) {
    
  1333.       return serializeByValueID(existingId);
    
  1334.     }
    
  1335.     // $FlowFixMe[incompatible-type] `description` might be undefined
    
  1336.     const name: string = value.description;
    
  1337. 
    
  1338.     if (Symbol.for(name) !== value) {
    
  1339.       throw new Error(
    
  1340.         'Only global symbols received from Symbol.for(...) can be passed to Client Components. ' +
    
  1341.           `The symbol Symbol.for(${
    
  1342.             // $FlowFixMe[incompatible-type] `description` might be undefined
    
  1343.             value.description
    
  1344.           }) cannot be found among global symbols.` +
    
  1345.           describeObjectForErrorMessage(parent, key),
    
  1346.       );
    
  1347.     }
    
  1348. 
    
  1349.     request.pendingChunks++;
    
  1350.     const symbolId = request.nextChunkId++;
    
  1351.     emitSymbolChunk(request, symbolId, name);
    
  1352.     writtenSymbols.set(value, symbolId);
    
  1353.     return serializeByValueID(symbolId);
    
  1354.   }
    
  1355. 
    
  1356.   if (typeof value === 'bigint') {
    
  1357.     if (enableTaint) {
    
  1358.       const tainted = TaintRegistryValues.get(value);
    
  1359.       if (tainted !== undefined) {
    
  1360.         throwTaintViolation(tainted.message);
    
  1361.       }
    
  1362.     }
    
  1363.     return serializeBigInt(value);
    
  1364.   }
    
  1365. 
    
  1366.   throw new Error(
    
  1367.     `Type ${typeof value} is not supported in Client Component props.` +
    
  1368.       describeObjectForErrorMessage(parent, key),
    
  1369.   );
    
  1370. }
    
  1371. 
    
  1372. function logPostpone(request: Request, reason: string): void {
    
  1373.   const onPostpone = request.onPostpone;
    
  1374.   onPostpone(reason);
    
  1375. }
    
  1376. 
    
  1377. function logRecoverableError(request: Request, error: mixed): string {
    
  1378.   const onError = request.onError;
    
  1379.   const errorDigest = onError(error);
    
  1380.   if (errorDigest != null && typeof errorDigest !== 'string') {
    
  1381.     // eslint-disable-next-line react-internal/prod-error-codes
    
  1382.     throw new Error(
    
  1383.       `onError returned something with a type other than "string". onError should return a string and may return null or undefined but must not return anything else. It received something of type "${typeof errorDigest}" instead`,
    
  1384.     );
    
  1385.   }
    
  1386.   return errorDigest || '';
    
  1387. }
    
  1388. 
    
  1389. function fatalError(request: Request, error: mixed): void {
    
  1390.   if (enableTaint) {
    
  1391.     cleanupTaintQueue(request);
    
  1392.   }
    
  1393.   // This is called outside error handling code such as if an error happens in React internals.
    
  1394.   if (request.destination !== null) {
    
  1395.     request.status = CLOSED;
    
  1396.     closeWithError(request.destination, error);
    
  1397.   } else {
    
  1398.     request.status = CLOSING;
    
  1399.     request.fatalError = error;
    
  1400.   }
    
  1401. }
    
  1402. 
    
  1403. function emitPostponeChunk(
    
  1404.   request: Request,
    
  1405.   id: number,
    
  1406.   postponeInstance: Postpone,
    
  1407. ): void {
    
  1408.   let row;
    
  1409.   if (__DEV__) {
    
  1410.     let reason = '';
    
  1411.     let stack = '';
    
  1412.     try {
    
  1413.       // eslint-disable-next-line react-internal/safe-string-coercion
    
  1414.       reason = String(postponeInstance.message);
    
  1415.       // eslint-disable-next-line react-internal/safe-string-coercion
    
  1416.       stack = String(postponeInstance.stack);
    
  1417.     } catch (x) {}
    
  1418.     row = serializeRowHeader('P', id) + stringify({reason, stack}) + '\n';
    
  1419.   } else {
    
  1420.     // No reason included in prod.
    
  1421.     row = serializeRowHeader('P', id) + '\n';
    
  1422.   }
    
  1423.   const processedChunk = stringToChunk(row);
    
  1424.   request.completedErrorChunks.push(processedChunk);
    
  1425. }
    
  1426. 
    
  1427. function emitErrorChunk(
    
  1428.   request: Request,
    
  1429.   id: number,
    
  1430.   digest: string,
    
  1431.   error: mixed,
    
  1432. ): void {
    
  1433.   let errorInfo: any;
    
  1434.   if (__DEV__) {
    
  1435.     let message;
    
  1436.     let stack = '';
    
  1437.     try {
    
  1438.       if (error instanceof Error) {
    
  1439.         // eslint-disable-next-line react-internal/safe-string-coercion
    
  1440.         message = String(error.message);
    
  1441.         // eslint-disable-next-line react-internal/safe-string-coercion
    
  1442.         stack = String(error.stack);
    
  1443.       } else {
    
  1444.         message = 'Error: ' + (error: any);
    
  1445.       }
    
  1446.     } catch (x) {
    
  1447.       message = 'An error occurred but serializing the error message failed.';
    
  1448.     }
    
  1449.     errorInfo = {digest, message, stack};
    
  1450.   } else {
    
  1451.     errorInfo = {digest};
    
  1452.   }
    
  1453.   const row = serializeRowHeader('E', id) + stringify(errorInfo) + '\n';
    
  1454.   const processedChunk = stringToChunk(row);
    
  1455.   request.completedErrorChunks.push(processedChunk);
    
  1456. }
    
  1457. 
    
  1458. function emitImportChunk(
    
  1459.   request: Request,
    
  1460.   id: number,
    
  1461.   clientReferenceMetadata: ClientReferenceMetadata,
    
  1462. ): void {
    
  1463.   // $FlowFixMe[incompatible-type] stringify can return null
    
  1464.   const json: string = stringify(clientReferenceMetadata);
    
  1465.   const row = serializeRowHeader('I', id) + json + '\n';
    
  1466.   const processedChunk = stringToChunk(row);
    
  1467.   request.completedImportChunks.push(processedChunk);
    
  1468. }
    
  1469. 
    
  1470. function emitHintChunk<Code: HintCode>(
    
  1471.   request: Request,
    
  1472.   code: Code,
    
  1473.   model: HintModel<Code>,
    
  1474. ): void {
    
  1475.   const json: string = stringify(model);
    
  1476.   const id = request.nextChunkId++;
    
  1477.   const row = serializeRowHeader('H' + code, id) + json + '\n';
    
  1478.   const processedChunk = stringToChunk(row);
    
  1479.   request.completedHintChunks.push(processedChunk);
    
  1480. }
    
  1481. 
    
  1482. function emitSymbolChunk(request: Request, id: number, name: string): void {
    
  1483.   const symbolReference = serializeSymbolReference(name);
    
  1484.   const processedChunk = encodeReferenceChunk(request, id, symbolReference);
    
  1485.   request.completedImportChunks.push(processedChunk);
    
  1486. }
    
  1487. 
    
  1488. function emitProviderChunk(
    
  1489.   request: Request,
    
  1490.   id: number,
    
  1491.   contextName: string,
    
  1492. ): void {
    
  1493.   const contextReference = serializeProviderReference(contextName);
    
  1494.   const processedChunk = encodeReferenceChunk(request, id, contextReference);
    
  1495.   request.completedRegularChunks.push(processedChunk);
    
  1496. }
    
  1497. 
    
  1498. function emitModelChunk(
    
  1499.   request: Request,
    
  1500.   id: number,
    
  1501.   model: ReactClientValue,
    
  1502. ): void {
    
  1503.   // Track the root so we know that we have to emit this object even though it
    
  1504.   // already has an ID. This is needed because we might see this object twice
    
  1505.   // in the same toJSON if it is cyclic.
    
  1506.   modelRoot = model;
    
  1507.   // $FlowFixMe[incompatible-type] stringify can return null
    
  1508.   const json: string = stringify(model, request.toJSON);
    
  1509.   const row = id.toString(16) + ':' + json + '\n';
    
  1510.   const processedChunk = stringToChunk(row);
    
  1511.   request.completedRegularChunks.push(processedChunk);
    
  1512. }
    
  1513. 
    
  1514. function retryTask(request: Request, task: Task): void {
    
  1515.   if (task.status !== PENDING) {
    
  1516.     // We completed this by other means before we had a chance to retry it.
    
  1517.     return;
    
  1518.   }
    
  1519. 
    
  1520.   switchContext(task.context);
    
  1521.   try {
    
  1522.     let value = task.model;
    
  1523.     if (
    
  1524.       typeof value === 'object' &&
    
  1525.       value !== null &&
    
  1526.       (value: any).$$typeof === REACT_ELEMENT_TYPE
    
  1527.     ) {
    
  1528.       request.writtenObjects.set(value, task.id);
    
  1529. 
    
  1530.       // TODO: Concatenate keys of parents onto children.
    
  1531.       const element: React$Element<any> = (value: any);
    
  1532. 
    
  1533.       // When retrying a component, reuse the thenableState from the
    
  1534.       // previous attempt.
    
  1535.       const prevThenableState = task.thenableState;
    
  1536. 
    
  1537.       // Attempt to render the Server Component.
    
  1538.       // Doing this here lets us reuse this same task if the next component
    
  1539.       // also suspends.
    
  1540.       task.model = value;
    
  1541.       value = attemptResolveElement(
    
  1542.         request,
    
  1543.         element.type,
    
  1544.         element.key,
    
  1545.         element.ref,
    
  1546.         element.props,
    
  1547.         prevThenableState,
    
  1548.       );
    
  1549. 
    
  1550.       // Successfully finished this component. We're going to keep rendering
    
  1551.       // using the same task, but we reset its thenable state before continuing.
    
  1552.       task.thenableState = null;
    
  1553. 
    
  1554.       // Keep rendering and reuse the same task. This inner loop is separate
    
  1555.       // from the render above because we don't need to reset the thenable state
    
  1556.       // until the next time something suspends and retries.
    
  1557.       while (
    
  1558.         typeof value === 'object' &&
    
  1559.         value !== null &&
    
  1560.         (value: any).$$typeof === REACT_ELEMENT_TYPE
    
  1561.       ) {
    
  1562.         request.writtenObjects.set(value, task.id);
    
  1563.         // TODO: Concatenate keys of parents onto children.
    
  1564.         const nextElement: React$Element<any> = (value: any);
    
  1565.         task.model = value;
    
  1566.         value = attemptResolveElement(
    
  1567.           request,
    
  1568.           nextElement.type,
    
  1569.           nextElement.key,
    
  1570.           nextElement.ref,
    
  1571.           nextElement.props,
    
  1572.           null,
    
  1573.         );
    
  1574.       }
    
  1575.     }
    
  1576. 
    
  1577.     // Track that this object is outlined and has an id.
    
  1578.     if (typeof value === 'object' && value !== null) {
    
  1579.       request.writtenObjects.set(value, task.id);
    
  1580.     }
    
  1581. 
    
  1582.     emitModelChunk(request, task.id, value);
    
  1583.     request.abortableTasks.delete(task);
    
  1584.     task.status = COMPLETED;
    
  1585.   } catch (thrownValue) {
    
  1586.     const x =
    
  1587.       thrownValue === SuspenseException
    
  1588.         ? // This is a special type of exception used for Suspense. For historical
    
  1589.           // reasons, the rest of the Suspense implementation expects the thrown
    
  1590.           // value to be a thenable, because before `use` existed that was the
    
  1591.           // (unstable) API for suspending. This implementation detail can change
    
  1592.           // later, once we deprecate the old API in favor of `use`.
    
  1593.           getSuspendedThenable()
    
  1594.         : thrownValue;
    
  1595.     if (typeof x === 'object' && x !== null) {
    
  1596.       // $FlowFixMe[method-unbinding]
    
  1597.       if (typeof x.then === 'function') {
    
  1598.         // Something suspended again, let's pick it back up later.
    
  1599.         const ping = task.ping;
    
  1600.         x.then(ping, ping);
    
  1601.         task.thenableState = getThenableStateAfterSuspending();
    
  1602.         return;
    
  1603.       } else if (enablePostpone && x.$$typeof === REACT_POSTPONE_TYPE) {
    
  1604.         request.abortableTasks.delete(task);
    
  1605.         task.status = ERRORED;
    
  1606.         const postponeInstance: Postpone = (x: any);
    
  1607.         logPostpone(request, postponeInstance.message);
    
  1608.         emitPostponeChunk(request, task.id, postponeInstance);
    
  1609.         return;
    
  1610.       }
    
  1611.     }
    
  1612.     request.abortableTasks.delete(task);
    
  1613.     task.status = ERRORED;
    
  1614.     const digest = logRecoverableError(request, x);
    
  1615.     emitErrorChunk(request, task.id, digest, x);
    
  1616.   }
    
  1617. }
    
  1618. 
    
  1619. function performWork(request: Request): void {
    
  1620.   const prevDispatcher = ReactCurrentDispatcher.current;
    
  1621.   ReactCurrentDispatcher.current = HooksDispatcher;
    
  1622.   const prevRequest = currentRequest;
    
  1623.   currentRequest = request;
    
  1624.   prepareToUseHooksForRequest(request);
    
  1625. 
    
  1626.   try {
    
  1627.     const pingedTasks = request.pingedTasks;
    
  1628.     request.pingedTasks = [];
    
  1629.     for (let i = 0; i < pingedTasks.length; i++) {
    
  1630.       const task = pingedTasks[i];
    
  1631.       retryTask(request, task);
    
  1632.     }
    
  1633.     if (request.destination !== null) {
    
  1634.       flushCompletedChunks(request, request.destination);
    
  1635.     }
    
  1636.   } catch (error) {
    
  1637.     logRecoverableError(request, error);
    
  1638.     fatalError(request, error);
    
  1639.   } finally {
    
  1640.     ReactCurrentDispatcher.current = prevDispatcher;
    
  1641.     resetHooksForRequest();
    
  1642.     currentRequest = prevRequest;
    
  1643.   }
    
  1644. }
    
  1645. 
    
  1646. function abortTask(task: Task, request: Request, errorId: number): void {
    
  1647.   task.status = ABORTED;
    
  1648.   // Instead of emitting an error per task.id, we emit a model that only
    
  1649.   // has a single value referencing the error.
    
  1650.   const ref = serializeByValueID(errorId);
    
  1651.   const processedChunk = encodeReferenceChunk(request, task.id, ref);
    
  1652.   request.completedErrorChunks.push(processedChunk);
    
  1653. }
    
  1654. 
    
  1655. function flushCompletedChunks(
    
  1656.   request: Request,
    
  1657.   destination: Destination,
    
  1658. ): void {
    
  1659.   beginWriting(destination);
    
  1660.   try {
    
  1661.     // We emit module chunks first in the stream so that
    
  1662.     // they can be preloaded as early as possible.
    
  1663.     const importsChunks = request.completedImportChunks;
    
  1664.     let i = 0;
    
  1665.     for (; i < importsChunks.length; i++) {
    
  1666.       request.pendingChunks--;
    
  1667.       const chunk = importsChunks[i];
    
  1668.       const keepWriting: boolean = writeChunkAndReturn(destination, chunk);
    
  1669.       if (!keepWriting) {
    
  1670.         request.destination = null;
    
  1671.         i++;
    
  1672.         break;
    
  1673.       }
    
  1674.     }
    
  1675.     importsChunks.splice(0, i);
    
  1676. 
    
  1677.     // Next comes hints.
    
  1678.     const hintChunks = request.completedHintChunks;
    
  1679.     i = 0;
    
  1680.     for (; i < hintChunks.length; i++) {
    
  1681.       const chunk = hintChunks[i];
    
  1682.       const keepWriting: boolean = writeChunkAndReturn(destination, chunk);
    
  1683.       if (!keepWriting) {
    
  1684.         request.destination = null;
    
  1685.         i++;
    
  1686.         break;
    
  1687.       }
    
  1688.     }
    
  1689.     hintChunks.splice(0, i);
    
  1690. 
    
  1691.     // Next comes model data.
    
  1692.     const regularChunks = request.completedRegularChunks;
    
  1693.     i = 0;
    
  1694.     for (; i < regularChunks.length; i++) {
    
  1695.       request.pendingChunks--;
    
  1696.       const chunk = regularChunks[i];
    
  1697.       const keepWriting: boolean = writeChunkAndReturn(destination, chunk);
    
  1698.       if (!keepWriting) {
    
  1699.         request.destination = null;
    
  1700.         i++;
    
  1701.         break;
    
  1702.       }
    
  1703.     }
    
  1704.     regularChunks.splice(0, i);
    
  1705. 
    
  1706.     // Finally, errors are sent. The idea is that it's ok to delay
    
  1707.     // any error messages and prioritize display of other parts of
    
  1708.     // the page.
    
  1709.     const errorChunks = request.completedErrorChunks;
    
  1710.     i = 0;
    
  1711.     for (; i < errorChunks.length; i++) {
    
  1712.       request.pendingChunks--;
    
  1713.       const chunk = errorChunks[i];
    
  1714.       const keepWriting: boolean = writeChunkAndReturn(destination, chunk);
    
  1715.       if (!keepWriting) {
    
  1716.         request.destination = null;
    
  1717.         i++;
    
  1718.         break;
    
  1719.       }
    
  1720.     }
    
  1721.     errorChunks.splice(0, i);
    
  1722.   } finally {
    
  1723.     request.flushScheduled = false;
    
  1724.     completeWriting(destination);
    
  1725.   }
    
  1726.   flushBuffered(destination);
    
  1727.   if (request.pendingChunks === 0) {
    
  1728.     // We're done.
    
  1729.     if (enableTaint) {
    
  1730.       cleanupTaintQueue(request);
    
  1731.     }
    
  1732.     close(destination);
    
  1733.   }
    
  1734. }
    
  1735. 
    
  1736. export function startWork(request: Request): void {
    
  1737.   request.flushScheduled = request.destination !== null;
    
  1738.   if (supportsRequestStorage) {
    
  1739.     scheduleWork(() => requestStorage.run(request, performWork, request));
    
  1740.   } else {
    
  1741.     scheduleWork(() => performWork(request));
    
  1742.   }
    
  1743. }
    
  1744. 
    
  1745. function enqueueFlush(request: Request): void {
    
  1746.   if (
    
  1747.     request.flushScheduled === false &&
    
  1748.     // If there are pinged tasks we are going to flush anyway after work completes
    
  1749.     request.pingedTasks.length === 0 &&
    
  1750.     // If there is no destination there is nothing we can flush to. A flush will
    
  1751.     // happen when we start flowing again
    
  1752.     request.destination !== null
    
  1753.   ) {
    
  1754.     const destination = request.destination;
    
  1755.     request.flushScheduled = true;
    
  1756.     scheduleWork(() => flushCompletedChunks(request, destination));
    
  1757.   }
    
  1758. }
    
  1759. 
    
  1760. export function startFlowing(request: Request, destination: Destination): void {
    
  1761.   if (request.status === CLOSING) {
    
  1762.     request.status = CLOSED;
    
  1763.     closeWithError(destination, request.fatalError);
    
  1764.     return;
    
  1765.   }
    
  1766.   if (request.status === CLOSED) {
    
  1767.     return;
    
  1768.   }
    
  1769.   if (request.destination !== null) {
    
  1770.     // We're already flowing.
    
  1771.     return;
    
  1772.   }
    
  1773.   request.destination = destination;
    
  1774.   try {
    
  1775.     flushCompletedChunks(request, destination);
    
  1776.   } catch (error) {
    
  1777.     logRecoverableError(request, error);
    
  1778.     fatalError(request, error);
    
  1779.   }
    
  1780. }
    
  1781. 
    
  1782. export function stopFlowing(request: Request): void {
    
  1783.   request.destination = null;
    
  1784. }
    
  1785. 
    
  1786. // This is called to early terminate a request. It creates an error at all pending tasks.
    
  1787. export function abort(request: Request, reason: mixed): void {
    
  1788.   try {
    
  1789.     const abortableTasks = request.abortableTasks;
    
  1790.     if (abortableTasks.size > 0) {
    
  1791.       // We have tasks to abort. We'll emit one error row and then emit a reference
    
  1792.       // to that row from every row that's still remaining.
    
  1793.       request.pendingChunks++;
    
  1794.       const errorId = request.nextChunkId++;
    
  1795.       if (
    
  1796.         enablePostpone &&
    
  1797.         typeof reason === 'object' &&
    
  1798.         reason !== null &&
    
  1799.         (reason: any).$$typeof === REACT_POSTPONE_TYPE
    
  1800.       ) {
    
  1801.         const postponeInstance: Postpone = (reason: any);
    
  1802.         logPostpone(request, postponeInstance.message);
    
  1803.         emitPostponeChunk(request, errorId, postponeInstance);
    
  1804.       } else {
    
  1805.         const error =
    
  1806.           reason === undefined
    
  1807.             ? new Error(
    
  1808.                 'The render was aborted by the server without a reason.',
    
  1809.               )
    
  1810.             : reason;
    
  1811.         const digest = logRecoverableError(request, error);
    
  1812.         emitErrorChunk(request, errorId, digest, error);
    
  1813.       }
    
  1814.       abortableTasks.forEach(task => abortTask(task, request, errorId));
    
  1815.       abortableTasks.clear();
    
  1816.     }
    
  1817.     if (request.destination !== null) {
    
  1818.       flushCompletedChunks(request, request.destination);
    
  1819.     }
    
  1820.   } catch (error) {
    
  1821.     logRecoverableError(request, error);
    
  1822.     fatalError(request, error);
    
  1823.   }
    
  1824. }
    
  1825. 
    
  1826. function importServerContexts(
    
  1827.   contexts?: Array<[string, ServerContextJSONValue]>,
    
  1828. ) {
    
  1829.   if (enableServerContext && contexts) {
    
  1830.     const prevContext = getActiveContext();
    
  1831.     switchContext(rootContextSnapshot);
    
  1832.     for (let i = 0; i < contexts.length; i++) {
    
  1833.       const [name, value] = contexts[i];
    
  1834.       const context = getOrCreateServerContext(name);
    
  1835.       pushProvider(context, value);
    
  1836.     }
    
  1837.     const importedContext = getActiveContext();
    
  1838.     switchContext(prevContext);
    
  1839.     return importedContext;
    
  1840.   }
    
  1841.   return rootContextSnapshot;
    
  1842. }