import type {Chunk, BinaryChunk, Destination} from './ReactServerStreamConfig';
import type {Postpone} from 'react/src/ReactPostpone';
import type {TemporaryReferenceSet} from './ReactFlightServerTemporaryReferences';
import {
enableBinaryFlight,
enablePostpone,
enableTaint,
enableRefAsProp,
enableServerComponentLogs,
enableOwnerStacks,
} from 'shared/ReactFeatureFlags';
import {enableFlightReadableStream} 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,
ReactAsyncInfo,
} from 'shared/ReactTypes';
import type {ReactElement} from 'shared/ReactElementType';
import type {LazyComponent} from 'react/src/ReactLazy';
import {
resolveClientReferenceMetadata,
getServerReferenceId,
getServerReferenceBoundArguments,
getClientReferenceKey,
isClientReference,
isServerReference,
supportsRequestStorage,
requestStorage,
supportsComponentStorage,
componentStorage,
createHints,
initAsyncDebugInfo,
} from './ReactFlightServerConfig';
import {
resolveTemporaryReference,
isOpaqueTemporaryReference,
} from './ReactFlightServerTemporaryReferences';
import {
HooksDispatcher,
prepareToUseHooksForRequest,
prepareToUseHooksForComponent,
getThenableStateAfterSuspending,
resetHooksForRequest,
} from './ReactFlightHooks';
import {DefaultAsyncDispatcher} from './flight/ReactFlightAsyncDispatcher';
import {resolveOwner, setCurrentOwner} from './flight/ReactFlightCurrentOwner';
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 {
describeValueForErrorMessage,
describeObjectForErrorMessage,
isSimpleObject,
jsxPropsParents,
jsxChildrenParents,
objectName,
} from 'shared/ReactSerializationErrors';
import type {SharedStateServer} from 'react/src/ReactSharedInternalsServer';
import ReactSharedInternalsImpl from 'shared/ReactSharedInternals';
const ReactSharedInternals: SharedStateServer = (ReactSharedInternalsImpl: any);
import isArray from 'shared/isArray';
import getPrototypeOf from 'shared/getPrototypeOf';
import binaryToComparableString from 'shared/binaryToComparableString';
import {SuspenseException, getSuspendedThenable} from './ReactFlightThenable';
const externalRegExp = /\/node\_modules\/| \(node\:| node\:|\(\<anonymous\>\)/;
let callComponentFrame: null | string = null;
let callIteratorFrame: null | string = null;
let callLazyInitFrame: null | string = null;
function isNotExternal(stackFrame: string): boolean {
return !externalRegExp.test(stackFrame);
}
function prepareStackTrace(
error: Error,
structuredStackTrace: CallSite[],
): string {
const name = error.name || 'Error';
const message = error.message || '';
let stack = name + ': ' + message;
for (let i = 0; i < structuredStackTrace.length; i++) {
stack += '\n at ' + structuredStackTrace[i].toString();
}
return stack;
}
function getStack(error: Error): string {
const previousPrepare = Error.prepareStackTrace;
Error.prepareStackTrace = prepareStackTrace;
try {
return String(error.stack);
} finally {
Error.prepareStackTrace = previousPrepare;
}
}
function initCallComponentFrame(): string {
const error = callComponentInDEV(Error, 'react-stack-top-frame', {});
const stack = getStack(error);
const startIdx = stack.startsWith('Error: react-stack-top-frame\n') ? 29 : 0;
const endIdx = stack.indexOf('\n', startIdx);
if (endIdx === -1) {
return stack.slice(startIdx);
}
return stack.slice(startIdx, endIdx);
}
function initCallIteratorFrame(): string {
try {
(callIteratorInDEV: any)({next: null});
return '';
} catch (error) {
const stack = getStack(error);
const startIdx = stack.startsWith('TypeError: ')
? stack.indexOf('\n') + 1
: 0;
const endIdx = stack.indexOf('\n', startIdx);
if (endIdx === -1) {
return stack.slice(startIdx);
}
return stack.slice(startIdx, endIdx);
}
}
function initCallLazyInitFrame(): string {
const error = callLazyInitInDEV({
$$typeof: REACT_LAZY_TYPE,
_init: Error,
_payload: 'react-stack-top-frame',
});
const stack = getStack(error);
const startIdx = stack.startsWith('Error: react-stack-top-frame\n') ? 29 : 0;
const endIdx = stack.indexOf('\n', startIdx);
if (endIdx === -1) {
return stack.slice(startIdx);
}
return stack.slice(startIdx, endIdx);
}
function filterDebugStack(error: Error): string {
let stack = getStack(error);
if (stack.startsWith('Error: react-stack-top-frame\n')) {
stack = stack.slice(29);
}
const frames = stack.split('\n').slice(1);
if (callComponentFrame === null) {
callComponentFrame = initCallComponentFrame();
}
let lastFrameIdx = frames.indexOf(callComponentFrame);
if (lastFrameIdx === -1) {
if (callLazyInitFrame === null) {
callLazyInitFrame = initCallLazyInitFrame();
}
lastFrameIdx = frames.indexOf(callLazyInitFrame);
if (lastFrameIdx === -1) {
if (callIteratorFrame === null) {
callIteratorFrame = initCallIteratorFrame();
}
lastFrameIdx = frames.indexOf(callIteratorFrame);
}
}
if (lastFrameIdx !== -1) {
frames.length = lastFrameIdx;
}
return frames.filter(isNotExternal).join('\n');
}
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 = filterDebugStack(new Error('react-stack-top-frame'));
request.pendingChunks++;
const id = request.nextChunkId++;
const owner: null | ReactComponentInfo = resolveOwner();
emitConsoleChunk(request, id, methodName, owner, stack, arguments);
}
return originalMethod.apply(this, arguments);
};
if (originalName) {
Object.defineProperty(
wrapperMethod,
'name',
originalName,
);
}
Object.defineProperty(consoleInst, methodName, {
value: wrapperMethod,
});
}
}
if (
enableServerComponentLogs &&
__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');
}
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$AbstractComponent<any, 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,
environmentName: string,
};
interface Reference {}
export type Request = {
status: 0 | 1 | 2 | 3,
flushScheduled: boolean,
fatalError: mixed,
destination: null | Destination,
bundlerConfig: ClientManifest,
cache: Map<Function, mixed>,
nextChunkId: number,
pendingChunks: number,
hints: Hints,
abortListeners: Set<(reason: mixed) => void>,
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,
environmentName: () => string,
didWarnForKey: null | WeakSet<ReactComponentInfo>,
};
const AbortSigil = {};
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);
}
function defaultPostponeHandler(reason: string) {
}
const OPEN = 0;
const ABORTING = 1;
const CLOSING = 2;
const CLOSED = 3;
function RequestInstance(
this: $FlowFixMe,
model: ReactClientValue,
bundlerConfig: ClientManifest,
onError: void | ((error: mixed) => ?string),
identifierPrefix?: string,
onPostpone: void | ((reason: string) => void),
environmentName: void | string | (() => string),
temporaryReferences: void | TemporaryReferenceSet,
) {
if (
ReactSharedInternals.A !== null &&
ReactSharedInternals.A !== DefaultAsyncDispatcher
) {
throw new Error(
'Currently React only supports one RSC renderer at a time.',
);
}
ReactSharedInternals.A = DefaultAsyncDispatcher;
const abortSet: Set<Task> = new Set();
const pingedTasks: Array<Task> = [];
const cleanupQueue: Array<string | bigint> = [];
if (enableTaint) {
TaintRegistryPendingRequests.add(cleanupQueue);
}
const hints = createHints();
this.status = OPEN;
this.flushScheduled = false;
this.fatalError = null;
this.destination = null;
this.bundlerConfig = bundlerConfig;
this.cache = new Map();
this.nextChunkId = 0;
this.pendingChunks = 0;
this.hints = hints;
this.abortListeners = new Set();
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;
if (__DEV__) {
this.environmentName =
environmentName === undefined
? () => 'Server'
: typeof environmentName !== 'function'
? () => environmentName
: environmentName;
this.didWarnForKey = null;
}
const rootTask = createTask(this, model, null, false, abortSet);
pingedTasks.push(rootTask);
}
export function createRequest(
model: ReactClientValue,
bundlerConfig: ClientManifest,
onError: void | ((error: mixed) => ?string),
identifierPrefix?: string,
onPostpone: void | ((reason: string) => void),
environmentName: void | string | (() => string),
temporaryReferences: void | TemporaryReferenceSet,
): Request {
return new RequestInstance(
model,
bundlerConfig,
onError,
identifierPrefix,
onPostpone,
environmentName,
temporaryReferences,
);
}
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 serializeThenable(
request: Request,
task: Task,
thenable: Thenable<any>,
): number {
const newTask = createTask(
request,
null,
task.keyPath,
task.implicitSlot,
request.abortableTasks,
);
if (__DEV__) {
const debugInfo: ?ReactDebugInfo = (thenable: any)._debugInfo;
if (debugInfo) {
forwardDebugInfo(request, newTask.id, debugInfo);
}
}
switch (thenable.status) {
case 'fulfilled': {
newTask.model = thenable.value;
pingTask(request, newTask);
return newTask.id;
}
case 'rejected': {
const x = thenable.reason;
if (
enablePostpone &&
typeof x === 'object' &&
x !== null &&
(x: any).$$typeof === REACT_POSTPONE_TYPE
) {
const postponeInstance: Postpone = (x: any);
logPostpone(request, postponeInstance.message);
emitPostponeChunk(request, newTask.id, postponeInstance);
} else {
const digest = logRecoverableError(request, x);
emitErrorChunk(request, newTask.id, digest, x);
}
return newTask.id;
}
default: {
if (request.status === ABORTING) {
newTask.status = ABORTED;
const errorId: number = (request.fatalError: any);
const model = stringify(serializeByValueID(errorId));
emitModelChunk(request, newTask.id, model);
request.abortableTasks.delete(newTask);
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 => {
newTask.model = value;
pingTask(request, newTask);
},
reason => {
if (
enablePostpone &&
typeof reason === 'object' &&
reason !== null &&
(reason: any).$$typeof === REACT_POSTPONE_TYPE
) {
const postponeInstance: Postpone = (reason: any);
logPostpone(request, postponeInstance.message);
emitPostponeChunk(request, newTask.id, postponeInstance);
} else {
newTask.status = ERRORED;
const digest = logRecoverableError(request, reason);
emitErrorChunk(request, newTask.id, digest, reason);
}
request.abortableTasks.delete(newTask);
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,
);
request.abortableTasks.delete(streamTask);
request.pendingChunks++;
const startStreamRow =
streamTask.id.toString(16) + ':' + (supportsBYOB ? 'r' : 'R') + '\n';
request.completedRegularChunks.push(stringToChunk(startStreamRow));
let aborted = false;
function progress(entry: {done: boolean, value: ReactClientValue, ...}) {
if (aborted) {
return;
}
if (entry.done) {
request.abortListeners.delete(error);
const endStreamRow = streamTask.id.toString(16) + ':C\n';
request.completedRegularChunks.push(stringToChunk(endStreamRow));
enqueueFlush(request);
aborted = true;
} 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 (aborted) {
return;
}
aborted = true;
request.abortListeners.delete(error);
if (
enablePostpone &&
typeof reason === 'object' &&
reason !== null &&
(reason: any).$$typeof === REACT_POSTPONE_TYPE
) {
const postponeInstance: Postpone = (reason: any);
logPostpone(request, postponeInstance.message);
emitPostponeChunk(request, streamTask.id, postponeInstance);
} else {
const digest = logRecoverableError(request, reason);
emitErrorChunk(request, streamTask.id, digest, reason);
}
enqueueFlush(request);
reader.cancel(reason).then(error, error);
}
request.abortListeners.add(error);
reader.read().then(progress, error);
return serializeByValueID(streamTask.id);
}
function callIteratorInDEV(
iterator: $AsyncIterator<ReactClientValue, ReactClientValue, void>,
progress: (
entry:
| {done: false, +value: ReactClientValue, ...}
| {done: true, +value: ReactClientValue, ...},
) => void,
error: (reason: mixed) => void,
) {
iterator.next().then(progress, error);
}
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,
);
request.abortableTasks.delete(streamTask);
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.id, debugInfo);
}
}
let aborted = false;
function progress(
entry:
| {done: false, +value: ReactClientValue, ...}
| {done: true, +value: ReactClientValue, ...},
) {
if (aborted) {
return;
}
if (entry.done) {
request.abortListeners.delete(error);
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));
enqueueFlush(request);
aborted = true;
} 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 (aborted) {
return;
}
aborted = true;
request.abortListeners.delete(error);
if (
enablePostpone &&
typeof reason === 'object' &&
reason !== null &&
(reason: any).$$typeof === REACT_POSTPONE_TYPE
) {
const postponeInstance: Postpone = (reason: any);
logPostpone(request, postponeInstance.message);
emitPostponeChunk(request, streamTask.id, postponeInstance);
} else {
const digest = logRecoverableError(request, reason);
emitErrorChunk(request, streamTask.id, digest, reason);
}
enqueueFlush(request);
if (typeof (iterator: any).throw === 'function') {
iterator.throw(reason).then(error, error);
}
}
request.abortListeners.add(error);
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(wakeable: Wakeable) {
const thenable: Thenable<mixed> = (wakeable: any);
switch (thenable.status) {
case 'fulfilled':
case 'rejected':
break;
default: {
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;
}
}
const lazyType: LazyComponent<any, Thenable<any>> = {
$$typeof: REACT_LAZY_TYPE,
_payload: thenable,
_init: readThenable,
};
if (__DEV__) {
lazyType._debugInfo = (thenable: any)._debugInfo || [];
}
return lazyType;
}
function callComponentInDEV<Props, R>(
Component: (p: Props, arg: void) => R,
props: Props,
componentDebugInfo: ReactComponentInfo,
): R {
const secondArg = undefined;
setCurrentOwner(componentDebugInfo);
try {
if (supportsComponentStorage) {
return componentStorage.run(
componentDebugInfo,
Component,
props,
secondArg,
);
} else {
return Component(props, secondArg);
}
} finally {
setCurrentOwner(null);
}
}
function callLazyInitInDEV(lazy: LazyComponent<any, any>): any {
const payload = lazy._payload;
const init = lazy._init;
return init(payload);
}
function renderFunctionComponent<Props>(
request: Request,
task: Task,
key: null | string,
Component: (p: Props, arg: void) => any,
props: Props,
owner: null | ReactComponentInfo,
stack: null | string,
validated: number,
): ReactJSONValue {
const prevThenableState = task.thenableState;
task.thenableState = null;
let result;
let componentDebugInfo: ReactComponentInfo;
if (__DEV__) {
if (debugID === null) {
return outlineTask(request, task);
} else if (prevThenableState !== null) {
componentDebugInfo = (prevThenableState: any)._componentDebugInfo;
} else {
const componentDebugID = debugID;
const componentName =
(Component: any).displayName || Component.name || '';
const componentEnv = request.environmentName();
request.pendingChunks++;
componentDebugInfo = ({
name: componentName,
env: componentEnv,
owner: owner,
}: ReactComponentInfo);
if (enableOwnerStacks) {
componentDebugInfo.stack = stack;
}
outlineModel(request, componentDebugInfo);
emitDebugChunk(request, componentDebugID, componentDebugInfo);
task.environmentName = componentEnv;
if (enableOwnerStacks) {
warnForMissingKey(request, key, validated, componentDebugInfo);
}
}
prepareToUseHooksForComponent(prevThenableState, componentDebugInfo);
result = callComponentInDEV(Component, props, componentDebugInfo);
} else {
prepareToUseHooksForComponent(prevThenableState, null);
const secondArg = undefined;
result = Component(props, secondArg);
}
if (request.status === ABORTING) {
throw AbortSigil;
}
if (
typeof result === 'object' &&
result !== null &&
!isClientReference(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;
}
},
() => {},
);
}
if (thenable.status === 'fulfilled') {
return thenable.value;
}
result = createLazyWrapperAroundWakeable(result);
}
const iteratorFn = getIteratorFn(result);
if (iteratorFn) {
const iterableChild = result;
result = {
[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) {
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__) {
(result: any)._debugInfo = iterableChild._debugInfo;
}
} else if (
enableFlightReadableStream &&
typeof (result: any)[ASYNC_ITERATOR] === 'function' &&
(typeof ReadableStream !== 'function' ||
!(result instanceof ReadableStream))
) {
const iterableChild = result;
result = {
[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) {
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__) {
(result: any)._debugInfo = iterableChild._debugInfo;
}
} else if (__DEV__ && (result: any).$$typeof === REACT_ELEMENT_TYPE) {
(result: any)._store.validated = 1;
}
}
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,
validated: number,
componentDebugInfo: ReactComponentInfo,
): void {
if (__DEV__) {
if (validated !== 2) {
return;
}
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);
}
callComponentInDEV(
() => {
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.',
'',
'',
);
},
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__
? enableOwnerStacks
? [
REACT_ELEMENT_TYPE,
REACT_FRAGMENT_TYPE,
task.keyPath,
{children},
null,
null,
0,
]
: [
REACT_ELEMENT_TYPE,
REACT_FRAGMENT_TYPE,
task.keyPath,
{children},
null,
]
: [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 (debugID === null) {
return outlineTask(request, task);
} else {
forwardDebugInfo(request, debugID, 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__
? enableOwnerStacks
? [
REACT_ELEMENT_TYPE,
REACT_FRAGMENT_TYPE,
task.keyPath,
{children},
null,
null,
0,
]
: [
REACT_ELEMENT_TYPE,
REACT_FRAGMENT_TYPE,
task.keyPath,
{children},
null,
]
: [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(
task: Task,
type: any,
key: null | string,
props: any,
owner: null | ReactComponentInfo,
stack: null | string,
validated: number,
): ReactJSONValue {
const keyPath = task.keyPath;
if (key === null) {
key = keyPath;
} else if (keyPath !== null) {
key = keyPath + ',' + key;
}
const element = __DEV__
? enableOwnerStacks
? [REACT_ELEMENT_TYPE, type, key, props, owner, stack, validated]
: [REACT_ELEMENT_TYPE, type, key, props, owner]
: [REACT_ELEMENT_TYPE, type, key, props];
if (task.implicitSlot && key !== null) {
return [element];
}
return element;
}
let debugID: null | number = null;
function outlineTask(request: Request, task: Task): ReactJSONValue {
const newTask = createTask(
request,
task.model,
task.keyPath,
task.implicitSlot,
request.abortableTasks,
);
retryTask(request, newTask);
if (newTask.status === COMPLETED) {
return serializeByValueID(newTask.id);
}
return serializeLazyID(newTask.id);
}
function renderElement(
request: Request,
task: Task,
type: any,
key: null | string,
ref: mixed,
props: any,
owner: null | ReactComponentInfo,
stack: null | string,
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') {
if (isClientReference(type) || isOpaqueTemporaryReference(type)) {
return renderClientElement(
task,
type,
key,
props,
owner,
stack,
validated,
);
}
return renderFunctionComponent(
request,
task,
key,
type,
props,
owner,
stack,
validated,
);
} else if (typeof type === 'string') {
return renderClientElement(task, type, key, props, owner, stack, validated);
} else if (typeof type === 'symbol') {
if (type === REACT_FRAGMENT_TYPE && key === null) {
const prevImplicitSlot = task.implicitSlot;
if (task.keyPath === null) {
task.implicitSlot = true;
}
const json = renderModelDestructive(
request,
task,
emptyRoot,
'',
props.children,
);
task.implicitSlot = prevImplicitSlot;
return json;
}
return renderClientElement(task, type, key, props, owner, stack, validated);
} else if (type != null && typeof type === 'object') {
if (isClientReference(type)) {
return renderClientElement(
task,
type,
key,
props,
owner,
stack,
validated,
);
}
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 AbortSigil;
}
return renderElement(
request,
task,
wrappedType,
key,
ref,
props,
owner,
stack,
validated,
);
}
case REACT_FORWARD_REF_TYPE: {
return renderFunctionComponent(
request,
task,
key,
type.render,
props,
owner,
stack,
validated,
);
}
case REACT_MEMO_TYPE: {
return renderElement(
request,
task,
type.type,
key,
ref,
props,
owner,
stack,
validated,
);
}
}
}
throw new Error(
`Unsupported Server Component type: ${describeValueForErrorMessage(type)}`,
);
}
function pingTask(request: Request, task: Task): void {
const pingedTasks = request.pingedTasks;
pingedTasks.push(task);
if (pingedTasks.length === 1) {
request.flushScheduled = request.destination !== null;
scheduleMicrotask(() => performWork(request));
}
}
function createTask(
request: Request,
model: ReactClientValue,
keyPath: null | string,
implicitSlot: boolean,
abortSet: Set<Task>,
): 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)
) {
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, 'environmentName'>): any);
if (__DEV__) {
task.environmentName = request.environmentName();
}
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 serializeInfinitePromise(): string {
return '$@';
}
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 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 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);
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);
emitErrorChunk(request, errorId, digest, x);
return serializeByValueID(errorId);
}
}
function outlineModel(request: Request, value: ReactClientValue): number {
const newTask = createTask(
request,
value,
null,
false,
request.abortableTasks,
);
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 bound: null | Array<any> = getServerReferenceBoundArguments(
request.bundlerConfig,
serverReference,
);
const serverReferenceMetadata: {
id: ServerReferenceId,
bound: null | Promise<Array<any>>,
} = {
id: getServerReferenceId(request.bundlerConfig, serverReference),
bound: bound ? Promise.resolve(bound) : null,
};
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);
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 serializeSet(request: Request, set: Set<ReactClientValue>): string {
const entries = Array.from(set);
const id = outlineModel(request, 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);
return serializeByValueID(bufferId);
}
function serializeBlob(request: Request, blob: Blob): string {
const model: Array<string | Uint8Array> = [blob.type];
const newTask = createTask(
request,
model,
null,
false,
request.abortableTasks,
);
const reader = blob.stream().getReader();
let aborted = false;
function progress(
entry: {done: false, value: Uint8Array} | {done: true, value: void},
): Promise<void> | void {
if (aborted) {
return;
}
if (entry.done) {
request.abortListeners.delete(error);
aborted = true;
pingTask(request, newTask);
return;
}
model.push(entry.value);
return reader.read().then(progress).catch(error);
}
function error(reason: mixed) {
if (aborted) {
return;
}
aborted = true;
request.abortListeners.delete(error);
const digest = logRecoverableError(request, reason);
emitErrorChunk(request, newTask.id, digest, reason);
request.abortableTasks.delete(newTask);
enqueueFlush(request);
reader.cancel(reason).then(error, error);
}
request.abortListeners.add(error);
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 {
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);
const x =
thrownValue === SuspenseException
?
getSuspendedThenable()
: thrownValue;
if (typeof x === 'object' && x !== null) {
if (typeof x.then === 'function') {
if (request.status === ABORTING) {
task.status = ABORTED;
const errorId: number = (request.fatalError: any);
if (wasReactNode) {
return serializeLazyID(errorId);
}
return serializeByValueID(errorId);
}
const newTask = createTask(
request,
task.model,
task.keyPath,
task.implicitSlot,
request.abortableTasks,
);
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);
} else if (enablePostpone && x.$$typeof === REACT_POSTPONE_TYPE) {
const postponeInstance: Postpone = (x: any);
request.pendingChunks++;
const postponeId = request.nextChunkId++;
logPostpone(request, postponeInstance.message);
emitPostponeChunk(request, postponeId, postponeInstance);
task.keyPath = prevKeyPath;
task.implicitSlot = prevImplicitSlot;
if (wasReactNode) {
return serializeLazyID(postponeId);
}
return serializeByValueID(postponeId);
}
}
if (thrownValue === AbortSigil) {
task.status = ABORTED;
const errorId: number = (request.fatalError: any);
if (wasReactNode) {
return serializeLazyID(errorId);
}
return serializeByValueID(errorId);
}
task.keyPath = prevKeyPath;
task.implicitSlot = prevImplicitSlot;
request.pendingChunks++;
const errorId = request.nextChunkId++;
const digest = logRecoverableError(request, x);
emitErrorChunk(request, errorId, digest, x);
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 (__DEV__) {
const debugInfo: ?ReactDebugInfo = (value: any)._debugInfo;
if (debugInfo) {
if (debugID === null) {
return outlineTask(request, task);
} else {
forwardDebugInfo(request, debugID, debugInfo);
}
}
}
const props = element.props;
let ref;
if (enableRefAsProp) {
const refProp = props.ref;
ref = refProp !== undefined ? refProp : null;
} else {
ref = element.ref;
}
const newChild = renderElement(
request,
task,
element.type,
element.key,
ref,
props,
__DEV__ ? element._owner : null,
__DEV__ && enableOwnerStacks
? !element._debugStack || typeof element._debugStack === 'string'
? element._debugStack
: filterDebugStack(element._debugStack)
: null,
__DEV__ && enableOwnerStacks ? 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: {
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 AbortSigil;
}
if (__DEV__) {
const debugInfo: ?ReactDebugInfo = lazy._debugInfo;
if (debugInfo) {
if (debugID === null) {
return outlineTask(request, task);
} else {
forwardDebugInfo(request, debugID, 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) {
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;
}
}
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 (enableBinaryFlight) {
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 (enableFlightReadableStream) {
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,
);
}
}
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.',
);
}
if (__DEV__) {
if (
typeof value.task === 'object' &&
value.task !== null &&
typeof value.task.run === 'function' &&
typeof value.name === 'string' &&
typeof value.env === 'string' &&
value.owner !== undefined &&
(enableOwnerStacks
? typeof (value: any).stack === 'string'
: typeof (value: any).stack === 'undefined')
) {
const componentDebugInfo: Omit<ReactComponentInfo, 'task'> = {
name: value.name,
env: value.env,
owner: (value: any).owner,
};
if (enableOwnerStacks) {
componentDebugInfo.stack = (value: any).stack;
}
return componentDebugInfo;
}
if (objectName(value) !== 'Object') {
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)) {
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) {
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);
}
}
if (value[value.length - 1] === 'Z') {
const originalValue = parent[parentPropertyName];
if (originalValue instanceof Date) {
return serializeDateFromDateJSON(value);
}
}
if (value.length >= 1024) {
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): void {
const prevRequest = currentRequest;
currentRequest = null;
try {
const onPostpone = request.onPostpone;
if (supportsRequestStorage) {
requestStorage.run(undefined, onPostpone, reason);
} else {
onPostpone(reason);
}
} finally {
currentRequest = prevRequest;
}
}
function logRecoverableError(request: Request, error: mixed): string {
const prevRequest = currentRequest;
currentRequest = null;
let errorDigest;
try {
const onError = request.onError;
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 {
if (enableTaint) {
cleanupTaintQueue(request);
}
if (request.destination !== null) {
request.status = CLOSED;
closeWithError(request.destination, error);
} else {
request.status = CLOSING;
request.fatalError = error;
}
}
function emitPostponeChunk(
request: Request,
id: number,
postponeInstance: Postpone,
): void {
let row;
if (__DEV__) {
let reason = '';
let stack = '';
try {
reason = String(postponeInstance.message);
stack = getStack(postponeInstance);
} catch (x) {}
row = serializeRowHeader('P', id) + stringify({reason, stack}) + '\n';
} else {
row = serializeRowHeader('P', id) + '\n';
}
const processedChunk = stringToChunk(row);
request.completedErrorChunks.push(processedChunk);
}
function emitErrorChunk(
request: Request,
id: number,
digest: string,
error: mixed,
): void {
let errorInfo: any;
if (__DEV__) {
let message;
let stack = '';
try {
if (error instanceof Error) {
message = String(error.message);
stack = getStack(error);
} else if (typeof error === 'object' && error !== null) {
message = describeObjectForErrorMessage(error);
} else {
message = String(error);
}
} catch (x) {
message = 'An error occurred but serializing the error message failed.';
}
errorInfo = {digest, message, stack};
} else {
errorInfo = {digest};
}
const row = serializeRowHeader('E', id) + stringify(errorInfo) + '\n';
const processedChunk = stringToChunk(row);
request.completedErrorChunks.push(processedChunk);
}
function emitImportChunk(
request: Request,
id: number,
clientReferenceMetadata: ClientReferenceMetadata,
): void {
const json: string = stringify(clientReferenceMetadata);
const row = serializeRowHeader('I', id) + json + '\n';
const processedChunk = stringToChunk(row);
request.completedImportChunks.push(processedChunk);
}
function emitHintChunk<Code: HintCode>(
request: Request,
code: Code,
model: HintModel<Code>,
): void {
const json: string = stringify(model);
const id = request.nextChunkId++;
const row = serializeRowHeader('H' + code, id) + 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 emitDebugChunk(
request: Request,
id: number,
debugInfo: ReactComponentInfo | ReactAsyncInfo,
): void {
if (!__DEV__) {
throw new Error(
'emitDebugChunk should never be called in production mode. This is a bug in React.',
);
}
const counter = {objectCount: 0};
function replacer(
this:
| {+[key: string | number]: ReactClientValue}
| $ReadOnlyArray<ReactClientValue>,
parentPropertyName: string,
value: ReactClientValue,
): ReactJSONValue {
return renderConsoleValue(
request,
counter,
this,
parentPropertyName,
value,
);
}
const json: string = stringify(debugInfo, replacer);
const row = serializeRowHeader('D', id) + json + '\n';
const processedChunk = stringToChunk(row);
request.completedRegularChunks.push(processedChunk);
}
function emitTypedArrayChunk(
request: Request,
id: number,
tag: string,
typedArray: $ArrayBufferView,
): 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);
request.completedRegularChunks.push(headerChunk, binaryChunk);
}
function emitTextChunk(request: Request, id: number, text: string): void {
request.pendingChunks++;
const textChunk = stringToChunk(text);
const binaryLength = byteLengthOfChunk(textChunk);
const row = id.toString(16) + ':T' + binaryLength.toString(16) + ',';
const headerChunk = stringToChunk(row);
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;
}
function renderConsoleValue(
request: Request,
counter: {objectCount: number},
parent:
| {+[propertyName: string | number]: ReactClientValue}
| $ReadOnlyArray<ReactClientValue>,
parentPropertyName: string,
value: ReactClientValue,
): ReactJSONValue {
const originalValue = parent[parentPropertyName];
if (
typeof originalValue === 'object' &&
originalValue !== value &&
!(originalValue instanceof Date)
) {
}
if (value === null) {
return null;
}
if (typeof value === 'object') {
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 (counter.objectCount > 20) {
return Array.isArray(value) ? [] : {};
}
counter.objectCount++;
const writtenObjects = request.writtenObjects;
const existingReference = writtenObjects.get(value);
if (typeof value.then === 'function') {
if (existingReference !== undefined) {
return existingReference;
}
const thenable: Thenable<any> = (value: any);
switch (thenable.status) {
case 'fulfilled': {
return serializePromiseID(
outlineConsoleValue(request, counter, thenable.value),
);
}
case 'rejected': {
const x = thenable.reason;
request.pendingChunks++;
const errorId = request.nextChunkId++;
if (
enablePostpone &&
typeof x === 'object' &&
x !== null &&
(x: any).$$typeof === REACT_POSTPONE_TYPE
) {
const postponeInstance: Postpone = (x: any);
emitPostponeChunk(request, errorId, postponeInstance);
} else {
const digest = '';
emitErrorChunk(request, errorId, digest, x);
}
return serializePromiseID(errorId);
}
}
return serializeInfinitePromise();
}
if (existingReference !== undefined) {
return existingReference;
}
if (isArray(value)) {
return 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 (enableBinaryFlight) {
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) {
return Array.from((value: any));
}
return value;
}
if (typeof value === 'string') {
if (value[value.length - 1] === 'Z') {
if (originalValue instanceof Date) {
return serializeDateFromDateJSON(value);
}
}
if (value.length >= 1024) {
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 (request.temporaryReferences !== undefined) {
const tempRef = resolveTemporaryReference(
request.temporaryReferences,
value,
);
if (tempRef !== undefined) {
return serializeTemporaryReference(request, tempRef);
}
}
return serializeEval('(' + Function.prototype.toString.call(value) + ')');
}
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);
}
return 'unknown type ' + typeof value;
}
function outlineConsoleValue(
request: Request,
counter: {objectCount: number},
model: ReactClientValue,
): number {
if (!__DEV__) {
throw new Error(
'outlineConsoleValue should never be called in production mode. This is a bug in React.',
);
}
function replacer(
this:
| {+[key: string | number]: ReactClientValue}
| $ReadOnlyArray<ReactClientValue>,
parentPropertyName: string,
value: ReactClientValue,
): ReactJSONValue {
try {
return renderConsoleValue(
request,
counter,
this,
parentPropertyName,
value,
);
} catch (x) {
return 'unknown value';
}
}
const json: string = stringify(model, replacer);
request.pendingChunks++;
const id = request.nextChunkId++;
const row = id.toString(16) + ':' + json + '\n';
const processedChunk = stringToChunk(row);
request.completedRegularChunks.push(processedChunk);
return id;
}
function emitConsoleChunk(
request: Request,
id: number,
methodName: string,
owner: null | ReactComponentInfo,
stackTrace: string,
args: Array<any>,
): void {
if (!__DEV__) {
throw new Error(
'emitConsoleChunk should never be called in production mode. This is a bug in React.',
);
}
const counter = {objectCount: 0};
function replacer(
this:
| {+[key: string | number]: ReactClientValue}
| $ReadOnlyArray<ReactClientValue>,
parentPropertyName: string,
value: ReactClientValue,
): ReactJSONValue {
try {
return renderConsoleValue(
request,
counter,
this,
parentPropertyName,
value,
);
} catch (x) {
return 'unknown value';
}
}
const env = request.environmentName();
const payload = [methodName, stackTrace, owner, env];
payload.push.apply(payload, args);
const json: string = stringify(payload, replacer);
const row = serializeRowHeader('W', id) + json + '\n';
const processedChunk = stringToChunk(row);
request.completedRegularChunks.push(processedChunk);
}
function forwardDebugInfo(
request: Request,
id: number,
debugInfo: ReactDebugInfo,
) {
for (let i = 0; i < debugInfo.length; i++) {
request.pendingChunks++;
if (typeof debugInfo[i].name === 'string') {
outlineModel(request, debugInfo[i]);
}
emitDebugChunk(request, id, debugInfo[i]);
}
}
function emitChunk(
request: Request,
task: Task,
value: ReactClientValue,
): void {
const id = task.id;
if (typeof value === 'string') {
if (enableTaint) {
const tainted = TaintRegistryValues.get(value);
if (tainted !== undefined) {
throwTaintViolation(tainted.message);
}
}
emitTextChunk(request, id, value);
return;
}
if (enableBinaryFlight) {
if (value instanceof ArrayBuffer) {
emitTypedArrayChunk(request, id, 'A', new Uint8Array(value));
return;
}
if (value instanceof Int8Array) {
emitTypedArrayChunk(request, id, 'O', value);
return;
}
if (value instanceof Uint8Array) {
emitTypedArrayChunk(request, id, 'o', value);
return;
}
if (value instanceof Uint8ClampedArray) {
emitTypedArrayChunk(request, id, 'U', value);
return;
}
if (value instanceof Int16Array) {
emitTypedArrayChunk(request, id, 'S', value);
return;
}
if (value instanceof Uint16Array) {
emitTypedArrayChunk(request, id, 's', value);
return;
}
if (value instanceof Int32Array) {
emitTypedArrayChunk(request, id, 'L', value);
return;
}
if (value instanceof Uint32Array) {
emitTypedArrayChunk(request, id, 'l', value);
return;
}
if (value instanceof Float32Array) {
emitTypedArrayChunk(request, id, 'G', value);
return;
}
if (value instanceof Float64Array) {
emitTypedArrayChunk(request, id, 'g', value);
return;
}
if (value instanceof BigInt64Array) {
emitTypedArrayChunk(request, id, 'M', value);
return;
}
if (value instanceof BigUint64Array) {
emitTypedArrayChunk(request, id, 'm', value);
return;
}
if (value instanceof DataView) {
emitTypedArrayChunk(request, id, 'V', value);
return;
}
}
const json: string = stringify(value, task.toJSON);
emitModelChunk(request, task.id, json);
}
const emptyRoot = {};
function retryTask(request: Request, task: Task): void {
if (task.status !== PENDING) {
return;
}
const prevDebugID = debugID;
task.status = RENDERING;
try {
modelRoot = task.model;
if (__DEV__) {
debugID = task.id;
}
const resolvedModel = renderModelDestructive(
request,
task,
emptyRoot,
'',
task.model,
);
if (__DEV__) {
debugID = null;
}
modelRoot = resolvedModel;
task.keyPath = null;
task.implicitSlot = false;
if (typeof resolvedModel === 'object' && resolvedModel !== null) {
request.writtenObjects.set(resolvedModel, serializeByValueID(task.id));
if (__DEV__) {
const currentEnv = request.environmentName();
if (currentEnv !== task.environmentName) {
emitDebugChunk(request, task.id, {env: currentEnv});
}
}
emitChunk(request, task, resolvedModel);
} else {
const json: string = stringify(resolvedModel);
if (__DEV__) {
const currentEnv = request.environmentName();
if (currentEnv !== task.environmentName) {
emitDebugChunk(request, task.id, {env: currentEnv});
}
}
emitModelChunk(request, task.id, json);
}
request.abortableTasks.delete(task);
task.status = COMPLETED;
} catch (thrownValue) {
const x =
thrownValue === SuspenseException
?
getSuspendedThenable()
: thrownValue;
if (typeof x === 'object' && x !== null) {
if (typeof x.then === 'function') {
if (request.status === ABORTING) {
request.abortableTasks.delete(task);
task.status = ABORTED;
const errorId: number = (request.fatalError: any);
const model = stringify(serializeByValueID(errorId));
emitModelChunk(request, task.id, model);
return;
}
task.status = PENDING;
task.thenableState = getThenableStateAfterSuspending();
const ping = task.ping;
x.then(ping, ping);
return;
} else if (enablePostpone && x.$$typeof === REACT_POSTPONE_TYPE) {
request.abortableTasks.delete(task);
task.status = ERRORED;
const postponeInstance: Postpone = (x: any);
logPostpone(request, postponeInstance.message);
emitPostponeChunk(request, task.id, postponeInstance);
return;
}
}
if (x === AbortSigil) {
request.abortableTasks.delete(task);
task.status = ABORTED;
const errorId: number = (request.fatalError: any);
const model = stringify(serializeByValueID(errorId));
emitModelChunk(request, task.id, model);
return;
}
request.abortableTasks.delete(task);
task.status = ERRORED;
const digest = logRecoverableError(request, x);
emitErrorChunk(request, task.id, digest, x);
} finally {
if (__DEV__) {
debugID = prevDebugID;
}
}
}
function tryStreamTask(request: Request, task: Task): void {
const prevDebugID = debugID;
if (__DEV__) {
debugID = null;
}
try {
emitChunk(request, task, task.model);
} finally {
if (__DEV__) {
debugID = prevDebugID;
}
}
}
function performWork(request: Request): void {
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);
fatalError(request, error);
} finally {
ReactSharedInternals.H = prevDispatcher;
resetHooksForRequest();
currentRequest = prevRequest;
}
}
function abortTask(task: Task, request: Request, errorId: number): void {
if (task.status === RENDERING) {
return;
}
task.status = ABORTED;
const ref = serializeByValueID(errorId);
const processedChunk = encodeReferenceChunk(request, task.id, ref);
request.completedErrorChunks.push(processedChunk);
}
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);
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);
}
request.status = CLOSED;
close(destination);
request.destination = null;
}
}
export function startWork(request: Request): void {
request.flushScheduled = request.destination !== null;
if (supportsRequestStorage) {
scheduleWork(() => requestStorage.run(request, performWork, request));
} else {
scheduleWork(() => performWork(request));
}
}
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);
}
});
}
}
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);
fatalError(request, error);
}
}
export function stopFlowing(request: Request): void {
request.destination = null;
}
export function abort(request: Request, reason: mixed): void {
try {
request.status = ABORTING;
const abortableTasks = request.abortableTasks;
if (abortableTasks.size > 0) {
request.pendingChunks++;
const errorId = request.nextChunkId++;
request.fatalError = errorId;
if (
enablePostpone &&
typeof reason === 'object' &&
reason !== null &&
(reason: any).$$typeof === REACT_POSTPONE_TYPE
) {
const postponeInstance: Postpone = (reason: any);
logPostpone(request, postponeInstance.message);
emitPostponeChunk(request, errorId, postponeInstance);
} 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);
emitErrorChunk(request, errorId, digest, error);
}
abortableTasks.forEach(task => abortTask(task, request, errorId));
abortableTasks.clear();
}
const abortListeners = request.abortListeners;
if (abortListeners.size > 0) {
let error;
if (
enablePostpone &&
typeof reason === 'object' &&
reason !== null &&
(reason: any).$$typeof === REACT_POSTPONE_TYPE
) {
error = new Error('The render was aborted due to being postponed.');
} else {
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;
}
abortListeners.forEach(callback => callback(error));
abortListeners.clear();
}
if (request.destination !== null) {
flushCompletedChunks(request, request.destination);
}
} catch (error) {
logRecoverableError(request, error);
fatalError(request, error);
}
}