packages/react-client/src/ReactFlightClient.js JAVASCRIPT 5,435 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 5,435.
1/**2 * Copyright (c) Meta Platforms, Inc. and affiliates.3 *4 * This source code is licensed under the MIT license found in the5 * LICENSE file in the root directory of this source tree.6 *7 * @flow8 */910import type {11  JSONValue,12  Thenable,13  ReactDebugInfo,14  ReactDebugInfoEntry,15  ReactComponentInfo,16  ReactAsyncInfo,17  ReactIOInfo,18  ReactStackTrace,19  ReactFunctionLocation,20  ReactErrorInfoDev,21} from 'shared/ReactTypes';22import type {LazyComponent} from 'react/src/ReactLazy';2324import type {25  ClientReference,26  ClientReferenceMetadata,27  ServerConsumerModuleMap,28  ServerManifest,29  StringDecoder,30  ModuleLoading,31} from './ReactFlightClientConfig';3233import type {34  HintCode,35  HintModel,36} from 'react-server/src/ReactFlightServerConfig';3738import type {39  CallServerCallback,40  EncodeFormActionCallback,41} from './ReactFlightReplyClient';4243import type {TemporaryReferenceSet} from './ReactFlightTemporaryReferences';4445import {46  enableProfilerTimer,47  enableComponentPerformanceTrack,48  enableAsyncDebugInfo,49} from 'shared/ReactFeatureFlags';5051import {52  resolveClientReference,53  resolveServerReference,54  preloadModule,55  requireModule,56  getModuleDebugInfo,57  dispatchHint,58  readPartialStringChunk,59  readFinalStringChunk,60  createStringDecoder,61  prepareDestinationForModule,62  bindToConsole,63  rendererVersion,64  rendererPackageName,65  checkEvalAvailabilityOnceDev,66} from './ReactFlightClientConfig';6768import {69  createBoundServerReference,70  registerBoundServerReference,71} from './ReactFlightReplyClient';7273import {readTemporaryReference} from './ReactFlightTemporaryReferences';7475import {76  markAllTracksInOrder,77  logComponentRender,78  logDedupedComponentRender,79  logComponentAborted,80  logComponentErrored,81  logIOInfo,82  logIOInfoErrored,83  logComponentAwait,84  logComponentAwaitAborted,85  logComponentAwaitErrored,86} from './ReactFlightPerformanceTrack';8788import {89  REACT_LAZY_TYPE,90  REACT_ELEMENT_TYPE,91  ASYNC_ITERATOR,92  REACT_FRAGMENT_TYPE,93} from 'shared/ReactSymbols';9495import getComponentNameFromType from 'shared/getComponentNameFromType';9697import {getOwnerStackByComponentInfoInDev} from 'shared/ReactComponentInfoStack';9899import hasOwnProperty from 'shared/hasOwnProperty';100101import {injectInternals} from './ReactFlightClientDevToolsHook';102103import {OMITTED_PROP_ERROR} from 'shared/ReactFlightPropertyAccess';104105import ReactVersion from 'shared/ReactVersion';106107import isArray from 'shared/isArray';108109import * as React from 'react';110111import type {SharedStateServer} from 'react/src/ReactSharedInternalsServer';112import type {SharedStateClient} from 'react/src/ReactSharedInternalsClient';113114// TODO: This is an unfortunate hack. We shouldn't feature detect the internals115// like this. It's just that for now we support the same build of the Flight116// client both in the RSC environment, in the SSR environments as well as the117// browser client. We should probably have a separate RSC build. This is DEV118// only though.119const ReactSharedInteralsServer: void | SharedStateServer = (React as any)120  .__SERVER_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;121const ReactSharedInternals: SharedStateServer | SharedStateClient =122  React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE ||123  ReactSharedInteralsServer;124125export type {CallServerCallback, EncodeFormActionCallback};126127interface FlightStreamController {128  enqueueValue(value: any): void;129  enqueueModel(json: UninitializedModel): void;130  close(json: UninitializedModel): void;131  error(error: Error): void;132}133134type UninitializedModel = string;135136type ProfilingResult = {137  track: number,138  endTime: number,139  component: null | ReactComponentInfo,140};141142const ROW_ID = 0;143const ROW_TAG = 1;144const ROW_LENGTH = 2;145const ROW_CHUNK_BY_NEWLINE = 3;146const ROW_CHUNK_BY_LENGTH = 4;147148type RowParserState = 0 | 1 | 2 | 3 | 4;149150const PENDING = 'pending';151const BLOCKED = 'blocked';152const RESOLVED_MODEL = 'resolved_model';153const RESOLVED_MODULE = 'resolved_module';154const INITIALIZED = 'fulfilled';155const ERRORED = 'rejected';156const HALTED = 'halted'; // DEV-only. Means it never resolves even if connection closes.157158const __PROTO__ = '__proto__';159160type PendingChunk<T> = {161  status: 'pending',162  value: null | Array<InitializationReference | (T => mixed)>,163  reason: null | Array<InitializationReference | (mixed => mixed)>,164  _children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only165  _debugChunk: null | SomeChunk<ReactDebugInfoEntry>, // DEV-only166  _debugInfo: ReactDebugInfo, // DEV-only167  then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,168};169type BlockedChunk<T> = {170  status: 'blocked',171  value: null | Array<InitializationReference | (T => mixed)>,172  reason: null | Array<InitializationReference | (mixed => mixed)>,173  _children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only174  _debugChunk: null, // DEV-only175  _debugInfo: ReactDebugInfo, // DEV-only176  then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,177};178type ResolvedModelChunk<T> = {179  status: 'resolved_model',180  value: UninitializedModel,181  reason: Response,182  _children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only183  _debugChunk: null | SomeChunk<ReactDebugInfoEntry>, // DEV-only184  _debugInfo: ReactDebugInfo, // DEV-only185  then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,186};187type ResolvedModuleChunk<T> = {188  status: 'resolved_module',189  value: ClientReference<T>,190  reason: null,191  _children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only192  _debugChunk: null, // DEV-only193  _debugInfo: ReactDebugInfo, // DEV-only194  then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,195};196type InitializedChunk<T> = {197  status: 'fulfilled',198  value: T,199  reason: null | FlightStreamController,200  _children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only201  _debugChunk: null, // DEV-only202  _debugInfo: ReactDebugInfo, // DEV-only203  then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,204};205type InitializedStreamChunk<206  T: ReadableStream | $AsyncIterable<any, any, void>,207> = {208  status: 'fulfilled',209  value: T,210  reason: FlightStreamController,211  _children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only212  _debugChunk: null, // DEV-only213  _debugInfo: ReactDebugInfo, // DEV-only214  then(resolve: (ReadableStream) => mixed, reject?: (mixed) => mixed): void,215};216type ErroredChunk<T> = {217  status: 'rejected',218  value: null,219  reason: mixed,220  _children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only221  _debugChunk: null, // DEV-only222  _debugInfo: ReactDebugInfo, // DEV-only223  then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,224};225type HaltedChunk<T> = {226  status: 'halted',227  value: null,228  reason: null,229  _children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only230  _debugChunk: null, // DEV-only231  _debugInfo: ReactDebugInfo, // DEV-only232  then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,233};234type SomeChunk<T> =235  | PendingChunk<T>236  | BlockedChunk<T>237  | ResolvedModelChunk<T>238  | ResolvedModuleChunk<T>239  | InitializedChunk<T>240  | ErroredChunk<T>241  | HaltedChunk<T>;242243// $FlowFixMe[missing-this-annot]244function ReactPromise(status: any, value: any, reason: any) {245  this.status = status;246  this.value = value;247  this.reason = reason;248  if (enableProfilerTimer && enableComponentPerformanceTrack) {249    this._children = [];250  }251  if (__DEV__) {252    this._debugChunk = null;253    this._debugInfo = [];254  }255}256// We subclass Promise.prototype so that we get other methods like .catch257ReactPromise.prototype = Object.create(Promise.prototype) as any;258// TODO: This doesn't return a new Promise chain unlike the real .then259ReactPromise.prototype.then = function <T>(260  this: SomeChunk<T>,261  resolve: (value: T) => mixed,262  reject?: (reason: mixed) => mixed,263) {264  const chunk: SomeChunk<T> = this;265  // If we have resolved content, we try to initialize it first which266  // might put us back into one of the other states.267  switch (chunk.status) {268    case RESOLVED_MODEL:269      initializeModelChunk(chunk);270      break;271    case RESOLVED_MODULE:272      initializeModuleChunk(chunk);273      break;274  }275  if (__DEV__ && enableAsyncDebugInfo) {276    // Because only native Promises get picked up when we're awaiting we need to wrap277    // this in a native Promise in DEV. This means that these callbacks are no longer sync278    // but the lazy initialization is still sync and the .value can be inspected after,279    // allowing it to be read synchronously anyway.280    const resolveCallback = resolve;281    const rejectCallback = reject;282    const wrapperPromise: Promise<T> = new Promise((res, rej) => {283      resolve = value => {284        // $FlowFixMe[prop-missing]285        wrapperPromise._debugInfo = this._debugInfo;286        res(value);287      };288      reject = reason => {289        // $FlowFixMe[prop-missing]290        wrapperPromise._debugInfo = this._debugInfo;291        rej(reason);292      };293    });294    wrapperPromise.then(resolveCallback, rejectCallback);295  }296  // The status might have changed after initialization.297  switch (chunk.status) {298    case INITIALIZED:299      if (typeof resolve === 'function') {300        resolve(chunk.value);301      }302      break;303    case PENDING:304    case BLOCKED:305      if (typeof resolve === 'function') {306        if (chunk.value === null) {307          chunk.value = [] as Array<InitializationReference | (T => mixed)>;308        }309        chunk.value.push(resolve);310      }311      if (typeof reject === 'function') {312        if (chunk.reason === null) {313          chunk.reason = [] as Array<314            InitializationReference | (mixed => mixed),315          >;316        }317        chunk.reason.push(reject);318      }319      break;320    case HALTED: {321      break;322    }323    default:324      if (typeof reject === 'function') {325        reject(chunk.reason);326      }327      break;328  }329};330331export type FindSourceMapURLCallback = (332  fileName: string,333  environmentName: string,334) => null | string;335336export type DebugChannelCallback = (message: string) => void;337338export type DebugChannel = {339  hasReadable: boolean,340  callback: DebugChannelCallback | null,341};342343type Response = {344  _bundlerConfig: ServerConsumerModuleMap,345  _serverReferenceConfig: null | ServerManifest,346  _moduleLoading: ModuleLoading,347  _callServer: CallServerCallback,348  _encodeFormAction: void | EncodeFormActionCallback,349  _nonce: ?string,350  _chunks: Map<number, SomeChunk<any>>,351  _stringDecoder: StringDecoder,352  _closed: boolean,353  _closedReason: mixed,354  _allowPartialStream: boolean,355  _tempRefs: void | TemporaryReferenceSet, // the set temporary references can be resolved from356  _timeOrigin: number, // Profiling-only357  _pendingInitialRender: null | TimeoutID, // Profiling-only,358  _pendingChunks: number, // DEV-only359  _weakResponse: WeakResponse, // DEV-only360  _debugRootOwner?: null | ReactComponentInfo, // DEV-only361  _debugRootStack?: null | Error, // DEV-only362  _debugRootTask?: null | ConsoleTask, // DEV-only363  _debugStartTime: number, // DEV-only364  _debugEndTime: null | number, // DEV-only365  _debugIOStarted: boolean, // DEV-only366  _debugFindSourceMapURL?: void | FindSourceMapURLCallback, // DEV-only367  _debugChannel?: void | DebugChannel, // DEV-only368  _blockedConsole?: null | SomeChunk<ConsoleEntry>, // DEV-only369  _replayConsole: boolean, // DEV-only370  _rootEnvironmentName: string, // DEV-only, the requested environment name.371};372373// This indirection exists only to clean up DebugChannel when all Lazy References are GC:ed.374// Therefore we only use the indirection in DEV.375type WeakResponse = {376  weak: WeakRef<Response>,377  response: null | Response, // This is null when there are no pending chunks.378};379380export type {WeakResponse as Response};381382function hasGCedResponse(weakResponse: WeakResponse): boolean {383  return __DEV__ && weakResponse.weak.deref() === undefined;384}385386function unwrapWeakResponse(weakResponse: WeakResponse): Response {387  if (__DEV__) {388    const response = weakResponse.weak.deref();389    if (response === undefined) {390      // eslint-disable-next-line react-internal/prod-error-codes391      throw new Error(392        'We did not expect to receive new data after GC:ing the response.',393      );394    }395    return response;396  } else {397    return weakResponse as any; // In prod we just use the real Response directly.398  }399}400401function getWeakResponse(response: Response): WeakResponse {402  if (__DEV__) {403    return response._weakResponse;404  } else {405    return response as any; // In prod we just use the real Response directly.406  }407}408409function closeDebugChannel(debugChannel: DebugChannel): void {410  if (debugChannel.callback) {411    debugChannel.callback('');412  }413}414415// If FinalizationRegistry doesn't exist, we cannot use the debugChannel.416const debugChannelRegistry =417  __DEV__ && typeof FinalizationRegistry === 'function'418    ? new FinalizationRegistry(closeDebugChannel)419    : null;420421function readChunk<T>(chunk: SomeChunk<T>): T {422  // If we have resolved content, we try to initialize it first which423  // might put us back into one of the other states.424  switch (chunk.status) {425    case RESOLVED_MODEL:426      initializeModelChunk(chunk);427      break;428    case RESOLVED_MODULE:429      initializeModuleChunk(chunk);430      break;431  }432  // The status might have changed after initialization.433  switch (chunk.status) {434    case INITIALIZED:435      return chunk.value;436    case PENDING:437    case BLOCKED:438    case HALTED:439      // eslint-disable-next-line no-throw-literal440      throw chunk as any as Thenable<T>;441    default:442      throw chunk.reason;443  }444}445446export function getRoot<T>(weakResponse: WeakResponse): Thenable<T> {447  const response = unwrapWeakResponse(weakResponse);448  const chunk = getChunk(response, 0);449  return chunk as any;450}451452function createPendingChunk<T>(response: Response): PendingChunk<T> {453  if (__DEV__) {454    // Retain a strong reference to the Response while we wait for the result.455    if (response._pendingChunks++ === 0) {456      response._weakResponse.response = response;457      if (response._pendingInitialRender !== null) {458        clearTimeout(response._pendingInitialRender);459        response._pendingInitialRender = null;460      }461    }462  }463  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors464  return new ReactPromise(PENDING, null, null);465}466467function releasePendingChunk(response: Response, chunk: SomeChunk<any>): void {468  if (__DEV__ && chunk.status === PENDING) {469    if (--response._pendingChunks === 0) {470      // We're no longer waiting for any more chunks. We can release the strong reference471      // to the response. We'll regain it if we ask for any more data later on.472      response._weakResponse.response = null;473      // Wait a short period to see if any more chunks get asked for. E.g. by a React render.474      // These chunks might discover more pending chunks.475      // If we don't ask for more then we assume that those chunks weren't blocking initial476      // render and are excluded from the performance track.477      response._pendingInitialRender = setTimeout(478        flushInitialRenderPerformance.bind(null, response),479        100,480      );481    }482  }483}484485function createBlockedChunk<T>(response: Response): BlockedChunk<T> {486  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors487  return new ReactPromise(BLOCKED, null, null);488}489490function createErrorChunk<T>(491  response: Response,492  error: mixed,493): ErroredChunk<T> {494  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors495  return new ReactPromise(ERRORED, null, error);496}497498function filterDebugInfo(499  response: Response,500  value: {_debugInfo: ReactDebugInfo, ...},501) {502  if (response._debugEndTime === null) {503    // No end time was defined, so we keep all debug info entries.504    return;505  }506507  // Remove any debug info entries after the defined end time. For async info508  // that means we're including anything that was awaited before the end time,509  // but it doesn't need to be resolved before the end time.510  const relativeEndTime =511    response._debugEndTime -512    // $FlowFixMe[prop-missing]513    performance.timeOrigin;514  const debugInfo = [];515  for (let i = 0; i < value._debugInfo.length; i++) {516    const info = value._debugInfo[i];517    if (typeof info.time === 'number' && info.time > relativeEndTime) {518      break;519    }520    debugInfo.push(info);521  }522  value._debugInfo = debugInfo;523}524525function pruneDebugInfoAfterError(526  response: Response,527  chunk: ErroredChunk<any>,528): void {529  if (response._debugEndTime === null) {530    return;531  }532533  const relativeEndTime =534    response._debugEndTime -535    // $FlowFixMe[prop-missing]536    performance.timeOrigin;537  const debugInfo = chunk._debugInfo;538  for (let i = 0; i < debugInfo.length; i++) {539    const info = debugInfo[i];540    if (typeof info.time === 'number' && info.time > relativeEndTime) {541      // This array may already be attached to the Lazy suspended in Fizz.542      debugInfo.length = i;543      return;544    }545  }546}547548function moveDebugInfoFromChunkToInnerValue<T>(549  chunk: InitializedChunk<T> | InitializedStreamChunk<any>,550  value: T,551): void {552  // Remove the debug info from the initialized chunk, and add it to the inner553  // value instead. This can be a React element, an array, or an uninitialized554  // Lazy.555  const resolvedValue = resolveLazy(value);556  if (557    typeof resolvedValue === 'object' &&558    resolvedValue !== null &&559    (isArray(resolvedValue) ||560      typeof resolvedValue[ASYNC_ITERATOR] === 'function' ||561      resolvedValue.$$typeof === REACT_ELEMENT_TYPE ||562      resolvedValue.$$typeof === REACT_LAZY_TYPE)563  ) {564    const debugInfo = chunk._debugInfo.splice(0);565    if (isArray(resolvedValue._debugInfo)) {566      // $FlowFixMe[method-unbinding]567      resolvedValue._debugInfo.unshift.apply(568        resolvedValue._debugInfo,569        debugInfo,570      );571    } else if (!Object.isFrozen(resolvedValue)) {572      Object.defineProperty(resolvedValue as any, '_debugInfo', {573        configurable: false,574        enumerable: false,575        writable: true,576        value: debugInfo,577      });578    }579    // TODO: If the resolved value is a frozen element (e.g. a client-created580    // element from a temporary reference, or a JSX element exported as a client581    // reference), server debug info is currently dropped because the element582    // can't be mutated. We should probably clone the element so each rendering583    // context gets its own mutable copy with the correct debug info.584  }585}586587function processChunkDebugInfo<T>(588  response: Response,589  chunk: InitializedChunk<T> | InitializedStreamChunk<any>,590  value: T,591): void {592  filterDebugInfo(response, chunk);593  moveDebugInfoFromChunkToInnerValue(chunk, value);594}595596function wakeChunk<T>(597  response: Response,598  listeners: Array<InitializationReference | (T => mixed)>,599  value: T,600  chunk: InitializedChunk<T>,601): void {602  for (let i = 0; i < listeners.length; i++) {603    const listener = listeners[i];604    if (typeof listener === 'function') {605      listener(value);606    } else {607      fulfillReference(response, listener, value, chunk);608    }609  }610611  if (__DEV__) {612    processChunkDebugInfo(response, chunk, value);613  }614}615616function rejectChunk(617  response: Response,618  listeners: Array<InitializationReference | (mixed => mixed)>,619  error: mixed,620): void {621  for (let i = 0; i < listeners.length; i++) {622    const listener = listeners[i];623    if (typeof listener === 'function') {624      listener(error);625    } else {626      rejectReference(response, listener.handler, error);627    }628  }629}630631function resolveBlockedCycle<T>(632  resolvedChunk: SomeChunk<T>,633  reference: InitializationReference,634): null | InitializationHandler {635  const referencedChunk = reference.handler.chunk;636  if (referencedChunk === null) {637    return null;638  }639  if (referencedChunk === resolvedChunk) {640    // We found the cycle. We can resolve the blocked cycle now.641    return reference.handler;642  }643  const resolveListeners = referencedChunk.value;644  if (resolveListeners !== null) {645    for (let i = 0; i < resolveListeners.length; i++) {646      const listener = resolveListeners[i];647      if (typeof listener !== 'function') {648        const foundHandler = resolveBlockedCycle(resolvedChunk, listener);649        if (foundHandler !== null) {650          return foundHandler;651        }652      }653    }654  }655  return null;656}657658function wakeChunkIfInitialized<T>(659  response: Response,660  chunk: SomeChunk<T>,661  resolveListeners: Array<InitializationReference | (T => mixed)>,662  rejectListeners: null | Array<InitializationReference | (mixed => mixed)>,663): void {664  switch (chunk.status) {665    case INITIALIZED:666      wakeChunk(response, resolveListeners, chunk.value, chunk);667      break;668    case BLOCKED:669      // It is possible that we're blocked on our own chunk if it's a cycle.670      // Before adding back the listeners to the chunk, let's check if it would671      // result in a cycle.672      for (let i = 0; i < resolveListeners.length; i++) {673        const listener = resolveListeners[i];674        if (typeof listener !== 'function') {675          const reference: InitializationReference = listener;676          const cyclicHandler = resolveBlockedCycle(chunk, reference);677          if (cyclicHandler !== null) {678            // This reference points back to this chunk. We can resolve the cycle by679            // using the value from that handler.680            fulfillReference(response, reference, cyclicHandler.value, chunk);681            resolveListeners.splice(i, 1);682            i--;683            if (rejectListeners !== null) {684              const rejectionIdx = rejectListeners.indexOf(reference);685              if (rejectionIdx !== -1) {686                rejectListeners.splice(rejectionIdx, 1);687              }688            }689            // The status might have changed after fulfilling the reference.690            switch ((chunk as SomeChunk<T>).status) {691              case INITIALIZED:692                const initializedChunk: InitializedChunk<T> = chunk as any;693                wakeChunk(694                  response,695                  resolveListeners,696                  initializedChunk.value,697                  initializedChunk,698                );699                return;700              case ERRORED:701                if (rejectListeners !== null) {702                  rejectChunk(response, rejectListeners, chunk.reason);703                }704                return;705            }706          }707        }708      }709    // Fallthrough710    case PENDING:711      if (chunk.value) {712        for (let i = 0; i < resolveListeners.length; i++) {713          chunk.value.push(resolveListeners[i]);714        }715      } else {716        chunk.value = resolveListeners;717      }718719      if (chunk.reason) {720        if (rejectListeners) {721          for (let i = 0; i < rejectListeners.length; i++) {722            chunk.reason.push(rejectListeners[i]);723          }724        }725      } else {726        chunk.reason = rejectListeners;727      }728729      break;730    case ERRORED:731      if (rejectListeners) {732        rejectChunk(response, rejectListeners, chunk.reason);733      }734      break;735  }736}737738function triggerErrorOnChunk<T>(739  response: Response,740  chunk: SomeChunk<T>,741  error: mixed,742): void {743  if (chunk.status !== PENDING && chunk.status !== BLOCKED) {744    // If we get more data to an already resolved ID, we assume that it's745    // a stream chunk since any other row shouldn't have more than one entry.746    const streamChunk: InitializedStreamChunk<any> = chunk as any;747    const controller = streamChunk.reason;748    // $FlowFixMe[incompatible-type]: The error method should accept mixed.749    controller.error(error);750    return;751  }752  releasePendingChunk(response, chunk);753  const listeners = chunk.reason;754755  if (__DEV__ && chunk.status === PENDING) {756    // Lazily initialize any debug info and block the initializing chunk on any unresolved entries.757    if (chunk._debugChunk != null) {758      const prevHandler = initializingHandler;759      const prevChunk = initializingChunk;760      initializingHandler = null;761      const cyclicChunk: BlockedChunk<T> = chunk as any;762      cyclicChunk.status = BLOCKED;763      cyclicChunk.value = null;764      cyclicChunk.reason = null;765      if ((enableProfilerTimer && enableComponentPerformanceTrack) || __DEV__) {766        initializingChunk = cyclicChunk;767      }768      try {769        initializeDebugChunk(response, chunk);770        if (initializingHandler !== null) {771          if (initializingHandler.errored) {772            // Ignore error parsing debug info, we'll report the original error instead.773          } else if (initializingHandler.deps > 0) {774            // TODO: Block the resolution of the error until all the debug info has loaded.775            // We currently don't have a way to throw an error after all dependencies have776            // loaded because we currently treat errors as immediately cancelling the handler.777          }778        }779      } finally {780        initializingHandler = prevHandler;781        initializingChunk = prevChunk;782      }783    }784  }785786  const erroredChunk: ErroredChunk<T> = chunk as any;787  erroredChunk.status = ERRORED;788  erroredChunk.reason = error;789  if (__DEV__) {790    pruneDebugInfoAfterError(response, erroredChunk);791  }792  if (listeners !== null) {793    rejectChunk(response, listeners, error);794  }795}796797function createResolvedModelChunk<T>(798  response: Response,799  value: UninitializedModel,800): ResolvedModelChunk<T> {801  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors802  return new ReactPromise(RESOLVED_MODEL, value, response);803}804805function createResolvedModuleChunk<T>(806  response: Response,807  value: ClientReference<T>,808): ResolvedModuleChunk<T> {809  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors810  return new ReactPromise(RESOLVED_MODULE, value, null);811}812813function createInitializedTextChunk(814  response: Response,815  value: string,816): InitializedChunk<string> {817  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors818  return new ReactPromise(INITIALIZED, value, null);819}820821function createInitializedBufferChunk(822  response: Response,823  value: $ArrayBufferView | ArrayBuffer,824): InitializedChunk<Uint8Array> {825  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors826  return new ReactPromise(INITIALIZED, value, null);827}828829function createInitializedIteratorResultChunk<T>(830  response: Response,831  value: T,832  done: boolean,833): InitializedChunk<IteratorResult<T, T>> {834  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors835  return new ReactPromise(INITIALIZED, {done: done, value: value}, null);836}837838function createInitializedStreamChunk<839  T: ReadableStream | $AsyncIterable<any, any, void>,840>(841  response: Response,842  value: T,843  controller: FlightStreamController,844): InitializedChunk<T> {845  if (__DEV__) {846    // Retain a strong reference to the Response while we wait for chunks.847    if (response._pendingChunks++ === 0) {848      response._weakResponse.response = response;849    }850  }851  // We use the reason field to stash the controller since we already have that852  // field. It's a bit of a hack but efficient.853  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors854  return new ReactPromise(INITIALIZED, value, controller);855}856857function createResolvedIteratorResultChunk<T>(858  response: Response,859  value: UninitializedModel,860  done: boolean,861): ResolvedModelChunk<IteratorResult<T, T>> {862  // To reuse code as much code as possible we add the wrapper element as part of the JSON.863  const iteratorResultJSON =864    (done ? '{"done":true,"value":' : '{"done":false,"value":') + value + '}';865  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors866  return new ReactPromise(RESOLVED_MODEL, iteratorResultJSON, response);867}868869function resolveIteratorResultChunk<T>(870  response: Response,871  chunk: SomeChunk<IteratorResult<T, T>>,872  value: UninitializedModel,873  done: boolean,874): void {875  // To reuse code as much code as possible we add the wrapper element as part of the JSON.876  const iteratorResultJSON =877    (done ? '{"done":true,"value":' : '{"done":false,"value":') + value + '}';878  resolveModelChunk(response, chunk, iteratorResultJSON);879}880881function resolveModelChunk<T>(882  response: Response,883  chunk: SomeChunk<T>,884  value: UninitializedModel,885): void {886  if (chunk.status !== PENDING) {887    // If we get more data to an already resolved ID, we assume that it's888    // a stream chunk since any other row shouldn't have more than one entry.889    const streamChunk: InitializedStreamChunk<any> = chunk as any;890    const controller = streamChunk.reason;891    controller.enqueueModel(value);892    return;893  }894  releasePendingChunk(response, chunk);895  const resolveListeners = chunk.value;896  const rejectListeners = chunk.reason;897  const resolvedChunk: ResolvedModelChunk<T> = chunk as any;898  resolvedChunk.status = RESOLVED_MODEL;899  resolvedChunk.value = value;900  resolvedChunk.reason = response;901  if (resolveListeners !== null) {902    // This is unfortunate that we're reading this eagerly if903    // we already have listeners attached since they might no904    // longer be rendered or might not be the highest pri.905    initializeModelChunk(resolvedChunk);906    // The status might have changed after initialization.907    wakeChunkIfInitialized(response, chunk, resolveListeners, rejectListeners);908  }909}910911function resolveModuleChunk<T>(912  response: Response,913  chunk: SomeChunk<T>,914  value: ClientReference<T>,915): void {916  if (chunk.status !== PENDING && chunk.status !== BLOCKED) {917    // We already resolved. We didn't expect to see this.918    return;919  }920  releasePendingChunk(response, chunk);921  const resolveListeners = chunk.value;922  const rejectListeners = chunk.reason;923  const resolvedChunk: ResolvedModuleChunk<T> = chunk as any;924  resolvedChunk.status = RESOLVED_MODULE;925  resolvedChunk.value = value;926  resolvedChunk.reason = null;927  if (__DEV__) {928    const debugInfo = getModuleDebugInfo(value);929    if (debugInfo !== null) {930      // Add to the live set if it was already initialized.931      // $FlowFixMe[method-unbinding]932      resolvedChunk._debugInfo.push.apply(resolvedChunk._debugInfo, debugInfo);933    }934  }935  if (resolveListeners !== null) {936    initializeModuleChunk(resolvedChunk);937    wakeChunkIfInitialized(response, chunk, resolveListeners, rejectListeners);938  }939}940941type InitializationReference = {942  handler: InitializationHandler,943  parentObject: Object,944  key: string,945  map: (946    response: Response,947    model: any,948    parentObject: Object,949    key: string,950  ) => any,951  path: Array<string>,952  isDebug?: boolean, // DEV-only953};954type InitializationHandler = {955  parent: null | InitializationHandler,956  chunk: null | BlockedChunk<any>,957  value: any,958  reason: any,959  deps: number,960  errored: boolean,961};962let initializingHandler: null | InitializationHandler = null;963let initializingChunk: null | BlockedChunk<any> = null;964let isInitializingDebugInfo: boolean = false;965966function initializeDebugChunk(967  response: Response,968  chunk: ResolvedModelChunk<any> | PendingChunk<any>,969): void {970  const debugChunk = chunk._debugChunk;971  if (debugChunk !== null) {972    const debugInfo = chunk._debugInfo;973    const prevIsInitializingDebugInfo = isInitializingDebugInfo;974    isInitializingDebugInfo = true;975    try {976      if (debugChunk.status === RESOLVED_MODEL) {977        // Find the index of this debug info by walking the linked list.978        let idx = debugInfo.length;979        let c = debugChunk._debugChunk;980        while (c !== null) {981          if (c.status !== INITIALIZED) {982            idx++;983          }984          c = c._debugChunk;985        }986        // Initializing the model for the first time.987        initializeModelChunk(debugChunk);988        const initializedChunk = debugChunk as any as SomeChunk<any>;989        switch (initializedChunk.status) {990          case INITIALIZED: {991            debugInfo[idx] = initializeDebugInfo(992              response,993              initializedChunk.value,994            );995            break;996          }997          case BLOCKED:998          case PENDING: {999            waitForReference(1000              initializedChunk,1001              debugInfo,1002              '' + idx,1003              response,1004              initializeDebugInfo,1005              [''], // path1006              true,1007            );1008            break;1009          }1010          default:1011            throw initializedChunk.reason;1012        }1013      } else {1014        switch (debugChunk.status) {1015          case INITIALIZED: {1016            // Already done.1017            break;1018          }1019          case BLOCKED:1020          case PENDING: {1021            // Signal to the caller that we need to wait.1022            waitForReference(1023              debugChunk,1024              {}, // noop, since we'll have already added an entry to debug info1025              'debug', // noop, but we need it to not be empty string since that indicates the root object1026              response,1027              initializeDebugInfo,1028              [''], // path1029              true,1030            );1031            break;1032          }1033          default:1034            throw debugChunk.reason;1035        }1036      }1037    } catch (error) {1038      triggerErrorOnChunk(response, chunk, error);1039    } finally {1040      isInitializingDebugInfo = prevIsInitializingDebugInfo;1041    }1042  }1043}10441045function initializeModelChunk<T>(chunk: ResolvedModelChunk<T>): void {1046  const prevHandler = initializingHandler;1047  const prevChunk = initializingChunk;1048  initializingHandler = null;10491050  const resolvedModel = chunk.value;1051  const response = chunk.reason;10521053  // We go to the BLOCKED state until we've fully resolved this.1054  // We do this before parsing in case we try to initialize the same chunk1055  // while parsing the model. Such as in a cyclic reference.1056  const cyclicChunk: BlockedChunk<T> = chunk as any;1057  cyclicChunk.status = BLOCKED;1058  cyclicChunk.value = null;1059  cyclicChunk.reason = null;10601061  if ((enableProfilerTimer && enableComponentPerformanceTrack) || __DEV__) {1062    initializingChunk = cyclicChunk;1063  }10641065  if (__DEV__) {1066    // Initialize any debug info and block the initializing chunk on any1067    // unresolved entries.1068    initializeDebugChunk(response, chunk);1069    // TODO: The chunk might have transitioned to ERRORED now.1070    // Should we return early if that happens?1071  }10721073  try {1074    const value: T = parseModel(response, resolvedModel);1075    // Invoke any listeners added while resolving this model. I.e. cyclic1076    // references. This may or may not fully resolve the model depending on1077    // if they were blocked.1078    const resolveListeners = cyclicChunk.value;1079    if (resolveListeners !== null) {1080      cyclicChunk.value = null;1081      cyclicChunk.reason = null;1082      for (let i = 0; i < resolveListeners.length; i++) {1083        const listener = resolveListeners[i];1084        if (typeof listener === 'function') {1085          listener(value);1086        } else {1087          fulfillReference(response, listener, value, cyclicChunk);1088        }1089      }1090    }1091    if (initializingHandler !== null) {1092      if (initializingHandler.errored) {1093        throw initializingHandler.reason;1094      }1095      if (initializingHandler.deps > 0) {1096        // We discovered new dependencies on modules that are not yet resolved.1097        // We have to keep the BLOCKED state until they're resolved.1098        initializingHandler.value = value;1099        initializingHandler.chunk = cyclicChunk;1100        return;1101      }1102    }1103    const initializedChunk: InitializedChunk<T> = chunk as any;1104    initializedChunk.status = INITIALIZED;1105    initializedChunk.value = value;1106    initializedChunk.reason = null;11071108    if (__DEV__) {1109      processChunkDebugInfo(response, initializedChunk, value);1110    }1111  } catch (error) {1112    const erroredChunk: ErroredChunk<T> = chunk as any;1113    erroredChunk.status = ERRORED;1114    erroredChunk.reason = error;1115  } finally {1116    initializingHandler = prevHandler;1117    if ((enableProfilerTimer && enableComponentPerformanceTrack) || __DEV__) {1118      initializingChunk = prevChunk;1119    }1120  }1121}11221123function initializeModuleChunk<T>(chunk: ResolvedModuleChunk<T>): void {1124  try {1125    const value: T = requireModule(chunk.value);1126    const initializedChunk: InitializedChunk<T> = chunk as any;1127    initializedChunk.status = INITIALIZED;1128    initializedChunk.value = value;1129    initializedChunk.reason = null;1130  } catch (error) {1131    const erroredChunk: ErroredChunk<T> = chunk as any;1132    erroredChunk.status = ERRORED;1133    erroredChunk.reason = error;1134  }1135}11361137// Report that any missing chunks in the model is now going to throw this1138// error upon read. Also notify any pending promises.1139export function reportGlobalError(1140  weakResponse: WeakResponse,1141  error: Error,1142): void {1143  if (hasGCedResponse(weakResponse)) {1144    // Ignore close signal if we are not awaiting any more pending chunks.1145    return;1146  }1147  const response = unwrapWeakResponse(weakResponse);1148  response._closed = true;1149  response._closedReason = error;1150  response._chunks.forEach(chunk => {1151    // If this chunk was already resolved or errored, it won't1152    // trigger an error but if it wasn't then we need to1153    // because we won't be getting any new data to resolve it.1154    if (chunk.status === PENDING) {1155      triggerErrorOnChunk(response, chunk, error);1156    } else if (chunk.status === INITIALIZED && chunk.reason !== null) {1157      chunk.reason.error(error);1158    }1159  });1160  if (__DEV__) {1161    const debugChannel = response._debugChannel;1162    if (debugChannel !== undefined) {1163      // If we don't have any more ways of reading data, we don't have to send1164      // any more neither. So we close the writable side.1165      closeDebugChannel(debugChannel);1166      response._debugChannel = undefined;1167      // Make sure the debug channel is not closed a second time when the1168      // Response gets GC:ed.1169      if (debugChannelRegistry !== null) {1170        debugChannelRegistry.unregister(response);1171      }1172    }1173  }1174}11751176function nullRefGetter() {1177  if (__DEV__) {1178    return null;1179  }1180}11811182function getIOInfoTaskName(ioInfo: ReactIOInfo): string {1183  return ioInfo.name || 'unknown';1184}11851186function getAsyncInfoTaskName(asyncInfo: ReactAsyncInfo): string {1187  return 'await ' + getIOInfoTaskName(asyncInfo.awaited);1188}11891190function getServerComponentTaskName(componentInfo: ReactComponentInfo): string {1191  return '<' + (componentInfo.name || '...') + '>';1192}11931194function getTaskName(type: mixed): string {1195  if (type === REACT_FRAGMENT_TYPE) {1196    return '<>';1197  }1198  if (typeof type === 'function') {1199    // This is a function so it must have been a Client Reference that resolved to1200    // a function. We use "use client" to indicate that this is the boundary into1201    // the client. There should only be one for any given owner chain.1202    return '"use client"';1203  }1204  if (1205    typeof type === 'object' &&1206    type !== null &&1207    type.$$typeof === REACT_LAZY_TYPE1208  ) {1209    if (type._init === readChunk) {1210      // This is a lazy node created by Flight. It is probably a client reference.1211      // We use the "use client" string to indicate that this is the boundary into1212      // the client. There will only be one for any given owner chain.1213      return '"use client"';1214    }1215    // We don't want to eagerly initialize the initializer in DEV mode so we can't1216    // call it to extract the type so we don't know the type of this component.1217    return '<...>';1218  }1219  try {1220    const name = getComponentNameFromType(type);1221    return name ? '<' + name + '>' : '<...>';1222  } catch (x) {1223    return '<...>';1224  }1225}12261227function initializeElement(1228  response: Response,1229  element: any,1230  lazyNode: null | LazyComponent<1231    React$Element<any>,1232    SomeChunk<React$Element<any>>,1233  >,1234): void {1235  if (!__DEV__) {1236    return;1237  }1238  const stack = element._debugStack;1239  const owner = element._owner;1240  if (owner === null) {1241    element._owner = response._debugRootOwner;1242  }1243  let env = response._rootEnvironmentName;1244  if (owner !== null && owner.env != null) {1245    // Interestingly we don't actually have the environment name of where1246    // this JSX was created if it doesn't have an owner but if it does1247    // it must be the same environment as the owner. We could send it separately1248    // but it seems a bit unnecessary for this edge case.1249    env = owner.env;1250  }1251  let normalizedStackTrace: null | Error = null;1252  if (owner === null && response._debugRootStack != null) {1253    // We override the stack if we override the owner since the stack where the root JSX1254    // was created on the server isn't very useful but where the request was made is.1255    normalizedStackTrace = response._debugRootStack;1256  } else if (stack !== null) {1257    // We create a fake stack and then create an Error object inside of it.1258    // This means that the stack trace is now normalized into the native format1259    // of the browser and the stack frames will have been registered with1260    // source mapping information.1261    // This can unfortunately happen within a user space callstack which will1262    // remain on the stack.1263    normalizedStackTrace = createFakeJSXCallStackInDEV(response, stack, env);1264  }1265  element._debugStack = normalizedStackTrace;1266  let task: null | ConsoleTask = null;1267  if (supportsCreateTask && stack !== null) {1268    const createTaskFn = (console as any).createTask.bind(1269      console,1270      getTaskName(element.type),1271    );1272    const callStack = buildFakeCallStack(1273      response,1274      stack,1275      env,1276      false,1277      createTaskFn,1278    );1279    // This owner should ideally have already been initialized to avoid getting1280    // user stack frames on the stack.1281    const ownerTask =1282      owner === null ? null : initializeFakeTask(response, owner);1283    if (ownerTask === null) {1284      const rootTask = response._debugRootTask;1285      if (rootTask != null) {1286        task = rootTask.run(callStack);1287      } else {1288        task = callStack();1289      }1290    } else {1291      task = ownerTask.run(callStack);1292    }1293  }1294  element._debugTask = task;12951296  // This owner should ideally have already been initialized to avoid getting1297  // user stack frames on the stack.1298  if (owner !== null) {1299    initializeFakeStack(response, owner);1300  }13011302  if (lazyNode !== null) {1303    // In case the JSX runtime has validated the lazy type as a static child, we1304    // need to transfer this information to the element.1305    if (1306      lazyNode._store &&1307      lazyNode._store.validated &&1308      !element._store.validated1309    ) {1310      element._store.validated = lazyNode._store.validated;1311    }13121313    // If the lazy node is initialized, we move its debug info to the inner1314    // value.1315    if (lazyNode._payload.status === INITIALIZED && lazyNode._debugInfo) {1316      const debugInfo = lazyNode._debugInfo.splice(0);1317      if (element._debugInfo) {1318        // $FlowFixMe[method-unbinding]1319        element._debugInfo.unshift.apply(element._debugInfo, debugInfo);1320      } else {1321        Object.defineProperty(element, '_debugInfo', {1322          configurable: false,1323          enumerable: false,1324          writable: true,1325          value: debugInfo,1326        });1327      }1328    }1329  }13301331  // TODO: We should be freezing the element but currently, we might write into1332  // _debugInfo later. We could move it into _store which remains mutable.1333  Object.freeze(element.props);1334}13351336function createElement(1337  response: Response,1338  type: mixed,1339  key: mixed,1340  props: mixed,1341  owner: ?ReactComponentInfo, // DEV-only1342  stack: ?ReactStackTrace, // DEV-only1343  validated: 0 | 1 | 2, // DEV-only1344):1345  | React$Element<any>1346  | LazyComponent<React$Element<any>, SomeChunk<React$Element<any>>> {1347  let element: any;1348  if (__DEV__) {1349    // `ref` is non-enumerable in dev1350    element = {1351      $$typeof: REACT_ELEMENT_TYPE,1352      type,1353      key,1354      props,1355      _owner: owner === undefined ? null : owner,1356    } as any;1357    Object.defineProperty(element, 'ref', {1358      enumerable: false,1359      get: nullRefGetter,1360    });1361  } else {1362    element = {1363      // This tag allows us to uniquely identify this as a React Element1364      $$typeof: REACT_ELEMENT_TYPE,13651366      type,1367      key,1368      ref: null,1369      props,1370    } as any;1371  }13721373  if (__DEV__) {1374    // We don't really need to add any of these but keeping them for good measure.1375    // Unfortunately, _store is enumerable in jest matchers so for equality to1376    // work, I need to keep it or make _store non-enumerable in the other file.1377    element._store = {} as {1378      validated?: number,1379    };1380    Object.defineProperty(element._store, 'validated', {1381      configurable: false,1382      enumerable: false,1383      writable: true,1384      value: validated, // Whether the element has already been validated on the server.1385    });1386    // debugInfo contains Server Component debug information.1387    Object.defineProperty(element, '_debugInfo', {1388      configurable: false,1389      enumerable: false,1390      writable: true,1391      value: null,1392    });1393    Object.defineProperty(element, '_debugStack', {1394      configurable: false,1395      enumerable: false,1396      writable: true,1397      value: stack === undefined ? null : stack,1398    });1399    Object.defineProperty(element, '_debugTask', {1400      configurable: false,1401      enumerable: false,1402      writable: true,1403      value: null,1404    });1405  }14061407  if (initializingHandler !== null) {1408    const handler = initializingHandler;1409    // We pop the stack to the previous outer handler before leaving the Element.1410    // This is effectively the complete phase.1411    initializingHandler = handler.parent;1412    if (handler.errored) {1413      // Something errored inside this Element's props. We can turn this Element1414      // into a Lazy so that we can still render up until that Lazy is rendered.1415      const erroredChunk: ErroredChunk<React$Element<any>> = createErrorChunk(1416        response,1417        handler.reason,1418      );1419      if (__DEV__) {1420        initializeElement(response, element, null);1421        // Conceptually the error happened inside this Element but right before1422        // it was rendered. We don't have a client side component to render but1423        // we can add some DebugInfo to explain that this was conceptually a1424        // Server side error that errored inside this element. That way any stack1425        // traces will point to the nearest JSX that errored - e.g. during1426        // serialization.1427        const erroredComponent: ReactComponentInfo = {1428          name: getComponentNameFromType(element.type) || '',1429          owner: element._owner,1430        };1431        // $FlowFixMe[cannot-write]1432        erroredComponent.debugStack = element._debugStack;1433        if (supportsCreateTask) {1434          // $FlowFixMe[cannot-write]1435          erroredComponent.debugTask = element._debugTask;1436        }1437        erroredChunk._debugInfo = [erroredComponent];1438      }1439      return createLazyChunkWrapper(erroredChunk, validated);1440    }1441    if (handler.deps > 0) {1442      // We have blocked references inside this Element but we can turn this into1443      // a Lazy node referencing this Element to let everything around it proceed.1444      const blockedChunk: BlockedChunk<React$Element<any>> =1445        createBlockedChunk(response);1446      handler.value = element;1447      handler.chunk = blockedChunk;1448      const lazyNode = createLazyChunkWrapper(blockedChunk, validated);1449      if (__DEV__) {1450        // After we have initialized any blocked references, initialize stack etc.1451        const init = initializeElement.bind(null, response, element, lazyNode);1452        blockedChunk.then(init, init);1453      }1454      return lazyNode;1455    }1456  }1457  if (__DEV__) {1458    initializeElement(response, element, null);1459  }14601461  return element;1462}14631464function createLazyChunkWrapper<T>(1465  chunk: SomeChunk<T>,1466  validated: 0 | 1 | 2, // DEV-only1467): LazyComponent<T, SomeChunk<T>> {1468  const lazyType: LazyComponent<T, SomeChunk<T>> = {1469    $$typeof: REACT_LAZY_TYPE,1470    _payload: chunk,1471    _init: readChunk,1472  };1473  if (__DEV__) {1474    // Forward the live array1475    lazyType._debugInfo = chunk._debugInfo;1476    // Initialize a store for key validation by the JSX runtime.1477    lazyType._store = {validated: validated};1478  }1479  return lazyType;1480}14811482function getChunk(response: Response, id: number): SomeChunk<any> {1483  const chunks = response._chunks;1484  let chunk = chunks.get(id);1485  if (!chunk) {1486    if (response._closed) {1487      if (response._allowPartialStream) {1488        // For partial streams, chunks accessed after close should be HALTED1489        // (never resolve).1490        chunk = createPendingChunk(response);1491        const haltedChunk: HaltedChunk<any> = chunk as any;1492        haltedChunk.status = HALTED;1493        haltedChunk.value = null;1494        haltedChunk.reason = null;1495      } else {1496        // We have already errored the response and we're not going to get1497        // anything more streaming in so this will immediately error.1498        chunk = createErrorChunk(response, response._closedReason);1499      }1500    } else {1501      chunk = createPendingChunk(response);1502    }1503    chunks.set(id, chunk);1504  }1505  return chunk;1506}15071508function fulfillReference(1509  response: Response,1510  reference: InitializationReference,1511  value: any,1512  fulfilledChunk: SomeChunk<any>,1513): void {1514  const {handler, parentObject, key, map, path} = reference;15151516  try {1517    for (let i = 1; i < path.length; i++) {1518      while (1519        typeof value === 'object' &&1520        value !== null &&1521        value.$$typeof === REACT_LAZY_TYPE1522      ) {1523        // We never expect to see a Lazy node on this path because we encode those as1524        // separate models. This must mean that we have inserted an extra lazy node1525        // e.g. to replace a blocked element. We must instead look for it inside.1526        const referencedChunk: SomeChunk<any> = value._payload;1527        if (referencedChunk === handler.chunk) {1528          // This is a reference to the thing we're currently blocking. We can peak1529          // inside of it to get the value.1530          value = handler.value;1531          continue;1532        } else {1533          switch (referencedChunk.status) {1534            case RESOLVED_MODEL:1535              initializeModelChunk(referencedChunk);1536              break;1537            case RESOLVED_MODULE:1538              initializeModuleChunk(referencedChunk);1539              break;1540          }1541          switch (referencedChunk.status) {1542            case INITIALIZED: {1543              value = referencedChunk.value;1544              continue;1545            }1546            case BLOCKED: {1547              // It is possible that we're blocked on our own chunk if it's a cycle.1548              // Before adding the listener to the inner chunk, let's check if it would1549              // result in a cycle.1550              const cyclicHandler = resolveBlockedCycle(1551                referencedChunk,1552                reference,1553              );1554              if (cyclicHandler !== null) {1555                // This reference points back to this chunk. We can resolve the cycle by1556                // using the value from that handler.1557                value = cyclicHandler.value;1558                continue;1559              }1560              // Fallthrough1561            }1562            case PENDING: {1563              // If we're not yet initialized we need to skip what we've already drilled1564              // through and then wait for the next value to become available.1565              path.splice(0, i - 1);1566              // Add "listener" to our new chunk dependency.1567              if (referencedChunk.value === null) {1568                referencedChunk.value = [reference];1569              } else {1570                referencedChunk.value.push(reference);1571              }1572              if (referencedChunk.reason === null) {1573                referencedChunk.reason = [reference];1574              } else {1575                referencedChunk.reason.push(reference);1576              }1577              return;1578            }1579            case HALTED: {1580              // Do nothing. We couldn't fulfill.1581              // TODO: Mark downstreams as halted too.1582              return;1583            }1584            default: {1585              rejectReference(1586                response,1587                reference.handler,1588                referencedChunk.reason,1589              );1590              return;1591            }1592          }1593        }1594      }1595      const name = path[i];1596      if (1597        typeof value === 'object' &&1598        value !== null &&1599        hasOwnProperty.call(value, name)1600      ) {1601        value = value[name];1602      } else {1603        throw new Error('Invalid reference.');1604      }1605    }16061607    while (1608      typeof value === 'object' &&1609      value !== null &&1610      value.$$typeof === REACT_LAZY_TYPE1611    ) {1612      // If what we're referencing is a Lazy it must be because we inserted one as a virtual node1613      // while it was blocked by other data. If it's no longer blocked, we can unwrap it.1614      const referencedChunk: SomeChunk<any> = value._payload;1615      if (referencedChunk === handler.chunk) {1616        // This is a reference to the thing we're currently blocking. We can peak1617        // inside of it to get the value.1618        value = handler.value;1619        continue;1620      } else {1621        switch (referencedChunk.status) {1622          case RESOLVED_MODEL:1623            initializeModelChunk(referencedChunk);1624            break;1625          case RESOLVED_MODULE:1626            initializeModuleChunk(referencedChunk);1627            break;1628        }1629        switch (referencedChunk.status) {1630          case INITIALIZED: {1631            value = referencedChunk.value;1632            continue;1633          }1634        }1635      }1636      break;1637    }16381639    const mappedValue = map(response, value, parentObject, key);1640    if (key !== __PROTO__) {1641      parentObject[key] = mappedValue;1642    }16431644    // If this is the root object for a model reference, where `handler.value`1645    // is a stale `null`, the resolved value can be used directly.1646    if (key === '' && handler.value === null) {1647      handler.value = mappedValue;1648    }16491650    // If the parent object is an unparsed React element tuple, we also need to1651    // update the props and owner of the parsed element object (i.e.1652    // handler.value).1653    if (1654      parentObject[0] === REACT_ELEMENT_TYPE &&1655      typeof handler.value === 'object' &&1656      handler.value !== null &&1657      handler.value.$$typeof === REACT_ELEMENT_TYPE1658    ) {1659      const element: any = handler.value;1660      switch (key) {1661        case '3':1662          if (__DEV__) {1663            transferReferencedDebugInfo(handler.chunk, fulfilledChunk);1664          }1665          element.props = mappedValue;1666          break;1667        case '4':1668          // This path doesn't call transferReferencedDebugInfo because this reference is to a debug chunk.1669          if (__DEV__) {1670            element._owner = mappedValue;1671          }1672          break;1673        case '5':1674          // This path doesn't call transferReferencedDebugInfo because this reference is to a debug chunk.1675          if (__DEV__) {1676            element._debugStack = mappedValue;1677          }1678          break;1679        default:1680          if (__DEV__) {1681            transferReferencedDebugInfo(handler.chunk, fulfilledChunk);1682          }1683          break;1684      }1685    } else if (__DEV__ && !reference.isDebug) {1686      transferReferencedDebugInfo(handler.chunk, fulfilledChunk);1687    }1688  } catch (error) {1689    rejectReference(response, reference.handler, error);1690    return;1691  }16921693  handler.deps--;16941695  if (handler.deps === 0) {1696    const chunk = handler.chunk;1697    if (chunk === null || chunk.status !== BLOCKED) {1698      return;1699    }1700    const resolveListeners = chunk.value;1701    const initializedChunk: InitializedChunk<any> = chunk as any;1702    initializedChunk.status = INITIALIZED;1703    initializedChunk.value = handler.value;1704    initializedChunk.reason = handler.reason; // Used by streaming chunks1705    if (resolveListeners !== null) {1706      wakeChunk(response, resolveListeners, handler.value, initializedChunk);1707    } else {1708      if (__DEV__) {1709        processChunkDebugInfo(response, initializedChunk, handler.value);1710      }1711    }1712  }1713}17141715function rejectReference(1716  response: Response,1717  handler: InitializationHandler,1718  error: mixed,1719): void {1720  if (handler.errored) {1721    // We've already errored. We could instead build up an AggregateError1722    // but if there are multiple errors we just take the first one like1723    // Promise.all.1724    return;1725  }1726  const blockedValue = handler.value;1727  handler.errored = true;1728  handler.value = null;1729  handler.reason = error;1730  const chunk = handler.chunk;1731  if (chunk === null || chunk.status !== BLOCKED) {1732    return;1733  }17341735  if (__DEV__) {1736    if (1737      typeof blockedValue === 'object' &&1738      blockedValue !== null &&1739      blockedValue.$$typeof === REACT_ELEMENT_TYPE1740    ) {1741      const element = blockedValue;1742      // Conceptually the error happened inside this Element but right before1743      // it was rendered. We don't have a client side component to render but1744      // we can add some DebugInfo to explain that this was conceptually a1745      // Server side error that errored inside this element. That way any stack1746      // traces will point to the nearest JSX that errored - e.g. during1747      // serialization.1748      const erroredComponent: ReactComponentInfo = {1749        name: getComponentNameFromType(element.type) || '',1750        owner: element._owner,1751      };1752      // $FlowFixMe[cannot-write]1753      erroredComponent.debugStack = element._debugStack;1754      if (supportsCreateTask) {1755        // $FlowFixMe[cannot-write]1756        erroredComponent.debugTask = element._debugTask;1757      }1758      chunk._debugInfo.push(erroredComponent);1759    }1760  }17611762  triggerErrorOnChunk(response, chunk, error);1763}17641765function waitForReference<T>(1766  referencedChunk: PendingChunk<T> | BlockedChunk<T>,1767  parentObject: Object,1768  key: string,1769  response: Response,1770  map: (response: Response, model: any, parentObject: Object, key: string) => T,1771  path: Array<string>,1772  isAwaitingDebugInfo: boolean, // DEV-only1773): T {1774  if (1775    __DEV__ &&1776    (response._debugChannel === undefined ||1777      !response._debugChannel.hasReadable)1778  ) {1779    if (1780      referencedChunk.status === PENDING &&1781      parentObject[0] === REACT_ELEMENT_TYPE &&1782      (key === '4' || key === '5')1783    ) {1784      // If the parent object is an unparsed React element tuple, and this is a reference1785      // to the owner or debug stack. Then we expect the chunk to have been emitted earlier1786      // in the stream. It might be blocked on other things but chunk should no longer be pending.1787      // If it's still pending that suggests that it was referencing an object in the debug1788      // channel, but no debug channel was wired up so it's missing. In this case we can just1789      // drop the debug info instead of halting the whole stream.1790      return null as any;1791    }1792  }17931794  let handler: InitializationHandler;1795  if (initializingHandler) {1796    handler = initializingHandler;1797    handler.deps++;1798  } else {1799    handler = initializingHandler = {1800      parent: null,1801      chunk: null,1802      value: null,1803      reason: null,1804      deps: 1,1805      errored: false,1806    };1807  }18081809  const reference: InitializationReference = {1810    handler,1811    parentObject,1812    key,1813    map,1814    path,1815  };1816  if (__DEV__) {1817    reference.isDebug = isAwaitingDebugInfo;1818  }18191820  // Add "listener".1821  if (referencedChunk.value === null) {1822    referencedChunk.value = [reference];1823  } else {1824    referencedChunk.value.push(reference);1825  }1826  if (referencedChunk.reason === null) {1827    referencedChunk.reason = [reference];1828  } else {1829    referencedChunk.reason.push(reference);1830  }18311832  // Return a place holder value for now.1833  return null as any;1834}18351836function loadServerReference<A: Iterable<any>, T>(1837  response: Response,1838  metaData: {1839    id: any,1840    bound: null | Thenable<Array<any>>,1841    name?: string, // DEV-only1842    env?: string, // DEV-only1843    location?: ReactFunctionLocation, // DEV-only1844  },1845  parentObject: Object,1846  key: string,1847): (...A) => Promise<T> {1848  if (!response._serverReferenceConfig) {1849    // In the normal case, we can't load this Server Reference in the current environment and1850    // we just return a proxy to it.1851    return createBoundServerReference(1852      metaData,1853      response._callServer,1854      response._encodeFormAction,1855      __DEV__ ? response._debugFindSourceMapURL : undefined,1856    );1857  }1858  // If we have a module mapping we can load the real version of this Server Reference.1859  const serverReference: ClientReference<T> =1860    resolveServerReference<$FlowFixMe>(1861      response._serverReferenceConfig,1862      metaData.id,1863    );18641865  let promise: null | Thenable<any> = preloadModule(serverReference);1866  if (!promise) {1867    if (!metaData.bound) {1868      const resolvedValue = requireModule(serverReference) as any;1869      registerBoundServerReference(1870        resolvedValue,1871        metaData.id,1872        metaData.bound,1873        response._encodeFormAction,1874      );1875      return resolvedValue;1876    } else {1877      promise = Promise.resolve(metaData.bound);1878    }1879  } else if (metaData.bound) {1880    promise = Promise.all([promise, metaData.bound]);1881  }18821883  let handler: InitializationHandler;1884  if (initializingHandler) {1885    handler = initializingHandler;1886    handler.deps++;1887  } else {1888    handler = initializingHandler = {1889      parent: null,1890      chunk: null,1891      value: null,1892      reason: null,1893      deps: 1,1894      errored: false,1895    };1896  }18971898  function fulfill(): void {1899    let resolvedValue = requireModule(serverReference) as any;19001901    if (metaData.bound) {1902      // This promise is coming from us and should have initilialized by now.1903      const boundArgs: Array<any> = (metaData.bound as any).value.slice(0);1904      boundArgs.unshift(null); // this1905      resolvedValue = resolvedValue.bind.apply(resolvedValue, boundArgs);1906    }19071908    registerBoundServerReference(1909      resolvedValue,1910      metaData.id,1911      metaData.bound,1912      response._encodeFormAction,1913    );19141915    if (key !== __PROTO__) {1916      parentObject[key] = resolvedValue;1917    }19181919    // If this is the root object for a model reference, where `handler.value`1920    // is a stale `null`, the resolved value can be used directly.1921    if (key === '' && handler.value === null) {1922      handler.value = resolvedValue;1923    }19241925    // If the parent object is an unparsed React element tuple, we also need to1926    // update the props and owner of the parsed element object (i.e.1927    // handler.value).1928    if (1929      parentObject[0] === REACT_ELEMENT_TYPE &&1930      typeof handler.value === 'object' &&1931      handler.value !== null &&1932      handler.value.$$typeof === REACT_ELEMENT_TYPE1933    ) {1934      const element: any = handler.value;1935      switch (key) {1936        case '3':1937          element.props = resolvedValue;1938          break;1939        case '4':1940          if (__DEV__) {1941            element._owner = resolvedValue;1942          }1943          break;1944      }1945    }19461947    handler.deps--;19481949    if (handler.deps === 0) {1950      const chunk = handler.chunk;1951      if (chunk === null || chunk.status !== BLOCKED) {1952        return;1953      }1954      const resolveListeners = chunk.value;1955      const initializedChunk: InitializedChunk<T> = chunk as any;1956      initializedChunk.status = INITIALIZED;1957      initializedChunk.value = handler.value;1958      initializedChunk.reason = null;1959      if (resolveListeners !== null) {1960        wakeChunk(response, resolveListeners, handler.value, initializedChunk);1961      } else {1962        if (__DEV__) {1963          processChunkDebugInfo(response, initializedChunk, handler.value);1964        }1965      }1966    }1967  }19681969  function reject(error: mixed): void {1970    if (handler.errored) {1971      // We've already errored. We could instead build up an AggregateError1972      // but if there are multiple errors we just take the first one like1973      // Promise.all.1974      return;1975    }1976    const blockedValue = handler.value;1977    handler.errored = true;1978    handler.value = null;1979    handler.reason = error;1980    const chunk = handler.chunk;1981    if (chunk === null || chunk.status !== BLOCKED) {1982      return;1983    }19841985    if (__DEV__) {1986      if (1987        typeof blockedValue === 'object' &&1988        blockedValue !== null &&1989        blockedValue.$$typeof === REACT_ELEMENT_TYPE1990      ) {1991        const element = blockedValue;1992        // Conceptually the error happened inside this Element but right before1993        // it was rendered. We don't have a client side component to render but1994        // we can add some DebugInfo to explain that this was conceptually a1995        // Server side error that errored inside this element. That way any stack1996        // traces will point to the nearest JSX that errored - e.g. during1997        // serialization.1998        const erroredComponent: ReactComponentInfo = {1999          name: getComponentNameFromType(element.type) || '',2000          owner: element._owner,

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.