import type {Chunk, BinaryChunk, Destination} from './ReactServerStreamConfig';
import type {Postpone} from 'react/src/ReactPostpone';
import type {TemporaryReferenceSet} from './ReactFlightServerTemporaryReferences';
import {
enablePostpone,
enableHalt,
enableTaint,
enableProfilerTimer,
enableComponentPerformanceTrack,
enableAsyncDebugInfo,
} from 'shared/ReactFeatureFlags';
import {
scheduleWork,
scheduleMicrotask,
flushBuffered,
beginWriting,
writeChunkAndReturn,
stringToChunk,
typedArrayToBinaryChunk,
byteLengthOfChunk,
byteLengthOfBinaryChunk,
completeWriting,
close,
closeWithError,
} from './ReactServerStreamConfig';
export type {Destination, Chunk} from './ReactServerStreamConfig';
import type {
ClientManifest,
ClientReferenceMetadata,
ClientReference,
ClientReferenceKey,
ServerReference,
ServerReferenceId,
Hints,
HintCode,
HintModel,
} from './ReactFlightServerConfig';
import type {ThenableState} from './ReactFlightThenable';
import type {
Wakeable,
Thenable,
PendingThenable,
FulfilledThenable,
RejectedThenable,
ReactDebugInfo,
ReactComponentInfo,
ReactEnvironmentInfo,
ReactIOInfo,
ReactAsyncInfo,
ReactTimeInfo,
ReactStackTrace,
ReactCallSite,
ReactFunctionLocation,
ReactErrorInfo,
ReactErrorInfoDev,
} from 'shared/ReactTypes';
import type {ReactElement} from 'shared/ReactElementType';
import type {LazyComponent} from 'react/src/ReactLazy';
import type {
AsyncSequence,
IONode,
PromiseNode,
UnresolvedPromiseNode,
} from './ReactFlightAsyncSequence';
import {
resolveClientReferenceMetadata,
getServerReferenceId,
getServerReferenceBoundArguments,
getServerReferenceLocation,
getClientReferenceKey,
isClientReference,
isServerReference,
supportsRequestStorage,
requestStorage,
createHints,
initAsyncDebugInfo,
markAsyncSequenceRootTask,
getCurrentAsyncSequence,
getAsyncSequenceFromPromise,
parseStackTrace,
supportsComponentStorage,
componentStorage,
unbadgeConsole,
} from './ReactFlightServerConfig';
import {
resolveTemporaryReference,
isOpaqueTemporaryReference,
} from './ReactFlightServerTemporaryReferences';
import {
HooksDispatcher,
prepareToUseHooksForRequest,
prepareToUseHooksForComponent,
getThenableStateAfterSuspending,
getTrackedThenablesAfterRendering,
resetHooksForRequest,
} from './ReactFlightHooks';
import {DefaultAsyncDispatcher} from './flight/ReactFlightAsyncDispatcher';
import {resolveOwner, setCurrentOwner} from './flight/ReactFlightCurrentOwner';
import {getOwnerStackByComponentInfoInDev} from 'shared/ReactComponentInfoStack';
import {resetOwnerStackLimit} from 'shared/ReactOwnerStackReset';
import noop from 'shared/noop';
import {
callComponentInDEV,
callLazyInitInDEV,
callIteratorInDEV,
} from './ReactFlightCallUserSpace';
import {
getIteratorFn,
REACT_ELEMENT_TYPE,
REACT_LEGACY_ELEMENT_TYPE,
REACT_FORWARD_REF_TYPE,
REACT_FRAGMENT_TYPE,
REACT_LAZY_TYPE,
REACT_MEMO_TYPE,
REACT_POSTPONE_TYPE,
ASYNC_ITERATOR,
} from 'shared/ReactSymbols';
import {
describeObjectForErrorMessage,
isGetter,
isSimpleObject,
jsxPropsParents,
jsxChildrenParents,
objectName,
} from 'shared/ReactSerializationErrors';
import ReactSharedInternals from './ReactSharedInternalsServer';
import isArray from 'shared/isArray';
import getPrototypeOf from 'shared/getPrototypeOf';
import hasOwnProperty from 'shared/hasOwnProperty';
import binaryToComparableString from 'shared/binaryToComparableString';
import {SuspenseException, getSuspendedThenable} from './ReactFlightThenable';
import {
IO_NODE,
PROMISE_NODE,
AWAIT_NODE,
UNRESOLVED_AWAIT_NODE,
UNRESOLVED_PROMISE_NODE,
} from './ReactFlightAsyncSequence';
const doNotLimit: WeakSet<Reference> = __DEV__ ? new WeakSet() : (null: any);
function defaultFilterStackFrame(
filename: string,
functionName: string,
): boolean {
return (
filename !== '' &&
!filename.startsWith('node:') &&
!filename.includes('node_modules')
);
}
function devirtualizeURL(url: string): string {
if (url.startsWith('rsc://React/')) {
const envIdx = url.indexOf('/', 12);
const suffixIdx = url.lastIndexOf('?');
if (envIdx > -1 && suffixIdx > -1) {
return url.slice(envIdx + 1, suffixIdx);
}
}
return url;
}
function findCalledFunctionNameFromStackTrace(
request: Request,
stack: ReactStackTrace,
): string {
let bestMatch = '';
const filterStackFrame = request.filterStackFrame;
for (let i = 0; i < stack.length; i++) {
const callsite = stack[i];
const functionName = callsite[0];
const url = devirtualizeURL(callsite[1]);
if (filterStackFrame(url, functionName)) {
if (bestMatch === '') {
return functionName;
}
return bestMatch;
} else if (functionName === 'new Promise') {
} else if (url === 'node:internal/async_hooks') {
} else {
bestMatch = functionName;
}
}
return '';
}
function filterStackTrace(
request: Request,
stack: ReactStackTrace,
): ReactStackTrace {
const filterStackFrame = request.filterStackFrame;
const filteredStack: ReactStackTrace = [];
for (let i = 0; i < stack.length; i++) {
const callsite = stack[i];
const functionName = callsite[0];
const url = devirtualizeURL(callsite[1]);
if (filterStackFrame(url, functionName)) {
const clone: ReactCallSite = (callsite.slice(0): any);
clone[1] = url;
filteredStack.push(clone);
}
}
return filteredStack;
}
initAsyncDebugInfo();
function patchConsole(consoleInst: typeof console, methodName: string) {
const descriptor = Object.getOwnPropertyDescriptor(consoleInst, methodName);
if (
descriptor &&
(descriptor.configurable || descriptor.writable) &&
typeof descriptor.value === 'function'
) {
const originalMethod = descriptor.value;
const originalName = Object.getOwnPropertyDescriptor(
originalMethod,
'name',
);
const wrapperMethod = function (this: typeof console) {
const request = resolveRequest();
if (methodName === 'assert' && arguments[0]) {
} else if (request !== null) {
const stack = filterStackTrace(
request,
parseStackTrace(new Error('react-stack-top-frame'), 1),
);
request.pendingChunks++;
const owner: null | ReactComponentInfo = resolveOwner();
const args = Array.from(arguments);
let env = unbadgeConsole(methodName, args);
if (env === null) {
env = (0, request.environmentName)();
}
emitConsoleChunk(request, methodName, owner, env, stack, args);
}
return originalMethod.apply(this, arguments);
};
if (originalName) {
Object.defineProperty(
wrapperMethod,
'name',
originalName,
);
}
Object.defineProperty(consoleInst, methodName, {
value: wrapperMethod,
});
}
}
if (__DEV__ && typeof console === 'object' && console !== null) {
patchConsole(console, 'assert');
patchConsole(console, 'debug');
patchConsole(console, 'dir');
patchConsole(console, 'dirxml');
patchConsole(console, 'error');
patchConsole(console, 'group');
patchConsole(console, 'groupCollapsed');
patchConsole(console, 'groupEnd');
patchConsole(console, 'info');
patchConsole(console, 'log');
patchConsole(console, 'table');
patchConsole(console, 'trace');
patchConsole(console, 'warn');
}
function getCurrentStackInDEV(): string {
if (__DEV__) {
const owner: null | ReactComponentInfo = resolveOwner();
if (owner === null) {
return '';
}
return getOwnerStackByComponentInfoInDev(owner);
}
return '';
}
const ObjectPrototype = Object.prototype;
type JSONValue =
| string
| boolean
| number
| null
| {+[key: string]: JSONValue}
| $ReadOnlyArray<JSONValue>;
const stringify = JSON.stringify;
type ReactJSONValue =
| string
| boolean
| number
| null
| $ReadOnlyArray<ReactClientValue>
| ReactClientObject;
export type ReactClientValue =
| React$Element<React$ComponentType<any>>
| LazyComponent<ReactClientValue, any>
| ClientReference<any>
| ServerReference<any>
| React$Element<string>
| React$Element<ClientReference<any> & any>
| ReactComponentInfo
| string
| boolean
| number
| symbol
| null
| void
| bigint
| ReadableStream
| $AsyncIterable<ReactClientValue, ReactClientValue, void>
| $AsyncIterator<ReactClientValue, ReactClientValue, void>
| Iterable<ReactClientValue>
| Iterator<ReactClientValue>
| Array<ReactClientValue>
| Map<ReactClientValue, ReactClientValue>
| Set<ReactClientValue>
| FormData
| $ArrayBufferView
| ArrayBuffer
| Date
| ReactClientObject
| Promise<ReactClientValue>;
type ReactClientObject = {+[key: string]: ReactClientValue};
const PENDING = 0;
const COMPLETED = 1;
const ABORTED = 3;
const ERRORED = 4;
const RENDERING = 5;
type Task = {
id: number,
status: 0 | 1 | 3 | 4 | 5,
model: ReactClientValue,
ping: () => void,
toJSON: (key: string, value: ReactClientValue) => ReactJSONValue,
keyPath: null | string,
implicitSlot: boolean,
thenableState: ThenableState | null,
timed: boolean,
time: number,
environmentName: string,
debugOwner: null | ReactComponentInfo,
debugStack: null | Error,
debugTask: null | ConsoleTask,
};
interface Reference {}
type ReactClientReference = Reference & ReactClientValue;
type DeferredDebugStore = {
retained: Map<number, ReactClientReference | string>,
existing: Map<ReactClientReference | string, number>,
};
const OPENING = 10;
const OPEN = 11;
const ABORTING = 12;
const CLOSING = 13;
const CLOSED = 14;
const RENDER = 20;
const PRERENDER = 21;
export type Request = {
status: 10 | 11 | 12 | 13 | 14,
type: 20 | 21,
flushScheduled: boolean,
fatalError: mixed,
destination: null | Destination,
bundlerConfig: ClientManifest,
cache: Map<Function, mixed>,
cacheController: AbortController,
nextChunkId: number,
pendingChunks: number,
hints: Hints,
abortableTasks: Set<Task>,
pingedTasks: Array<Task>,
completedImportChunks: Array<Chunk>,
completedHintChunks: Array<Chunk>,
completedRegularChunks: Array<Chunk | BinaryChunk>,
completedErrorChunks: Array<Chunk>,
writtenSymbols: Map<symbol, number>,
writtenClientReferences: Map<ClientReferenceKey, number>,
writtenServerReferences: Map<ServerReference<any>, number>,
writtenObjects: WeakMap<Reference, string>,
temporaryReferences: void | TemporaryReferenceSet,
identifierPrefix: string,
identifierCount: number,
taintCleanupQueue: Array<string | bigint>,
onError: (error: mixed) => ?string,
onPostpone: (reason: string) => void,
onAllReady: () => void,
onFatalError: mixed => void,
timeOrigin: number,
abortTime: number,
completedDebugChunks: Array<Chunk | BinaryChunk>,
environmentName: () => string,
filterStackFrame: (url: string, functionName: string) => boolean,
didWarnForKey: null | WeakSet<ReactComponentInfo>,
writtenDebugObjects: WeakMap<Reference, string>,
deferredDebugObjects: null | DeferredDebugStore,
};
const {
TaintRegistryObjects,
TaintRegistryValues,
TaintRegistryByteLengths,
TaintRegistryPendingRequests,
} = ReactSharedInternals;
function throwTaintViolation(message: string) {
throw new Error(message);
}
function cleanupTaintQueue(request: Request): void {
const cleanupQueue = request.taintCleanupQueue;
TaintRegistryPendingRequests.delete(cleanupQueue);
for (let i = 0; i < cleanupQueue.length; i++) {
const entryValue = cleanupQueue[i];
const entry = TaintRegistryValues.get(entryValue);
if (entry !== undefined) {
if (entry.count === 1) {
TaintRegistryValues.delete(entryValue);
} else {
entry.count--;
}
}
}
cleanupQueue.length = 0;
}
function defaultErrorHandler(error: mixed) {
console['error'](error);
}
const defaultPostponeHandler: (reason: string) => void = noop;
function RequestInstance(
this: $FlowFixMe,
type: 20 | 21,
model: ReactClientValue,
bundlerConfig: ClientManifest,
onError: void | ((error: mixed) => ?string),
onPostpone: void | ((reason: string) => void),
onAllReady: () => void,
onFatalError: (error: mixed) => void,
identifierPrefix?: string,
temporaryReferences: void | TemporaryReferenceSet,
environmentName: void | string | (() => string),
filterStackFrame: void | ((url: string, functionName: string) => boolean),
keepDebugAlive: boolean,
) {
if (
ReactSharedInternals.A !== null &&
ReactSharedInternals.A !== DefaultAsyncDispatcher
) {
throw new Error(
'Currently React only supports one RSC renderer at a time.',
);
}
ReactSharedInternals.A = DefaultAsyncDispatcher;
if (__DEV__) {
ReactSharedInternals.getCurrentStack = getCurrentStackInDEV;
}
const abortSet: Set<Task> = new Set();
const pingedTasks: Array<Task> = [];
const cleanupQueue: Array<string | bigint> = [];
if (enableTaint) {
TaintRegistryPendingRequests.add(cleanupQueue);
}
const hints = createHints();
this.type = type;
this.status = OPENING;
this.flushScheduled = false;
this.fatalError = null;
this.destination = null;
this.bundlerConfig = bundlerConfig;
this.cache = new Map();
this.cacheController = new AbortController();
this.nextChunkId = 0;
this.pendingChunks = 0;
this.hints = hints;
this.abortableTasks = abortSet;
this.pingedTasks = pingedTasks;
this.completedImportChunks = ([]: Array<Chunk>);
this.completedHintChunks = ([]: Array<Chunk>);
this.completedRegularChunks = ([]: Array<Chunk | BinaryChunk>);
this.completedErrorChunks = ([]: Array<Chunk>);
this.writtenSymbols = new Map();
this.writtenClientReferences = new Map();
this.writtenServerReferences = new Map();
this.writtenObjects = new WeakMap();
this.temporaryReferences = temporaryReferences;
this.identifierPrefix = identifierPrefix || '';
this.identifierCount = 1;
this.taintCleanupQueue = cleanupQueue;
this.onError = onError === undefined ? defaultErrorHandler : onError;
this.onPostpone =
onPostpone === undefined ? defaultPostponeHandler : onPostpone;
this.onAllReady = onAllReady;
this.onFatalError = onFatalError;
if (__DEV__) {
this.completedDebugChunks = ([]: Array<Chunk>);
this.environmentName =
environmentName === undefined
? () => 'Server'
: typeof environmentName !== 'function'
? () => environmentName
: environmentName;
this.filterStackFrame =
filterStackFrame === undefined
? defaultFilterStackFrame
: filterStackFrame;
this.didWarnForKey = null;
this.writtenDebugObjects = new WeakMap();
this.deferredDebugObjects = keepDebugAlive
? {
retained: new Map(),
existing: new Map(),
}
: null;
}
let timeOrigin: number;
if (enableProfilerTimer && enableComponentPerformanceTrack) {
timeOrigin = this.timeOrigin = performance.now();
emitTimeOriginChunk(
this,
timeOrigin +
performance.timeOrigin,
);
this.abortTime = -0.0;
} else {
timeOrigin = 0;
}
const rootTask = createTask(
this,
model,
null,
false,
abortSet,
timeOrigin,
null,
null,
null,
);
pingedTasks.push(rootTask);
}
export function createRequest(
model: ReactClientValue,
bundlerConfig: ClientManifest,
onError: void | ((error: mixed) => ?string),
identifierPrefix: void | string,
onPostpone: void | ((reason: string) => void),
temporaryReferences: void | TemporaryReferenceSet,
environmentName: void | string | (() => string),
filterStackFrame: void | ((url: string, functionName: string) => boolean),
keepDebugAlive: boolean,
): Request {
if (__DEV__) {
resetOwnerStackLimit();
}
return new RequestInstance(
RENDER,
model,
bundlerConfig,
onError,
onPostpone,
noop,
noop,
identifierPrefix,
temporaryReferences,
environmentName,
filterStackFrame,
keepDebugAlive,
);
}
export function createPrerenderRequest(
model: ReactClientValue,
bundlerConfig: ClientManifest,
onAllReady: () => void,
onFatalError: () => void,
onError: void | ((error: mixed) => ?string),
identifierPrefix: void | string,
onPostpone: void | ((reason: string) => void),
temporaryReferences: void | TemporaryReferenceSet,
environmentName: void | string | (() => string),
filterStackFrame: void | ((url: string, functionName: string) => boolean),
keepDebugAlive: boolean,
): Request {
if (__DEV__) {
resetOwnerStackLimit();
}
return new RequestInstance(
PRERENDER,
model,
bundlerConfig,
onError,
onPostpone,
onAllReady,
onFatalError,
identifierPrefix,
temporaryReferences,
environmentName,
filterStackFrame,
keepDebugAlive,
);
}
let currentRequest: null | Request = null;
export function resolveRequest(): null | Request {
if (currentRequest) return currentRequest;
if (supportsRequestStorage) {
const store = requestStorage.getStore();
if (store) return store;
}
return null;
}
function serializeDebugThenable(
request: Request,
counter: {objectLimit: number},
thenable: Thenable<any>,
): string {
request.pendingChunks++;
const id = request.nextChunkId++;
const ref = serializePromiseID(id);
request.writtenDebugObjects.set(thenable, ref);
switch (thenable.status) {
case 'fulfilled': {
emitOutlinedDebugModelChunk(request, id, counter, thenable.value);
return ref;
}
case 'rejected': {
const x = thenable.reason;
if (
enablePostpone &&
typeof x === 'object' &&
x !== null &&
(x: any).$$typeof === REACT_POSTPONE_TYPE
) {
const postponeInstance: Postpone = (x: any);
emitPostponeChunk(request, id, postponeInstance);
} else {
const digest = '';
emitErrorChunk(request, id, digest, x, true);
}
return ref;
}
}
if (request.status === ABORTING) {
emitDebugHaltChunk(request, id);
return ref;
}
let cancelled = false;
thenable.then(
value => {
if (cancelled) {
return;
}
cancelled = true;
if (request.status === ABORTING) {
emitDebugHaltChunk(request, id);
enqueueFlush(request);
return;
}
emitOutlinedDebugModelChunk(request, id, counter, value);
enqueueFlush(request);
},
reason => {
if (cancelled) {
return;
}
cancelled = true;
if (request.status === ABORTING) {
emitDebugHaltChunk(request, id);
enqueueFlush(request);
return;
}
if (
enablePostpone &&
typeof reason === 'object' &&
reason !== null &&
(reason: any).$$typeof === REACT_POSTPONE_TYPE
) {
const postponeInstance: Postpone = (reason: any);
emitPostponeChunk(request, id, postponeInstance);
} else {
const digest = '';
emitErrorChunk(request, id, digest, reason, true);
}
enqueueFlush(request);
},
);
Promise.resolve().then(() => {
if (cancelled) {
return;
}
cancelled = true;
emitDebugHaltChunk(request, id);
enqueueFlush(request);
request = (null: any);
counter = (null: any);
});
return ref;
}
function serializeThenable(
request: Request,
task: Task,
thenable: Thenable<any>,
): number {
const newTask = createTask(
request,
(thenable: any),
task.keyPath,
task.implicitSlot,
request.abortableTasks,
enableProfilerTimer && enableComponentPerformanceTrack ? task.time : 0,
__DEV__ ? task.debugOwner : null,
__DEV__ ? task.debugStack : null,
__DEV__ ? task.debugTask : null,
);
switch (thenable.status) {
case 'fulfilled': {
forwardDebugInfoFromThenable(request, newTask, thenable, null, null);
newTask.model = thenable.value;
pingTask(request, newTask);
return newTask.id;
}
case 'rejected': {
forwardDebugInfoFromThenable(request, newTask, thenable, null, null);
const x = thenable.reason;
erroredTask(request, newTask, x);
return newTask.id;
}
default: {
if (request.status === ABORTING) {
request.abortableTasks.delete(newTask);
if (enableHalt && request.type === PRERENDER) {
haltTask(newTask, request);
finishHaltedTask(newTask, request);
} else {
const errorId: number = (request.fatalError: any);
abortTask(newTask, request, errorId);
finishAbortedTask(newTask, request, errorId);
}
return newTask.id;
}
if (typeof thenable.status === 'string') {
break;
}
const pendingThenable: PendingThenable<mixed> = (thenable: any);
pendingThenable.status = 'pending';
pendingThenable.then(
fulfilledValue => {
if (thenable.status === 'pending') {
const fulfilledThenable: FulfilledThenable<mixed> = (thenable: any);
fulfilledThenable.status = 'fulfilled';
fulfilledThenable.value = fulfilledValue;
}
},
(error: mixed) => {
if (thenable.status === 'pending') {
const rejectedThenable: RejectedThenable<mixed> = (thenable: any);
rejectedThenable.status = 'rejected';
rejectedThenable.reason = error;
}
},
);
break;
}
}
thenable.then(
value => {
forwardDebugInfoFromCurrentContext(request, newTask, thenable);
newTask.model = value;
pingTask(request, newTask);
},
reason => {
if (newTask.status === PENDING) {
if (enableProfilerTimer && enableComponentPerformanceTrack) {
newTask.timed = true;
}
erroredTask(request, newTask, reason);
enqueueFlush(request);
}
},
);
return newTask.id;
}
function serializeReadableStream(
request: Request,
task: Task,
stream: ReadableStream,
): string {
let supportsBYOB: void | boolean = stream.supportsBYOB;
if (supportsBYOB === undefined) {
try {
stream.getReader({mode: 'byob'}).releaseLock();
supportsBYOB = true;
} catch (x) {
supportsBYOB = false;
}
}
const reader = stream.getReader();
const streamTask = createTask(
request,
task.model,
task.keyPath,
task.implicitSlot,
request.abortableTasks,
enableProfilerTimer && enableComponentPerformanceTrack ? task.time : 0,
__DEV__ ? task.debugOwner : null,
__DEV__ ? task.debugStack : null,
__DEV__ ? task.debugTask : null,
);
request.pendingChunks++;
const startStreamRow =
streamTask.id.toString(16) + ':' + (supportsBYOB ? 'r' : 'R') + '\n';
request.completedRegularChunks.push(stringToChunk(startStreamRow));
function progress(entry: {done: boolean, value: ReactClientValue, ...}) {
if (streamTask.status !== PENDING) {
return;
}
if (entry.done) {
streamTask.status = COMPLETED;
const endStreamRow = streamTask.id.toString(16) + ':C\n';
request.completedRegularChunks.push(stringToChunk(endStreamRow));
request.abortableTasks.delete(streamTask);
request.cacheController.signal.removeEventListener('abort', abortStream);
enqueueFlush(request);
callOnAllReadyIfReady(request);
} else {
try {
streamTask.model = entry.value;
request.pendingChunks++;
tryStreamTask(request, streamTask);
enqueueFlush(request);
reader.read().then(progress, error);
} catch (x) {
error(x);
}
}
}
function error(reason: mixed) {
if (streamTask.status !== PENDING) {
return;
}
request.cacheController.signal.removeEventListener('abort', abortStream);
erroredTask(request, streamTask, reason);
enqueueFlush(request);
reader.cancel(reason).then(error, error);
}
function abortStream() {
if (streamTask.status !== PENDING) {
return;
}
const signal = request.cacheController.signal;
signal.removeEventListener('abort', abortStream);
const reason = signal.reason;
if (enableHalt && request.type === PRERENDER) {
haltTask(streamTask, request);
request.abortableTasks.delete(streamTask);
} else {
erroredTask(request, streamTask, reason);
enqueueFlush(request);
}
reader.cancel(reason).then(error, error);
}
request.cacheController.signal.addEventListener('abort', abortStream);
reader.read().then(progress, error);
return serializeByValueID(streamTask.id);
}
function serializeAsyncIterable(
request: Request,
task: Task,
iterable: $AsyncIterable<ReactClientValue, ReactClientValue, void>,
iterator: $AsyncIterator<ReactClientValue, ReactClientValue, void>,
): string {
const isIterator = iterable === iterator;
const streamTask = createTask(
request,
task.model,
task.keyPath,
task.implicitSlot,
request.abortableTasks,
enableProfilerTimer && enableComponentPerformanceTrack ? task.time : 0,
__DEV__ ? task.debugOwner : null,
__DEV__ ? task.debugStack : null,
__DEV__ ? task.debugTask : null,
);
request.pendingChunks++;
const startStreamRow =
streamTask.id.toString(16) + ':' + (isIterator ? 'x' : 'X') + '\n';
request.completedRegularChunks.push(stringToChunk(startStreamRow));
if (__DEV__) {
const debugInfo: ?ReactDebugInfo = (iterable: any)._debugInfo;
if (debugInfo) {
forwardDebugInfo(request, streamTask, debugInfo);
}
}
function progress(
entry:
| {done: false, +value: ReactClientValue, ...}
| {done: true, +value: ReactClientValue, ...},
) {
if (streamTask.status !== PENDING) {
return;
}
if (entry.done) {
streamTask.status = COMPLETED;
let endStreamRow;
if (entry.value === undefined) {
endStreamRow = streamTask.id.toString(16) + ':C\n';
} else {
try {
const chunkId = outlineModel(request, entry.value);
endStreamRow =
streamTask.id.toString(16) +
':C' +
stringify(serializeByValueID(chunkId)) +
'\n';
} catch (x) {
error(x);
return;
}
}
request.completedRegularChunks.push(stringToChunk(endStreamRow));
request.abortableTasks.delete(streamTask);
request.cacheController.signal.removeEventListener(
'abort',
abortIterable,
);
enqueueFlush(request);
callOnAllReadyIfReady(request);
} else {
try {
streamTask.model = entry.value;
request.pendingChunks++;
tryStreamTask(request, streamTask);
enqueueFlush(request);
if (__DEV__) {
callIteratorInDEV(iterator, progress, error);
} else {
iterator.next().then(progress, error);
}
} catch (x) {
error(x);
return;
}
}
}
function error(reason: mixed) {
if (streamTask.status !== PENDING) {
return;
}
request.cacheController.signal.removeEventListener('abort', abortIterable);
erroredTask(request, streamTask, reason);
enqueueFlush(request);
if (typeof (iterator: any).throw === 'function') {
iterator.throw(reason).then(error, error);
}
}
function abortIterable() {
if (streamTask.status !== PENDING) {
return;
}
const signal = request.cacheController.signal;
signal.removeEventListener('abort', abortIterable);
const reason = signal.reason;
if (enableHalt && request.type === PRERENDER) {
haltTask(streamTask, request);
request.abortableTasks.delete(streamTask);
} else {
erroredTask(request, streamTask, signal.reason);
enqueueFlush(request);
}
if (typeof (iterator: any).throw === 'function') {
iterator.throw(reason).then(error, error);
}
}
request.cacheController.signal.addEventListener('abort', abortIterable);
if (__DEV__) {
callIteratorInDEV(iterator, progress, error);
} else {
iterator.next().then(progress, error);
}
return serializeByValueID(streamTask.id);
}
export function emitHint<Code: HintCode>(
request: Request,
code: Code,
model: HintModel<Code>,
): void {
emitHintChunk(request, code, model);
enqueueFlush(request);
}
export function getHints(request: Request): Hints {
return request.hints;
}
export function getCache(request: Request): Map<Function, mixed> {
return request.cache;
}
function readThenable<T>(thenable: Thenable<T>): T {
if (thenable.status === 'fulfilled') {
return thenable.value;
} else if (thenable.status === 'rejected') {
throw thenable.reason;
}
throw thenable;
}
function createLazyWrapperAroundWakeable(
request: Request,
task: Task,
wakeable: Wakeable,
) {
const thenable: Thenable<mixed> = (wakeable: any);
switch (thenable.status) {
case 'fulfilled': {
forwardDebugInfoFromThenable(request, task, thenable, null, null);
return thenable.value;
}
case 'rejected':
forwardDebugInfoFromThenable(request, task, thenable, null, null);
break;
default: {
if (typeof thenable.status === 'string') {
break;
}
const pendingThenable: PendingThenable<mixed> = (thenable: any);
pendingThenable.status = 'pending';
pendingThenable.then(
fulfilledValue => {
forwardDebugInfoFromCurrentContext(request, task, thenable);
if (thenable.status === 'pending') {
const fulfilledThenable: FulfilledThenable<mixed> = (thenable: any);
fulfilledThenable.status = 'fulfilled';
fulfilledThenable.value = fulfilledValue;
}
},
(error: mixed) => {
forwardDebugInfoFromCurrentContext(request, task, thenable);
if (thenable.status === 'pending') {
const rejectedThenable: RejectedThenable<mixed> = (thenable: any);
rejectedThenable.status = 'rejected';
rejectedThenable.reason = error;
}
},
);
break;
}
}
const lazyType: LazyComponent<any, Thenable<any>> = {
$$typeof: REACT_LAZY_TYPE,
_payload: thenable,
_init: readThenable,
};
return lazyType;
}
function callWithDebugContextInDEV<A, T>(
request: Request,
task: Task,
callback: A => T,
arg: A,
): T {
const componentDebugInfo: ReactComponentInfo = {
name: '',
env: task.environmentName,
key: null,
owner: task.debugOwner,
};
componentDebugInfo.stack =
task.debugStack === null
? null
: filterStackTrace(request, parseStackTrace(task.debugStack, 1));
componentDebugInfo.debugStack = task.debugStack;
componentDebugInfo.debugTask = task.debugTask;
const debugTask = task.debugTask;
setCurrentOwner(componentDebugInfo);
try {
if (debugTask) {
return debugTask.run(callback.bind(null, arg));
}
return callback(arg);
} finally {
setCurrentOwner(null);
}
}
const voidHandler = () => {};
function processServerComponentReturnValue(
request: Request,
task: Task,
Component: any,
result: any,
): any {
if (
typeof result !== 'object' ||
result === null ||
isClientReference(result)
) {
return result;
}
if (typeof result.then === 'function') {
const thenable: Thenable<any> = result;
if (__DEV__) {
thenable.then(resolvedValue => {
if (
typeof resolvedValue === 'object' &&
resolvedValue !== null &&
resolvedValue.$$typeof === REACT_ELEMENT_TYPE
) {
resolvedValue._store.validated = 1;
}
}, voidHandler);
}
return createLazyWrapperAroundWakeable(request, task, result);
}
if (__DEV__) {
if ((result: any).$$typeof === REACT_ELEMENT_TYPE) {
(result: any)._store.validated = 1;
}
}
const iteratorFn = getIteratorFn(result);
if (iteratorFn) {
const iterableChild = result;
const multiShot = {
[Symbol.iterator]: function () {
const iterator = iteratorFn.call(iterableChild);
if (__DEV__) {
if (iterator === iterableChild) {
const isGeneratorComponent =
Object.prototype.toString.call(Component) ===
'[object GeneratorFunction]' &&
Object.prototype.toString.call(iterableChild) ===
'[object Generator]';
if (!isGeneratorComponent) {
callWithDebugContextInDEV(request, task, () => {
console.error(
'Returning an Iterator from a Server Component is not supported ' +
'since it cannot be looped over more than once. ',
);
});
}
}
}
return (iterator: any);
},
};
if (__DEV__) {
(multiShot: any)._debugInfo = iterableChild._debugInfo;
}
return multiShot;
}
if (
typeof (result: any)[ASYNC_ITERATOR] === 'function' &&
(typeof ReadableStream !== 'function' ||
!(result instanceof ReadableStream))
) {
const iterableChild = result;
const multishot = {
[ASYNC_ITERATOR]: function () {
const iterator = (iterableChild: any)[ASYNC_ITERATOR]();
if (__DEV__) {
if (iterator === iterableChild) {
const isGeneratorComponent =
Object.prototype.toString.call(Component) ===
'[object AsyncGeneratorFunction]' &&
Object.prototype.toString.call(iterableChild) ===
'[object AsyncGenerator]';
if (!isGeneratorComponent) {
callWithDebugContextInDEV(request, task, () => {
console.error(
'Returning an AsyncIterator from a Server Component is not supported ' +
'since it cannot be looped over more than once. ',
);
});
}
}
}
return iterator;
},
};
if (__DEV__) {
(multishot: any)._debugInfo = iterableChild._debugInfo;
}
return multishot;
}
return result;
}
function renderFunctionComponent<Props>(
request: Request,
task: Task,
key: null | string,
Component: (p: Props, arg: void) => any,
props: Props,
validated: number,
): ReactJSONValue {
const prevThenableState = task.thenableState;
task.thenableState = null;
let result;
let componentDebugInfo: ReactComponentInfo;
if (__DEV__) {
if (!canEmitDebugInfo) {
return outlineTask(request, task);
} else if (prevThenableState !== null) {
componentDebugInfo = (prevThenableState: any)._componentDebugInfo;
} else {
const componentDebugID = task.id;
const componentName =
(Component: any).displayName || Component.name || '';
const componentEnv = (0, request.environmentName)();
request.pendingChunks++;
componentDebugInfo = ({
name: componentName,
env: componentEnv,
key: key,
owner: task.debugOwner,
}: ReactComponentInfo);
componentDebugInfo.stack =
task.debugStack === null
? null
: filterStackTrace(request, parseStackTrace(task.debugStack, 1));
componentDebugInfo.props = props;
componentDebugInfo.debugStack = task.debugStack;
componentDebugInfo.debugTask = task.debugTask;
outlineComponentInfo(request, componentDebugInfo);
if (enableProfilerTimer && enableComponentPerformanceTrack) {
advanceTaskTime(request, task, performance.now());
}
emitDebugChunk(request, componentDebugID, componentDebugInfo);
task.environmentName = componentEnv;
if (validated === 2) {
warnForMissingKey(request, key, componentDebugInfo, task.debugTask);
}
}
prepareToUseHooksForComponent(prevThenableState, componentDebugInfo);
if (supportsComponentStorage) {
if (task.debugTask) {
result = task.debugTask.run(
componentStorage.run.bind(
componentStorage,
componentDebugInfo,
callComponentInDEV,
Component,
props,
componentDebugInfo,
),
);
} else {
result = componentStorage.run(
componentDebugInfo,
callComponentInDEV,
Component,
props,
componentDebugInfo,
);
}
} else {
if (task.debugTask) {
result = task.debugTask.run(
callComponentInDEV.bind(null, Component, props, componentDebugInfo),
);
} else {
result = callComponentInDEV(Component, props, componentDebugInfo);
}
}
} else {
componentDebugInfo = (null: any);
prepareToUseHooksForComponent(prevThenableState, null);
const secondArg = undefined;
result = Component(props, secondArg);
}
if (request.status === ABORTING) {
if (
typeof result === 'object' &&
result !== null &&
typeof result.then === 'function' &&
!isClientReference(result)
) {
result.then(voidHandler, voidHandler);
}
throw null;
}
if (
__DEV__ ||
(enableProfilerTimer &&
enableComponentPerformanceTrack &&
enableAsyncDebugInfo)
) {
const trackedThenables = getTrackedThenablesAfterRendering();
if (trackedThenables !== null) {
const stacks: Array<Error> =
__DEV__ && enableAsyncDebugInfo
? (trackedThenables: any)._stacks ||
((trackedThenables: any)._stacks = [])
: (null: any);
for (let i = 0; i < trackedThenables.length; i++) {
const stack = __DEV__ && enableAsyncDebugInfo ? stacks[i] : null;
forwardDebugInfoFromThenable(
request,
task,
trackedThenables[i],
__DEV__ ? componentDebugInfo : null,
stack,
);
}
}
}
result = processServerComponentReturnValue(request, task, Component, result);
const prevKeyPath = task.keyPath;
const prevImplicitSlot = task.implicitSlot;
if (key !== null) {
task.keyPath = prevKeyPath === null ? key : prevKeyPath + ',' + key;
} else if (prevKeyPath === null) {
task.implicitSlot = true;
}
const json = renderModelDestructive(request, task, emptyRoot, '', result);
task.keyPath = prevKeyPath;
task.implicitSlot = prevImplicitSlot;
return json;
}
function warnForMissingKey(
request: Request,
key: null | string,
componentDebugInfo: ReactComponentInfo,
debugTask: null | ConsoleTask,
): void {
if (__DEV__) {
let didWarnForKey = request.didWarnForKey;
if (didWarnForKey == null) {
didWarnForKey = request.didWarnForKey = new WeakSet();
}
const parentOwner = componentDebugInfo.owner;
if (parentOwner != null) {
if (didWarnForKey.has(parentOwner)) {
return;
}
didWarnForKey.add(parentOwner);
}
const logKeyError = () => {
console.error(
'Each child in a list should have a unique "key" prop.' +
'%s%s See https://react.dev/link/warning-keys for more information.',
'',
'',
);
};
if (supportsComponentStorage) {
if (debugTask) {
debugTask.run(
componentStorage.run.bind(
componentStorage,
componentDebugInfo,
callComponentInDEV,
logKeyError,
null,
componentDebugInfo,
),
);
} else {
componentStorage.run(
componentDebugInfo,
callComponentInDEV,
logKeyError,
null,
componentDebugInfo,
);
}
} else {
if (debugTask) {
debugTask.run(
callComponentInDEV.bind(null, logKeyError, null, componentDebugInfo),
);
} else {
callComponentInDEV(logKeyError, null, componentDebugInfo);
}
}
}
}
function renderFragment(
request: Request,
task: Task,
children: $ReadOnlyArray<ReactClientValue>,
): ReactJSONValue {
if (__DEV__) {
for (let i = 0; i < children.length; i++) {
const child = children[i];
if (
child !== null &&
typeof child === 'object' &&
child.$$typeof === REACT_ELEMENT_TYPE
) {
const element: ReactElement = (child: any);
if (element.key === null && !element._store.validated) {
element._store.validated = 2;
}
}
}
}
if (task.keyPath !== null) {
const fragment = __DEV__
? [
REACT_ELEMENT_TYPE,
REACT_FRAGMENT_TYPE,
task.keyPath,
{children},
null,
null,
0,
]
: [REACT_ELEMENT_TYPE, REACT_FRAGMENT_TYPE, task.keyPath, {children}];
if (!task.implicitSlot) {
return fragment;
}
return [fragment];
}
if (__DEV__) {
const debugInfo: ?ReactDebugInfo = (children: any)._debugInfo;
if (debugInfo) {
if (!canEmitDebugInfo) {
return outlineTask(request, task);
} else {
forwardDebugInfo(request, task, debugInfo);
}
children = Array.from(children);
}
}
return children;
}
function renderAsyncFragment(
request: Request,
task: Task,
children: $AsyncIterable<ReactClientValue, ReactClientValue, void>,
getAsyncIterator: () => $AsyncIterator<any, any, any>,
): ReactJSONValue {
if (task.keyPath !== null) {
const fragment = __DEV__
? [
REACT_ELEMENT_TYPE,
REACT_FRAGMENT_TYPE,
task.keyPath,
{children},
null,
null,
0,
]
: [REACT_ELEMENT_TYPE, REACT_FRAGMENT_TYPE, task.keyPath, {children}];
if (!task.implicitSlot) {
return fragment;
}
return [fragment];
}
const asyncIterator = getAsyncIterator.call(children);
return serializeAsyncIterable(request, task, children, asyncIterator);
}
function renderClientElement(
request: Request,
task: Task,
type: any,
key: null | string,
props: any,
validated: number,
): ReactJSONValue {
const keyPath = task.keyPath;
if (key === null) {
key = keyPath;
} else if (keyPath !== null) {
key = keyPath + ',' + key;
}
let debugOwner = null;
let debugStack = null;
if (__DEV__) {
debugOwner = task.debugOwner;
if (debugOwner !== null) {
outlineComponentInfo(request, debugOwner);
}
if (task.debugStack !== null) {
debugStack = filterStackTrace(
request,
parseStackTrace(task.debugStack, 1),
);
const id = outlineDebugModel(
request,
{objectLimit: debugStack.length * 2 + 1},
debugStack,
);
request.writtenObjects.set(debugStack, serializeByValueID(id));
}
}
const element = __DEV__
? [REACT_ELEMENT_TYPE, type, key, props, debugOwner, debugStack, validated]
: [REACT_ELEMENT_TYPE, type, key, props];
if (task.implicitSlot && key !== null) {
return [element];
}
return element;
}
let canEmitDebugInfo: boolean = false;
let serializedSize = 0;
const MAX_ROW_SIZE = 3200;
function deferTask(request: Request, task: Task): ReactJSONValue {
const newTask = createTask(
request,
task.model,
task.keyPath,
task.implicitSlot,
request.abortableTasks,
enableProfilerTimer && enableComponentPerformanceTrack ? task.time : 0,
__DEV__ ? task.debugOwner : null,
__DEV__ ? task.debugStack : null,
__DEV__ ? task.debugTask : null,
);
pingTask(request, newTask);
return serializeLazyID(newTask.id);
}
function outlineTask(request: Request, task: Task): ReactJSONValue {
const newTask = createTask(
request,
task.model,
task.keyPath,
task.implicitSlot,
request.abortableTasks,
enableProfilerTimer && enableComponentPerformanceTrack ? task.time : 0,
__DEV__ ? task.debugOwner : null,
__DEV__ ? task.debugStack : null,
__DEV__ ? task.debugTask : null,
);
retryTask(request, newTask);
if (newTask.status === COMPLETED) {
return serializeByValueID(newTask.id);
}
return serializeLazyID(newTask.id);
}
function outlineHaltedTask(
request: Request,
task: Task,
allowLazy: boolean,
): ReactJSONValue {
const taskId = request.nextChunkId++;
if (allowLazy) {
return serializeLazyID(taskId);
} else {
return serializeByValueID(taskId);
}
}
function renderElement(
request: Request,
task: Task,
type: any,
key: null | string,
ref: mixed,
props: any,
validated: number,
): ReactJSONValue {
if (ref !== null && ref !== undefined) {
throw new Error(
'Refs cannot be used in Server Components, nor passed to Client Components.',
);
}
if (__DEV__) {
jsxPropsParents.set(props, type);
if (typeof props.children === 'object' && props.children !== null) {
jsxChildrenParents.set(props.children, type);
}
}
if (
typeof type === 'function' &&
!isClientReference(type) &&
!isOpaqueTemporaryReference(type)
) {
return renderFunctionComponent(request, task, key, type, props, validated);
} else if (type === REACT_FRAGMENT_TYPE && key === null) {
if (__DEV__ && validated === 2) {
const componentDebugInfo: ReactComponentInfo = {
name: 'Fragment',
env: (0, request.environmentName)(),
key: key,
owner: task.debugOwner,
stack:
task.debugStack === null
? null
: filterStackTrace(request, parseStackTrace(task.debugStack, 1)),
props: props,
debugStack: task.debugStack,
debugTask: task.debugTask,
};
warnForMissingKey(request, key, componentDebugInfo, task.debugTask);
}
const prevImplicitSlot = task.implicitSlot;
if (task.keyPath === null) {
task.implicitSlot = true;
}
const json = renderModelDestructive(
request,
task,
emptyRoot,
'',
props.children,
);
task.implicitSlot = prevImplicitSlot;
return json;
} else if (
type != null &&
typeof type === 'object' &&
!isClientReference(type)
) {
switch (type.$$typeof) {
case REACT_LAZY_TYPE: {
let wrappedType;
if (__DEV__) {
wrappedType = callLazyInitInDEV(type);
} else {
const payload = type._payload;
const init = type._init;
wrappedType = init(payload);
}
if (request.status === ABORTING) {
throw null;
}
return renderElement(
request,
task,
wrappedType,
key,
ref,
props,
validated,
);
}
case REACT_FORWARD_REF_TYPE: {
return renderFunctionComponent(
request,
task,
key,
type.render,
props,
validated,
);
}
case REACT_MEMO_TYPE: {
return renderElement(
request,
task,
type.type,
key,
ref,
props,
validated,
);
}
case REACT_ELEMENT_TYPE: {
if (__DEV__) {
type._store.validated = 1;
}
}
}
}
return renderClientElement(request, task, type, key, props, validated);
}
function visitAsyncNode(
request: Request,
task: Task,
node: AsyncSequence,
visited: Set<AsyncSequence | ReactDebugInfo>,
cutOff: number,
): void | null | PromiseNode | IONode {
if (visited.has(node)) {
return null;
}
visited.add(node);
if (node.previous !== null && node.end > request.timeOrigin) {
const ioNode = visitAsyncNode(
request,
task,
node.previous,
visited,
cutOff,
);
if (ioNode === undefined) {
return undefined;
}
}
switch (node.tag) {
case IO_NODE: {
return node;
}
case UNRESOLVED_PROMISE_NODE: {
return null;
}
case PROMISE_NODE: {
if (node.end <= request.timeOrigin) {
return null;
}
const awaited = node.awaited;
let match = null;
if (awaited !== null) {
const ioNode = visitAsyncNode(request, task, awaited, visited, cutOff);
if (ioNode === undefined) {
return undefined;
} else if (ioNode !== null) {
if (ioNode.tag === PROMISE_NODE) {
match = ioNode;
} else if (filterStackTrace(request, node.stack).length === 0) {
match = ioNode;
} else {
match = node;
}
} else if (request.status === ABORTING) {
if (node.start < request.abortTime && node.end > request.abortTime) {
if (filterStackTrace(request, node.stack).length > 0) {
match = node;
}
}
}
}
const promise = node.promise.deref();
if (promise !== undefined) {
const debugInfo = promise._debugInfo;
if (debugInfo != null && !visited.has(debugInfo)) {
visited.add(debugInfo);
forwardDebugInfo(request, task, debugInfo);
}
}
return match;
}
case UNRESOLVED_AWAIT_NODE: {
return null;
}
case AWAIT_NODE: {
const awaited = node.awaited;
let match = null;
if (awaited !== null) {
const ioNode = visitAsyncNode(request, task, awaited, visited, cutOff);
if (ioNode === undefined) {
return undefined;
} else if (ioNode !== null) {
const startTime: number = node.start;
const endTime: number = node.end;
if (endTime <= request.timeOrigin) {
return null;
} else if (startTime < cutOff) {
match = ioNode;
} else {
let isAwaitInUserspace = false;
const fullStack = node.stack;
if (fullStack.length > 0) {
const filterStackFrame = request.filterStackFrame;
const callsite = fullStack[0];
const functionName = callsite[0];
const url = devirtualizeURL(callsite[1]);
isAwaitInUserspace = filterStackFrame(url, functionName);
}
if (!isAwaitInUserspace) {
match = ioNode;
} else if (
request.status === ABORTING &&
startTime > request.abortTime
) {
} else {
serializeIONode(request, ioNode, awaited.promise);
const env = (0, request.environmentName)();
advanceTaskTime(request, task, startTime);
request.pendingChunks++;
emitDebugChunk(request, task.id, {
awaited: ((ioNode: any): ReactIOInfo),
env: env,
owner: node.owner,
stack: filterStackTrace(request, node.stack),
});
markOperationEndTime(request, task, endTime);
if (request.status === ABORTING) {
match = undefined;
}
}
}
}
}
const promise = node.promise.deref();
if (promise !== undefined) {
const debugInfo = promise._debugInfo;
if (debugInfo != null && !visited.has(debugInfo)) {
visited.add(debugInfo);
forwardDebugInfo(request, task, debugInfo);
}
}
return match;
}
default: {
throw new Error('Unknown AsyncSequence tag. This is a bug in React.');
}
}
}
function emitAsyncSequence(
request: Request,
task: Task,
node: AsyncSequence,
alreadyForwardedDebugInfo: ?ReactDebugInfo,
owner: null | ReactComponentInfo,
stack: null | Error,
): void {
const visited: Set<AsyncSequence | ReactDebugInfo> = new Set();
if (__DEV__ && alreadyForwardedDebugInfo) {
visited.add(alreadyForwardedDebugInfo);
}
const awaitedNode = visitAsyncNode(request, task, node, visited, task.time);
if (awaitedNode === undefined) {
} else if (awaitedNode !== null) {
serializeIONode(request, awaitedNode, awaitedNode.promise);
request.pendingChunks++;
const env = (0, request.environmentName)();
const debugInfo: ReactAsyncInfo = {
awaited: ((awaitedNode: any): ReactIOInfo),
env: env,
};
if (__DEV__) {
if (owner != null) {
debugInfo.owner = owner;
}
if (stack != null) {
debugInfo.stack = filterStackTrace(request, parseStackTrace(stack, 1));
}
}
advanceTaskTime(request, task, task.time);
emitDebugChunk(request, task.id, debugInfo);
markOperationEndTime(request, task, awaitedNode.end);
}
}
function pingTask(request: Request, task: Task): void {
if (enableProfilerTimer && enableComponentPerformanceTrack) {
task.timed = true;
}
const pingedTasks = request.pingedTasks;
pingedTasks.push(task);
if (pingedTasks.length === 1) {
request.flushScheduled = request.destination !== null;
if (request.type === PRERENDER || request.status === OPENING) {
scheduleMicrotask(() => performWork(request));
} else {
scheduleWork(() => performWork(request));
}
}
}
function createTask(
request: Request,
model: ReactClientValue,
keyPath: null | string,
implicitSlot: boolean,
abortSet: Set<Task>,
lastTimestamp: number,
debugOwner: null | ReactComponentInfo,
debugStack: null | Error,
debugTask: null | ConsoleTask,
): Task {
request.pendingChunks++;
const id = request.nextChunkId++;
if (typeof model === 'object' && model !== null) {
if (keyPath !== null || implicitSlot) {
} else {
request.writtenObjects.set(model, serializeByValueID(id));
}
}
const task: Task = (({
id,
status: PENDING,
model,
keyPath,
implicitSlot,
ping: () => pingTask(request, task),
toJSON: function (
this:
| {+[key: string | number]: ReactClientValue}
| $ReadOnlyArray<ReactClientValue>,
parentPropertyName: string,
value: ReactClientValue,
): ReactJSONValue {
const parent = this;
if (__DEV__) {
const originalValue = parent[parentPropertyName];
if (
typeof originalValue === 'object' &&
originalValue !== value &&
!(originalValue instanceof Date)
) {
callWithDebugContextInDEV(request, task, () => {
if (objectName(originalValue) !== 'Object') {
const jsxParentType = jsxChildrenParents.get(parent);
if (typeof jsxParentType === 'string') {
console.error(
'%s objects cannot be rendered as text children. Try formatting it using toString().%s',
objectName(originalValue),
describeObjectForErrorMessage(parent, parentPropertyName),
);
} else {
console.error(
'Only plain objects can be passed to Client Components from Server Components. ' +
'%s objects are not supported.%s',
objectName(originalValue),
describeObjectForErrorMessage(parent, parentPropertyName),
);
}
} else {
console.error(
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with toJSON methods are not supported. Convert it manually ' +
'to a simple value before passing it to props.%s',
describeObjectForErrorMessage(parent, parentPropertyName),
);
}
});
}
}
return renderModel(request, task, parent, parentPropertyName, value);
},
thenableState: null,
}: Omit<
Task,
| 'timed'
| 'time'
| 'environmentName'
| 'debugOwner'
| 'debugStack'
| 'debugTask',
>): any);
if (enableProfilerTimer && enableComponentPerformanceTrack) {
task.timed = false;
task.time = lastTimestamp;
}
if (__DEV__) {
task.environmentName = request.environmentName();
task.debugOwner = debugOwner;
task.debugStack = debugStack;
task.debugTask = debugTask;
}
abortSet.add(task);
return task;
}
function serializeByValueID(id: number): string {
return '$' + id.toString(16);
}
function serializeLazyID(id: number): string {
return '$L' + id.toString(16);
}
function serializePromiseID(id: number): string {
return '$@' + id.toString(16);
}
function serializeServerReferenceID(id: number): string {
return '$F' + id.toString(16);
}
function serializeSymbolReference(name: string): string {
return '$S' + name;
}
function serializeDeferredObject(
request: Request,
value: ReactClientReference | string,
): string {
const deferredDebugObjects = request.deferredDebugObjects;
if (deferredDebugObjects !== null) {
request.pendingChunks++;
const id = request.nextChunkId++;
deferredDebugObjects.existing.set(value, id);
deferredDebugObjects.retained.set(id, value);
return '$Y' + id.toString(16);
}
return '$Y';
}
function serializeNumber(number: number): string | number {
if (Number.isFinite(number)) {
if (number === 0 && 1 / number === -Infinity) {
return '$-0';
} else {
return number;
}
} else {
if (number === Infinity) {
return '$Infinity';
} else if (number === -Infinity) {
return '$-Infinity';
} else {
return '$NaN';
}
}
}
function serializeUndefined(): string {
return '$undefined';
}
function serializeDate(date: Date): string {
return '$D' + date.toJSON();
}
function serializeDateFromDateJSON(dateJSON: string): string {
return '$D' + dateJSON;
}
function serializeBigInt(n: bigint): string {
return '$n' + n.toString(10);
}
function serializeRowHeader(tag: string, id: number) {
return id.toString(16) + ':' + tag;
}
function encodeReferenceChunk(
request: Request,
id: number,
reference: string,
): Chunk {
const json = stringify(reference);
const row = id.toString(16) + ':' + json + '\n';
return stringToChunk(row);
}
function serializeClientReference(
request: Request,
parent:
| {+[propertyName: string | number]: ReactClientValue}
| $ReadOnlyArray<ReactClientValue>,
parentPropertyName: string,
clientReference: ClientReference<any>,
): string {
const clientReferenceKey: ClientReferenceKey =
getClientReferenceKey(clientReference);
const writtenClientReferences = request.writtenClientReferences;
const existingId = writtenClientReferences.get(clientReferenceKey);
if (existingId !== undefined) {
if (parent[0] === REACT_ELEMENT_TYPE && parentPropertyName === '1') {
return serializeLazyID(existingId);
}
return serializeByValueID(existingId);
}
try {
const clientReferenceMetadata: ClientReferenceMetadata =
resolveClientReferenceMetadata(request.bundlerConfig, clientReference);
request.pendingChunks++;
const importId = request.nextChunkId++;
emitImportChunk(request, importId, clientReferenceMetadata, false);
writtenClientReferences.set(clientReferenceKey, importId);
if (parent[0] === REACT_ELEMENT_TYPE && parentPropertyName === '1') {
return serializeLazyID(importId);
}
return serializeByValueID(importId);
} catch (x) {
request.pendingChunks++;
const errorId = request.nextChunkId++;
const digest = logRecoverableError(request, x, null);
emitErrorChunk(request, errorId, digest, x, false);
return serializeByValueID(errorId);
}
}
function serializeDebugClientReference(
request: Request,
parent:
| {+[propertyName: string | number]: ReactClientValue}
| $ReadOnlyArray<ReactClientValue>,
parentPropertyName: string,
clientReference: ClientReference<any>,
): string {
const clientReferenceKey: ClientReferenceKey =
getClientReferenceKey(clientReference);
const writtenClientReferences = request.writtenClientReferences;
const existingId = writtenClientReferences.get(clientReferenceKey);
if (existingId !== undefined) {
if (parent[0] === REACT_ELEMENT_TYPE && parentPropertyName === '1') {
return serializeLazyID(existingId);
}
return serializeByValueID(existingId);
}
try {
const clientReferenceMetadata: ClientReferenceMetadata =
resolveClientReferenceMetadata(request.bundlerConfig, clientReference);
request.pendingChunks++;
const importId = request.nextChunkId++;
emitImportChunk(request, importId, clientReferenceMetadata, true);
if (parent[0] === REACT_ELEMENT_TYPE && parentPropertyName === '1') {
return serializeLazyID(importId);
}
return serializeByValueID(importId);
} catch (x) {
request.pendingChunks++;
const errorId = request.nextChunkId++;
const digest = logRecoverableError(request, x, null);
emitErrorChunk(request, errorId, digest, x, true);
return serializeByValueID(errorId);
}
}
function outlineModel(request: Request, value: ReactClientValue): number {
const newTask = createTask(
request,
value,
null,
false,
request.abortableTasks,
enableProfilerTimer && enableComponentPerformanceTrack
? performance.now()
: 0,
null,
null,
null,
);
retryTask(request, newTask);
return newTask.id;
}
function serializeServerReference(
request: Request,
serverReference: ServerReference<any>,
): string {
const writtenServerReferences = request.writtenServerReferences;
const existingId = writtenServerReferences.get(serverReference);
if (existingId !== undefined) {
return serializeServerReferenceID(existingId);
}
const boundArgs: null | Array<any> = getServerReferenceBoundArguments(
request.bundlerConfig,
serverReference,
);
const bound = boundArgs === null ? null : Promise.resolve(boundArgs);
const id = getServerReferenceId(request.bundlerConfig, serverReference);
let location: null | ReactFunctionLocation = null;
if (__DEV__) {
const error = getServerReferenceLocation(
request.bundlerConfig,
serverReference,
);
if (error) {
const frames = parseStackTrace(error, 1);
if (frames.length > 0) {
const firstFrame = frames[0];
location = [
firstFrame[0],
firstFrame[1],
firstFrame[2],
firstFrame[3],
];
}
}
}
const serverReferenceMetadata: {
id: ServerReferenceId,
bound: null | Promise<Array<any>>,
name?: string,
env?: string,
location?: ReactFunctionLocation,
} =
__DEV__ && location !== null
? {
id,
bound,
name:
typeof serverReference === 'function' ? serverReference.name : '',
env: (0, request.environmentName)(),
location,
}
: {
id,
bound,
};
const metadataId = outlineModel(request, serverReferenceMetadata);
writtenServerReferences.set(serverReference, metadataId);
return serializeServerReferenceID(metadataId);
}
function serializeTemporaryReference(
request: Request,
reference: string,
): string {
return '$T' + reference;
}
function serializeLargeTextString(request: Request, text: string): string {
request.pendingChunks++;
const textId = request.nextChunkId++;
emitTextChunk(request, textId, text, false);
return serializeByValueID(textId);
}
function serializeDebugLargeTextString(request: Request, text: string): string {
request.pendingChunks++;
const textId = request.nextChunkId++;
emitTextChunk(request, textId, text, true);
return serializeByValueID(textId);
}
function serializeMap(
request: Request,
map: Map<ReactClientValue, ReactClientValue>,
): string {
const entries = Array.from(map);
const id = outlineModel(request, entries);
return '$Q' + id.toString(16);
}
function serializeFormData(request: Request, formData: FormData): string {
const entries = Array.from(formData.entries());
const id = outlineModel(request, (entries: any));
return '$K' + id.toString(16);
}
function serializeDebugFormData(request: Request, formData: FormData): string {
const entries = Array.from(formData.entries());
const id = outlineDebugModel(
request,
{objectLimit: entries.length * 2 + 1},
(entries: any),
);
return '$K' + id.toString(16);
}
function serializeSet(request: Request, set: Set<ReactClientValue>): string {
const entries = Array.from(set);
const id = outlineModel(request, entries);
return '$W' + id.toString(16);
}
function serializeDebugMap(
request: Request,
counter: {objectLimit: number},
map: Map<ReactClientValue, ReactClientValue>,
): string {
const entries = Array.from(map);
counter.objectLimit++;
for (let i = 0; i < entries.length; i++) {
const entry = entries[i];
doNotLimit.add(entry);
const key = entry[0];
const value = entry[1];
if (typeof key === 'object' && key !== null) {
doNotLimit.add(key);
}
if (typeof value === 'object' && value !== null) {
doNotLimit.add(value);
}
}
const id = outlineDebugModel(request, counter, entries);
return '$Q' + id.toString(16);
}
function serializeDebugSet(
request: Request,
counter: {objectLimit: number},
set: Set<ReactClientValue>,
): string {
const entries = Array.from(set);
counter.objectLimit++;
for (let i = 0; i < entries.length; i++) {
const entry = entries[i];
if (typeof entry === 'object' && entry !== null) {
doNotLimit.add(entry);
}
}
const id = outlineDebugModel(request, counter, entries);
return '$W' + id.toString(16);
}
function serializeIterator(
request: Request,
iterator: Iterator<ReactClientValue>,
): string {
const id = outlineModel(request, Array.from(iterator));
return '$i' + id.toString(16);
}
function serializeTypedArray(
request: Request,
tag: string,
typedArray: $ArrayBufferView,
): string {
request.pendingChunks++;
const bufferId = request.nextChunkId++;
emitTypedArrayChunk(request, bufferId, tag, typedArray, false);
return serializeByValueID(bufferId);
}
function serializeDebugTypedArray(
request: Request,
tag: string,
typedArray: $ArrayBufferView,
): string {
request.pendingChunks++;
const bufferId = request.nextChunkId++;
emitTypedArrayChunk(request, bufferId, tag, typedArray, true);
return serializeByValueID(bufferId);
}
function serializeDebugBlob(request: Request, blob: Blob): string {
const model: Array<string | Uint8Array> = [blob.type];
const reader = blob.stream().getReader();
const id = request.nextChunkId++;
function progress(
entry: {done: false, value: Uint8Array} | {done: true, value: void},
): Promise<void> | void {
if (entry.done) {
emitOutlinedDebugModelChunk(
request,
id,
{objectLimit: model.length + 2},
model,
);
enqueueFlush(request);
return;
}
model.push(entry.value);
return reader.read().then(progress).catch(error);
}
function error(reason: mixed) {
const digest = '';
emitErrorChunk(request, id, digest, reason, true);
enqueueFlush(request);
reader.cancel(reason).then(noop, noop);
}
reader.read().then(progress).catch(error);
return '$B' + id.toString(16);
}
function serializeBlob(request: Request, blob: Blob): string {
const model: Array<string | Uint8Array> = [blob.type];
const newTask = createTask(
request,
model,
null,
false,
request.abortableTasks,
enableProfilerTimer && enableComponentPerformanceTrack
? performance.now()
: 0,
null,
null,
null,
);
const reader = blob.stream().getReader();
function progress(
entry: {done: false, value: Uint8Array} | {done: true, value: void},
): Promise<void> | void {
if (newTask.status !== PENDING) {
return;
}
if (entry.done) {
request.cacheController.signal.removeEventListener('abort', abortBlob);
pingTask(request, newTask);
return;
}
model.push(entry.value);
return reader.read().then(progress).catch(error);
}
function error(reason: mixed) {
if (newTask.status !== PENDING) {
return;
}
request.cacheController.signal.removeEventListener('abort', abortBlob);
erroredTask(request, newTask, reason);
enqueueFlush(request);
reader.cancel(reason).then(error, error);
}
function abortBlob() {
if (newTask.status !== PENDING) {
return;
}
const signal = request.cacheController.signal;
signal.removeEventListener('abort', abortBlob);
const reason = signal.reason;
if (enableHalt && request.type === PRERENDER) {
haltTask(newTask, request);
} else {
erroredTask(request, newTask, reason);
enqueueFlush(request);
}
reader.cancel(reason).then(error, error);
}
request.cacheController.signal.addEventListener('abort', abortBlob);
reader.read().then(progress).catch(error);
return '$B' + newTask.id.toString(16);
}
function escapeStringValue(value: string): string {
if (value[0] === '$') {
return '$' + value;
} else {
return value;
}
}
let modelRoot: null | ReactClientValue = false;
function renderModel(
request: Request,
task: Task,
parent:
| {+[key: string | number]: ReactClientValue}
| $ReadOnlyArray<ReactClientValue>,
key: string,
value: ReactClientValue,
): ReactJSONValue {
serializedSize += key.length;
const prevKeyPath = task.keyPath;
const prevImplicitSlot = task.implicitSlot;
try {
return renderModelDestructive(request, task, parent, key, value);
} catch (thrownValue) {
const model = task.model;
const wasReactNode =
typeof model === 'object' &&
model !== null &&
((model: any).$$typeof === REACT_ELEMENT_TYPE ||
(model: any).$$typeof === REACT_LAZY_TYPE);
if (request.status === ABORTING) {
task.status = ABORTED;
if (enableHalt && request.type === PRERENDER) {
return outlineHaltedTask(request, task, wasReactNode);
}
const errorId = (request.fatalError: any);
if (wasReactNode) {
return serializeLazyID(errorId);
}
return serializeByValueID(errorId);
}
const x =
thrownValue === SuspenseException
?
getSuspendedThenable()
: thrownValue;
if (typeof x === 'object' && x !== null) {
if (typeof x.then === 'function') {
const newTask = createTask(
request,
task.model,
task.keyPath,
task.implicitSlot,
request.abortableTasks,
enableProfilerTimer && enableComponentPerformanceTrack
? task.time
: 0,
__DEV__ ? task.debugOwner : null,
__DEV__ ? task.debugStack : null,
__DEV__ ? task.debugTask : null,
);
const ping = newTask.ping;
(x: any).then(ping, ping);
newTask.thenableState = getThenableStateAfterSuspending();
task.keyPath = prevKeyPath;
task.implicitSlot = prevImplicitSlot;
if (wasReactNode) {
return serializeLazyID(newTask.id);
}
return serializeByValueID(newTask.id);
}
}
task.keyPath = prevKeyPath;
task.implicitSlot = prevImplicitSlot;
request.pendingChunks++;
const errorId = request.nextChunkId++;
if (
enablePostpone &&
typeof x === 'object' &&
x !== null &&
x.$$typeof === REACT_POSTPONE_TYPE
) {
const postponeInstance: Postpone = (x: any);
logPostpone(request, postponeInstance.message, task);
emitPostponeChunk(request, errorId, postponeInstance);
} else {
const digest = logRecoverableError(request, x, task);
emitErrorChunk(request, errorId, digest, x, false);
}
if (wasReactNode) {
return serializeLazyID(errorId);
}
return serializeByValueID(errorId);
}
}
function renderModelDestructive(
request: Request,
task: Task,
parent:
| {+[propertyName: string | number]: ReactClientValue}
| $ReadOnlyArray<ReactClientValue>,
parentPropertyName: string,
value: ReactClientValue,
): ReactJSONValue {
task.model = value;
if (value === REACT_ELEMENT_TYPE) {
return '$';
}
if (value === null) {
return null;
}
if (typeof value === 'object') {
switch ((value: any).$$typeof) {
case REACT_ELEMENT_TYPE: {
let elementReference = null;
const writtenObjects = request.writtenObjects;
if (task.keyPath !== null || task.implicitSlot) {
} else {
const existingReference = writtenObjects.get(value);
if (existingReference !== undefined) {
if (modelRoot === value) {
modelRoot = null;
} else {
return existingReference;
}
} else if (parentPropertyName.indexOf(':') === -1) {
const parentReference = writtenObjects.get(parent);
if (parentReference !== undefined) {
elementReference = parentReference + ':' + parentPropertyName;
writtenObjects.set(value, elementReference);
}
}
}
const element: ReactElement = (value: any);
if (serializedSize > MAX_ROW_SIZE) {
return deferTask(request, task);
}
if (__DEV__) {
const debugInfo: ?ReactDebugInfo = (value: any)._debugInfo;
if (debugInfo) {
if (!canEmitDebugInfo) {
return outlineTask(request, task);
} else {
forwardDebugInfo(request, task, debugInfo);
}
}
}
const props = element.props;
const refProp = props.ref;
const ref = refProp !== undefined ? refProp : null;
if (__DEV__) {
task.debugOwner = element._owner;
task.debugStack = element._debugStack;
task.debugTask = element._debugTask;
}
const newChild = renderElement(
request,
task,
element.type,
element.key,
ref,
props,
__DEV__ ? element._store.validated : 0,
);
if (
typeof newChild === 'object' &&
newChild !== null &&
elementReference !== null
) {
if (!writtenObjects.has(newChild)) {
writtenObjects.set(newChild, elementReference);
}
}
return newChild;
}
case REACT_LAZY_TYPE: {
if (serializedSize > MAX_ROW_SIZE) {
return deferTask(request, task);
}
task.thenableState = null;
const lazy: LazyComponent<any, any> = (value: any);
let resolvedModel;
if (__DEV__) {
resolvedModel = callLazyInitInDEV(lazy);
} else {
const payload = lazy._payload;
const init = lazy._init;
resolvedModel = init(payload);
}
if (request.status === ABORTING) {
throw null;
}
if (__DEV__) {
const debugInfo: ?ReactDebugInfo = lazy._debugInfo;
if (debugInfo) {
if (!canEmitDebugInfo) {
return outlineTask(request, task);
} else {
forwardDebugInfo(request, task, debugInfo);
}
}
}
return renderModelDestructive(
request,
task,
emptyRoot,
'',
resolvedModel,
);
}
case REACT_LEGACY_ELEMENT_TYPE: {
throw new Error(
'A React Element from an older version of React was rendered. ' +
'This is not supported. It can happen if:\n' +
'- Multiple copies of the "react" package is used.\n' +
'- A library pre-bundled an old copy of "react" or "react/jsx-runtime".\n' +
'- A compiler tries to "inline" JSX instead of using the runtime.',
);
}
}
if (isClientReference(value)) {
return serializeClientReference(
request,
parent,
parentPropertyName,
(value: any),
);
}
if (request.temporaryReferences !== undefined) {
const tempRef = resolveTemporaryReference(
request.temporaryReferences,
value,
);
if (tempRef !== undefined) {
return serializeTemporaryReference(request, tempRef);
}
}
if (enableTaint) {
const tainted = TaintRegistryObjects.get(value);
if (tainted !== undefined) {
throwTaintViolation(tainted);
}
}
const writtenObjects = request.writtenObjects;
const existingReference = writtenObjects.get(value);
if (typeof value.then === 'function') {
if (existingReference !== undefined) {
if (task.keyPath !== null || task.implicitSlot) {
const promiseId = serializeThenable(request, task, (value: any));
return serializePromiseID(promiseId);
} else if (modelRoot === value) {
modelRoot = null;
} else {
return existingReference;
}
}
const promiseId = serializeThenable(request, task, (value: any));
const promiseReference = serializePromiseID(promiseId);
writtenObjects.set(value, promiseReference);
return promiseReference;
}
if (existingReference !== undefined) {
if (modelRoot === value) {
if (existingReference !== serializeByValueID(task.id)) {
return existingReference;
}
modelRoot = null;
} else {
return existingReference;
}
} else if (parentPropertyName.indexOf(':') === -1) {
const parentReference = writtenObjects.get(parent);
if (parentReference !== undefined) {
let propertyName = parentPropertyName;
if (isArray(parent) && parent[0] === REACT_ELEMENT_TYPE) {
switch (parentPropertyName) {
case '1':
propertyName = 'type';
break;
case '2':
propertyName = 'key';
break;
case '3':
propertyName = 'props';
break;
case '4':
propertyName = '_owner';
break;
}
}
writtenObjects.set(value, parentReference + ':' + propertyName);
}
}
if (isArray(value)) {
return renderFragment(request, task, value);
}
if (value instanceof Map) {
return serializeMap(request, value);
}
if (value instanceof Set) {
return serializeSet(request, value);
}
if (typeof FormData === 'function' && value instanceof FormData) {
return serializeFormData(request, value);
}
if (value instanceof Error) {
return serializeErrorValue(request, value);
}
if (value instanceof ArrayBuffer) {
return serializeTypedArray(request, 'A', new Uint8Array(value));
}
if (value instanceof Int8Array) {
return serializeTypedArray(request, 'O', value);
}
if (value instanceof Uint8Array) {
return serializeTypedArray(request, 'o', value);
}
if (value instanceof Uint8ClampedArray) {
return serializeTypedArray(request, 'U', value);
}
if (value instanceof Int16Array) {
return serializeTypedArray(request, 'S', value);
}
if (value instanceof Uint16Array) {
return serializeTypedArray(request, 's', value);
}
if (value instanceof Int32Array) {
return serializeTypedArray(request, 'L', value);
}
if (value instanceof Uint32Array) {
return serializeTypedArray(request, 'l', value);
}
if (value instanceof Float32Array) {
return serializeTypedArray(request, 'G', value);
}
if (value instanceof Float64Array) {
return serializeTypedArray(request, 'g', value);
}
if (value instanceof BigInt64Array) {
return serializeTypedArray(request, 'M', value);
}
if (value instanceof BigUint64Array) {
return serializeTypedArray(request, 'm', value);
}
if (value instanceof DataView) {
return serializeTypedArray(request, 'V', value);
}
if (typeof Blob === 'function' && value instanceof Blob) {
return serializeBlob(request, value);
}
const iteratorFn = getIteratorFn(value);
if (iteratorFn) {
const iterator = iteratorFn.call(value);
if (iterator === value) {
return serializeIterator(request, (iterator: any));
}
return renderFragment(request, task, Array.from((iterator: any)));
}
if (
typeof ReadableStream === 'function' &&
value instanceof ReadableStream
) {
return serializeReadableStream(request, task, value);
}
const getAsyncIterator: void | (() => $AsyncIterator<any, any, any>) =
(value: any)[ASYNC_ITERATOR];
if (typeof getAsyncIterator === 'function') {
return renderAsyncFragment(request, task, (value: any), getAsyncIterator);
}
if (value instanceof Date) {
return serializeDate(value);
}
const proto = getPrototypeOf(value);
if (
proto !== ObjectPrototype &&
(proto === null || getPrototypeOf(proto) !== null)
) {
throw new Error(
'Only plain objects, and a few built-ins, can be passed to Client Components ' +
'from Server Components. Classes or null prototypes are not supported.' +
describeObjectForErrorMessage(parent, parentPropertyName),
);
}
if (__DEV__) {
if (objectName(value) !== 'Object') {
callWithDebugContextInDEV(request, task, () => {
console.error(
'Only plain objects can be passed to Client Components from Server Components. ' +
'%s objects are not supported.%s',
objectName(value),
describeObjectForErrorMessage(parent, parentPropertyName),
);
});
} else if (!isSimpleObject(value)) {
callWithDebugContextInDEV(request, task, () => {
console.error(
'Only plain objects can be passed to Client Components from Server Components. ' +
'Classes or other objects with methods are not supported.%s',
describeObjectForErrorMessage(parent, parentPropertyName),
);
});
} else if (Object.getOwnPropertySymbols) {
const symbols = Object.getOwnPropertySymbols(value);
if (symbols.length > 0) {
callWithDebugContextInDEV(request, task, () => {
console.error(
'Only plain objects can be passed to Client Components from Server Components. ' +
'Objects with symbol properties like %s are not supported.%s',
symbols[0].description,
describeObjectForErrorMessage(parent, parentPropertyName),
);
});
}
}
}
return value;
}
if (typeof value === 'string') {
if (enableTaint) {
const tainted = TaintRegistryValues.get(value);
if (tainted !== undefined) {
throwTaintViolation(tainted.message);
}
}
serializedSize += value.length;
if (value[value.length - 1] === 'Z') {
const originalValue = parent[parentPropertyName];
if (originalValue instanceof Date) {
return serializeDateFromDateJSON(value);
}
}
if (value.length >= 1024 && byteLengthOfChunk !== null) {
return serializeLargeTextString(request, value);
}
return escapeStringValue(value);
}
if (typeof value === 'boolean') {
return value;
}
if (typeof value === 'number') {
return serializeNumber(value);
}
if (typeof value === 'undefined') {
return serializeUndefined();
}
if (typeof value === 'function') {
if (isClientReference(value)) {
return serializeClientReference(
request,
parent,
parentPropertyName,
(value: any),
);
}
if (isServerReference(value)) {
return serializeServerReference(request, (value: any));
}
if (request.temporaryReferences !== undefined) {
const tempRef = resolveTemporaryReference(
request.temporaryReferences,
value,
);
if (tempRef !== undefined) {
return serializeTemporaryReference(request, tempRef);
}
}
if (enableTaint) {
const tainted = TaintRegistryObjects.get(value);
if (tainted !== undefined) {
throwTaintViolation(tainted);
}
}
if (isOpaqueTemporaryReference(value)) {
throw new Error(
'Could not reference an opaque temporary reference. ' +
'This is likely due to misconfiguring the temporaryReferences options ' +
'on the server.',
);
} else if (/^on[A-Z]/.test(parentPropertyName)) {
throw new Error(
'Event handlers cannot be passed to Client Component props.' +
describeObjectForErrorMessage(parent, parentPropertyName) +
'\nIf you need interactivity, consider converting part of this to a Client Component.',
);
} else if (
__DEV__ &&
(jsxChildrenParents.has(parent) ||
(jsxPropsParents.has(parent) && parentPropertyName === 'children'))
) {
const componentName = value.displayName || value.name || 'Component';
throw new Error(
'Functions are not valid as a child of Client Components. This may happen if ' +
'you return ' +
componentName +
' instead of <' +
componentName +
' /> from render. ' +
'Or maybe you meant to call this function rather than return it.' +
describeObjectForErrorMessage(parent, parentPropertyName),
);
} else {
throw new Error(
'Functions cannot be passed directly to Client Components ' +
'unless you explicitly expose it by marking it with "use server". ' +
'Or maybe you meant to call this function rather than return it.' +
describeObjectForErrorMessage(parent, parentPropertyName),
);
}
}
if (typeof value === 'symbol') {
const writtenSymbols = request.writtenSymbols;
const existingId = writtenSymbols.get(value);
if (existingId !== undefined) {
return serializeByValueID(existingId);
}
const name: string = value.description;
if (Symbol.for(name) !== value) {
throw new Error(
'Only global symbols received from Symbol.for(...) can be passed to Client Components. ' +
`The symbol Symbol.for(${
// $FlowFixMe[incompatible-type] `description` might be undefined
value.description
}) cannot be found among global symbols.` +
describeObjectForErrorMessage(parent, parentPropertyName),
);
}
request.pendingChunks++;
const symbolId = request.nextChunkId++;
emitSymbolChunk(request, symbolId, name);
writtenSymbols.set(value, symbolId);
return serializeByValueID(symbolId);
}
if (typeof value === 'bigint') {
if (enableTaint) {
const tainted = TaintRegistryValues.get(value);
if (tainted !== undefined) {
throwTaintViolation(tainted.message);
}
}
return serializeBigInt(value);
}
throw new Error(
`Type ${typeof value} is not supported in Client Component props.` +
describeObjectForErrorMessage(parent, parentPropertyName),
);
}
function logPostpone(
request: Request,
reason: string,
task: Task | null,
): void {
const prevRequest = currentRequest;
currentRequest = null;
try {
const onPostpone = request.onPostpone;
if (__DEV__ && task !== null) {
if (supportsRequestStorage) {
requestStorage.run(
undefined,
callWithDebugContextInDEV,
request,
task,
onPostpone,
reason,
);
} else {
callWithDebugContextInDEV(request, task, onPostpone, reason);
}
} else if (supportsRequestStorage) {
requestStorage.run(undefined, onPostpone, reason);
} else {
onPostpone(reason);
}
} finally {
currentRequest = prevRequest;
}
}
function logRecoverableError(
request: Request,
error: mixed,
task: Task | null,
): string {
const prevRequest = currentRequest;
currentRequest = null;
let errorDigest;
try {
const onError = request.onError;
if (__DEV__ && task !== null) {
if (supportsRequestStorage) {
errorDigest = requestStorage.run(
undefined,
callWithDebugContextInDEV,
request,
task,
onError,
error,
);
} else {
errorDigest = callWithDebugContextInDEV(request, task, onError, error);
}
} else if (supportsRequestStorage) {
errorDigest = requestStorage.run(undefined, onError, error);
} else {
errorDigest = onError(error);
}
} finally {
currentRequest = prevRequest;
}
if (errorDigest != null && typeof errorDigest !== 'string') {
throw new Error(
`onError returned something with a type other than "string". onError should return a string and may return null or undefined but must not return anything else. It received something of type "${typeof errorDigest}" instead`,
);
}
return errorDigest || '';
}
function fatalError(request: Request, error: mixed): void {
const onFatalError = request.onFatalError;
onFatalError(error);
if (enableTaint) {
cleanupTaintQueue(request);
}
if (request.destination !== null) {
request.status = CLOSED;
closeWithError(request.destination, error);
} else {
request.status = CLOSING;
request.fatalError = error;
}
const abortReason = new Error(
'The render was aborted due to a fatal error.',
{
cause: error,
},
);
request.cacheController.abort(abortReason);
}
function emitPostponeChunk(
request: Request,
id: number,
postponeInstance: Postpone,
): void {
let row;
if (__DEV__) {
let reason = '';
let stack: ReactStackTrace;
const env = request.environmentName();
try {
reason = String(postponeInstance.message);
stack = filterStackTrace(request, parseStackTrace(postponeInstance, 0));
} catch (x) {
stack = [];
}
row = serializeRowHeader('P', id) + stringify({reason, stack, env}) + '\n';
} else {
row = serializeRowHeader('P', id) + '\n';
}
const processedChunk = stringToChunk(row);
request.completedErrorChunks.push(processedChunk);
}
function serializeErrorValue(request: Request, error: Error): string {
if (__DEV__) {
let name: string = 'Error';
let message: string;
let stack: ReactStackTrace;
let env = (0, request.environmentName)();
try {
name = error.name;
message = String(error.message);
stack = filterStackTrace(request, parseStackTrace(error, 0));
const errorEnv = (error: any).environmentName;
if (typeof errorEnv === 'string') {
env = errorEnv;
}
} catch (x) {
message = 'An error occurred but serializing the error message failed.';
stack = [];
}
const errorInfo: ReactErrorInfoDev = {name, message, stack, env};
const id = outlineModel(request, errorInfo);
return '$Z' + id.toString(16);
} else {
return '$Z';
}
}
function serializeDebugErrorValue(request: Request, error: Error): string {
if (__DEV__) {
let name: string = 'Error';
let message: string;
let stack: ReactStackTrace;
let env = (0, request.environmentName)();
try {
name = error.name;
message = String(error.message);
stack = filterStackTrace(request, parseStackTrace(error, 0));
const errorEnv = (error: any).environmentName;
if (typeof errorEnv === 'string') {
env = errorEnv;
}
} catch (x) {
message = 'An error occurred but serializing the error message failed.';
stack = [];
}
const errorInfo: ReactErrorInfoDev = {name, message, stack, env};
const id = outlineDebugModel(
request,
{objectLimit: stack.length * 2 + 1},
errorInfo,
);
return '$Z' + id.toString(16);
} else {
return '$Z';
}
}
function emitErrorChunk(
request: Request,
id: number,
digest: string,
error: mixed,
debug: boolean,
): void {
let errorInfo: ReactErrorInfo;
if (__DEV__) {
let name: string = 'Error';
let message: string;
let stack: ReactStackTrace;
let env = (0, request.environmentName)();
try {
if (error instanceof Error) {
name = error.name;
message = String(error.message);
stack = filterStackTrace(request, parseStackTrace(error, 0));
const errorEnv = (error: any).environmentName;
if (typeof errorEnv === 'string') {
env = errorEnv;
}
} else if (typeof error === 'object' && error !== null) {
message = describeObjectForErrorMessage(error);
stack = [];
} else {
message = String(error);
stack = [];
}
} catch (x) {
message = 'An error occurred but serializing the error message failed.';
stack = [];
}
errorInfo = {digest, name, message, stack, env};
} else {
errorInfo = {digest};
}
const row = serializeRowHeader('E', id) + stringify(errorInfo) + '\n';
const processedChunk = stringToChunk(row);
if (__DEV__ && debug) {
request.completedDebugChunks.push(processedChunk);
} else {
request.completedErrorChunks.push(processedChunk);
}
}
function emitImportChunk(
request: Request,
id: number,
clientReferenceMetadata: ClientReferenceMetadata,
debug: boolean,
): void {
const json: string = stringify(clientReferenceMetadata);
const row = serializeRowHeader('I', id) + json + '\n';
const processedChunk = stringToChunk(row);
if (__DEV__ && debug) {
request.completedDebugChunks.push(processedChunk);
} else {
request.completedImportChunks.push(processedChunk);
}
}
function emitHintChunk<Code: HintCode>(
request: Request,
code: Code,
model: HintModel<Code>,
): void {
const json: string = stringify(model);
const row = ':H' + code + json + '\n';
const processedChunk = stringToChunk(row);
request.completedHintChunks.push(processedChunk);
}
function emitSymbolChunk(request: Request, id: number, name: string): void {
const symbolReference = serializeSymbolReference(name);
const processedChunk = encodeReferenceChunk(request, id, symbolReference);
request.completedImportChunks.push(processedChunk);
}
function emitModelChunk(request: Request, id: number, json: string): void {
const row = id.toString(16) + ':' + json + '\n';
const processedChunk = stringToChunk(row);
request.completedRegularChunks.push(processedChunk);
}
function emitDebugHaltChunk(request: Request, id: number): void {
if (!__DEV__) {
throw new Error(
'emitDebugHaltChunk should never be called in production mode. This is a bug in React.',
);
}
const row = id.toString(16) + ':\n';
const processedChunk = stringToChunk(row);
request.completedDebugChunks.push(processedChunk);
}
function emitDebugChunk(
request: Request,
id: number,
debugInfo:
| ReactComponentInfo
| ReactAsyncInfo
| ReactEnvironmentInfo
| ReactTimeInfo,
): void {
if (!__DEV__) {
throw new Error(
'emitDebugChunk should never be called in production mode. This is a bug in React.',
);
}
const json: string = serializeDebugModel(request, 500, debugInfo);
const row = serializeRowHeader('D', id) + json + '\n';
const processedChunk = stringToChunk(row);
request.completedDebugChunks.push(processedChunk);
}
function outlineComponentInfo(
request: Request,
componentInfo: ReactComponentInfo,
): void {
if (!__DEV__) {
throw new Error(
'outlineComponentInfo should never be called in production mode. This is a bug in React.',
);
}
if (request.writtenDebugObjects.has(componentInfo)) {
return;
}
if (componentInfo.owner != null) {
outlineComponentInfo(request, componentInfo.owner);
}
let objectLimit = 10;
if (componentInfo.stack != null) {
objectLimit += componentInfo.stack.length;
}
const counter = {objectLimit};
const componentDebugInfo: Omit<
ReactComponentInfo,
'debugTask' | 'debugStack',
> = {
name: componentInfo.name,
key: componentInfo.key,
};
if (componentInfo.env != null) {
componentDebugInfo.env = componentInfo.env;
}
if (componentInfo.owner != null) {
componentDebugInfo.owner = componentInfo.owner;
}
if (componentInfo.stack == null && componentInfo.debugStack != null) {
componentDebugInfo.stack = filterStackTrace(
request,
parseStackTrace(componentInfo.debugStack, 1),
);
} else if (componentInfo.stack != null) {
componentDebugInfo.stack = componentInfo.stack;
}
componentDebugInfo.props = componentInfo.props;
const id = outlineDebugModel(request, counter, componentDebugInfo);
const ref = serializeByValueID(id);
request.writtenDebugObjects.set(componentInfo, ref);
request.writtenObjects.set(componentInfo, ref);
}
function emitIOInfoChunk(
request: Request,
id: number,
name: string,
start: number,
end: number,
value: ?Promise<mixed>,
env: ?string,
owner: ?ReactComponentInfo,
stack: ?ReactStackTrace,
): void {
if (!__DEV__) {
throw new Error(
'emitIOInfoChunk should never be called in production mode. This is a bug in React.',
);
}
let objectLimit = 10;
if (stack) {
objectLimit += stack.length;
}
const relativeStartTimestamp = start - request.timeOrigin;
const relativeEndTimestamp = end - request.timeOrigin;
const debugIOInfo: Omit<ReactIOInfo, 'debugTask' | 'debugStack'> = {
name: name,
start: relativeStartTimestamp,
end: relativeEndTimestamp,
};
if (value !== undefined) {
debugIOInfo.value = value;
}
if (env != null) {
debugIOInfo.env = env;
}
if (stack != null) {
debugIOInfo.stack = stack;
}
if (owner != null) {
debugIOInfo.owner = owner;
}
const json: string = serializeDebugModel(request, objectLimit, debugIOInfo);
const row = id.toString(16) + ':J' + json + '\n';
const processedChunk = stringToChunk(row);
request.completedDebugChunks.push(processedChunk);
}
function outlineIOInfo(request: Request, ioInfo: ReactIOInfo): void {
if (request.writtenObjects.has(ioInfo)) {
return;
}
request.pendingChunks++;
const id = request.nextChunkId++;
const owner = ioInfo.owner;
if (owner != null) {
outlineComponentInfo(request, owner);
}
let debugStack;
if (ioInfo.stack == null && ioInfo.debugStack != null) {
debugStack = filterStackTrace(
request,
parseStackTrace(ioInfo.debugStack, 1),
);
} else {
debugStack = ioInfo.stack;
}
emitIOInfoChunk(
request,
id,
ioInfo.name,
ioInfo.start,
ioInfo.end,
ioInfo.value,
ioInfo.env,
owner,
debugStack,
);
request.writtenDebugObjects.set(ioInfo, serializeByValueID(id));
}
function serializeIONode(
request: Request,
ioNode: IONode | PromiseNode | UnresolvedPromiseNode,
promiseRef: null | WeakRef<Promise<mixed>>,
): string {
const existingRef = request.writtenDebugObjects.get(ioNode);
if (existingRef !== undefined) {
return existingRef;
}
let stack = null;
let name = '';
if (ioNode.stack !== null) {
const fullStack = ioNode.stack;
stack = filterStackTrace(request, fullStack);
name = findCalledFunctionNameFromStackTrace(request, fullStack);
if (name.startsWith('Window.')) {
name = name.slice(7);
} else if (name.startsWith('<anonymous>.')) {
name = name.slice(7);
}
}
const owner = ioNode.owner;
if (owner != null) {
outlineComponentInfo(request, owner);
}
let value: void | Promise<mixed> = undefined;
if (promiseRef !== null) {
value = promiseRef.deref();
}
const env = (0, request.environmentName)();
const endTime =
ioNode.tag === UNRESOLVED_PROMISE_NODE
?
request.abortTime
: ioNode.end;
request.pendingChunks++;
const id = request.nextChunkId++;
emitIOInfoChunk(
request,
id,
name,
ioNode.start,
endTime,
value,
env,
owner,
stack,
);
const ref = serializeByValueID(id);
request.writtenDebugObjects.set(ioNode, ref);
return ref;
}
function emitTypedArrayChunk(
request: Request,
id: number,
tag: string,
typedArray: $ArrayBufferView,
debug: boolean,
): void {
if (enableTaint) {
if (TaintRegistryByteLengths.has(typedArray.byteLength)) {
const tainted = TaintRegistryValues.get(
binaryToComparableString(typedArray),
);
if (tainted !== undefined) {
throwTaintViolation(tainted.message);
}
}
}
request.pendingChunks++;
const binaryChunk = typedArrayToBinaryChunk(typedArray);
const binaryLength = byteLengthOfBinaryChunk(binaryChunk);
const row = id.toString(16) + ':' + tag + binaryLength.toString(16) + ',';
const headerChunk = stringToChunk(row);
if (__DEV__ && debug) {
request.completedDebugChunks.push(headerChunk, binaryChunk);
} else {
request.completedRegularChunks.push(headerChunk, binaryChunk);
}
}
function emitTextChunk(
request: Request,
id: number,
text: string,
debug: boolean,
): void {
if (byteLengthOfChunk === null) {
throw new Error(
'Existence of byteLengthOfChunk should have already been checked. This is a bug in React.',
);
}
request.pendingChunks++;
const textChunk = stringToChunk(text);
const binaryLength = byteLengthOfChunk(textChunk);
const row = id.toString(16) + ':T' + binaryLength.toString(16) + ',';
const headerChunk = stringToChunk(row);
if (__DEV__ && debug) {
request.completedDebugChunks.push(headerChunk, textChunk);
} else {
request.completedRegularChunks.push(headerChunk, textChunk);
}
}
function serializeEval(source: string): string {
if (!__DEV__) {
throw new Error(
'serializeEval should never be called in production mode. This is a bug in React.',
);
}
return '$E' + source;
}
const CONSTRUCTOR_MARKER: symbol = __DEV__ ? Symbol() : (null: any);
let debugModelRoot: mixed = null;
let debugNoOutline: mixed = null;
function renderDebugModel(
request: Request,
counter: {objectLimit: number},
parent:
| {+[propertyName: string | number]: ReactClientValue}
| $ReadOnlyArray<ReactClientValue>,
parentPropertyName: string,
value: ReactClientValue,
): ReactJSONValue {
if (value === null) {
return null;
}
if (value === REACT_ELEMENT_TYPE) {
return '$';
}
if (typeof value === 'object') {
if (isClientReference(value)) {
return serializeDebugClientReference(
request,
parent,
parentPropertyName,
(value: any),
);
}
if (value.$$typeof === CONSTRUCTOR_MARKER) {
const constructor: Function = (value: any).constructor;
let ref = request.writtenDebugObjects.get(constructor);
if (ref === undefined) {
const id = outlineDebugModel(request, counter, constructor);
ref = serializeByValueID(id);
}
return '$P' + ref.slice(1);
}
if (request.temporaryReferences !== undefined) {
const tempRef = resolveTemporaryReference(
request.temporaryReferences,
value,
);
if (tempRef !== undefined) {
return serializeTemporaryReference(request, tempRef);
}
}
const writtenDebugObjects = request.writtenDebugObjects;
const existingDebugReference = writtenDebugObjects.get(value);
if (existingDebugReference !== undefined) {
if (debugModelRoot === value) {
debugModelRoot = null;
} else {
return existingDebugReference;
}
} else if (parentPropertyName.indexOf(':') === -1) {
const parentReference = writtenDebugObjects.get(parent);
if (parentReference !== undefined) {
let propertyName = parentPropertyName;
if (isArray(parent) && parent[0] === REACT_ELEMENT_TYPE) {
switch (parentPropertyName) {
case '1':
propertyName = 'type';
break;
case '2':
propertyName = 'key';
break;
case '3':
propertyName = 'props';
break;
case '4':
propertyName = '_owner';
break;
}
}
writtenDebugObjects.set(value, parentReference + ':' + propertyName);
} else if (debugNoOutline !== value) {
const outlinedId = outlineDebugModel(request, counter, value);
return serializeByValueID(outlinedId);
}
}
const writtenObjects = request.writtenObjects;
const existingReference = writtenObjects.get(value);
if (existingReference !== undefined) {
return existingReference;
}
if (counter.objectLimit <= 0 && !doNotLimit.has(value)) {
return serializeDeferredObject(request, value);
}
counter.objectLimit--;
const deferredDebugObjects = request.deferredDebugObjects;
if (deferredDebugObjects !== null) {
const deferredId = deferredDebugObjects.existing.get(value);
if (deferredId !== undefined) {
deferredDebugObjects.existing.delete(value);
deferredDebugObjects.retained.delete(deferredId);
emitOutlinedDebugModelChunk(request, deferredId, counter, value);
return serializeByValueID(deferredId);
}
}
switch ((value: any).$$typeof) {
case REACT_ELEMENT_TYPE: {
const element: ReactElement = (value: any);
if (element._owner != null) {
outlineComponentInfo(request, element._owner);
}
if (typeof element.type === 'object' && element.type !== null) {
doNotLimit.add(element.type);
}
if (typeof element.key === 'object' && element.key !== null) {
doNotLimit.add(element.key);
}
doNotLimit.add(element.props);
if (element._owner !== null) {
doNotLimit.add(element._owner);
}
let debugStack: null | ReactStackTrace = null;
if (element._debugStack != null) {
debugStack = filterStackTrace(
request,
parseStackTrace(element._debugStack, 1),
);
doNotLimit.add(debugStack);
for (let i = 0; i < debugStack.length; i++) {
doNotLimit.add(debugStack[i]);
}
}
return [
REACT_ELEMENT_TYPE,
element.type,
element.key,
element.props,
element._owner,
debugStack,
element._store.validated,
];
}
}
if (typeof value.then === 'function') {
const thenable: Thenable<any> = (value: any);
return serializeDebugThenable(request, counter, thenable);
}
if (isArray(value)) {
return value;
}
if (value instanceof Map) {
return serializeDebugMap(request, counter, value);
}
if (value instanceof Set) {
return serializeDebugSet(request, counter, value);
}
if (typeof FormData === 'function' && value instanceof FormData) {
return serializeDebugFormData(request, value);
}
if (value instanceof Error) {
return serializeDebugErrorValue(request, value);
}
if (value instanceof ArrayBuffer) {
return serializeDebugTypedArray(request, 'A', new Uint8Array(value));
}
if (value instanceof Int8Array) {
return serializeDebugTypedArray(request, 'O', value);
}
if (value instanceof Uint8Array) {
return serializeDebugTypedArray(request, 'o', value);
}
if (value instanceof Uint8ClampedArray) {
return serializeDebugTypedArray(request, 'U', value);
}
if (value instanceof Int16Array) {
return serializeDebugTypedArray(request, 'S', value);
}
if (value instanceof Uint16Array) {
return serializeDebugTypedArray(request, 's', value);
}
if (value instanceof Int32Array) {
return serializeDebugTypedArray(request, 'L', value);
}
if (value instanceof Uint32Array) {
return serializeDebugTypedArray(request, 'l', value);
}
if (value instanceof Float32Array) {
return serializeDebugTypedArray(request, 'G', value);
}
if (value instanceof Float64Array) {
return serializeDebugTypedArray(request, 'g', value);
}
if (value instanceof BigInt64Array) {
return serializeDebugTypedArray(request, 'M', value);
}
if (value instanceof BigUint64Array) {
return serializeDebugTypedArray(request, 'm', value);
}
if (value instanceof DataView) {
return serializeDebugTypedArray(request, 'V', value);
}
if (typeof Blob === 'function' && value instanceof Blob) {
return serializeDebugBlob(request, value);
}
const iteratorFn = getIteratorFn(value);
if (iteratorFn) {
return Array.from((value: any));
}
const proto = getPrototypeOf(value);
if (proto !== ObjectPrototype && proto !== null) {
const object: Object = value;
const instanceDescription: Object = Object.create(null);
for (const propName in object) {
if (hasOwnProperty.call(value, propName) || isGetter(proto, propName)) {
instanceDescription[propName] = object[propName];
}
}
const constructor = proto.constructor;
if (
typeof constructor === 'function' &&
constructor.prototype === proto
) {
if (hasOwnProperty.call(object, '') || isGetter(proto, '')) {
} else {
instanceDescription[''] = {
$$typeof: CONSTRUCTOR_MARKER,
constructor: constructor,
};
}
}
return instanceDescription;
}
return value;
}
if (typeof value === 'string') {
if (value[value.length - 1] === 'Z') {
const originalValue = parent[parentPropertyName];
if (originalValue instanceof Date) {
return serializeDateFromDateJSON(value);
}
}
if (value.length >= 1024) {
if (counter.objectLimit <= 0) {
return serializeDeferredObject(request, value);
}
counter.objectLimit--;
return serializeDebugLargeTextString(request, value);
}
return escapeStringValue(value);
}
if (typeof value === 'boolean') {
return value;
}
if (typeof value === 'number') {
return serializeNumber(value);
}
if (typeof value === 'undefined') {
return serializeUndefined();
}
if (typeof value === 'function') {
if (isClientReference(value)) {
return serializeDebugClientReference(
request,
parent,
parentPropertyName,
(value: any),
);
}
if (request.temporaryReferences !== undefined) {
const tempRef = resolveTemporaryReference(
request.temporaryReferences,
value,
);
if (tempRef !== undefined) {
return serializeTemporaryReference(request, tempRef);
}
}
const writtenDebugObjects = request.writtenDebugObjects;
const existingReference = writtenDebugObjects.get(value);
if (existingReference !== undefined) {
return existingReference;
}
const serializedValue = serializeEval(
'(' + Function.prototype.toString.call(value) + ')',
);
request.pendingChunks++;
const id = request.nextChunkId++;
const processedChunk = encodeReferenceChunk(request, id, serializedValue);
request.completedDebugChunks.push(processedChunk);
const reference = serializeByValueID(id);
writtenDebugObjects.set(value, reference);
return reference;
}
if (typeof value === 'symbol') {
const writtenSymbols = request.writtenSymbols;
const existingId = writtenSymbols.get(value);
if (existingId !== undefined) {
return serializeByValueID(existingId);
}
const name: string = value.description;
request.pendingChunks++;
const symbolId = request.nextChunkId++;
emitSymbolChunk(request, symbolId, name);
return serializeByValueID(symbolId);
}
if (typeof value === 'bigint') {
return serializeBigInt(value);
}
if (value instanceof Date) {
return serializeDate(value);
}
return 'unknown type ' + typeof value;
}
function serializeDebugModel(
request: Request,
objectLimit: number,
model: mixed,
): string {
const counter = {objectLimit: objectLimit};
function replacer(
this:
| {+[key: string | number]: ReactClientValue}
| $ReadOnlyArray<ReactClientValue>,
parentPropertyName: string,
value: ReactClientValue,
): ReactJSONValue {
try {
return renderDebugModel(
request,
counter,
this,
parentPropertyName,
value,
);
} catch (x) {
return (
'Unknown Value: React could not send it from the server.\n' + x.message
);
}
}
const prevNoOutline = debugNoOutline;
debugNoOutline = model;
try {
return (stringify(model, replacer): string);
} catch (x) {
return (stringify(
'Unknown Value: React could not send it from the server.\n' + x.message,
): string);
} finally {
debugNoOutline = prevNoOutline;
}
}
function emitOutlinedDebugModelChunk(
request: Request,
id: number,
counter: {objectLimit: number},
model: ReactClientValue,
): void {
if (!__DEV__) {
throw new Error(
'emitOutlinedDebugModel should never be called in production mode. This is a bug in React.',
);
}
if (typeof model === 'object' && model !== null) {
doNotLimit.add(model);
}
function replacer(
this:
| {+[key: string | number]: ReactClientValue}
| $ReadOnlyArray<ReactClientValue>,
parentPropertyName: string,
value: ReactClientValue,
): ReactJSONValue {
try {
return renderDebugModel(
request,
counter,
this,
parentPropertyName,
value,
);
} catch (x) {
return (
'Unknown Value: React could not send it from the server.\n' + x.message
);
}
}
const prevModelRoot = debugModelRoot;
debugModelRoot = model;
if (typeof model === 'object' && model !== null) {
request.writtenDebugObjects.set(model, serializeByValueID(id));
}
let json: string;
try {
json = (stringify(model, replacer): string);
} catch (x) {
json = (stringify(
'Unknown Value: React could not send it from the server.\n' + x.message,
): string);
} finally {
debugModelRoot = prevModelRoot;
}
const row = id.toString(16) + ':' + json + '\n';
const processedChunk = stringToChunk(row);
request.completedDebugChunks.push(processedChunk);
}
function outlineDebugModel(
request: Request,
counter: {objectLimit: number},
model: ReactClientValue,
): number {
if (!__DEV__) {
throw new Error(
'outlineDebugModel should never be called in production mode. This is a bug in React.',
);
}
const id = request.nextChunkId++;
request.pendingChunks++;
emitOutlinedDebugModelChunk(request, id, counter, model);
return id;
}
function emitConsoleChunk(
request: Request,
methodName: string,
owner: null | ReactComponentInfo,
env: string,
stackTrace: ReactStackTrace,
args: Array<any>,
): void {
if (!__DEV__) {
throw new Error(
'emitConsoleChunk should never be called in production mode. This is a bug in React.',
);
}
if (owner != null) {
outlineComponentInfo(request, owner);
}
const payload = [methodName, stackTrace, owner, env];
payload.push.apply(payload, args);
let json = serializeDebugModel(request, 500, payload);
if (json[0] !== '[') {
json = serializeDebugModel(request, 500, [
methodName,
stackTrace,
owner,
env,
'Unknown Value: React could not send it from the server.',
]);
}
const row = ':W' + json + '\n';
const processedChunk = stringToChunk(row);
request.completedDebugChunks.push(processedChunk);
}
function emitTimeOriginChunk(request: Request, timeOrigin: number): void {
request.pendingChunks++;
const row = ':N' + timeOrigin + '\n';
const processedChunk = stringToChunk(row);
request.completedDebugChunks.push(processedChunk);
}
function forwardDebugInfo(
request: Request,
task: Task,
debugInfo: ReactDebugInfo,
) {
const id = task.id;
for (let i = 0; i < debugInfo.length; i++) {
const info = debugInfo[i];
if (typeof info.time === 'number') {
markOperationEndTime(request, task, info.time);
} else {
if (typeof info.name === 'string') {
outlineComponentInfo(request, (info: any));
request.pendingChunks++;
emitDebugChunk(request, id, info);
} else if (info.awaited) {
const ioInfo = info.awaited;
if (ioInfo.end <= request.timeOrigin) {
} else {
outlineIOInfo(request, ioInfo);
let debugStack;
if (info.stack == null && info.debugStack != null) {
debugStack = filterStackTrace(
request,
parseStackTrace(info.debugStack, 1),
);
} else {
debugStack = info.stack;
}
const debugAsyncInfo: Omit<
ReactAsyncInfo,
'debugTask' | 'debugStack',
> = {
awaited: ioInfo,
};
if (info.env != null) {
debugAsyncInfo.env = info.env;
}
if (info.owner != null) {
debugAsyncInfo.owner = info.owner;
}
if (debugStack != null) {
debugAsyncInfo.stack = debugStack;
}
request.pendingChunks++;
emitDebugChunk(request, id, debugAsyncInfo);
}
} else {
request.pendingChunks++;
emitDebugChunk(request, id, info);
}
}
}
}
function forwardDebugInfoFromThenable(
request: Request,
task: Task,
thenable: Thenable<any>,
owner: null | ReactComponentInfo,
stack: null | Error,
): void {
let debugInfo: ?ReactDebugInfo;
if (__DEV__) {
debugInfo = thenable._debugInfo;
if (debugInfo) {
forwardDebugInfo(request, task, debugInfo);
}
}
if (
enableProfilerTimer &&
enableComponentPerformanceTrack &&
enableAsyncDebugInfo
) {
const sequence = getAsyncSequenceFromPromise(thenable);
if (sequence !== null) {
emitAsyncSequence(request, task, sequence, debugInfo, owner, stack);
}
}
}
function forwardDebugInfoFromCurrentContext(
request: Request,
task: Task,
thenable: Thenable<any>,
): void {
let debugInfo: ?ReactDebugInfo;
if (__DEV__) {
debugInfo = thenable._debugInfo;
if (debugInfo) {
forwardDebugInfo(request, task, debugInfo);
}
}
if (
enableProfilerTimer &&
enableComponentPerformanceTrack &&
enableAsyncDebugInfo
) {
const sequence = getCurrentAsyncSequence();
if (sequence !== null) {
emitAsyncSequence(request, task, sequence, debugInfo, null, null);
}
}
}
function forwardDebugInfoFromAbortedTask(request: Request, task: Task): void {
const model: any = task.model;
if (typeof model !== 'object' || model === null) {
return;
}
let debugInfo: ?ReactDebugInfo;
if (__DEV__) {
debugInfo = model._debugInfo;
if (debugInfo) {
forwardDebugInfo(request, task, debugInfo);
}
}
if (
enableProfilerTimer &&
enableComponentPerformanceTrack &&
enableAsyncDebugInfo
) {
let thenable: null | Thenable<any> = null;
if (typeof model.then === 'function') {
thenable = (model: any);
} else if (model.$$typeof === REACT_LAZY_TYPE) {
const payload = model._payload;
if (typeof payload.then === 'function') {
thenable = payload;
}
}
if (thenable !== null) {
const sequence = getAsyncSequenceFromPromise(thenable);
if (sequence !== null) {
let node = sequence;
while (node.tag === UNRESOLVED_AWAIT_NODE && node.awaited !== null) {
node = node.awaited;
}
if (node.tag === UNRESOLVED_PROMISE_NODE) {
serializeIONode(request, node, null);
request.pendingChunks++;
const env = (0, request.environmentName)();
const asyncInfo: ReactAsyncInfo = {
awaited: ((node: any): ReactIOInfo),
env: env,
};
advanceTaskTime(request, task, task.time);
emitDebugChunk(request, task.id, asyncInfo);
} else {
emitAsyncSequence(request, task, sequence, debugInfo, null, null);
}
}
}
}
}
function emitTimingChunk(
request: Request,
id: number,
timestamp: number,
): void {
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
return;
}
request.pendingChunks++;
const relativeTimestamp = timestamp - request.timeOrigin;
const row =
serializeRowHeader('D', id) + '{"time":' + relativeTimestamp + '}\n';
const processedChunk = stringToChunk(row);
request.completedDebugChunks.push(processedChunk);
}
function advanceTaskTime(
request: Request,
task: Task,
timestamp: number,
): void {
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
return;
}
if (timestamp > task.time) {
emitTimingChunk(request, task.id, timestamp);
task.time = timestamp;
} else if (!task.timed) {
emitTimingChunk(request, task.id, task.time);
}
task.timed = true;
}
function markOperationEndTime(request: Request, task: Task, timestamp: number) {
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
return;
}
if (request.status === ABORTING && timestamp > request.abortTime) {
return;
}
if (timestamp > task.time) {
emitTimingChunk(request, task.id, timestamp);
task.time = timestamp;
} else {
emitTimingChunk(request, task.id, task.time);
}
}
function emitChunk(
request: Request,
task: Task,
value: ReactClientValue,
): void {
const id = task.id;
if (typeof value === 'string' && byteLengthOfChunk !== null) {
if (enableTaint) {
const tainted = TaintRegistryValues.get(value);
if (tainted !== undefined) {
throwTaintViolation(tainted.message);
}
}
emitTextChunk(request, id, value, false);
return;
}
if (value instanceof ArrayBuffer) {
emitTypedArrayChunk(request, id, 'A', new Uint8Array(value), false);
return;
}
if (value instanceof Int8Array) {
emitTypedArrayChunk(request, id, 'O', value, false);
return;
}
if (value instanceof Uint8Array) {
emitTypedArrayChunk(request, id, 'o', value, false);
return;
}
if (value instanceof Uint8ClampedArray) {
emitTypedArrayChunk(request, id, 'U', value, false);
return;
}
if (value instanceof Int16Array) {
emitTypedArrayChunk(request, id, 'S', value, false);
return;
}
if (value instanceof Uint16Array) {
emitTypedArrayChunk(request, id, 's', value, false);
return;
}
if (value instanceof Int32Array) {
emitTypedArrayChunk(request, id, 'L', value, false);
return;
}
if (value instanceof Uint32Array) {
emitTypedArrayChunk(request, id, 'l', value, false);
return;
}
if (value instanceof Float32Array) {
emitTypedArrayChunk(request, id, 'G', value, false);
return;
}
if (value instanceof Float64Array) {
emitTypedArrayChunk(request, id, 'g', value, false);
return;
}
if (value instanceof BigInt64Array) {
emitTypedArrayChunk(request, id, 'M', value, false);
return;
}
if (value instanceof BigUint64Array) {
emitTypedArrayChunk(request, id, 'm', value, false);
return;
}
if (value instanceof DataView) {
emitTypedArrayChunk(request, id, 'V', value, false);
return;
}
const json: string = stringify(value, task.toJSON);
emitModelChunk(request, task.id, json);
}
function erroredTask(request: Request, task: Task, error: mixed): void {
if (enableProfilerTimer && enableComponentPerformanceTrack) {
if (task.timed) {
markOperationEndTime(request, task, performance.now());
}
}
task.status = ERRORED;
if (
enablePostpone &&
typeof error === 'object' &&
error !== null &&
error.$$typeof === REACT_POSTPONE_TYPE
) {
const postponeInstance: Postpone = (error: any);
logPostpone(request, postponeInstance.message, task);
emitPostponeChunk(request, task.id, postponeInstance);
} else {
const digest = logRecoverableError(request, error, task);
emitErrorChunk(request, task.id, digest, error, false);
}
request.abortableTasks.delete(task);
callOnAllReadyIfReady(request);
}
const emptyRoot = {};
function retryTask(request: Request, task: Task): void {
if (task.status !== PENDING) {
return;
}
const prevCanEmitDebugInfo = canEmitDebugInfo;
task.status = RENDERING;
const parentSerializedSize = serializedSize;
try {
modelRoot = task.model;
if (__DEV__) {
canEmitDebugInfo = true;
}
const resolvedModel = renderModelDestructive(
request,
task,
emptyRoot,
'',
task.model,
);
if (__DEV__) {
canEmitDebugInfo = false;
}
modelRoot = resolvedModel;
task.keyPath = null;
task.implicitSlot = false;
if (__DEV__) {
const currentEnv = (0, request.environmentName)();
if (currentEnv !== task.environmentName) {
request.pendingChunks++;
emitDebugChunk(request, task.id, {env: currentEnv});
}
}
if (enableProfilerTimer && enableComponentPerformanceTrack) {
if (task.timed) {
markOperationEndTime(request, task, performance.now());
}
}
if (typeof resolvedModel === 'object' && resolvedModel !== null) {
request.writtenObjects.set(resolvedModel, serializeByValueID(task.id));
emitChunk(request, task, resolvedModel);
} else {
const json: string = stringify(resolvedModel);
emitModelChunk(request, task.id, json);
}
task.status = COMPLETED;
request.abortableTasks.delete(task);
callOnAllReadyIfReady(request);
} catch (thrownValue) {
if (request.status === ABORTING) {
request.abortableTasks.delete(task);
task.status = PENDING;
if (enableHalt && request.type === PRERENDER) {
haltTask(task, request);
finishHaltedTask(task, request);
} else {
const errorId: number = (request.fatalError: any);
abortTask(task, request, errorId);
finishAbortedTask(task, request, errorId);
}
return;
}
const x =
thrownValue === SuspenseException
?
getSuspendedThenable()
: thrownValue;
if (typeof x === 'object' && x !== null) {
if (typeof x.then === 'function') {
task.status = PENDING;
task.thenableState = getThenableStateAfterSuspending();
const ping = task.ping;
x.then(ping, ping);
return;
}
}
erroredTask(request, task, x);
} finally {
if (__DEV__) {
canEmitDebugInfo = prevCanEmitDebugInfo;
}
serializedSize = parentSerializedSize;
}
}
function tryStreamTask(request: Request, task: Task): void {
const prevCanEmitDebugInfo = canEmitDebugInfo;
if (__DEV__) {
canEmitDebugInfo = false;
}
const parentSerializedSize = serializedSize;
try {
emitChunk(request, task, task.model);
} finally {
serializedSize = parentSerializedSize;
if (__DEV__) {
canEmitDebugInfo = prevCanEmitDebugInfo;
}
}
}
function performWork(request: Request): void {
markAsyncSequenceRootTask();
const prevDispatcher = ReactSharedInternals.H;
ReactSharedInternals.H = HooksDispatcher;
const prevRequest = currentRequest;
currentRequest = request;
prepareToUseHooksForRequest(request);
try {
const pingedTasks = request.pingedTasks;
request.pingedTasks = [];
for (let i = 0; i < pingedTasks.length; i++) {
const task = pingedTasks[i];
retryTask(request, task);
}
if (request.destination !== null) {
flushCompletedChunks(request, request.destination);
}
} catch (error) {
logRecoverableError(request, error, null);
fatalError(request, error);
} finally {
ReactSharedInternals.H = prevDispatcher;
resetHooksForRequest();
currentRequest = prevRequest;
}
}
function abortTask(task: Task, request: Request, errorId: number): void {
if (task.status !== PENDING) {
return;
}
task.status = ABORTED;
}
function finishAbortedTask(
task: Task,
request: Request,
errorId: number,
): void {
if (task.status !== ABORTED) {
return;
}
forwardDebugInfoFromAbortedTask(request, task);
if (enableProfilerTimer && enableComponentPerformanceTrack) {
if (task.timed) {
markOperationEndTime(request, task, request.abortTime);
}
}
const ref = serializeByValueID(errorId);
const processedChunk = encodeReferenceChunk(request, task.id, ref);
request.completedErrorChunks.push(processedChunk);
}
function haltTask(task: Task, request: Request): void {
if (task.status !== PENDING) {
return;
}
task.status = ABORTED;
}
function finishHaltedTask(task: Task, request: Request): void {
if (task.status !== ABORTED) {
return;
}
forwardDebugInfoFromAbortedTask(request, task);
request.pendingChunks--;
}
function flushCompletedChunks(
request: Request,
destination: Destination,
): void {
beginWriting(destination);
try {
const importsChunks = request.completedImportChunks;
let i = 0;
for (; i < importsChunks.length; i++) {
request.pendingChunks--;
const chunk = importsChunks[i];
const keepWriting: boolean = writeChunkAndReturn(destination, chunk);
if (!keepWriting) {
request.destination = null;
i++;
break;
}
}
importsChunks.splice(0, i);
const hintChunks = request.completedHintChunks;
i = 0;
for (; i < hintChunks.length; i++) {
const chunk = hintChunks[i];
const keepWriting: boolean = writeChunkAndReturn(destination, chunk);
if (!keepWriting) {
request.destination = null;
i++;
break;
}
}
hintChunks.splice(0, i);
if (__DEV__) {
const debugChunks = request.completedDebugChunks;
i = 0;
for (; i < debugChunks.length; i++) {
request.pendingChunks--;
const chunk = debugChunks[i];
const keepWriting: boolean = writeChunkAndReturn(destination, chunk);
if (!keepWriting) {
request.destination = null;
i++;
break;
}
}
debugChunks.splice(0, i);
}
const regularChunks = request.completedRegularChunks;
i = 0;
for (; i < regularChunks.length; i++) {
request.pendingChunks--;
const chunk = regularChunks[i];
const keepWriting: boolean = writeChunkAndReturn(destination, chunk);
if (!keepWriting) {
request.destination = null;
i++;
break;
}
}
regularChunks.splice(0, i);
const errorChunks = request.completedErrorChunks;
i = 0;
for (; i < errorChunks.length; i++) {
request.pendingChunks--;
const chunk = errorChunks[i];
const keepWriting: boolean = writeChunkAndReturn(destination, chunk);
if (!keepWriting) {
request.destination = null;
i++;
break;
}
}
errorChunks.splice(0, i);
} finally {
request.flushScheduled = false;
completeWriting(destination);
}
flushBuffered(destination);
if (request.pendingChunks === 0) {
if (enableTaint) {
cleanupTaintQueue(request);
}
if (request.status < ABORTING) {
const abortReason = new Error(
'This render completed successfully. All cacheSignals are now aborted to allow clean up of any unused resources.',
);
request.cacheController.abort(abortReason);
}
request.status = CLOSED;
close(destination);
request.destination = null;
}
}
export function startWork(request: Request): void {
request.flushScheduled = request.destination !== null;
if (supportsRequestStorage) {
scheduleMicrotask(() => {
requestStorage.run(request, performWork, request);
});
} else {
scheduleMicrotask(() => performWork(request));
}
scheduleWork(() => {
if (request.status === OPENING) {
request.status = OPEN;
}
});
}
function enqueueFlush(request: Request): void {
if (
request.flushScheduled === false &&
request.pingedTasks.length === 0 &&
request.destination !== null
) {
request.flushScheduled = true;
scheduleWork(() => {
request.flushScheduled = false;
const destination = request.destination;
if (destination) {
flushCompletedChunks(request, destination);
}
});
}
}
function callOnAllReadyIfReady(request: Request): void {
if (request.abortableTasks.size === 0) {
const onAllReady = request.onAllReady;
onAllReady();
}
}
export function startFlowing(request: Request, destination: Destination): void {
if (request.status === CLOSING) {
request.status = CLOSED;
closeWithError(destination, request.fatalError);
return;
}
if (request.status === CLOSED) {
return;
}
if (request.destination !== null) {
return;
}
request.destination = destination;
try {
flushCompletedChunks(request, destination);
} catch (error) {
logRecoverableError(request, error, null);
fatalError(request, error);
}
}
export function stopFlowing(request: Request): void {
request.destination = null;
}
function finishHalt(request: Request, abortedTasks: Set<Task>): void {
try {
abortedTasks.forEach(task => finishHaltedTask(task, request));
const onAllReady = request.onAllReady;
onAllReady();
if (request.destination !== null) {
flushCompletedChunks(request, request.destination);
}
} catch (error) {
logRecoverableError(request, error, null);
fatalError(request, error);
}
}
function finishAbort(
request: Request,
abortedTasks: Set<Task>,
errorId: number,
): void {
try {
abortedTasks.forEach(task => finishAbortedTask(task, request, errorId));
const onAllReady = request.onAllReady;
onAllReady();
if (request.destination !== null) {
flushCompletedChunks(request, request.destination);
}
} catch (error) {
logRecoverableError(request, error, null);
fatalError(request, error);
}
}
export function abort(request: Request, reason: mixed): void {
if (request.status > OPEN) {
return;
}
try {
request.status = ABORTING;
if (enableProfilerTimer && enableComponentPerformanceTrack) {
request.abortTime = performance.now();
}
request.cacheController.abort(reason);
const abortableTasks = request.abortableTasks;
if (abortableTasks.size > 0) {
if (enableHalt && request.type === PRERENDER) {
abortableTasks.forEach(task => haltTask(task, request));
scheduleWork(() => finishHalt(request, abortableTasks));
} else if (
enablePostpone &&
typeof reason === 'object' &&
reason !== null &&
(reason: any).$$typeof === REACT_POSTPONE_TYPE
) {
const postponeInstance: Postpone = (reason: any);
logPostpone(request, postponeInstance.message, null);
const errorId = request.nextChunkId++;
request.fatalError = errorId;
request.pendingChunks++;
emitPostponeChunk(request, errorId, postponeInstance);
abortableTasks.forEach(task => abortTask(task, request, errorId));
scheduleWork(() => finishAbort(request, abortableTasks, errorId));
} else {
const error =
reason === undefined
? new Error(
'The render was aborted by the server without a reason.',
)
: typeof reason === 'object' &&
reason !== null &&
typeof reason.then === 'function'
? new Error(
'The render was aborted by the server with a promise.',
)
: reason;
const digest = logRecoverableError(request, error, null);
const errorId = request.nextChunkId++;
request.fatalError = errorId;
request.pendingChunks++;
emitErrorChunk(request, errorId, digest, error, false);
abortableTasks.forEach(task => abortTask(task, request, errorId));
scheduleWork(() => finishAbort(request, abortableTasks, errorId));
}
} else {
const onAllReady = request.onAllReady;
onAllReady();
if (request.destination !== null) {
flushCompletedChunks(request, request.destination);
}
}
} catch (error) {
logRecoverableError(request, error, null);
fatalError(request, error);
}
}
function fromHex(str: string): number {
return parseInt(str, 16);
}
export function resolveDebugMessage(request: Request, message: string): void {
if (!__DEV__) {
throw new Error(
'resolveDebugMessage should never be called in production mode. This is a bug in React.',
);
}
const deferredDebugObjects = request.deferredDebugObjects;
if (deferredDebugObjects === null) {
throw new Error(
"resolveDebugMessage/closeDebugChannel should not be called for a Request that wasn't kept alive. This is a bug in React.",
);
}
const command = message.charCodeAt(0);
const ids = message.slice(2).split(',').map(fromHex);
switch (command) {
case 82 :
for (let i = 0; i < ids.length; i++) {
const id = ids[i];
const retainedValue = deferredDebugObjects.retained.get(id);
if (retainedValue !== undefined) {
request.pendingChunks--;
deferredDebugObjects.retained.delete(id);
deferredDebugObjects.existing.delete(retainedValue);
enqueueFlush(request);
}
}
break;
case 81 :
for (let i = 0; i < ids.length; i++) {
const id = ids[i];
const retainedValue = deferredDebugObjects.retained.get(id);
if (retainedValue !== undefined) {
const counter = {objectLimit: 10};
emitOutlinedDebugModelChunk(request, id, counter, retainedValue);
enqueueFlush(request);
}
}
break;
default:
throw new Error(
'Unknown command. The debugChannel was not wired up properly.',
);
}
}
export function closeDebugChannel(request: Request): void {
if (!__DEV__) {
throw new Error(
'closeDebugChannel should never be called in production mode. This is a bug in React.',
);
}
const deferredDebugObjects = request.deferredDebugObjects;
if (deferredDebugObjects === null) {
throw new Error(
"resolveDebugMessage/closeDebugChannel should not be called for a Request that wasn't kept alive. This is a bug in React.",
);
}
deferredDebugObjects.retained.forEach((value, id) => {
request.pendingChunks--;
deferredDebugObjects.retained.delete(id);
deferredDebugObjects.existing.delete(value);
});
enqueueFlush(request);
}