76
const INITIALIZED = 'fulfilled';
77
const ERRORED = 'rejected';
78
79
+// Dev-only
80
+type ReactDebugInfo = Array<{+name?: string}>;
81
+
82
type PendingChunk<T> = {
83
status: 'pending',
84
value: null | Array<(T) => mixed>,
85
reason: null | Array<(mixed) => mixed>,
86
_response: Response,
87
+ _debugInfo?: null | ReactDebugInfo,
88
then(resolve: (T) => mixed, reject: (mixed) => mixed): void,
89
};
90
type BlockedChunk<T> = {
92
value: null | Array<(T) => mixed>,
93
reason: null | Array<(mixed) => mixed>,
94
_response: Response,
95
+ _debugInfo?: null | ReactDebugInfo,
96
then(resolve: (T) => mixed, reject: (mixed) => mixed): void,
97
};
98
type CyclicChunk<T> = {
100
value: null | Array<(T) => mixed>,
101
reason: null | Array<(mixed) => mixed>,
102
_response: Response,
103
+ _debugInfo?: null | ReactDebugInfo,
104
then(resolve: (T) => mixed, reject: (mixed) => mixed): void,
105
};
106
type ResolvedModelChunk<T> = {
108
value: UninitializedModel,
109
reason: null,
110
_response: Response,
111
+ _debugInfo?: null | ReactDebugInfo,
112
then(resolve: (T) => mixed, reject: (mixed) => mixed): void,
113
};
114
type ResolvedModuleChunk<T> = {
116
value: ClientReference<T>,
117
reason: null,
118
_response: Response,
119
+ _debugInfo?: null | ReactDebugInfo,
120
then(resolve: (T) => mixed, reject: (mixed) => mixed): void,
121
};
122
type InitializedChunk<T> = {
124
value: T,
125
reason: null,
126
_response: Response,
127
+ _debugInfo?: null | ReactDebugInfo,
128
then(resolve: (T) => mixed, reject: (mixed) => mixed): void,
129
};
130
type ErroredChunk<T> = {
132
value: null,
133
reason: mixed,
134
_response: Response,
135
+ _debugInfo?: null | ReactDebugInfo,
136
then(resolve: (T) => mixed, reject: (mixed) => mixed): void,
137
};
138
type SomeChunk<T> =
150
this.value = value;
151
this.reason = reason;
152
this._response = response;
153
+ if (__DEV__) {
154
+ this._debugInfo = null;
155
+ }
156
}
157
// We subclass Promise.prototype so that we get other methods like .catch
158
Chunk.prototype = (Object.create(Promise.prototype): any);
488
writable: true,
489
value: true, // This element has already been validated on the server.
490
});
491
+ // debugInfo contains Server Component debug information.
492
+ Object.defineProperty(element, '_debugInfo', {
493
+ configurable: false,
494
+ enumerable: false,
495
+ writable: true,
496
+ value: null,
497
+ });
498
}
499
return element;
500
}
507
_payload: chunk,
508
_init: readChunk,
509
};
510
+ if (__DEV__) {
511
+ // Ensure we have a live array to track future debug info.
512
+ const chunkDebugInfo: ReactDebugInfo =
513
+ chunk._debugInfo || (chunk._debugInfo = []);
514
+ lazyType._debugInfo = chunkDebugInfo;
515
+ }
516
return lazyType;
517
}
518
708
// The status might have changed after initialization.
709
switch (chunk.status) {
710
case INITIALIZED:
685
- return chunk.value;
711
+ const chunkValue = chunk.value;
712
+ if (__DEV__ && chunk._debugInfo) {
713
+ // If we have a direct reference to an object that was rendered by a synchronous
714
+ // server component, it might have some debug info about how it was rendered.
715
+ // We forward this to the underlying object. This might be a React Element or
716
+ // an Array fragment.
717
+ // If this was a string / number return value we lose the debug info. We choose
718
+ // that tradeoff to allow sync server components to return plain values and not
719
+ // use them as React Nodes necessarily. We could otherwise wrap them in a Lazy.
720
+ if (
721
+ typeof chunkValue === 'object' &&
722
+ chunkValue !== null &&
723
+ (Array.isArray(chunkValue) ||
724
+ chunkValue.$$typeof === REACT_ELEMENT_TYPE) &&
725
+ !chunkValue._debugInfo
726
+ ) {
727
+ // We should maybe use a unique symbol for arrays but this is a React owned array.
728
+ // $FlowFixMe[prop-missing]: This should be added to elements.
729
+ Object.defineProperty(chunkValue, '_debugInfo', {
730
+ configurable: false,
731
+ enumerable: false,
732
+ writable: true,
733
+ value: chunk._debugInfo,
734
+ });
735
+ }
736
+ }
737
+ return chunkValue;
738
case PENDING:
739
case BLOCKED:
740
case CYCLIC:
1011
dispatchHint(code, hintModel);
1012
}
1013
1014
+function resolveDebugInfo(
1015
+ response: Response,
1016
+ id: number,
1017
+ debugInfo: {name: string},
1018
+): void {
1019
+ if (!__DEV__) {
1020
+ // These errors should never make it into a build so we don't need to encode them in codes.json
1021
+ // eslint-disable-next-line react-internal/prod-error-codes
1022
+ throw new Error(
1023
+ 'resolveDebugInfo should never be called in production mode. This is a bug in React.',
1024
+ );
1025
+ }
1026
+ const chunk = getChunk(response, id);
1027
+ const chunkDebugInfo: ReactDebugInfo =
1028
+ chunk._debugInfo || (chunk._debugInfo = []);
1029
+ chunkDebugInfo.push(debugInfo);
1030
+}
1031
+
1032
function mergeBuffer(
1033
buffer: Array<Uint8Array>,
1034
lastChunk: Uint8Array,
1122
case 70 /* "F" */:
1123
resolveTypedArray(response, id, buffer, chunk, Float32Array, 4);
1124
return;
1055
- case 68 /* "D" */:
1125
+ case 100 /* "d" */:
1126
resolveTypedArray(response, id, buffer, chunk, Float64Array, 8);
1127
return;
1128
case 78 /* "N" */:
1172
resolveText(response, id, row);
1173
return;
1174
}
1175
+ case 68 /* "D" */: {
1176
+ if (__DEV__) {
1177
+ const debugInfo = JSON.parse(row);
1178
+ resolveDebugInfo(response, id, debugInfo);
1179
+ return;
1180
+ }
1181
+ throw new Error(
1182
+ 'Failed to read a RSC payload created by a development version of React ' +
1183
+ 'on the server while using a production version on the client. Always use ' +
1184
+ 'matching versions on the server and the client.',
1185
+ );
1186
+ }
1187
case 80 /* "P" */: {
1188
if (enablePostpone) {
1189
if (__DEV__) {
1247
resolvedRowTag === 76 /* "L" */ ||
1248
resolvedRowTag === 108 /* "l" */ ||
1249
resolvedRowTag === 70 /* "F" */ ||
1168
- resolvedRowTag === 68 /* "D" */ ||
1250
+ resolvedRowTag === 100 /* "d" */ ||
1251
resolvedRowTag === 78 /* "N" */ ||
1252
resolvedRowTag === 109 /* "m" */ ||
1253
resolvedRowTag === 86)) /* "V" */