packages/react-client/src/ReactFlightClient.js JAVASCRIPT 5,779 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 5,779.
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  enableFlightWeakThenables,49  enableFlightObjectReferences,50} from 'shared/ReactFeatureFlags';5152import {53  resolveClientReference,54  resolveServerReference,55  preloadModule,56  requireModule,57  getModuleDebugInfo,58  dispatchHint,59  readPartialStringChunk,60  readFinalStringChunk,61  createStringDecoder,62  prepareDestinationForModule,63  bindToConsole,64  rendererVersion,65  rendererPackageName,66  checkEvalAvailabilityOnceDev,67} from './ReactFlightClientConfig';6869import {70  createBoundServerReference,71  registerBoundServerReference,72  createServerObjectReference,73} from './ReactFlightReplyClient';7475import {readTemporaryReference} from './ReactFlightTemporaryReferences';7677import {78  markAllTracksInOrder,79  logComponentRender,80  logDedupedComponentRender,81  logComponentAborted,82  logComponentErrored,83  logIOInfo,84  logIOInfoErrored,85  logComponentAwait,86  logComponentAwaitAborted,87  logComponentAwaitErrored,88} from './ReactFlightPerformanceTrack';8990import {91  REACT_LAZY_TYPE,92  REACT_ELEMENT_TYPE,93  ASYNC_ITERATOR,94  REACT_FRAGMENT_TYPE,95} from 'shared/ReactSymbols';9697import getComponentNameFromType from 'shared/getComponentNameFromType';9899import {getOwnerStackByComponentInfoInDev} from 'shared/ReactComponentInfoStack';100101import hasOwnProperty from 'shared/hasOwnProperty';102103import getPrototypeOf from 'shared/getPrototypeOf';104105import {injectInternals} from './ReactFlightClientDevToolsHook';106107import {OMITTED_PROP_ERROR} from 'shared/ReactFlightPropertyAccess';108109import ReactVersion from 'shared/ReactVersion';110111import isArray from 'shared/isArray';112113import * as React from 'react';114115import type {SharedStateServer} from 'react/src/ReactSharedInternalsServer';116import type {SharedStateClient} from 'react/src/ReactSharedInternalsClient';117118// TODO: This is an unfortunate hack. We shouldn't feature detect the internals119// like this. It's just that for now we support the same build of the Flight120// client both in the RSC environment, in the SSR environments as well as the121// browser client. We should probably have a separate RSC build. This is DEV122// only though.123const ReactSharedInteralsServer: void | SharedStateServer = (React as any)124  .__SERVER_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;125const ReactSharedInternals: SharedStateServer | SharedStateClient =126  React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE ||127  ReactSharedInteralsServer;128129export type {CallServerCallback, EncodeFormActionCallback};130131interface FlightStreamController {132  enqueueValue(value: any): void;133  enqueueModel(json: UninitializedModel): void;134  close(json: UninitializedModel): void;135  error(error: Error): void;136}137138type UninitializedModel = string;139140type ProfilingResult = {141  track: number,142  endTime: number,143  component: null | ReactComponentInfo,144};145146const ROW_ID = 0;147const ROW_TAG = 1;148const ROW_LENGTH = 2;149const ROW_CHUNK_BY_NEWLINE = 3;150const ROW_CHUNK_BY_LENGTH = 4;151152type RowParserState = 0 | 1 | 2 | 3 | 4;153154const PENDING = 'pending';155// A weak Promise reference. Behaves like PENDING except that when the stream156// closes it transitions to HALTED instead of erroring, because the server157// may intentionally never emit it. Only used when enableFlightWeakThenables158// is on.159const PENDING_WEAK = 'pending_weak';160const BLOCKED = 'blocked';161const RESOLVED_MODEL = 'resolved_model';162const RESOLVED_MODULE = 'resolved_module';163const INITIALIZED = 'fulfilled';164const ERRORED = 'rejected';165// Means it never resolves, even when the connection closes. The shared166// terminal state of a weak chunk that didn't settle before close, of any167// pending chunk at close when partial streams are allowed, and of DEV-only168// debug halts.169const HALTED = 'halted';170171const __PROTO__ = '__proto__';172173const ObjectPrototype = Object.prototype;174const ArrayPrototype = Array.prototype;175176type RESPONSE_SYMBOL_TYPE = 'RESPONSE_SYMBOL'; // Fake symbol type.177const RESPONSE_SYMBOL: RESPONSE_SYMBOL_TYPE = Symbol() as any;178179type PendingChunk<T> = {180  status: 'pending',181  value: null | Array<InitializationReference | (T => mixed)>,182  reason: null | Array<InitializationReference | (mixed => mixed)>,183  _children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only184  _debugChunk: null | SomeChunk<ReactDebugInfoEntry>, // DEV-only185  _debugInfo: ReactDebugInfo, // DEV-only186  then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,187};188type PendingWeakChunk<T> = {189  status: 'pending_weak',190  value: null | Array<InitializationReference | (T => mixed)>,191  reason: null | Array<InitializationReference | (mixed => mixed)>,192  _children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only193  _debugChunk: null | SomeChunk<ReactDebugInfoEntry>, // DEV-only194  _debugInfo: ReactDebugInfo, // DEV-only195  then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,196};197type BlockedChunk<T> = {198  status: 'blocked',199  value: null | Array<InitializationReference | (T => mixed)>,200  reason: null | Array<InitializationReference | (mixed => mixed)>,201  _children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only202  _debugChunk: null, // DEV-only203  _debugInfo: ReactDebugInfo, // DEV-only204  _receivedDebugInfo: null | Set<ReactDebugInfoEntry>, // DEV-only205  then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,206};207type ResolvedModelChunk<T> = {208  status: 'resolved_model',209  value: UninitializedModel,210  reason: {[RESPONSE_SYMBOL_TYPE]: Response},211  _children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only212  _debugChunk: null | SomeChunk<ReactDebugInfoEntry>, // DEV-only213  _debugInfo: ReactDebugInfo, // DEV-only214  then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,215};216type ResolvedModuleChunk<T> = {217  status: 'resolved_module',218  value: ClientReference<T>,219  reason: null,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 InitializedChunk<T> = {226  status: 'fulfilled',227  value: T,228  reason: null | FlightStreamController,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 InitializedStreamChunk<235  T: ReadableStream | $AsyncIterable<any, any, void>,236> = {237  status: 'fulfilled',238  value: T,239  reason: FlightStreamController,240  _children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only241  _debugChunk: null, // DEV-only242  _debugInfo: ReactDebugInfo, // DEV-only243  then(resolve: (ReadableStream) => mixed, reject?: (mixed) => mixed): void,244};245type ErroredChunk<T> = {246  status: 'rejected',247  value: null,248  reason: mixed,249  _children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only250  _debugChunk: null, // DEV-only251  _debugInfo: ReactDebugInfo, // DEV-only252  then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,253};254type HaltedChunk<T> = {255  status: 'halted',256  value: null,257  reason: null,258  _children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only259  _debugChunk: null, // DEV-only260  _debugInfo: ReactDebugInfo, // DEV-only261  then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,262};263type SomeChunk<T> =264  | PendingChunk<T>265  | PendingWeakChunk<T>266  | BlockedChunk<T>267  | ResolvedModelChunk<T>268  | ResolvedModuleChunk<T>269  | InitializedChunk<T>270  | ErroredChunk<T>271  | HaltedChunk<T>;272273// $FlowFixMe[missing-this-annot]274function ReactPromise(status: any, value: any, reason: any) {275  this.status = status;276  this.value = value;277  this.reason = reason;278  if (enableProfilerTimer && enableComponentPerformanceTrack) {279    this._children = [];280  }281  if (__DEV__) {282    this._debugChunk = null;283    this._debugInfo = [];284    this._receivedDebugInfo = null;285  }286}287// We subclass Promise.prototype so that we get other methods like .catch288ReactPromise.prototype = Object.create(Promise.prototype) as any;289// TODO: This doesn't return a new Promise chain unlike the real .then290function reactPromiseThen<T>(291  this: SomeChunk<T>,292  resolve: (value: T) => mixed,293  reject?: (reason: mixed) => mixed,294) {295  const chunk: SomeChunk<T> = this;296  // If we have resolved content, we try to initialize it first which297  // might put us back into one of the other states.298  switch (chunk.status) {299    case RESOLVED_MODEL:300      initializeModelChunk(chunk);301      break;302    case RESOLVED_MODULE:303      initializeModuleChunk(chunk);304      break;305  }306  if (__DEV__) {307    // Because only native Promises get picked up when we're awaiting we need to wrap308    // this in a native Promise in DEV. This means that these callbacks are no longer sync309    // but the lazy initialization is still sync and the .value can be inspected after,310    // allowing it to be read synchronously anyway.311    const resolveCallback = resolve;312    const rejectCallback = reject;313    const wrapperPromise: Promise<T> = new Promise((res, rej) => {314      resolve = value => {315        // $FlowFixMe[prop-missing]316        wrapperPromise._debugInfo = this._debugInfo;317        res(value);318      };319      reject = reason => {320        // $FlowFixMe[prop-missing]321        wrapperPromise._debugInfo = this._debugInfo;322        rej(reason);323      };324    });325    wrapperPromise.then(resolveCallback, rejectCallback);326  }327  // The status might have changed after initialization.328  switch (chunk.status) {329    case INITIALIZED:330      if (typeof resolve === 'function') {331        resolve(chunk.value);332      }333      break;334    case PENDING:335    case PENDING_WEAK:336    case BLOCKED:337      if (typeof resolve === 'function') {338        if (chunk.value === null) {339          chunk.value = [] as Array<InitializationReference | (T => mixed)>;340        }341        chunk.value.push(resolve);342      }343      if (typeof reject === 'function') {344        if (chunk.reason === null) {345          chunk.reason = [] as Array<346            InitializationReference | (mixed => mixed),347          >;348        }349        chunk.reason.push(reject);350      }351      break;352    case HALTED: {353      break;354    }355    default:356      if (typeof reject === 'function') {357        reject(chunk.reason);358      }359      break;360  }361}362// The shadowing `then` must be defined with `Object.defineProperty` instead of363// assignment. Assignment would throw when `Promise.prototype` is frozen (e.g.364// by SES lockdown) because assigning over an inherited non-writable property365// is rejected.366Object.defineProperty(ReactPromise.prototype, 'then', {367  writable: true,368  enumerable: true,369  configurable: true,370  value: reactPromiseThen,371});372373export type FindSourceMapURLCallback = (374  fileName: string,375  environmentName: string,376) => null | string;377378export type DebugChannelCallback = (message: string) => void;379380export type DebugChannel = {381  hasReadable: boolean,382  callback: DebugChannelCallback | null,383};384385type Response = {386  _bundlerConfig: ServerConsumerModuleMap,387  _serverReferenceConfig: null | ServerManifest,388  _moduleLoading: ModuleLoading,389  _callServer: CallServerCallback,390  _encodeFormAction: void | EncodeFormActionCallback,391  _nonce: ?string,392  _chunks: Map<number, SomeChunk<any>>,393  _stringDecoder: StringDecoder,394  _closed: boolean,395  _closedReason: mixed,396  _allowPartialStream: boolean,397  _tempRefs: void | TemporaryReferenceSet, // the set temporary references can be resolved from398  _timeOrigin: number, // Profiling-only399  _pendingInitialRender: null | TimeoutID, // Profiling-only,400  _pendingChunks: number, // DEV-only401  _weakResponse: WeakResponse, // DEV-only402  _debugRootOwner?: null | ReactComponentInfo, // DEV-only403  _debugRootStack?: null | Error, // DEV-only404  _debugRootTask?: null | ConsoleTask, // DEV-only405  _debugStartTime: number, // DEV-only406  _debugEndTime: null | number, // DEV-only407  _debugIOStarted: boolean, // DEV-only408  _debugFindSourceMapURL?: void | FindSourceMapURLCallback, // DEV-only409  _debugChannel?: void | DebugChannel, // DEV-only410  _blockedConsole?: null | SomeChunk<ConsoleEntry>, // DEV-only411  _replayConsole: boolean, // DEV-only412  _rootEnvironmentName: string, // DEV-only, the requested environment name.413};414415// This indirection exists only to clean up DebugChannel when all Lazy References are GC:ed.416// Therefore we only use the indirection in DEV.417type WeakResponse = {418  weak: WeakRef<Response>,419  response: null | Response, // This is null when there are no pending chunks.420};421422export type {WeakResponse as Response};423424function hasGCedResponse(weakResponse: WeakResponse): boolean {425  return __DEV__ && weakResponse.weak.deref() === undefined;426}427428function unwrapWeakResponse(weakResponse: WeakResponse): Response {429  if (__DEV__) {430    const response = weakResponse.weak.deref();431    if (response === undefined) {432      // eslint-disable-next-line react-internal/prod-error-codes433      throw new Error(434        'We did not expect to receive new data after GC:ing the response.',435      );436    }437    return response;438  } else {439    return weakResponse as any; // In prod we just use the real Response directly.440  }441}442443function getWeakResponse(response: Response): WeakResponse {444  if (__DEV__) {445    return response._weakResponse;446  } else {447    return response as any; // In prod we just use the real Response directly.448  }449}450451function closeDebugChannel(debugChannel: DebugChannel): void {452  if (debugChannel.callback) {453    debugChannel.callback('');454  }455}456457// If FinalizationRegistry doesn't exist, we cannot use the debugChannel.458const debugChannelRegistry =459  __DEV__ && typeof FinalizationRegistry === 'function'460    ? new FinalizationRegistry(closeDebugChannel)461    : null;462463function readChunk<T>(chunk: SomeChunk<T>): T {464  // If we have resolved content, we try to initialize it first which465  // might put us back into one of the other states.466  switch (chunk.status) {467    case RESOLVED_MODEL:468      initializeModelChunk(chunk);469      break;470    case RESOLVED_MODULE:471      initializeModuleChunk(chunk);472      break;473  }474  // The status might have changed after initialization.475  switch (chunk.status) {476    case INITIALIZED:477      return chunk.value;478    case PENDING:479    case PENDING_WEAK:480    case BLOCKED:481    case HALTED:482      // eslint-disable-next-line no-throw-literal483      throw chunk as any as Thenable<T>;484    default:485      throw chunk.reason;486  }487}488489export function getRoot<T>(weakResponse: WeakResponse): Thenable<T> {490  const response = unwrapWeakResponse(weakResponse);491  const chunk = getChunk(response, 0);492  return chunk as any;493}494495function createPendingChunk<T>(response: Response): PendingChunk<T> {496  if (__DEV__) {497    // Retain a strong reference to the Response while we wait for the result.498    if (response._pendingChunks++ === 0) {499      response._weakResponse.response = response;500      if (response._pendingInitialRender !== null) {501        clearTimeout(response._pendingInitialRender);502        response._pendingInitialRender = null;503      }504    }505  }506  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors507  return new ReactPromise(PENDING, null, null);508}509510function createPendingWeakChunk<T>(response: Response): PendingWeakChunk<T> {511  // Unlike a regular pending chunk, a weak chunk may never settle, so it512  // doesn't retain a strong reference to the Response while it waits.513  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors514  return new ReactPromise(PENDING_WEAK, null, null);515}516517function releasePendingChunk(response: Response, chunk: SomeChunk<any>): void {518  if (__DEV__ && chunk.status === PENDING) {519    if (--response._pendingChunks === 0) {520      // We're no longer waiting for any more chunks. We can release the strong reference521      // to the response. We'll regain it if we ask for any more data later on.522      response._weakResponse.response = null;523      // Wait a short period to see if any more chunks get asked for. E.g. by a React render.524      // These chunks might discover more pending chunks.525      // If we don't ask for more then we assume that those chunks weren't blocking initial526      // render and are excluded from the performance track.527      response._pendingInitialRender = setTimeout(528        flushInitialRenderPerformance.bind(null, response),529        100,530      );531    }532  }533}534535function createHaltedChunk<T>(response: Response): HaltedChunk<T> {536  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors537  return new ReactPromise(HALTED, null, null);538}539540// Transition a chunk to HALTED: it will never resolve, even when the541// connection closes. Clears any listeners to release their closures. Future542// .then() calls on HALTED chunks are no-ops.543function haltChunk<T>(response: Response, chunk: SomeChunk<T>): void {544  releasePendingChunk(response, chunk);545  const haltedChunk: HaltedChunk<T> = chunk as any;546  haltedChunk.status = HALTED;547  haltedChunk.value = null;548  haltedChunk.reason = null;549}550551function createBlockedChunk<T>(response: Response): BlockedChunk<T> {552  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors553  return new ReactPromise(BLOCKED, null, null);554}555556function createErrorChunk<T>(557  response: Response,558  error: mixed,559): ErroredChunk<T> {560  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors561  return new ReactPromise(ERRORED, null, error);562}563564function filterDebugInfo(565  response: Response,566  value: {_debugInfo: ReactDebugInfo, ...},567) {568  if (response._debugEndTime === null) {569    // No end time was defined, so we keep all debug info entries.570    return;571  }572573  // Remove any debug info entries after the defined end time. For async info574  // that means we're including anything that was awaited before the end time,575  // but it doesn't need to be resolved before the end time.576  const relativeEndTime =577    response._debugEndTime -578    // $FlowFixMe[prop-missing]579    performance.timeOrigin;580  const debugInfo = [];581  for (let i = 0; i < value._debugInfo.length; i++) {582    const info = value._debugInfo[i];583    if (typeof info.time === 'number' && info.time > relativeEndTime) {584      break;585    }586    debugInfo.push(info);587  }588  value._debugInfo = debugInfo;589}590591function pruneDebugInfoAfterError(592  response: Response,593  chunk: ErroredChunk<any>,594): void {595  if (response._debugEndTime === null) {596    return;597  }598599  const relativeEndTime =600    response._debugEndTime -601    // $FlowFixMe[prop-missing]602    performance.timeOrigin;603  const debugInfo = chunk._debugInfo;604  for (let i = 0; i < debugInfo.length; i++) {605    const info = debugInfo[i];606    if (typeof info.time === 'number' && info.time > relativeEndTime) {607      // This array may already be attached to the Lazy suspended in Fizz.608      debugInfo.length = i;609      return;610    }611  }612}613614function moveDebugInfoFromChunkToInnerValue<T>(615  chunk: InitializedChunk<T> | InitializedStreamChunk<any>,616  value: T,617): void {618  // Remove the debug info from the initialized chunk, and add it to the inner619  // value instead. This can be a React element, an array, or an uninitialized620  // Lazy.621  const resolvedValue = resolveLazy(value);622  if (623    typeof resolvedValue === 'object' &&624    resolvedValue !== null &&625    (isArray(resolvedValue) ||626      typeof resolvedValue[ASYNC_ITERATOR] === 'function' ||627      resolvedValue.$$typeof === REACT_ELEMENT_TYPE ||628      resolvedValue.$$typeof === REACT_LAZY_TYPE)629  ) {630    const debugInfo = chunk._debugInfo.splice(0);631    if (isArray(resolvedValue._debugInfo)) {632      // $FlowFixMe[method-unbinding]633      resolvedValue._debugInfo.unshift.apply(634        resolvedValue._debugInfo,635        debugInfo,636      );637    } else if (!Object.isFrozen(resolvedValue)) {638      Object.defineProperty(resolvedValue as any, '_debugInfo', {639        configurable: false,640        enumerable: false,641        writable: true,642        value: debugInfo,643      });644    }645    // TODO: If the resolved value is a frozen element (e.g. a client-created646    // element from a temporary reference, or a JSX element exported as a client647    // reference), server debug info is currently dropped because the element648    // can't be mutated. We should probably clone the element so each rendering649    // context gets its own mutable copy with the correct debug info.650  }651}652653function processChunkDebugInfo<T>(654  response: Response,655  chunk: InitializedChunk<T> | InitializedStreamChunk<any>,656  value: T,657): void {658  filterDebugInfo(response, chunk);659  moveDebugInfoFromChunkToInnerValue(chunk, value);660}661662function wakeChunk<T>(663  response: Response,664  listeners: Array<InitializationReference | (T => mixed)>,665  value: T,666  chunk: InitializedChunk<T>,667): void {668  for (let i = 0; i < listeners.length; i++) {669    const listener = listeners[i];670    if (typeof listener === 'function') {671      listener(value);672    } else {673      fulfillReference(response, listener, value, chunk);674    }675  }676677  if (__DEV__) {678    processChunkDebugInfo(response, chunk, value);679  }680}681682function rejectChunk(683  response: Response,684  listeners: Array<InitializationReference | (mixed => mixed)>,685  error: mixed,686): void {687  for (let i = 0; i < listeners.length; i++) {688    const listener = listeners[i];689    if (typeof listener === 'function') {690      listener(error);691    } else {692      rejectReference(response, listener.handler, error);693    }694  }695}696697function resolveBlockedCycle<T>(698  resolvedChunk: SomeChunk<T>,699  reference: InitializationReference,700): null | InitializationHandler {701  const referencedChunk = reference.handler.chunk;702  if (referencedChunk === null) {703    return null;704  }705  if (referencedChunk === resolvedChunk) {706    // We found the cycle. We can resolve the blocked cycle now.707    return reference.handler;708  }709  const resolveListeners = referencedChunk.value;710  if (resolveListeners !== null) {711    for (let i = 0; i < resolveListeners.length; i++) {712      const listener = resolveListeners[i];713      if (typeof listener !== 'function') {714        const foundHandler = resolveBlockedCycle(resolvedChunk, listener);715        if (foundHandler !== null) {716          return foundHandler;717        }718      }719    }720  }721  return null;722}723724function wakeChunkIfInitialized<T>(725  response: Response,726  chunk: SomeChunk<T>,727  resolveListeners: Array<InitializationReference | (T => mixed)>,728  rejectListeners: null | Array<InitializationReference | (mixed => mixed)>,729): void {730  switch (chunk.status) {731    case INITIALIZED:732      wakeChunk(response, resolveListeners, chunk.value, chunk);733      break;734    case BLOCKED:735      // It is possible that we're blocked on our own chunk if it's a cycle.736      // Before adding back the listeners to the chunk, let's check if it would737      // result in a cycle.738      for (let i = 0; i < resolveListeners.length; i++) {739        const listener = resolveListeners[i];740        if (typeof listener !== 'function') {741          const reference: InitializationReference = listener;742          const cyclicHandler = resolveBlockedCycle(chunk, reference);743          if (cyclicHandler !== null) {744            // This reference points back to this chunk. We can resolve the cycle by745            // using the value from that handler.746            fulfillReference(response, reference, cyclicHandler.value, chunk);747            resolveListeners.splice(i, 1);748            i--;749            if (rejectListeners !== null) {750              const rejectionIdx = rejectListeners.indexOf(reference);751              if (rejectionIdx !== -1) {752                rejectListeners.splice(rejectionIdx, 1);753              }754            }755            // The status might have changed after fulfilling the reference.756            switch ((chunk as SomeChunk<T>).status) {757              case INITIALIZED:758                const initializedChunk: InitializedChunk<T> = chunk as any;759                wakeChunk(760                  response,761                  resolveListeners,762                  initializedChunk.value,763                  initializedChunk,764                );765                return;766              case ERRORED:767                if (rejectListeners !== null) {768                  rejectChunk(response, rejectListeners, chunk.reason);769                }770                return;771            }772          }773        }774      }775    // Fallthrough776    case PENDING:777      if (chunk.value) {778        for (let i = 0; i < resolveListeners.length; i++) {779          chunk.value.push(resolveListeners[i]);780        }781      } else {782        chunk.value = resolveListeners;783      }784785      if (chunk.reason) {786        if (rejectListeners) {787          for (let i = 0; i < rejectListeners.length; i++) {788            chunk.reason.push(rejectListeners[i]);789          }790        }791      } else {792        chunk.reason = rejectListeners;793      }794795      break;796    case ERRORED:797      if (rejectListeners) {798        rejectChunk(response, rejectListeners, chunk.reason);799      }800      break;801  }802}803804function triggerErrorOnChunk<T>(805  response: Response,806  chunk: SomeChunk<T>,807  error: mixed,808): void {809  if (810    chunk.status !== PENDING &&811    chunk.status !== PENDING_WEAK &&812    chunk.status !== BLOCKED813  ) {814    // If we get more data to an already resolved ID, we assume that it's815    // a stream chunk since any other row shouldn't have more than one entry.816    const streamChunk: InitializedStreamChunk<any> = chunk as any;817    const controller = streamChunk.reason;818    // $FlowFixMe[incompatible-type]: The error method should accept mixed.819    controller.error(error);820    return;821  }822  releasePendingChunk(response, chunk);823  const listeners = chunk.reason;824825  if (__DEV__ && (chunk.status === PENDING || chunk.status === PENDING_WEAK)) {826    // Lazily initialize any debug info and block the initializing chunk on any unresolved entries.827    if (chunk._debugChunk != null) {828      const prevHandler = initializingHandler;829      const prevChunk = initializingChunk;830      initializingHandler = null;831      const cyclicChunk: BlockedChunk<T> = chunk as any;832      cyclicChunk.status = BLOCKED;833      cyclicChunk.value = null;834      cyclicChunk.reason = null;835      if ((enableProfilerTimer && enableComponentPerformanceTrack) || __DEV__) {836        initializingChunk = cyclicChunk;837      }838      try {839        initializeDebugChunk(response, chunk);840        if (initializingHandler !== null) {841          if (initializingHandler.errored) {842            // Ignore error parsing debug info, we'll report the original error instead.843          } else if (initializingHandler.deps > 0) {844            // TODO: Block the resolution of the error until all the debug info has loaded.845            // We currently don't have a way to throw an error after all dependencies have846            // loaded because we currently treat errors as immediately cancelling the handler.847          }848        }849      } finally {850        initializingHandler = prevHandler;851        initializingChunk = prevChunk;852      }853    }854  }855856  const erroredChunk: ErroredChunk<T> = chunk as any;857  erroredChunk.status = ERRORED;858  erroredChunk.reason = error;859  if (__DEV__) {860    pruneDebugInfoAfterError(response, erroredChunk);861  }862  if (listeners !== null) {863    rejectChunk(response, listeners, error);864  }865}866867function createResolvedModelChunk<T>(868  response: Response,869  value: UninitializedModel,870): ResolvedModelChunk<T> {871  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors872  return new ReactPromise(RESOLVED_MODEL, value, {[RESPONSE_SYMBOL]: response});873}874875function createResolvedModuleChunk<T>(876  response: Response,877  value: ClientReference<T>,878): ResolvedModuleChunk<T> {879  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors880  return new ReactPromise(RESOLVED_MODULE, value, null);881}882883function createInitializedTextChunk(884  response: Response,885  value: string,886): InitializedChunk<string> {887  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors888  return new ReactPromise(INITIALIZED, value, null);889}890891function createInitializedBufferChunk(892  response: Response,893  value: $ArrayBufferView | ArrayBuffer,894): InitializedChunk<Uint8Array> {895  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors896  return new ReactPromise(INITIALIZED, value, null);897}898899function createInitializedIteratorResultChunk<T>(900  response: Response,901  value: T,902  done: boolean,903): InitializedChunk<IteratorResult<T, T>> {904  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors905  return new ReactPromise(INITIALIZED, {done: done, value: value}, null);906}907908function createInitializedStreamChunk<909  T: ReadableStream | $AsyncIterable<any, any, void>,910>(911  response: Response,912  value: T,913  controller: FlightStreamController,914): InitializedChunk<T> {915  if (__DEV__) {916    // Retain a strong reference to the Response while we wait for chunks.917    if (response._pendingChunks++ === 0) {918      response._weakResponse.response = response;919    }920  }921  // We use the reason field to stash the controller since we already have that922  // field. It's a bit of a hack but efficient.923  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors924  return new ReactPromise(INITIALIZED, value, controller);925}926927function createResolvedIteratorResultChunk<T>(928  response: Response,929  value: UninitializedModel,930  done: boolean,931): ResolvedModelChunk<IteratorResult<T, T>> {932  // To reuse code as much code as possible we add the wrapper element as part of the JSON.933  const iteratorResultJSON =934    (done ? '{"done":true,"value":' : '{"done":false,"value":') + value + '}';935  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors936  return new ReactPromise(RESOLVED_MODEL, iteratorResultJSON, {937    [RESPONSE_SYMBOL]: response,938  });939}940941function resolveIteratorResultChunk<T>(942  response: Response,943  chunk: SomeChunk<IteratorResult<T, T>>,944  value: UninitializedModel,945  done: boolean,946): void {947  // To reuse code as much code as possible we add the wrapper element as part of the JSON.948  const iteratorResultJSON =949    (done ? '{"done":true,"value":' : '{"done":false,"value":') + value + '}';950  resolveModelChunk(response, chunk, iteratorResultJSON);951}952953function resolveModelChunk<T>(954  response: Response,955  chunk: SomeChunk<T>,956  value: UninitializedModel,957): void {958  if (chunk.status !== PENDING && chunk.status !== PENDING_WEAK) {959    // If we get more data to an already resolved ID, we assume that it's960    // a stream chunk since any other row shouldn't have more than one entry.961    const streamChunk: InitializedStreamChunk<any> = chunk as any;962    const controller = streamChunk.reason;963    controller.enqueueModel(value);964    return;965  }966  releasePendingChunk(response, chunk);967  const resolveListeners = chunk.value;968  const rejectListeners = chunk.reason;969  const resolvedChunk: ResolvedModelChunk<T> = chunk as any;970  resolvedChunk.status = RESOLVED_MODEL;971  resolvedChunk.value = value;972  resolvedChunk.reason = {[RESPONSE_SYMBOL]: response};973  if (resolveListeners !== null) {974    // This is unfortunate that we're reading this eagerly if975    // we already have listeners attached since they might no976    // longer be rendered or might not be the highest pri.977    initializeModelChunk(resolvedChunk);978    // The status might have changed after initialization.979    wakeChunkIfInitialized(response, chunk, resolveListeners, rejectListeners);980  }981}982983function resolveModuleChunk<T>(984  response: Response,985  chunk: SomeChunk<T>,986  value: ClientReference<T>,987): void {988  if (989    chunk.status !== PENDING &&990    chunk.status !== PENDING_WEAK &&991    chunk.status !== BLOCKED992  ) {993    // We already resolved. We didn't expect to see this.994    return;995  }996  releasePendingChunk(response, chunk);997  const resolveListeners = chunk.value;998  const rejectListeners = chunk.reason;999  const resolvedChunk: ResolvedModuleChunk<T> = chunk as any;1000  resolvedChunk.status = RESOLVED_MODULE;1001  resolvedChunk.value = value;1002  resolvedChunk.reason = null;1003  if (__DEV__) {1004    const debugInfo = getModuleDebugInfo(value);1005    if (debugInfo !== null) {1006      // Add to the live set if it was already initialized.1007      // $FlowFixMe[method-unbinding]1008      resolvedChunk._debugInfo.push.apply(resolvedChunk._debugInfo, debugInfo);1009    }1010  }1011  if (resolveListeners !== null) {1012    initializeModuleChunk(resolvedChunk);1013    wakeChunkIfInitialized(response, chunk, resolveListeners, rejectListeners);1014  }1015}10161017type InitializationReference = {1018  handler: InitializationHandler,1019  parentObject: Object,1020  key: string,1021  map: (1022    response: Response,1023    model: any,1024    parentObject: Object,1025    key: string,1026  ) => any,1027  path: Array<string>,1028  isDebug?: boolean, // DEV-only1029};1030type PendingInitializationHandler = {1031  parent: null | InitializationHandler,1032  chunk: null | BlockedChunk<any>,1033  value: any,1034  // The controller of a stream whose chunk is blocked on its debug info. Null1035  // for every other model.1036  reason: null | FlightStreamController,1037  deps: number,1038  errored: false,1039};1040type ErroredInitializationHandler = {1041  parent: null | InitializationHandler,1042  chunk: null | BlockedChunk<any>,1043  value: null,1044  // The error the handler was rejected with.1045  reason: mixed,1046  deps: number,1047  errored: true,1048};1049type InitializationHandler =1050  | PendingInitializationHandler1051  | ErroredInitializationHandler;1052let initializingHandler: null | InitializationHandler = null;1053let initializingChunk: null | BlockedChunk<any> = null;1054let isInitializingDebugInfo: boolean = false;10551056function initializeDebugChunk(1057  response: Response,1058  chunk: ResolvedModelChunk<any> | PendingChunk<any> | PendingWeakChunk<any>,1059): void {1060  const debugChunk = chunk._debugChunk;1061  if (debugChunk !== null) {1062    const debugInfo = chunk._debugInfo;1063    const prevIsInitializingDebugInfo = isInitializingDebugInfo;1064    isInitializingDebugInfo = true;1065    try {1066      if (debugChunk.status === RESOLVED_MODEL) {1067        // Find the index of this debug info by walking the linked list.1068        let idx = debugInfo.length;1069        let c = debugChunk._debugChunk;1070        while (c !== null) {1071          if (c.status !== INITIALIZED) {1072            idx++;1073          }1074          c = c._debugChunk;1075        }1076        // Initializing the model for the first time.1077        initializeModelChunk(debugChunk);1078        const initializedChunk = debugChunk as any as SomeChunk<any>;1079        switch (initializedChunk.status) {1080          case INITIALIZED: {1081            debugInfo[idx] = initializeDebugInfo(1082              response,1083              initializedChunk.value,1084            );1085            break;1086          }1087          case BLOCKED:1088          case PENDING:1089          case PENDING_WEAK: {1090            waitForReference(1091              initializedChunk,1092              debugInfo,1093              '' + idx,1094              response,1095              initializeDebugInfo,1096              [''], // path1097              true,1098            );1099            break;1100          }1101          default:1102            throw initializedChunk.reason;1103        }1104      } else {1105        switch (debugChunk.status) {1106          case INITIALIZED: {1107            // Already done.1108            break;1109          }1110          case BLOCKED:1111          case PENDING:1112          case PENDING_WEAK: {1113            // Signal to the caller that we need to wait.1114            waitForReference(1115              debugChunk,1116              {}, // noop, since we'll have already added an entry to debug info1117              'debug', // noop, but we need it to not be empty string since that indicates the root object1118              response,1119              initializeDebugInfo,1120              [''], // path1121              true,1122            );1123            break;1124          }1125          default:1126            throw debugChunk.reason;1127        }1128      }1129    } catch (error) {1130      triggerErrorOnChunk(response, chunk, error);1131    } finally {1132      isInitializingDebugInfo = prevIsInitializingDebugInfo;1133    }1134  }1135}11361137function initializeModelChunk<T>(chunk: ResolvedModelChunk<T>): void {1138  const prevHandler = initializingHandler;1139  const prevChunk = initializingChunk;1140  initializingHandler = null;11411142  const resolvedModel = chunk.value;1143  const response = chunk.reason[RESPONSE_SYMBOL];11441145  // We go to the BLOCKED state until we've fully resolved this.1146  // We do this before parsing in case we try to initialize the same chunk1147  // while parsing the model. Such as in a cyclic reference.1148  const cyclicChunk: BlockedChunk<T> = chunk as any;1149  cyclicChunk.status = BLOCKED;1150  cyclicChunk.value = null;1151  cyclicChunk.reason = null;11521153  if ((enableProfilerTimer && enableComponentPerformanceTrack) || __DEV__) {1154    initializingChunk = cyclicChunk;1155  }11561157  if (__DEV__) {1158    // Initialize any debug info and block the initializing chunk on any1159    // unresolved entries.1160    initializeDebugChunk(response, chunk);1161    // TODO: The chunk might have transitioned to ERRORED now.1162    // Should we return early if that happens?1163  }11641165  try {1166    const value: T = parseModel(response, resolvedModel);1167    const handler = initializingHandler;1168    if (handler !== null) {1169      if (handler.errored) {1170        // The handler errored during the parse, so `cyclicChunk` errors with1171        // the same reason. `triggerErrorOnChunk` also rejects the references1172        // that nested parses queued on `cyclicChunk` during the parse. No value1173        // will arrive for them. `initializeDebugChunk` can have errored1174        // `cyclicChunk` before the parse. That error stays.1175        if ((cyclicChunk as any).status === BLOCKED) {1176          triggerErrorOnChunk(response, cyclicChunk, handler.reason);1177        }1178        return;1179      }1180      // Record on the handler which chunk it completes, and with what value,1181      // before the listeners below are examined. `resolveBlockedCycle` walks1182      // from a reference to its handler and on to that handler's chunk. A cycle1183      // that closes through `cyclicChunk` is only found once `handler.chunk` is1184      // `cyclicChunk`.1185      handler.value = value;1186      handler.chunk = cyclicChunk;1187    }11881189    const listeners = cyclicChunk.value;1190    const rejectListeners = cyclicChunk.reason;1191    cyclicChunk.value = null;1192    cyclicChunk.reason = null;1193    if (listeners !== null) {1194      // These listeners were added to `cyclicChunk` while its model was1195      // parsing. They come from models that were parsed nested inside that1196      // parse and that pointed back at `cyclicChunk`. They fall in two groups.1197      //1198      // A reference whose handler is transitively waiting on `cyclicChunk` is a1199      // cycle. Neither side can complete before the other, so one of them has1200      // to accept the value as it is now. The reference receives the current1201      // object, and the outstanding references fill it in place.1202      //1203      // Every other listener waits. Its handler is not waiting on1204      // `cyclicChunk`, so it can receive the value once the model has resolved1205      // its own references, like any reference into a blocked chunk does.1206      // Handing it the value now would complete that handler with an object1207      // that still has references outstanding. Function listeners have no1208      // handler and always wait.1209      let cyclic: null | Array<InitializationReference> = null;1210      let deferred: null | Array<InitializationReference | (T => mixed)> = null;1211      for (let i = 0; i < listeners.length; i++) {1212        const listener = listeners[i];1213        if (1214          typeof listener !== 'function' &&1215          resolveBlockedCycle(cyclicChunk, listener) !== null1216        ) {1217          if (cyclic === null) {1218            cyclic = [];1219          }1220          cyclic.push(listener);1221          // A reference is queued for rejection as the same object that is1222          // queued for resolution. It is fulfilled below, so its rejection1223          // entry goes.1224          if (rejectListeners !== null) {1225            const rejectionIdx = rejectListeners.indexOf(listener);1226            if (rejectionIdx !== -1) {1227              rejectListeners.splice(rejectionIdx, 1);1228            }1229          }1230        } else {1231          if (deferred === null) {1232            deferred = [];1233          }1234          deferred.push(listener);1235        }1236      }1237      // Put the deferred listeners back on `cyclicChunk` before any cyclic1238      // reference is fulfilled. Fulfilling one can complete `cyclicChunk`, and1239      // completion wakes what is queued on it at that moment.1240      if (deferred !== null) {1241        cyclicChunk.value = deferred;1242        cyclicChunk.reason = rejectListeners;1243      }1244      if (cyclic !== null) {1245        for (let i = 0; i < cyclic.length; i++) {1246          fulfillReference(response, cyclic[i], value, cyclicChunk);1247        }1248      }1249    }12501251    if ((cyclicChunk as any).status !== BLOCKED) {1252      // Fulfilling a cyclic reference completed `cyclicChunk`, or failed and1253      // errored it. A failure rejects the reference's handler. The rejection1254      // reaches `cyclicChunk`, directly or through the cycle, because1255      // `handler.chunk` is set.1256      return;1257    }1258    if (handler !== null && handler.deps > 0) {1259      // The model references chunks that have not resolved yet. `cyclicChunk`1260      // stays BLOCKED, with the deferred listeners queued on it, until the last1261      // of those resolves.1262      return;1263    }1264    initializeBlockedChunk(response, cyclicChunk, value, null);1265  } catch (error) {1266    const erroredChunk: ErroredChunk<T> = chunk as any;1267    erroredChunk.status = ERRORED;1268    erroredChunk.reason = error;1269  } finally {1270    initializingHandler = prevHandler;1271    if ((enableProfilerTimer && enableComponentPerformanceTrack) || __DEV__) {1272      initializingChunk = prevChunk;1273    }1274  }1275}12761277function initializeModuleChunk<T>(chunk: ResolvedModuleChunk<T>): void {1278  try {1279    const value: T = requireModule(chunk.value);1280    const initializedChunk: InitializedChunk<T> = chunk as any;1281    initializedChunk.status = INITIALIZED;1282    initializedChunk.value = value;1283    initializedChunk.reason = null;1284  } catch (error) {1285    const erroredChunk: ErroredChunk<T> = chunk as any;1286    erroredChunk.status = ERRORED;1287    erroredChunk.reason = error;1288  }1289}12901291// Report that any missing chunks in the model is now going to throw this1292// error upon read. Also notify any pending promises.1293export function reportGlobalError(1294  weakResponse: WeakResponse,1295  error: Error,1296): void {1297  if (hasGCedResponse(weakResponse)) {1298    // Ignore close signal if we are not awaiting any more pending chunks.1299    return;1300  }1301  const response = unwrapWeakResponse(weakResponse);1302  response._closed = true;1303  response._closedReason = error;1304  response._chunks.forEach(chunk => {1305    // If this chunk was already resolved or errored, it won't1306    // trigger an error but if it wasn't then we need to1307    // because we won't be getting any new data to resolve it.1308    if (chunk.status === PENDING) {1309      triggerErrorOnChunk(response, chunk, error);1310    } else if (enableFlightWeakThenables && chunk.status === PENDING_WEAK) {1311      // A weak Promise reference may never be emitted by the server. It1312      // stays forever pending instead of erroring.1313      haltChunk(response, chunk);1314    } else if (chunk.status === INITIALIZED && chunk.reason !== null) {1315      chunk.reason.error(error);1316    }1317  });1318  if (__DEV__) {1319    const debugChannel = response._debugChannel;1320    if (debugChannel !== undefined) {1321      // If we don't have any more ways of reading data, we don't have to send1322      // any more neither. So we close the writable side.1323      closeDebugChannel(debugChannel);1324      response._debugChannel = undefined;1325      // Make sure the debug channel is not closed a second time when the1326      // Response gets GC:ed.1327      if (debugChannelRegistry !== null) {1328        debugChannelRegistry.unregister(response);1329      }1330    }1331  }1332}13331334function nullRefGetter() {1335  if (__DEV__) {1336    return null;1337  }1338}13391340function getIOInfoTaskName(ioInfo: ReactIOInfo): string {1341  return ioInfo.name || 'unknown';1342}13431344function getAsyncInfoTaskName(asyncInfo: ReactAsyncInfo): string {1345  return 'await ' + getIOInfoTaskName(asyncInfo.awaited);1346}13471348function getServerComponentTaskName(componentInfo: ReactComponentInfo): string {1349  return '<' + (componentInfo.name || '...') + '>';1350}13511352function getTaskName(type: mixed): string {1353  if (type === REACT_FRAGMENT_TYPE) {1354    return '<>';1355  }1356  if (typeof type === 'function') {1357    // This is a function so it must have been a Client Reference that resolved to1358    // a function. We use "use client" to indicate that this is the boundary into1359    // the client. There should only be one for any given owner chain.1360    return '"use client"';1361  }1362  if (1363    typeof type === 'object' &&1364    type !== null &&1365    type.$$typeof === REACT_LAZY_TYPE1366  ) {1367    if (type._payload instanceof ReactPromise) {1368      // This is a lazy node created by Flight, i.e. it wraps a chunk. It is1369      // probably a client reference. We use the "use client" string to indicate1370      // that this is the boundary into the client. There will only be one for1371      // any given owner chain.1372      return '"use client"';1373    }1374    // We don't want to eagerly initialize the initializer in DEV mode so we can't1375    // call it to extract the type so we don't know the type of this component.1376    return '<...>';1377  }1378  try {1379    const name = getComponentNameFromType(type);1380    return name ? '<' + name + '>' : '<...>';1381  } catch (x) {1382    return '<...>';1383  }1384}13851386function initializeElement(1387  response: Response,1388  element: any,1389  lazyNode: null | LazyComponent<1390    React$Element<any>,1391    SomeChunk<React$Element<any>>,1392  >,1393): void {1394  if (!__DEV__) {1395    return;1396  }1397  const stack = element._debugStack;1398  const owner = element._owner;1399  if (owner === null) {1400    element._owner = response._debugRootOwner;1401  }1402  let env = response._rootEnvironmentName;1403  if (owner !== null && owner.env != null) {1404    // Interestingly we don't actually have the environment name of where1405    // this JSX was created if it doesn't have an owner but if it does1406    // it must be the same environment as the owner. We could send it separately1407    // but it seems a bit unnecessary for this edge case.1408    env = owner.env;1409  }1410  let normalizedStackTrace: null | Error = null;1411  if (owner === null && response._debugRootStack != null) {1412    // We override the stack if we override the owner since the stack where the root JSX1413    // was created on the server isn't very useful but where the request was made is.1414    normalizedStackTrace = response._debugRootStack;1415  } else if (stack !== null) {1416    // We create a fake stack and then create an Error object inside of it.1417    // This means that the stack trace is now normalized into the native format1418    // of the browser and the stack frames will have been registered with1419    // source mapping information.1420    // This can unfortunately happen within a user space callstack which will1421    // remain on the stack.1422    normalizedStackTrace = createFakeJSXCallStackInDEV(response, stack, env);1423  }1424  element._debugStack = normalizedStackTrace;1425  let task: null | ConsoleTask = null;1426  if (supportsCreateTask && stack !== null) {1427    const createTaskFn = (console as any).createTask.bind(1428      console,1429      getTaskName(element.type),1430    );1431    const callStack = buildFakeCallStack(1432      response,1433      stack,1434      env,1435      false,1436      createTaskFn,1437    );1438    // This owner should ideally have already been initialized to avoid getting1439    // user stack frames on the stack.1440    const ownerTask =1441      owner === null ? null : initializeFakeTask(response, owner);1442    if (ownerTask === null) {1443      const rootTask = response._debugRootTask;1444      if (rootTask != null) {1445        task = rootTask.run(callStack);1446      } else {1447        task = callStack();1448      }1449    } else {1450      task = ownerTask.run(callStack);1451    }1452  }1453  element._debugTask = task;14541455  // This owner should ideally have already been initialized to avoid getting1456  // user stack frames on the stack.1457  if (owner !== null) {1458    initializeFakeStack(response, owner);1459  }14601461  if (lazyNode !== null) {1462    // If the lazy node is initialized, we move its debug info to the inner1463    // value.1464    if (lazyNode._payload.status === INITIALIZED && lazyNode._debugInfo) {1465      const debugInfo = lazyNode._debugInfo.splice(0);1466      if (element._debugInfo) {1467        // $FlowFixMe[method-unbinding]1468        element._debugInfo.unshift.apply(element._debugInfo, debugInfo);1469      } else {1470        Object.defineProperty(element, '_debugInfo', {1471          configurable: false,1472          enumerable: false,1473          writable: true,1474          value: debugInfo,1475        });1476      }1477    }1478  }14791480  // TODO: We should be freezing the element but currently, we might write into1481  // _debugInfo later. We could move it into _store which remains mutable.1482  Object.freeze(element.props);1483}14841485function createElement(1486  response: Response,1487  type: mixed,1488  key: mixed,1489  props: mixed,1490  owner: ?ReactComponentInfo, // DEV-only1491  stack: ?ReactStackTrace, // DEV-only1492  validated: 0 | 1 | 2, // DEV-only1493):1494  | React$Element<any>1495  | LazyComponent<React$Element<any>, SomeChunk<React$Element<any>>> {1496  let element: any;1497  if (__DEV__) {1498    // `ref` is non-enumerable in dev1499    element = {1500      $$typeof: REACT_ELEMENT_TYPE,1501      type,1502      key,1503      props,1504      _owner: owner === undefined ? null : owner,1505    } as any;1506    Object.defineProperty(element, 'ref', {1507      enumerable: false,1508      get: nullRefGetter,1509    });1510  } else {1511    element = {1512      // This tag allows us to uniquely identify this as a React Element1513      $$typeof: REACT_ELEMENT_TYPE,15141515      type,1516      key,1517      ref: null,1518      props,1519    } as any;1520  }15211522  if (__DEV__) {1523    // We don't really need to add any of these but keeping them for good measure.1524    // Unfortunately, _store is enumerable in jest matchers so for equality to1525    // work, I need to keep it or make _store non-enumerable in the other file.1526    element._store = {} as {1527      validated?: number,1528    };1529    Object.defineProperty(element._store, 'validated', {1530      configurable: false,1531      enumerable: false,1532      writable: true,1533      value: validated, // Whether the element has already been validated on the server.1534    });1535    // debugInfo contains Server Component debug information.1536    Object.defineProperty(element, '_debugInfo', {1537      configurable: false,1538      enumerable: false,1539      writable: true,1540      value: null,1541    });1542    Object.defineProperty(element, '_debugStack', {1543      configurable: false,1544      enumerable: false,1545      writable: true,1546      value: stack === undefined ? null : stack,1547    });1548    Object.defineProperty(element, '_debugTask', {1549      configurable: false,1550      enumerable: false,1551      writable: true,1552      value: null,1553    });1554  }15551556  if (initializingHandler !== null) {1557    const handler = initializingHandler;1558    // We pop the stack to the previous outer handler before leaving the Element.1559    // This is effectively the complete phase.1560    initializingHandler = handler.parent;1561    if (handler.errored) {1562      // Something errored inside this Element's props. We can turn this Element1563      // into a Lazy so that we can still render up until that Lazy is rendered.1564      const erroredChunk: ErroredChunk<React$Element<any>> = createErrorChunk(1565        response,1566        handler.reason,1567      );1568      if (__DEV__) {1569        initializeElement(response, element, null);1570        // Conceptually the error happened inside this Element but right before1571        // it was rendered. We don't have a client side component to render but1572        // we can add some DebugInfo to explain that this was conceptually a1573        // Server side error that errored inside this element. That way any stack1574        // traces will point to the nearest JSX that errored - e.g. during1575        // serialization.1576        const erroredComponent: ReactComponentInfo = {1577          name: getComponentNameFromType(element.type) || '',1578          owner: element._owner,1579        };1580        // $FlowFixMe[cannot-write]1581        erroredComponent.debugStack = element._debugStack;1582        if (supportsCreateTask) {1583          // $FlowFixMe[cannot-write]1584          erroredComponent.debugTask = element._debugTask;1585        }1586        erroredChunk._debugInfo = [erroredComponent];1587      }1588      return createLazyChunkWrapper(erroredChunk, validated);1589    }1590    if (handler.deps > 0) {1591      // We have blocked references inside this Element but we can turn this into1592      // a Lazy node referencing this Element to let everything around it proceed.1593      const blockedChunk: BlockedChunk<React$Element<any>> =1594        createBlockedChunk(response);1595      handler.value = element;1596      handler.chunk = blockedChunk;1597      const lazyNode = createLazyChunkWrapper(blockedChunk, validated);1598      if (__DEV__) {1599        // After we have initialized any blocked references, initialize stack etc.1600        const init = initializeElement.bind(null, response, element, lazyNode);1601        blockedChunk.then(init, init);1602      }1603      return lazyNode;1604    }1605  }1606  if (__DEV__) {1607    initializeElement(response, element, null);1608  }16091610  return element;1611}16121613function transferValidation(store: {validated: 0 | 1 | 2}, value: mixed): void {1614  if (store.validated && typeof value === 'object' && value !== null) {1615    // Only elements and lazy nodes carry key validation. Any other value, e.g.1616    // an array of children, needs to have its own items validated instead.1617    const $$typeof = (value as any).$$typeof;1618    if ($$typeof === REACT_ELEMENT_TYPE || $$typeof === REACT_LAZY_TYPE) {1619      const valueStore = (value as any)._store;1620      if (valueStore && !valueStore.validated) {1621        valueStore.validated = store.validated;1622      }1623    }1624  }1625}16261627function readChunkAndTransferValidation<T>(1628  store: {validated: 0 | 1 | 2},1629  payload: SomeChunk<T>,1630): T {1631  const value: T = readChunk(payload);1632  transferValidation(store, value);1633  return value;1634}16351636function createLazyChunkWrapper<T>(1637  chunk: SomeChunk<T>,1638  validated: 0 | 1 | 2, // DEV-only1639): LazyComponent<T, SomeChunk<T>> {1640  const lazyType: LazyComponent<T, SomeChunk<T>> = {1641    $$typeof: REACT_LAZY_TYPE,1642    _payload: chunk,1643    _init: readChunk,1644  };1645  if (__DEV__) {1646    // Forward the live array1647    lazyType._debugInfo = chunk._debugInfo;1648    // Initialize a store for key validation by the JSX runtime. It can only1649    // validate the lazy node itself, because the value it refers to might not1650    // exist yet at that point, e.g. if it's an outlined row that hasn't been1651    // initialized. So the validation is transferred to the value when the lazy1652    // node is unwrapped. If the value is another lazy node, unwrapping that one1653    // forwards the validation further.1654    const store = {validated: validated};1655    lazyType._store = store;1656    // $FlowFixMe[incompatible-type] `bind` loses the type argument.1657    lazyType._init = readChunkAndTransferValidation.bind(null, store);1658  }1659  return lazyType;1660}16611662function getChunk(response: Response, id: number): SomeChunk<any> {1663  const chunks = response._chunks;1664  let chunk = chunks.get(id);1665  if (!chunk) {1666    if (response._closed) {1667      if (response._allowPartialStream) {1668        // For partial streams, chunks accessed after close should be HALTED1669        // (never resolve).1670        chunk = createHaltedChunk(response);1671      } else {1672        // We have already errored the response and we're not going to get1673        // anything more streaming in so this will immediately error.1674        chunk = createErrorChunk(response, response._closedReason);1675      }1676    } else {1677      chunk = createPendingChunk(response);1678    }1679    chunks.set(id, chunk);1680  }1681  return chunk;1682}16831684// Like getChunk, but for weak Promise references. The server may never emit1685// the row for a weak reference, so an unresolved weak chunk halts (stays1686// forever pending) instead of erroring when the stream closes.1687function getWeakChunk(response: Response, id: number): SomeChunk<any> {1688  const chunks = response._chunks;1689  let chunk = chunks.get(id);1690  if (!chunk) {1691    if (response._closed) {1692      // The stream already closed without emitting this row, so it will1693      // never resolve.1694      chunk = createHaltedChunk(response);1695    } else {1696      chunk = createPendingWeakChunk(response);1697    }1698    chunks.set(id, chunk);1699  }1700  return chunk;1701}17021703// Moves a blocked chunk to INITIALIZED and wakes whatever is waiting on it. The1704// other `initialize*Chunk` functions start from a resolved chunk and parse it.1705// This one starts from a chunk whose model is already parsed and whose1706// references have all resolved.1707function initializeBlockedChunk<T>(1708  response: Response,1709  chunk: BlockedChunk<T>,1710  value: T,1711  reason: InitializedChunk<T>['reason'],1712): void {1713  const resolveListeners = chunk.value;1714  if (__DEV__) {1715    // Only a blocked chunk receives debug info, so release the set here.1716    chunk._receivedDebugInfo = null;1717  }1718  const initializedChunk: InitializedChunk<T> = chunk as any;1719  initializedChunk.status = INITIALIZED;1720  initializedChunk.value = value;1721  initializedChunk.reason = reason;1722  if (resolveListeners !== null) {1723    wakeChunk(response, resolveListeners, value, initializedChunk);1724  } else if (__DEV__) {1725    processChunkDebugInfo(response, initializedChunk, value);1726  }1727}17281729// Initializes the handler's chunk once the handler has no references left to1730// wait on. `handler.chunk` is null while the handler's model is still parsing.1731// `initializeModelChunk` handles that case when the parse ends.1732function initializeChunkIfUnblocked(1733  response: Response,1734  handler: InitializationHandler,1735): void {1736  if (handler.deps !== 0 || handler.errored) {1737    return;1738  }1739  const chunk = handler.chunk;1740  if (chunk === null) {1741    return;1742  }1743  // `BlockedChunk` is the chunk's type at the time the handler recorded it.1744  // The chunk can have errored since, or a cyclic reference can have completed1745  // it, so its status is read again here.1746  if ((chunk as SomeChunk<any>).status !== BLOCKED) {1747    return;1748  }1749  // `handler.reason` is the controller of a stream whose chunk was blocked on1750  // its debug info, and null otherwise. It becomes the initialized chunk's1751  // `reason` either way.1752  initializeBlockedChunk(response, chunk, handler.value, handler.reason);1753}17541755function fulfillReference(1756  response: Response,1757  reference: InitializationReference,1758  value: any,1759  fulfilledChunk: SomeChunk<any>,1760): void {1761  const {handler, parentObject, key, map, path} = reference;17621763  try {1764    for (let i = 1; i < path.length; i++) {1765      while (1766        typeof value === 'object' &&1767        value !== null &&1768        value.$$typeof === REACT_LAZY_TYPE1769      ) {1770        // We never expect to see a Lazy node on this path because we encode those as1771        // separate models. This must mean that we have inserted an extra lazy node1772        // e.g. to replace a blocked element. We must instead look for it inside.1773        const referencedChunk: SomeChunk<any> = value._payload;1774        if (referencedChunk === handler.chunk) {1775          // This is a reference to the thing we're currently blocking. We can peak1776          // inside of it to get the value.1777          value = handler.value;1778          continue;1779        } else {1780          switch (referencedChunk.status) {1781            case RESOLVED_MODEL:1782              initializeModelChunk(referencedChunk);1783              break;1784            case RESOLVED_MODULE:1785              initializeModuleChunk(referencedChunk);1786              break;1787          }1788          switch (referencedChunk.status) {1789            case INITIALIZED: {1790              value = referencedChunk.value;1791              continue;1792            }1793            case BLOCKED: {1794              // It is possible that we're blocked on our own chunk if it's a cycle.1795              // Before adding the listener to the inner chunk, let's check if it would1796              // result in a cycle.1797              const cyclicHandler = resolveBlockedCycle(1798                referencedChunk,1799                reference,1800              );1801              if (cyclicHandler !== null) {1802                // This reference points back to this chunk. We can resolve the cycle by1803                // using the value from that handler.1804                value = cyclicHandler.value;1805                continue;1806              }1807              // Fallthrough1808            }1809            case PENDING:1810            case PENDING_WEAK: {1811              // If we're not yet initialized we need to skip what we've already drilled1812              // through and then wait for the next value to become available.1813              path.splice(0, i - 1);1814              // Add "listener" to our new chunk dependency.1815              if (referencedChunk.value === null) {1816                referencedChunk.value = [reference];1817              } else {1818                referencedChunk.value.push(reference);1819              }1820              if (referencedChunk.reason === null) {1821                referencedChunk.reason = [reference];1822              } else {1823                referencedChunk.reason.push(reference);1824              }1825              return;1826            }1827            case HALTED: {1828              // Do nothing. We couldn't fulfill.1829              // TODO: Mark downstreams as halted too.1830              return;1831            }1832            default: {1833              rejectReference(1834                response,1835                reference.handler,1836                referencedChunk.reason,1837              );1838              return;1839            }1840          }1841        }1842      }1843      const name = path[i];1844      if (1845        typeof value === 'object' &&1846        value !== null &&1847        hasOwnProperty.call(value, name)1848      ) {1849        value = value[name];1850      } else {1851        throw new Error('Invalid reference.');1852      }1853    }18541855    while (1856      typeof value === 'object' &&1857      value !== null &&1858      value.$$typeof === REACT_LAZY_TYPE1859    ) {1860      // If what we're referencing is a Lazy it must be because we inserted one as a virtual node1861      // while it was blocked by other data. If it's no longer blocked, we can unwrap it.1862      const referencedChunk: SomeChunk<any> = value._payload;1863      if (referencedChunk === handler.chunk) {1864        // This is a reference to the thing we're currently blocking. We can peak1865        // inside of it to get the value.1866        value = handler.value;1867        continue;1868      } else {1869        switch (referencedChunk.status) {1870          case RESOLVED_MODEL:1871            initializeModelChunk(referencedChunk);1872            break;1873          case RESOLVED_MODULE:1874            initializeModuleChunk(referencedChunk);1875            break;1876        }1877        switch (referencedChunk.status) {1878          case INITIALIZED: {1879            value = referencedChunk.value;1880            continue;1881          }1882        }1883      }1884      break;1885    }18861887    const mappedValue = map(response, value, parentObject, key);1888    if (key !== __PROTO__) {1889      parentObject[key] = mappedValue;1890    }18911892    // If this is the root object for a model reference, where `handler.value`1893    // is a stale `null`, the resolved value can be used directly.1894    if (key === '' && handler.value === null) {1895      handler.value = mappedValue;1896    }18971898    // If the parent object is an unparsed React element tuple, we also need to1899    // update the props and owner of the parsed element object (i.e.1900    // handler.value).1901    if (1902      parentObject[0] === REACT_ELEMENT_TYPE &&1903      typeof handler.value === 'object' &&1904      handler.value !== null &&1905      handler.value.$$typeof === REACT_ELEMENT_TYPE1906    ) {1907      const element: any = handler.value;1908      switch (key) {1909        case '3':1910          if (__DEV__ && !reference.isDebug) {1911            transferReferencedDebugInfo(handler.chunk, fulfilledChunk);1912          }1913          element.props = mappedValue;1914          break;1915        case '4':1916          // This path doesn't call transferReferencedDebugInfo because this reference is to a debug chunk.1917          if (__DEV__) {1918            element._owner = mappedValue;1919          }1920          break;1921        case '5':1922          // This path doesn't call transferReferencedDebugInfo because this reference is to a debug chunk.1923          if (__DEV__) {1924            element._debugStack = mappedValue;1925          }1926          break;1927        default:1928          if (__DEV__ && !reference.isDebug) {1929            transferReferencedDebugInfo(handler.chunk, fulfilledChunk);1930          }1931          break;1932      }1933    } else if (__DEV__ && !reference.isDebug) {1934      transferReferencedDebugInfo(handler.chunk, fulfilledChunk);1935    }1936  } catch (error) {1937    rejectReference(response, reference.handler, error);1938    return;1939  }19401941  handler.deps--;1942  initializeChunkIfUnblocked(response, handler);1943}19441945function rejectReference(1946  response: Response,1947  handler: InitializationHandler,1948  error: mixed,1949): void {1950  if (handler.errored) {1951    // We've already errored. We could instead build up an AggregateError1952    // but if there are multiple errors we just take the first one like1953    // Promise.all.1954    return;1955  }1956  const blockedValue = handler.value;1957  const erroredHandler: ErroredInitializationHandler = handler as any;1958  erroredHandler.errored = true;1959  erroredHandler.value = null;1960  erroredHandler.reason = error;1961  const chunk = handler.chunk;1962  if (chunk === null || chunk.status !== BLOCKED) {1963    return;1964  }19651966  if (__DEV__) {1967    if (1968      typeof blockedValue === 'object' &&1969      blockedValue !== null &&1970      blockedValue.$$typeof === REACT_ELEMENT_TYPE1971    ) {1972      const element = blockedValue;1973      // Conceptually the error happened inside this Element but right before1974      // it was rendered. We don't have a client side component to render but1975      // we can add some DebugInfo to explain that this was conceptually a1976      // Server side error that errored inside this element. That way any stack1977      // traces will point to the nearest JSX that errored - e.g. during1978      // serialization.1979      const erroredComponent: ReactComponentInfo = {1980        name: getComponentNameFromType(element.type) || '',1981        owner: element._owner,1982      };1983      // $FlowFixMe[cannot-write]1984      erroredComponent.debugStack = element._debugStack;1985      if (supportsCreateTask) {1986        // $FlowFixMe[cannot-write]1987        erroredComponent.debugTask = element._debugTask;1988      }1989      chunk._debugInfo.push(erroredComponent);1990    }1991  }19921993  triggerErrorOnChunk(response, chunk, error);1994}19951996function waitForReference<T>(1997  referencedChunk: PendingChunk<T> | PendingWeakChunk<T> | BlockedChunk<T>,1998  parentObject: Object,1999  key: string,2000  response: Response,

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.

Generated by searchcode.com · powered by code_get_file + code_get_findings