packages/react-client/src/ReactFlightClient.js JAVASCRIPT 5,607 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 5,607.
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  enableFlightWeakThenables,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} from './ReactFlightReplyClient';7374import {readTemporaryReference} from './ReactFlightTemporaryReferences';7576import {77  markAllTracksInOrder,78  logComponentRender,79  logDedupedComponentRender,80  logComponentAborted,81  logComponentErrored,82  logIOInfo,83  logIOInfoErrored,84  logComponentAwait,85  logComponentAwaitAborted,86  logComponentAwaitErrored,87} from './ReactFlightPerformanceTrack';8889import {90  REACT_LAZY_TYPE,91  REACT_ELEMENT_TYPE,92  ASYNC_ITERATOR,93  REACT_FRAGMENT_TYPE,94} from 'shared/ReactSymbols';9596import getComponentNameFromType from 'shared/getComponentNameFromType';9798import {getOwnerStackByComponentInfoInDev} from 'shared/ReactComponentInfoStack';99100import hasOwnProperty from 'shared/hasOwnProperty';101102import getPrototypeOf from 'shared/getPrototypeOf';103104import {injectInternals} from './ReactFlightClientDevToolsHook';105106import {OMITTED_PROP_ERROR} from 'shared/ReactFlightPropertyAccess';107108import ReactVersion from 'shared/ReactVersion';109110import isArray from 'shared/isArray';111112import * as React from 'react';113114import type {SharedStateServer} from 'react/src/ReactSharedInternalsServer';115import type {SharedStateClient} from 'react/src/ReactSharedInternalsClient';116117// TODO: This is an unfortunate hack. We shouldn't feature detect the internals118// like this. It's just that for now we support the same build of the Flight119// client both in the RSC environment, in the SSR environments as well as the120// browser client. We should probably have a separate RSC build. This is DEV121// only though.122const ReactSharedInteralsServer: void | SharedStateServer = (React as any)123  .__SERVER_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;124const ReactSharedInternals: SharedStateServer | SharedStateClient =125  React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE ||126  ReactSharedInteralsServer;127128export type {CallServerCallback, EncodeFormActionCallback};129130interface FlightStreamController {131  enqueueValue(value: any): void;132  enqueueModel(json: UninitializedModel): void;133  close(json: UninitializedModel): void;134  error(error: Error): void;135}136137type UninitializedModel = string;138139type ProfilingResult = {140  track: number,141  endTime: number,142  component: null | ReactComponentInfo,143};144145const ROW_ID = 0;146const ROW_TAG = 1;147const ROW_LENGTH = 2;148const ROW_CHUNK_BY_NEWLINE = 3;149const ROW_CHUNK_BY_LENGTH = 4;150151type RowParserState = 0 | 1 | 2 | 3 | 4;152153const PENDING = 'pending';154// A weak Promise reference. Behaves like PENDING except that when the stream155// closes it transitions to HALTED instead of erroring, because the server156// may intentionally never emit it. Only used when enableFlightWeakThenables157// is on.158const PENDING_WEAK = 'pending_weak';159const BLOCKED = 'blocked';160const RESOLVED_MODEL = 'resolved_model';161const RESOLVED_MODULE = 'resolved_module';162const INITIALIZED = 'fulfilled';163const ERRORED = 'rejected';164// Means it never resolves, even when the connection closes. The shared165// terminal state of a weak chunk that didn't settle before close, of any166// pending chunk at close when partial streams are allowed, and of DEV-only167// debug halts.168const HALTED = 'halted';169170const __PROTO__ = '__proto__';171172const ObjectPrototype = Object.prototype;173const ArrayPrototype = Array.prototype;174175type PendingChunk<T> = {176  status: 'pending',177  value: null | Array<InitializationReference | (T => mixed)>,178  reason: null | Array<InitializationReference | (mixed => mixed)>,179  _children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only180  _debugChunk: null | SomeChunk<ReactDebugInfoEntry>, // DEV-only181  _debugInfo: ReactDebugInfo, // DEV-only182  then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,183};184type PendingWeakChunk<T> = {185  status: 'pending_weak',186  value: null | Array<InitializationReference | (T => mixed)>,187  reason: null | Array<InitializationReference | (mixed => mixed)>,188  _children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only189  _debugChunk: null | SomeChunk<ReactDebugInfoEntry>, // DEV-only190  _debugInfo: ReactDebugInfo, // DEV-only191  then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,192};193type BlockedChunk<T> = {194  status: 'blocked',195  value: null | Array<InitializationReference | (T => mixed)>,196  reason: null | Array<InitializationReference | (mixed => mixed)>,197  _children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only198  _debugChunk: null, // DEV-only199  _debugInfo: ReactDebugInfo, // DEV-only200  then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,201};202type ResolvedModelChunk<T> = {203  status: 'resolved_model',204  value: UninitializedModel,205  reason: Response,206  _children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only207  _debugChunk: null | SomeChunk<ReactDebugInfoEntry>, // DEV-only208  _debugInfo: ReactDebugInfo, // DEV-only209  then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,210};211type ResolvedModuleChunk<T> = {212  status: 'resolved_module',213  value: ClientReference<T>,214  reason: null,215  _children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only216  _debugChunk: null, // DEV-only217  _debugInfo: ReactDebugInfo, // DEV-only218  then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,219};220type InitializedChunk<T> = {221  status: 'fulfilled',222  value: T,223  reason: null | FlightStreamController,224  _children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only225  _debugChunk: null, // DEV-only226  _debugInfo: ReactDebugInfo, // DEV-only227  then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,228};229type InitializedStreamChunk<230  T: ReadableStream | $AsyncIterable<any, any, void>,231> = {232  status: 'fulfilled',233  value: T,234  reason: FlightStreamController,235  _children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only236  _debugChunk: null, // DEV-only237  _debugInfo: ReactDebugInfo, // DEV-only238  then(resolve: (ReadableStream) => mixed, reject?: (mixed) => mixed): void,239};240type ErroredChunk<T> = {241  status: 'rejected',242  value: null,243  reason: mixed,244  _children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only245  _debugChunk: null, // DEV-only246  _debugInfo: ReactDebugInfo, // DEV-only247  then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,248};249type HaltedChunk<T> = {250  status: 'halted',251  value: null,252  reason: null,253  _children: Array<SomeChunk<any>> | ProfilingResult, // Profiling-only254  _debugChunk: null, // DEV-only255  _debugInfo: ReactDebugInfo, // DEV-only256  then(resolve: (T) => mixed, reject?: (mixed) => mixed): void,257};258type SomeChunk<T> =259  | PendingChunk<T>260  | PendingWeakChunk<T>261  | BlockedChunk<T>262  | ResolvedModelChunk<T>263  | ResolvedModuleChunk<T>264  | InitializedChunk<T>265  | ErroredChunk<T>266  | HaltedChunk<T>;267268// $FlowFixMe[missing-this-annot]269function ReactPromise(status: any, value: any, reason: any) {270  this.status = status;271  this.value = value;272  this.reason = reason;273  if (enableProfilerTimer && enableComponentPerformanceTrack) {274    this._children = [];275  }276  if (__DEV__) {277    this._debugChunk = null;278    this._debugInfo = [];279  }280}281// We subclass Promise.prototype so that we get other methods like .catch282ReactPromise.prototype = Object.create(Promise.prototype) as any;283// TODO: This doesn't return a new Promise chain unlike the real .then284function reactPromiseThen<T>(285  this: SomeChunk<T>,286  resolve: (value: T) => mixed,287  reject?: (reason: mixed) => mixed,288) {289  const chunk: SomeChunk<T> = this;290  // If we have resolved content, we try to initialize it first which291  // might put us back into one of the other states.292  switch (chunk.status) {293    case RESOLVED_MODEL:294      initializeModelChunk(chunk);295      break;296    case RESOLVED_MODULE:297      initializeModuleChunk(chunk);298      break;299  }300  if (__DEV__ && enableAsyncDebugInfo) {301    // Because only native Promises get picked up when we're awaiting we need to wrap302    // this in a native Promise in DEV. This means that these callbacks are no longer sync303    // but the lazy initialization is still sync and the .value can be inspected after,304    // allowing it to be read synchronously anyway.305    const resolveCallback = resolve;306    const rejectCallback = reject;307    const wrapperPromise: Promise<T> = new Promise((res, rej) => {308      resolve = value => {309        // $FlowFixMe[prop-missing]310        wrapperPromise._debugInfo = this._debugInfo;311        res(value);312      };313      reject = reason => {314        // $FlowFixMe[prop-missing]315        wrapperPromise._debugInfo = this._debugInfo;316        rej(reason);317      };318    });319    wrapperPromise.then(resolveCallback, rejectCallback);320  }321  // The status might have changed after initialization.322  switch (chunk.status) {323    case INITIALIZED:324      if (typeof resolve === 'function') {325        resolve(chunk.value);326      }327      break;328    case PENDING:329    case PENDING_WEAK:330    case BLOCKED:331      if (typeof resolve === 'function') {332        if (chunk.value === null) {333          chunk.value = [] as Array<InitializationReference | (T => mixed)>;334        }335        chunk.value.push(resolve);336      }337      if (typeof reject === 'function') {338        if (chunk.reason === null) {339          chunk.reason = [] as Array<340            InitializationReference | (mixed => mixed),341          >;342        }343        chunk.reason.push(reject);344      }345      break;346    case HALTED: {347      break;348    }349    default:350      if (typeof reject === 'function') {351        reject(chunk.reason);352      }353      break;354  }355}356// The shadowing `then` must be defined with `Object.defineProperty` instead of357// assignment. Assignment would throw when `Promise.prototype` is frozen (e.g.358// by SES lockdown) because assigning over an inherited non-writable property359// is rejected.360Object.defineProperty(ReactPromise.prototype, 'then', {361  writable: true,362  enumerable: true,363  configurable: true,364  value: reactPromiseThen,365});366367export type FindSourceMapURLCallback = (368  fileName: string,369  environmentName: string,370) => null | string;371372export type DebugChannelCallback = (message: string) => void;373374export type DebugChannel = {375  hasReadable: boolean,376  callback: DebugChannelCallback | null,377};378379type Response = {380  _bundlerConfig: ServerConsumerModuleMap,381  _serverReferenceConfig: null | ServerManifest,382  _moduleLoading: ModuleLoading,383  _callServer: CallServerCallback,384  _encodeFormAction: void | EncodeFormActionCallback,385  _nonce: ?string,386  _chunks: Map<number, SomeChunk<any>>,387  _stringDecoder: StringDecoder,388  _closed: boolean,389  _closedReason: mixed,390  _allowPartialStream: boolean,391  _tempRefs: void | TemporaryReferenceSet, // the set temporary references can be resolved from392  _timeOrigin: number, // Profiling-only393  _pendingInitialRender: null | TimeoutID, // Profiling-only,394  _pendingChunks: number, // DEV-only395  _weakResponse: WeakResponse, // DEV-only396  _debugRootOwner?: null | ReactComponentInfo, // DEV-only397  _debugRootStack?: null | Error, // DEV-only398  _debugRootTask?: null | ConsoleTask, // DEV-only399  _debugStartTime: number, // DEV-only400  _debugEndTime: null | number, // DEV-only401  _debugIOStarted: boolean, // DEV-only402  _debugFindSourceMapURL?: void | FindSourceMapURLCallback, // DEV-only403  _debugChannel?: void | DebugChannel, // DEV-only404  _blockedConsole?: null | SomeChunk<ConsoleEntry>, // DEV-only405  _replayConsole: boolean, // DEV-only406  _rootEnvironmentName: string, // DEV-only, the requested environment name.407};408409// This indirection exists only to clean up DebugChannel when all Lazy References are GC:ed.410// Therefore we only use the indirection in DEV.411type WeakResponse = {412  weak: WeakRef<Response>,413  response: null | Response, // This is null when there are no pending chunks.414};415416export type {WeakResponse as Response};417418function hasGCedResponse(weakResponse: WeakResponse): boolean {419  return __DEV__ && weakResponse.weak.deref() === undefined;420}421422function unwrapWeakResponse(weakResponse: WeakResponse): Response {423  if (__DEV__) {424    const response = weakResponse.weak.deref();425    if (response === undefined) {426      // eslint-disable-next-line react-internal/prod-error-codes427      throw new Error(428        'We did not expect to receive new data after GC:ing the response.',429      );430    }431    return response;432  } else {433    return weakResponse as any; // In prod we just use the real Response directly.434  }435}436437function getWeakResponse(response: Response): WeakResponse {438  if (__DEV__) {439    return response._weakResponse;440  } else {441    return response as any; // In prod we just use the real Response directly.442  }443}444445function closeDebugChannel(debugChannel: DebugChannel): void {446  if (debugChannel.callback) {447    debugChannel.callback('');448  }449}450451// If FinalizationRegistry doesn't exist, we cannot use the debugChannel.452const debugChannelRegistry =453  __DEV__ && typeof FinalizationRegistry === 'function'454    ? new FinalizationRegistry(closeDebugChannel)455    : null;456457function readChunk<T>(chunk: SomeChunk<T>): T {458  // If we have resolved content, we try to initialize it first which459  // might put us back into one of the other states.460  switch (chunk.status) {461    case RESOLVED_MODEL:462      initializeModelChunk(chunk);463      break;464    case RESOLVED_MODULE:465      initializeModuleChunk(chunk);466      break;467  }468  // The status might have changed after initialization.469  switch (chunk.status) {470    case INITIALIZED:471      return chunk.value;472    case PENDING:473    case PENDING_WEAK:474    case BLOCKED:475    case HALTED:476      // eslint-disable-next-line no-throw-literal477      throw chunk as any as Thenable<T>;478    default:479      throw chunk.reason;480  }481}482483export function getRoot<T>(weakResponse: WeakResponse): Thenable<T> {484  const response = unwrapWeakResponse(weakResponse);485  const chunk = getChunk(response, 0);486  return chunk as any;487}488489function createPendingChunk<T>(response: Response): PendingChunk<T> {490  if (__DEV__) {491    // Retain a strong reference to the Response while we wait for the result.492    if (response._pendingChunks++ === 0) {493      response._weakResponse.response = response;494      if (response._pendingInitialRender !== null) {495        clearTimeout(response._pendingInitialRender);496        response._pendingInitialRender = null;497      }498    }499  }500  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors501  return new ReactPromise(PENDING, null, null);502}503504function createPendingWeakChunk<T>(response: Response): PendingWeakChunk<T> {505  // Unlike a regular pending chunk, a weak chunk may never settle, so it506  // doesn't retain a strong reference to the Response while it waits.507  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors508  return new ReactPromise(PENDING_WEAK, null, null);509}510511function releasePendingChunk(response: Response, chunk: SomeChunk<any>): void {512  if (__DEV__ && chunk.status === PENDING) {513    if (--response._pendingChunks === 0) {514      // We're no longer waiting for any more chunks. We can release the strong reference515      // to the response. We'll regain it if we ask for any more data later on.516      response._weakResponse.response = null;517      // Wait a short period to see if any more chunks get asked for. E.g. by a React render.518      // These chunks might discover more pending chunks.519      // If we don't ask for more then we assume that those chunks weren't blocking initial520      // render and are excluded from the performance track.521      response._pendingInitialRender = setTimeout(522        flushInitialRenderPerformance.bind(null, response),523        100,524      );525    }526  }527}528529function createHaltedChunk<T>(response: Response): HaltedChunk<T> {530  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors531  return new ReactPromise(HALTED, null, null);532}533534// Transition a chunk to HALTED: it will never resolve, even when the535// connection closes. Clears any listeners to release their closures. Future536// .then() calls on HALTED chunks are no-ops.537function haltChunk<T>(response: Response, chunk: SomeChunk<T>): void {538  releasePendingChunk(response, chunk);539  const haltedChunk: HaltedChunk<T> = chunk as any;540  haltedChunk.status = HALTED;541  haltedChunk.value = null;542  haltedChunk.reason = null;543}544545function createBlockedChunk<T>(response: Response): BlockedChunk<T> {546  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors547  return new ReactPromise(BLOCKED, null, null);548}549550function createErrorChunk<T>(551  response: Response,552  error: mixed,553): ErroredChunk<T> {554  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors555  return new ReactPromise(ERRORED, null, error);556}557558function filterDebugInfo(559  response: Response,560  value: {_debugInfo: ReactDebugInfo, ...},561) {562  if (response._debugEndTime === null) {563    // No end time was defined, so we keep all debug info entries.564    return;565  }566567  // Remove any debug info entries after the defined end time. For async info568  // that means we're including anything that was awaited before the end time,569  // but it doesn't need to be resolved before the end time.570  const relativeEndTime =571    response._debugEndTime -572    // $FlowFixMe[prop-missing]573    performance.timeOrigin;574  const debugInfo = [];575  for (let i = 0; i < value._debugInfo.length; i++) {576    const info = value._debugInfo[i];577    if (typeof info.time === 'number' && info.time > relativeEndTime) {578      break;579    }580    debugInfo.push(info);581  }582  value._debugInfo = debugInfo;583}584585function pruneDebugInfoAfterError(586  response: Response,587  chunk: ErroredChunk<any>,588): void {589  if (response._debugEndTime === null) {590    return;591  }592593  const relativeEndTime =594    response._debugEndTime -595    // $FlowFixMe[prop-missing]596    performance.timeOrigin;597  const debugInfo = chunk._debugInfo;598  for (let i = 0; i < debugInfo.length; i++) {599    const info = debugInfo[i];600    if (typeof info.time === 'number' && info.time > relativeEndTime) {601      // This array may already be attached to the Lazy suspended in Fizz.602      debugInfo.length = i;603      return;604    }605  }606}607608function moveDebugInfoFromChunkToInnerValue<T>(609  chunk: InitializedChunk<T> | InitializedStreamChunk<any>,610  value: T,611): void {612  // Remove the debug info from the initialized chunk, and add it to the inner613  // value instead. This can be a React element, an array, or an uninitialized614  // Lazy.615  const resolvedValue = resolveLazy(value);616  if (617    typeof resolvedValue === 'object' &&618    resolvedValue !== null &&619    (isArray(resolvedValue) ||620      typeof resolvedValue[ASYNC_ITERATOR] === 'function' ||621      resolvedValue.$$typeof === REACT_ELEMENT_TYPE ||622      resolvedValue.$$typeof === REACT_LAZY_TYPE)623  ) {624    const debugInfo = chunk._debugInfo.splice(0);625    if (isArray(resolvedValue._debugInfo)) {626      // $FlowFixMe[method-unbinding]627      resolvedValue._debugInfo.unshift.apply(628        resolvedValue._debugInfo,629        debugInfo,630      );631    } else if (!Object.isFrozen(resolvedValue)) {632      Object.defineProperty(resolvedValue as any, '_debugInfo', {633        configurable: false,634        enumerable: false,635        writable: true,636        value: debugInfo,637      });638    }639    // TODO: If the resolved value is a frozen element (e.g. a client-created640    // element from a temporary reference, or a JSX element exported as a client641    // reference), server debug info is currently dropped because the element642    // can't be mutated. We should probably clone the element so each rendering643    // context gets its own mutable copy with the correct debug info.644  }645}646647function processChunkDebugInfo<T>(648  response: Response,649  chunk: InitializedChunk<T> | InitializedStreamChunk<any>,650  value: T,651): void {652  filterDebugInfo(response, chunk);653  moveDebugInfoFromChunkToInnerValue(chunk, value);654}655656function wakeChunk<T>(657  response: Response,658  listeners: Array<InitializationReference | (T => mixed)>,659  value: T,660  chunk: InitializedChunk<T>,661): void {662  for (let i = 0; i < listeners.length; i++) {663    const listener = listeners[i];664    if (typeof listener === 'function') {665      listener(value);666    } else {667      fulfillReference(response, listener, value, chunk);668    }669  }670671  if (__DEV__) {672    processChunkDebugInfo(response, chunk, value);673  }674}675676function rejectChunk(677  response: Response,678  listeners: Array<InitializationReference | (mixed => mixed)>,679  error: mixed,680): void {681  for (let i = 0; i < listeners.length; i++) {682    const listener = listeners[i];683    if (typeof listener === 'function') {684      listener(error);685    } else {686      rejectReference(response, listener.handler, error);687    }688  }689}690691function resolveBlockedCycle<T>(692  resolvedChunk: SomeChunk<T>,693  reference: InitializationReference,694): null | InitializationHandler {695  const referencedChunk = reference.handler.chunk;696  if (referencedChunk === null) {697    return null;698  }699  if (referencedChunk === resolvedChunk) {700    // We found the cycle. We can resolve the blocked cycle now.701    return reference.handler;702  }703  const resolveListeners = referencedChunk.value;704  if (resolveListeners !== null) {705    for (let i = 0; i < resolveListeners.length; i++) {706      const listener = resolveListeners[i];707      if (typeof listener !== 'function') {708        const foundHandler = resolveBlockedCycle(resolvedChunk, listener);709        if (foundHandler !== null) {710          return foundHandler;711        }712      }713    }714  }715  return null;716}717718function wakeChunkIfInitialized<T>(719  response: Response,720  chunk: SomeChunk<T>,721  resolveListeners: Array<InitializationReference | (T => mixed)>,722  rejectListeners: null | Array<InitializationReference | (mixed => mixed)>,723): void {724  switch (chunk.status) {725    case INITIALIZED:726      wakeChunk(response, resolveListeners, chunk.value, chunk);727      break;728    case BLOCKED:729      // It is possible that we're blocked on our own chunk if it's a cycle.730      // Before adding back the listeners to the chunk, let's check if it would731      // result in a cycle.732      for (let i = 0; i < resolveListeners.length; i++) {733        const listener = resolveListeners[i];734        if (typeof listener !== 'function') {735          const reference: InitializationReference = listener;736          const cyclicHandler = resolveBlockedCycle(chunk, reference);737          if (cyclicHandler !== null) {738            // This reference points back to this chunk. We can resolve the cycle by739            // using the value from that handler.740            fulfillReference(response, reference, cyclicHandler.value, chunk);741            resolveListeners.splice(i, 1);742            i--;743            if (rejectListeners !== null) {744              const rejectionIdx = rejectListeners.indexOf(reference);745              if (rejectionIdx !== -1) {746                rejectListeners.splice(rejectionIdx, 1);747              }748            }749            // The status might have changed after fulfilling the reference.750            switch ((chunk as SomeChunk<T>).status) {751              case INITIALIZED:752                const initializedChunk: InitializedChunk<T> = chunk as any;753                wakeChunk(754                  response,755                  resolveListeners,756                  initializedChunk.value,757                  initializedChunk,758                );759                return;760              case ERRORED:761                if (rejectListeners !== null) {762                  rejectChunk(response, rejectListeners, chunk.reason);763                }764                return;765            }766          }767        }768      }769    // Fallthrough770    case PENDING:771      if (chunk.value) {772        for (let i = 0; i < resolveListeners.length; i++) {773          chunk.value.push(resolveListeners[i]);774        }775      } else {776        chunk.value = resolveListeners;777      }778779      if (chunk.reason) {780        if (rejectListeners) {781          for (let i = 0; i < rejectListeners.length; i++) {782            chunk.reason.push(rejectListeners[i]);783          }784        }785      } else {786        chunk.reason = rejectListeners;787      }788789      break;790    case ERRORED:791      if (rejectListeners) {792        rejectChunk(response, rejectListeners, chunk.reason);793      }794      break;795  }796}797798function triggerErrorOnChunk<T>(799  response: Response,800  chunk: SomeChunk<T>,801  error: mixed,802): void {803  if (804    chunk.status !== PENDING &&805    chunk.status !== PENDING_WEAK &&806    chunk.status !== BLOCKED807  ) {808    // If we get more data to an already resolved ID, we assume that it's809    // a stream chunk since any other row shouldn't have more than one entry.810    const streamChunk: InitializedStreamChunk<any> = chunk as any;811    const controller = streamChunk.reason;812    // $FlowFixMe[incompatible-type]: The error method should accept mixed.813    controller.error(error);814    return;815  }816  releasePendingChunk(response, chunk);817  const listeners = chunk.reason;818819  if (__DEV__ && (chunk.status === PENDING || chunk.status === PENDING_WEAK)) {820    // Lazily initialize any debug info and block the initializing chunk on any unresolved entries.821    if (chunk._debugChunk != null) {822      const prevHandler = initializingHandler;823      const prevChunk = initializingChunk;824      initializingHandler = null;825      const cyclicChunk: BlockedChunk<T> = chunk as any;826      cyclicChunk.status = BLOCKED;827      cyclicChunk.value = null;828      cyclicChunk.reason = null;829      if ((enableProfilerTimer && enableComponentPerformanceTrack) || __DEV__) {830        initializingChunk = cyclicChunk;831      }832      try {833        initializeDebugChunk(response, chunk);834        if (initializingHandler !== null) {835          if (initializingHandler.errored) {836            // Ignore error parsing debug info, we'll report the original error instead.837          } else if (initializingHandler.deps > 0) {838            // TODO: Block the resolution of the error until all the debug info has loaded.839            // We currently don't have a way to throw an error after all dependencies have840            // loaded because we currently treat errors as immediately cancelling the handler.841          }842        }843      } finally {844        initializingHandler = prevHandler;845        initializingChunk = prevChunk;846      }847    }848  }849850  const erroredChunk: ErroredChunk<T> = chunk as any;851  erroredChunk.status = ERRORED;852  erroredChunk.reason = error;853  if (__DEV__) {854    pruneDebugInfoAfterError(response, erroredChunk);855  }856  if (listeners !== null) {857    rejectChunk(response, listeners, error);858  }859}860861function createResolvedModelChunk<T>(862  response: Response,863  value: UninitializedModel,864): ResolvedModelChunk<T> {865  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors866  return new ReactPromise(RESOLVED_MODEL, value, response);867}868869function createResolvedModuleChunk<T>(870  response: Response,871  value: ClientReference<T>,872): ResolvedModuleChunk<T> {873  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors874  return new ReactPromise(RESOLVED_MODULE, value, null);875}876877function createInitializedTextChunk(878  response: Response,879  value: string,880): InitializedChunk<string> {881  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors882  return new ReactPromise(INITIALIZED, value, null);883}884885function createInitializedBufferChunk(886  response: Response,887  value: $ArrayBufferView | ArrayBuffer,888): InitializedChunk<Uint8Array> {889  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors890  return new ReactPromise(INITIALIZED, value, null);891}892893function createInitializedIteratorResultChunk<T>(894  response: Response,895  value: T,896  done: boolean,897): InitializedChunk<IteratorResult<T, T>> {898  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors899  return new ReactPromise(INITIALIZED, {done: done, value: value}, null);900}901902function createInitializedStreamChunk<903  T: ReadableStream | $AsyncIterable<any, any, void>,904>(905  response: Response,906  value: T,907  controller: FlightStreamController,908): InitializedChunk<T> {909  if (__DEV__) {910    // Retain a strong reference to the Response while we wait for chunks.911    if (response._pendingChunks++ === 0) {912      response._weakResponse.response = response;913    }914  }915  // We use the reason field to stash the controller since we already have that916  // field. It's a bit of a hack but efficient.917  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors918  return new ReactPromise(INITIALIZED, value, controller);919}920921function createResolvedIteratorResultChunk<T>(922  response: Response,923  value: UninitializedModel,924  done: boolean,925): ResolvedModelChunk<IteratorResult<T, T>> {926  // To reuse code as much code as possible we add the wrapper element as part of the JSON.927  const iteratorResultJSON =928    (done ? '{"done":true,"value":' : '{"done":false,"value":') + value + '}';929  // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors930  return new ReactPromise(RESOLVED_MODEL, iteratorResultJSON, response);931}932933function resolveIteratorResultChunk<T>(934  response: Response,935  chunk: SomeChunk<IteratorResult<T, T>>,936  value: UninitializedModel,937  done: boolean,938): void {939  // To reuse code as much code as possible we add the wrapper element as part of the JSON.940  const iteratorResultJSON =941    (done ? '{"done":true,"value":' : '{"done":false,"value":') + value + '}';942  resolveModelChunk(response, chunk, iteratorResultJSON);943}944945function resolveModelChunk<T>(946  response: Response,947  chunk: SomeChunk<T>,948  value: UninitializedModel,949): void {950  if (chunk.status !== PENDING && chunk.status !== PENDING_WEAK) {951    // If we get more data to an already resolved ID, we assume that it's952    // a stream chunk since any other row shouldn't have more than one entry.953    const streamChunk: InitializedStreamChunk<any> = chunk as any;954    const controller = streamChunk.reason;955    controller.enqueueModel(value);956    return;957  }958  releasePendingChunk(response, chunk);959  const resolveListeners = chunk.value;960  const rejectListeners = chunk.reason;961  const resolvedChunk: ResolvedModelChunk<T> = chunk as any;962  resolvedChunk.status = RESOLVED_MODEL;963  resolvedChunk.value = value;964  resolvedChunk.reason = response;965  if (resolveListeners !== null) {966    // This is unfortunate that we're reading this eagerly if967    // we already have listeners attached since they might no968    // longer be rendered or might not be the highest pri.969    initializeModelChunk(resolvedChunk);970    // The status might have changed after initialization.971    wakeChunkIfInitialized(response, chunk, resolveListeners, rejectListeners);972  }973}974975function resolveModuleChunk<T>(976  response: Response,977  chunk: SomeChunk<T>,978  value: ClientReference<T>,979): void {980  if (981    chunk.status !== PENDING &&982    chunk.status !== PENDING_WEAK &&983    chunk.status !== BLOCKED984  ) {985    // We already resolved. We didn't expect to see this.986    return;987  }988  releasePendingChunk(response, chunk);989  const resolveListeners = chunk.value;990  const rejectListeners = chunk.reason;991  const resolvedChunk: ResolvedModuleChunk<T> = chunk as any;992  resolvedChunk.status = RESOLVED_MODULE;993  resolvedChunk.value = value;994  resolvedChunk.reason = null;995  if (__DEV__) {996    const debugInfo = getModuleDebugInfo(value);997    if (debugInfo !== null) {998      // Add to the live set if it was already initialized.999      // $FlowFixMe[method-unbinding]1000      resolvedChunk._debugInfo.push.apply(resolvedChunk._debugInfo, debugInfo);1001    }1002  }1003  if (resolveListeners !== null) {1004    initializeModuleChunk(resolvedChunk);1005    wakeChunkIfInitialized(response, chunk, resolveListeners, rejectListeners);1006  }1007}10081009type InitializationReference = {1010  handler: InitializationHandler,1011  parentObject: Object,1012  key: string,1013  map: (1014    response: Response,1015    model: any,1016    parentObject: Object,1017    key: string,1018  ) => any,1019  path: Array<string>,1020  isDebug?: boolean, // DEV-only1021};1022type InitializationHandler = {1023  parent: null | InitializationHandler,1024  chunk: null | BlockedChunk<any>,1025  value: any,1026  reason: any,1027  deps: number,1028  errored: boolean,1029};1030let initializingHandler: null | InitializationHandler = null;1031let initializingChunk: null | BlockedChunk<any> = null;1032let isInitializingDebugInfo: boolean = false;10331034function initializeDebugChunk(1035  response: Response,1036  chunk: ResolvedModelChunk<any> | PendingChunk<any> | PendingWeakChunk<any>,1037): void {1038  const debugChunk = chunk._debugChunk;1039  if (debugChunk !== null) {1040    const debugInfo = chunk._debugInfo;1041    const prevIsInitializingDebugInfo = isInitializingDebugInfo;1042    isInitializingDebugInfo = true;1043    try {1044      if (debugChunk.status === RESOLVED_MODEL) {1045        // Find the index of this debug info by walking the linked list.1046        let idx = debugInfo.length;1047        let c = debugChunk._debugChunk;1048        while (c !== null) {1049          if (c.status !== INITIALIZED) {1050            idx++;1051          }1052          c = c._debugChunk;1053        }1054        // Initializing the model for the first time.1055        initializeModelChunk(debugChunk);1056        const initializedChunk = debugChunk as any as SomeChunk<any>;1057        switch (initializedChunk.status) {1058          case INITIALIZED: {1059            debugInfo[idx] = initializeDebugInfo(1060              response,1061              initializedChunk.value,1062            );1063            break;1064          }1065          case BLOCKED:1066          case PENDING:1067          case PENDING_WEAK: {1068            waitForReference(1069              initializedChunk,1070              debugInfo,1071              '' + idx,1072              response,1073              initializeDebugInfo,1074              [''], // path1075              true,1076            );1077            break;1078          }1079          default:1080            throw initializedChunk.reason;1081        }1082      } else {1083        switch (debugChunk.status) {1084          case INITIALIZED: {1085            // Already done.1086            break;1087          }1088          case BLOCKED:1089          case PENDING:1090          case PENDING_WEAK: {1091            // Signal to the caller that we need to wait.1092            waitForReference(1093              debugChunk,1094              {}, // noop, since we'll have already added an entry to debug info1095              'debug', // noop, but we need it to not be empty string since that indicates the root object1096              response,1097              initializeDebugInfo,1098              [''], // path1099              true,1100            );1101            break;1102          }1103          default:1104            throw debugChunk.reason;1105        }1106      }1107    } catch (error) {1108      triggerErrorOnChunk(response, chunk, error);1109    } finally {1110      isInitializingDebugInfo = prevIsInitializingDebugInfo;1111    }1112  }1113}11141115function initializeModelChunk<T>(chunk: ResolvedModelChunk<T>): void {1116  const prevHandler = initializingHandler;1117  const prevChunk = initializingChunk;1118  initializingHandler = null;11191120  const resolvedModel = chunk.value;1121  const response = chunk.reason;11221123  // We go to the BLOCKED state until we've fully resolved this.1124  // We do this before parsing in case we try to initialize the same chunk1125  // while parsing the model. Such as in a cyclic reference.1126  const cyclicChunk: BlockedChunk<T> = chunk as any;1127  cyclicChunk.status = BLOCKED;1128  cyclicChunk.value = null;1129  cyclicChunk.reason = null;11301131  if ((enableProfilerTimer && enableComponentPerformanceTrack) || __DEV__) {1132    initializingChunk = cyclicChunk;1133  }11341135  if (__DEV__) {1136    // Initialize any debug info and block the initializing chunk on any1137    // unresolved entries.1138    initializeDebugChunk(response, chunk);1139    // TODO: The chunk might have transitioned to ERRORED now.1140    // Should we return early if that happens?1141  }11421143  try {1144    const value: T = parseModel(response, resolvedModel);1145    // Invoke any listeners added while resolving this model. I.e. cyclic1146    // references. This may or may not fully resolve the model depending on1147    // if they were blocked.1148    const resolveListeners = cyclicChunk.value;1149    if (resolveListeners !== null) {1150      cyclicChunk.value = null;1151      cyclicChunk.reason = null;1152      for (let i = 0; i < resolveListeners.length; i++) {1153        const listener = resolveListeners[i];1154        if (typeof listener === 'function') {1155          listener(value);1156        } else {1157          fulfillReference(response, listener, value, cyclicChunk);1158        }1159      }1160    }1161    if (initializingHandler !== null) {1162      if (initializingHandler.errored) {1163        throw initializingHandler.reason;1164      }1165      if (initializingHandler.deps > 0) {1166        // We discovered new dependencies on modules that are not yet resolved.1167        // We have to keep the BLOCKED state until they're resolved.1168        initializingHandler.value = value;1169        initializingHandler.chunk = cyclicChunk;1170        return;1171      }1172    }1173    const initializedChunk: InitializedChunk<T> = chunk as any;1174    initializedChunk.status = INITIALIZED;1175    initializedChunk.value = value;1176    initializedChunk.reason = null;11771178    if (__DEV__) {1179      processChunkDebugInfo(response, initializedChunk, value);1180    }1181  } catch (error) {1182    const erroredChunk: ErroredChunk<T> = chunk as any;1183    erroredChunk.status = ERRORED;1184    erroredChunk.reason = error;1185  } finally {1186    initializingHandler = prevHandler;1187    if ((enableProfilerTimer && enableComponentPerformanceTrack) || __DEV__) {1188      initializingChunk = prevChunk;1189    }1190  }1191}11921193function initializeModuleChunk<T>(chunk: ResolvedModuleChunk<T>): void {1194  try {1195    const value: T = requireModule(chunk.value);1196    const initializedChunk: InitializedChunk<T> = chunk as any;1197    initializedChunk.status = INITIALIZED;1198    initializedChunk.value = value;1199    initializedChunk.reason = null;1200  } catch (error) {1201    const erroredChunk: ErroredChunk<T> = chunk as any;1202    erroredChunk.status = ERRORED;1203    erroredChunk.reason = error;1204  }1205}12061207// Report that any missing chunks in the model is now going to throw this1208// error upon read. Also notify any pending promises.1209export function reportGlobalError(1210  weakResponse: WeakResponse,1211  error: Error,1212): void {1213  if (hasGCedResponse(weakResponse)) {1214    // Ignore close signal if we are not awaiting any more pending chunks.1215    return;1216  }1217  const response = unwrapWeakResponse(weakResponse);1218  response._closed = true;1219  response._closedReason = error;1220  response._chunks.forEach(chunk => {1221    // If this chunk was already resolved or errored, it won't1222    // trigger an error but if it wasn't then we need to1223    // because we won't be getting any new data to resolve it.1224    if (chunk.status === PENDING) {1225      triggerErrorOnChunk(response, chunk, error);1226    } else if (enableFlightWeakThenables && chunk.status === PENDING_WEAK) {1227      // A weak Promise reference may never be emitted by the server. It1228      // stays forever pending instead of erroring.1229      haltChunk(response, chunk);1230    } else if (chunk.status === INITIALIZED && chunk.reason !== null) {1231      chunk.reason.error(error);1232    }1233  });1234  if (__DEV__) {1235    const debugChannel = response._debugChannel;1236    if (debugChannel !== undefined) {1237      // If we don't have any more ways of reading data, we don't have to send1238      // any more neither. So we close the writable side.1239      closeDebugChannel(debugChannel);1240      response._debugChannel = undefined;1241      // Make sure the debug channel is not closed a second time when the1242      // Response gets GC:ed.1243      if (debugChannelRegistry !== null) {1244        debugChannelRegistry.unregister(response);1245      }1246    }1247  }1248}12491250function nullRefGetter() {1251  if (__DEV__) {1252    return null;1253  }1254}12551256function getIOInfoTaskName(ioInfo: ReactIOInfo): string {1257  return ioInfo.name || 'unknown';1258}12591260function getAsyncInfoTaskName(asyncInfo: ReactAsyncInfo): string {1261  return 'await ' + getIOInfoTaskName(asyncInfo.awaited);1262}12631264function getServerComponentTaskName(componentInfo: ReactComponentInfo): string {1265  return '<' + (componentInfo.name || '...') + '>';1266}12671268function getTaskName(type: mixed): string {1269  if (type === REACT_FRAGMENT_TYPE) {1270    return '<>';1271  }1272  if (typeof type === 'function') {1273    // This is a function so it must have been a Client Reference that resolved to1274    // a function. We use "use client" to indicate that this is the boundary into1275    // the client. There should only be one for any given owner chain.1276    return '"use client"';1277  }1278  if (1279    typeof type === 'object' &&1280    type !== null &&1281    type.$$typeof === REACT_LAZY_TYPE1282  ) {1283    if (type._payload instanceof ReactPromise) {1284      // This is a lazy node created by Flight, i.e. it wraps a chunk. It is1285      // probably a client reference. We use the "use client" string to indicate1286      // that this is the boundary into the client. There will only be one for1287      // any given owner chain.1288      return '"use client"';1289    }1290    // We don't want to eagerly initialize the initializer in DEV mode so we can't1291    // call it to extract the type so we don't know the type of this component.1292    return '<...>';1293  }1294  try {1295    const name = getComponentNameFromType(type);1296    return name ? '<' + name + '>' : '<...>';1297  } catch (x) {1298    return '<...>';1299  }1300}13011302function initializeElement(1303  response: Response,1304  element: any,1305  lazyNode: null | LazyComponent<1306    React$Element<any>,1307    SomeChunk<React$Element<any>>,1308  >,1309): void {1310  if (!__DEV__) {1311    return;1312  }1313  const stack = element._debugStack;1314  const owner = element._owner;1315  if (owner === null) {1316    element._owner = response._debugRootOwner;1317  }1318  let env = response._rootEnvironmentName;1319  if (owner !== null && owner.env != null) {1320    // Interestingly we don't actually have the environment name of where1321    // this JSX was created if it doesn't have an owner but if it does1322    // it must be the same environment as the owner. We could send it separately1323    // but it seems a bit unnecessary for this edge case.1324    env = owner.env;1325  }1326  let normalizedStackTrace: null | Error = null;1327  if (owner === null && response._debugRootStack != null) {1328    // We override the stack if we override the owner since the stack where the root JSX1329    // was created on the server isn't very useful but where the request was made is.1330    normalizedStackTrace = response._debugRootStack;1331  } else if (stack !== null) {1332    // We create a fake stack and then create an Error object inside of it.1333    // This means that the stack trace is now normalized into the native format1334    // of the browser and the stack frames will have been registered with1335    // source mapping information.1336    // This can unfortunately happen within a user space callstack which will1337    // remain on the stack.1338    normalizedStackTrace = createFakeJSXCallStackInDEV(response, stack, env);1339  }1340  element._debugStack = normalizedStackTrace;1341  let task: null | ConsoleTask = null;1342  if (supportsCreateTask && stack !== null) {1343    const createTaskFn = (console as any).createTask.bind(1344      console,1345      getTaskName(element.type),1346    );1347    const callStack = buildFakeCallStack(1348      response,1349      stack,1350      env,1351      false,1352      createTaskFn,1353    );1354    // This owner should ideally have already been initialized to avoid getting1355    // user stack frames on the stack.1356    const ownerTask =1357      owner === null ? null : initializeFakeTask(response, owner);1358    if (ownerTask === null) {1359      const rootTask = response._debugRootTask;1360      if (rootTask != null) {1361        task = rootTask.run(callStack);1362      } else {1363        task = callStack();1364      }1365    } else {1366      task = ownerTask.run(callStack);1367    }1368  }1369  element._debugTask = task;13701371  // This owner should ideally have already been initialized to avoid getting1372  // user stack frames on the stack.1373  if (owner !== null) {1374    initializeFakeStack(response, owner);1375  }13761377  if (lazyNode !== null) {1378    // If the lazy node is initialized, we move its debug info to the inner1379    // value.1380    if (lazyNode._payload.status === INITIALIZED && lazyNode._debugInfo) {1381      const debugInfo = lazyNode._debugInfo.splice(0);1382      if (element._debugInfo) {1383        // $FlowFixMe[method-unbinding]1384        element._debugInfo.unshift.apply(element._debugInfo, debugInfo);1385      } else {1386        Object.defineProperty(element, '_debugInfo', {1387          configurable: false,1388          enumerable: false,1389          writable: true,1390          value: debugInfo,1391        });1392      }1393    }1394  }13951396  // TODO: We should be freezing the element but currently, we might write into1397  // _debugInfo later. We could move it into _store which remains mutable.1398  Object.freeze(element.props);1399}14001401function createElement(1402  response: Response,1403  type: mixed,1404  key: mixed,1405  props: mixed,1406  owner: ?ReactComponentInfo, // DEV-only1407  stack: ?ReactStackTrace, // DEV-only1408  validated: 0 | 1 | 2, // DEV-only1409):1410  | React$Element<any>1411  | LazyComponent<React$Element<any>, SomeChunk<React$Element<any>>> {1412  let element: any;1413  if (__DEV__) {1414    // `ref` is non-enumerable in dev1415    element = {1416      $$typeof: REACT_ELEMENT_TYPE,1417      type,1418      key,1419      props,1420      _owner: owner === undefined ? null : owner,1421    } as any;1422    Object.defineProperty(element, 'ref', {1423      enumerable: false,1424      get: nullRefGetter,1425    });1426  } else {1427    element = {1428      // This tag allows us to uniquely identify this as a React Element1429      $$typeof: REACT_ELEMENT_TYPE,14301431      type,1432      key,1433      ref: null,1434      props,1435    } as any;1436  }14371438  if (__DEV__) {1439    // We don't really need to add any of these but keeping them for good measure.1440    // Unfortunately, _store is enumerable in jest matchers so for equality to1441    // work, I need to keep it or make _store non-enumerable in the other file.1442    element._store = {} as {1443      validated?: number,1444    };1445    Object.defineProperty(element._store, 'validated', {1446      configurable: false,1447      enumerable: false,1448      writable: true,1449      value: validated, // Whether the element has already been validated on the server.1450    });1451    // debugInfo contains Server Component debug information.1452    Object.defineProperty(element, '_debugInfo', {1453      configurable: false,1454      enumerable: false,1455      writable: true,1456      value: null,1457    });1458    Object.defineProperty(element, '_debugStack', {1459      configurable: false,1460      enumerable: false,1461      writable: true,1462      value: stack === undefined ? null : stack,1463    });1464    Object.defineProperty(element, '_debugTask', {1465      configurable: false,1466      enumerable: false,1467      writable: true,1468      value: null,1469    });1470  }14711472  if (initializingHandler !== null) {1473    const handler = initializingHandler;1474    // We pop the stack to the previous outer handler before leaving the Element.1475    // This is effectively the complete phase.1476    initializingHandler = handler.parent;1477    if (handler.errored) {1478      // Something errored inside this Element's props. We can turn this Element1479      // into a Lazy so that we can still render up until that Lazy is rendered.1480      const erroredChunk: ErroredChunk<React$Element<any>> = createErrorChunk(1481        response,1482        handler.reason,1483      );1484      if (__DEV__) {1485        initializeElement(response, element, null);1486        // Conceptually the error happened inside this Element but right before1487        // it was rendered. We don't have a client side component to render but1488        // we can add some DebugInfo to explain that this was conceptually a1489        // Server side error that errored inside this element. That way any stack1490        // traces will point to the nearest JSX that errored - e.g. during1491        // serialization.1492        const erroredComponent: ReactComponentInfo = {1493          name: getComponentNameFromType(element.type) || '',1494          owner: element._owner,1495        };1496        // $FlowFixMe[cannot-write]1497        erroredComponent.debugStack = element._debugStack;1498        if (supportsCreateTask) {1499          // $FlowFixMe[cannot-write]1500          erroredComponent.debugTask = element._debugTask;1501        }1502        erroredChunk._debugInfo = [erroredComponent];1503      }1504      return createLazyChunkWrapper(erroredChunk, validated);1505    }1506    if (handler.deps > 0) {1507      // We have blocked references inside this Element but we can turn this into1508      // a Lazy node referencing this Element to let everything around it proceed.1509      const blockedChunk: BlockedChunk<React$Element<any>> =1510        createBlockedChunk(response);1511      handler.value = element;1512      handler.chunk = blockedChunk;1513      const lazyNode = createLazyChunkWrapper(blockedChunk, validated);1514      if (__DEV__) {1515        // After we have initialized any blocked references, initialize stack etc.1516        const init = initializeElement.bind(null, response, element, lazyNode);1517        blockedChunk.then(init, init);1518      }1519      return lazyNode;1520    }1521  }1522  if (__DEV__) {1523    initializeElement(response, element, null);1524  }15251526  return element;1527}15281529function transferValidation(store: {validated: 0 | 1 | 2}, value: mixed): void {1530  if (store.validated && typeof value === 'object' && value !== null) {1531    // Only elements and lazy nodes carry key validation. Any other value, e.g.1532    // an array of children, needs to have its own items validated instead.1533    const $$typeof = (value as any).$$typeof;1534    if ($$typeof === REACT_ELEMENT_TYPE || $$typeof === REACT_LAZY_TYPE) {1535      const valueStore = (value as any)._store;1536      if (valueStore && !valueStore.validated) {1537        valueStore.validated = store.validated;1538      }1539    }1540  }1541}15421543function readChunkAndTransferValidation<T>(1544  store: {validated: 0 | 1 | 2},1545  payload: SomeChunk<T>,1546): T {1547  const value: T = readChunk(payload);1548  transferValidation(store, value);1549  return value;1550}15511552function createLazyChunkWrapper<T>(1553  chunk: SomeChunk<T>,1554  validated: 0 | 1 | 2, // DEV-only1555): LazyComponent<T, SomeChunk<T>> {1556  const lazyType: LazyComponent<T, SomeChunk<T>> = {1557    $$typeof: REACT_LAZY_TYPE,1558    _payload: chunk,1559    _init: readChunk,1560  };1561  if (__DEV__) {1562    // Forward the live array1563    lazyType._debugInfo = chunk._debugInfo;1564    // Initialize a store for key validation by the JSX runtime. It can only1565    // validate the lazy node itself, because the value it refers to might not1566    // exist yet at that point, e.g. if it's an outlined row that hasn't been1567    // initialized. So the validation is transferred to the value when the lazy1568    // node is unwrapped. If the value is another lazy node, unwrapping that one1569    // forwards the validation further.1570    const store = {validated: validated};1571    lazyType._store = store;1572    // $FlowFixMe[incompatible-type] `bind` loses the type argument.1573    lazyType._init = readChunkAndTransferValidation.bind(null, store);1574  }1575  return lazyType;1576}15771578function getChunk(response: Response, id: number): SomeChunk<any> {1579  const chunks = response._chunks;1580  let chunk = chunks.get(id);1581  if (!chunk) {1582    if (response._closed) {1583      if (response._allowPartialStream) {1584        // For partial streams, chunks accessed after close should be HALTED1585        // (never resolve).1586        chunk = createHaltedChunk(response);1587      } else {1588        // We have already errored the response and we're not going to get1589        // anything more streaming in so this will immediately error.1590        chunk = createErrorChunk(response, response._closedReason);1591      }1592    } else {1593      chunk = createPendingChunk(response);1594    }1595    chunks.set(id, chunk);1596  }1597  return chunk;1598}15991600// Like getChunk, but for weak Promise references. The server may never emit1601// the row for a weak reference, so an unresolved weak chunk halts (stays1602// forever pending) instead of erroring when the stream closes.1603function getWeakChunk(response: Response, id: number): SomeChunk<any> {1604  const chunks = response._chunks;1605  let chunk = chunks.get(id);1606  if (!chunk) {1607    if (response._closed) {1608      // The stream already closed without emitting this row, so it will1609      // never resolve.1610      chunk = createHaltedChunk(response);1611    } else {1612      chunk = createPendingWeakChunk(response);1613    }1614    chunks.set(id, chunk);1615  }1616  return chunk;1617}16181619function fulfillReference(1620  response: Response,1621  reference: InitializationReference,1622  value: any,1623  fulfilledChunk: SomeChunk<any>,1624): void {1625  const {handler, parentObject, key, map, path} = reference;16261627  try {1628    for (let i = 1; i < path.length; i++) {1629      while (1630        typeof value === 'object' &&1631        value !== null &&1632        value.$$typeof === REACT_LAZY_TYPE1633      ) {1634        // We never expect to see a Lazy node on this path because we encode those as1635        // separate models. This must mean that we have inserted an extra lazy node1636        // e.g. to replace a blocked element. We must instead look for it inside.1637        const referencedChunk: SomeChunk<any> = value._payload;1638        if (referencedChunk === handler.chunk) {1639          // This is a reference to the thing we're currently blocking. We can peak1640          // inside of it to get the value.1641          value = handler.value;1642          continue;1643        } else {1644          switch (referencedChunk.status) {1645            case RESOLVED_MODEL:1646              initializeModelChunk(referencedChunk);1647              break;1648            case RESOLVED_MODULE:1649              initializeModuleChunk(referencedChunk);1650              break;1651          }1652          switch (referencedChunk.status) {1653            case INITIALIZED: {1654              value = referencedChunk.value;1655              continue;1656            }1657            case BLOCKED: {1658              // It is possible that we're blocked on our own chunk if it's a cycle.1659              // Before adding the listener to the inner chunk, let's check if it would1660              // result in a cycle.1661              const cyclicHandler = resolveBlockedCycle(1662                referencedChunk,1663                reference,1664              );1665              if (cyclicHandler !== null) {1666                // This reference points back to this chunk. We can resolve the cycle by1667                // using the value from that handler.1668                value = cyclicHandler.value;1669                continue;1670              }1671              // Fallthrough1672            }1673            case PENDING:1674            case PENDING_WEAK: {1675              // If we're not yet initialized we need to skip what we've already drilled1676              // through and then wait for the next value to become available.1677              path.splice(0, i - 1);1678              // Add "listener" to our new chunk dependency.1679              if (referencedChunk.value === null) {1680                referencedChunk.value = [reference];1681              } else {1682                referencedChunk.value.push(reference);1683              }1684              if (referencedChunk.reason === null) {1685                referencedChunk.reason = [reference];1686              } else {1687                referencedChunk.reason.push(reference);1688              }1689              return;1690            }1691            case HALTED: {1692              // Do nothing. We couldn't fulfill.1693              // TODO: Mark downstreams as halted too.1694              return;1695            }1696            default: {1697              rejectReference(1698                response,1699                reference.handler,1700                referencedChunk.reason,1701              );1702              return;1703            }1704          }1705        }1706      }1707      const name = path[i];1708      if (1709        typeof value === 'object' &&1710        value !== null &&1711        hasOwnProperty.call(value, name)1712      ) {1713        value = value[name];1714      } else {1715        throw new Error('Invalid reference.');1716      }1717    }17181719    while (1720      typeof value === 'object' &&1721      value !== null &&1722      value.$$typeof === REACT_LAZY_TYPE1723    ) {1724      // If what we're referencing is a Lazy it must be because we inserted one as a virtual node1725      // while it was blocked by other data. If it's no longer blocked, we can unwrap it.1726      const referencedChunk: SomeChunk<any> = value._payload;1727      if (referencedChunk === handler.chunk) {1728        // This is a reference to the thing we're currently blocking. We can peak1729        // inside of it to get the value.1730        value = handler.value;1731        continue;1732      } else {1733        switch (referencedChunk.status) {1734          case RESOLVED_MODEL:1735            initializeModelChunk(referencedChunk);1736            break;1737          case RESOLVED_MODULE:1738            initializeModuleChunk(referencedChunk);1739            break;1740        }1741        switch (referencedChunk.status) {1742          case INITIALIZED: {1743            value = referencedChunk.value;1744            continue;1745          }1746        }1747      }1748      break;1749    }17501751    const mappedValue = map(response, value, parentObject, key);1752    if (key !== __PROTO__) {1753      parentObject[key] = mappedValue;1754    }17551756    // If this is the root object for a model reference, where `handler.value`1757    // is a stale `null`, the resolved value can be used directly.1758    if (key === '' && handler.value === null) {1759      handler.value = mappedValue;1760    }17611762    // If the parent object is an unparsed React element tuple, we also need to1763    // update the props and owner of the parsed element object (i.e.1764    // handler.value).1765    if (1766      parentObject[0] === REACT_ELEMENT_TYPE &&1767      typeof handler.value === 'object' &&1768      handler.value !== null &&1769      handler.value.$$typeof === REACT_ELEMENT_TYPE1770    ) {1771      const element: any = handler.value;1772      switch (key) {1773        case '3':1774          if (__DEV__) {1775            transferReferencedDebugInfo(handler.chunk, fulfilledChunk);1776          }1777          element.props = mappedValue;1778          break;1779        case '4':1780          // This path doesn't call transferReferencedDebugInfo because this reference is to a debug chunk.1781          if (__DEV__) {1782            element._owner = mappedValue;1783          }1784          break;1785        case '5':1786          // This path doesn't call transferReferencedDebugInfo because this reference is to a debug chunk.1787          if (__DEV__) {1788            element._debugStack = mappedValue;1789          }1790          break;1791        default:1792          if (__DEV__) {1793            transferReferencedDebugInfo(handler.chunk, fulfilledChunk);1794          }1795          break;1796      }1797    } else if (__DEV__ && !reference.isDebug) {1798      transferReferencedDebugInfo(handler.chunk, fulfilledChunk);1799    }1800  } catch (error) {1801    rejectReference(response, reference.handler, error);1802    return;1803  }18041805  handler.deps--;18061807  if (handler.deps === 0) {1808    const chunk = handler.chunk;1809    if (chunk === null || chunk.status !== BLOCKED) {1810      return;1811    }1812    const resolveListeners = chunk.value;1813    const initializedChunk: InitializedChunk<any> = chunk as any;1814    initializedChunk.status = INITIALIZED;1815    initializedChunk.value = handler.value;1816    initializedChunk.reason = handler.reason; // Used by streaming chunks1817    if (resolveListeners !== null) {1818      wakeChunk(response, resolveListeners, handler.value, initializedChunk);1819    } else {1820      if (__DEV__) {1821        processChunkDebugInfo(response, initializedChunk, handler.value);1822      }1823    }1824  }1825}18261827function rejectReference(1828  response: Response,1829  handler: InitializationHandler,1830  error: mixed,1831): void {1832  if (handler.errored) {1833    // We've already errored. We could instead build up an AggregateError1834    // but if there are multiple errors we just take the first one like1835    // Promise.all.1836    return;1837  }1838  const blockedValue = handler.value;1839  handler.errored = true;1840  handler.value = null;1841  handler.reason = error;1842  const chunk = handler.chunk;1843  if (chunk === null || chunk.status !== BLOCKED) {1844    return;1845  }18461847  if (__DEV__) {1848    if (1849      typeof blockedValue === 'object' &&1850      blockedValue !== null &&1851      blockedValue.$$typeof === REACT_ELEMENT_TYPE1852    ) {1853      const element = blockedValue;1854      // Conceptually the error happened inside this Element but right before1855      // it was rendered. We don't have a client side component to render but1856      // we can add some DebugInfo to explain that this was conceptually a1857      // Server side error that errored inside this element. That way any stack1858      // traces will point to the nearest JSX that errored - e.g. during1859      // serialization.1860      const erroredComponent: ReactComponentInfo = {1861        name: getComponentNameFromType(element.type) || '',1862        owner: element._owner,1863      };1864      // $FlowFixMe[cannot-write]1865      erroredComponent.debugStack = element._debugStack;1866      if (supportsCreateTask) {1867        // $FlowFixMe[cannot-write]1868        erroredComponent.debugTask = element._debugTask;1869      }1870      chunk._debugInfo.push(erroredComponent);1871    }1872  }18731874  triggerErrorOnChunk(response, chunk, error);1875}18761877function waitForReference<T>(1878  referencedChunk: PendingChunk<T> | PendingWeakChunk<T> | BlockedChunk<T>,1879  parentObject: Object,1880  key: string,1881  response: Response,1882  map: (response: Response, model: any, parentObject: Object, key: string) => T,1883  path: Array<string>,1884  isAwaitingDebugInfo: boolean, // DEV-only1885): T {1886  if (1887    __DEV__ &&1888    (response._debugChannel === undefined ||1889      !response._debugChannel.hasReadable)1890  ) {1891    if (1892      referencedChunk.status === PENDING &&1893      parentObject[0] === REACT_ELEMENT_TYPE &&1894      (key === '4' || key === '5')1895    ) {1896      // If the parent object is an unparsed React element tuple, and this is a reference1897      // to the owner or debug stack. Then we expect the chunk to have been emitted earlier1898      // in the stream. It might be blocked on other things but chunk should no longer be pending.1899      // If it's still pending that suggests that it was referencing an object in the debug1900      // channel, but no debug channel was wired up so it's missing. In this case we can just1901      // drop the debug info instead of halting the whole stream.1902      return null as any;1903    }1904  }19051906  let handler: InitializationHandler;1907  if (initializingHandler) {1908    handler = initializingHandler;1909    handler.deps++;1910  } else {1911    handler = initializingHandler = {1912      parent: null,1913      chunk: null,1914      value: null,1915      reason: null,1916      deps: 1,1917      errored: false,1918    };1919  }19201921  const reference: InitializationReference = {1922    handler,1923    parentObject,1924    key,1925    map,1926    path,1927  };1928  if (__DEV__) {1929    reference.isDebug = isAwaitingDebugInfo;1930  }19311932  // Add "listener".1933  if (referencedChunk.value === null) {1934    referencedChunk.value = [reference];1935  } else {1936    referencedChunk.value.push(reference);1937  }1938  if (referencedChunk.reason === null) {1939    referencedChunk.reason = [reference];1940  } else {1941    referencedChunk.reason.push(reference);1942  }19431944  // Return a place holder value for now.1945  return null as any;1946}19471948function loadServerReference<A: Iterable<any>, T>(1949  response: Response,1950  metaData: {1951    id: any,1952    bound: null | Thenable<Array<any>>,1953    name?: string, // DEV-only1954    env?: string, // DEV-only1955    location?: ReactFunctionLocation, // DEV-only1956  },1957  parentObject: Object,1958  key: string,1959): (...A) => Promise<T> {1960  if (!response._serverReferenceConfig) {1961    // In the normal case, we can't load this Server Reference in the current environment and1962    // we just return a proxy to it.1963    return createBoundServerReference(1964      metaData,1965      response._callServer,1966      response._encodeFormAction,1967      __DEV__ ? response._debugFindSourceMapURL : undefined,1968    );1969  }1970  // If we have a module mapping we can load the real version of this Server Reference.1971  const serverReference: ClientReference<T> =1972    resolveServerReference<$FlowFixMe>(1973      response._serverReferenceConfig,1974      metaData.id,1975    );19761977  let promise: null | Thenable<any> = preloadModule(serverReference);1978  if (!promise) {1979    if (!metaData.bound) {1980      const resolvedValue = requireModule(serverReference) as any;1981      registerBoundServerReference(1982        resolvedValue,1983        metaData.id,1984        metaData.bound,1985        response._encodeFormAction,1986      );1987      return resolvedValue;1988    } else {1989      promise = Promise.resolve(metaData.bound);1990    }1991  } else if (metaData.bound) {1992    promise = Promise.all([promise, metaData.bound]);1993  }19941995  let handler: InitializationHandler;1996  if (initializingHandler) {1997    handler = initializingHandler;1998    handler.deps++;1999  } else {2000    handler = initializingHandler = {

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.