Files
react/packages/react-server/src/ReactFlightServerConfigStream.js
T
Sebastian Markbåge 2b003a5cc6 Split out ServerReferenceMetadata into Id and Bound Arguments (#26351)
This is just moving some stuff around and renaming things.

This tuple is opaque to the Flight implementation and we should probably
encode it separately as a single string instead of a model object.

The term "Metadata" isn't the same as when used for ClientReferences so
it's not really the right term anyway.

I also made it optional since a bound function with no arguments bound
is technically different than a raw instance of that function (it's a
clone).

I also renamed the type ReactModel to ReactClientValue. This is the
generic serializable type for something that can pass through the
serializable boundary from server to client. There will be another one
for client to server.

I also filled in missing classes and ensure the serializable sub-types
are explicit. E.g. Array and Thenable.
2023-03-08 23:45:55 -05:00

169 lines
3.8 KiB
JavaScript

/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
// This file is an intermediate layer to translate between Flight
// calls to stream output over a binary stream.
/*
FLIGHT PROTOCOL GRAMMAR
Response
- RowSequence
RowSequence
- Row RowSequence
- Row
Row
- "J" RowID JSONData
- "M" RowID JSONModuleData
- "H" RowID HTMLData
- "B" RowID BlobData
- "U" RowID URLData
- "E" RowID ErrorData
RowID
- HexDigits ":"
HexDigits
- HexDigit HexDigits
- HexDigit
HexDigit
- 0-F
URLData
- (UTF8 encoded URL) "\n"
ErrorData
- (UTF8 encoded JSON: {message: "...", stack: "..."}) "\n"
JSONData
- (UTF8 encoded JSON) "\n"
- String values that begin with $ are escaped with a "$" prefix.
- References to other rows are encoding as JSONReference strings.
JSONReference
- "$" HexDigits
HTMLData
- ByteSize (UTF8 encoded HTML)
BlobData
- ByteSize (Binary Data)
ByteSize
- (unsigned 32-bit integer)
*/
// TODO: Implement HTMLData, BlobData and URLData.
import type {
Request,
ReactClientValue,
} from 'react-server/src/ReactFlightServer';
import {stringToChunk} from './ReactServerStreamConfig';
import type {Chunk} from './ReactServerStreamConfig';
export type {Destination, Chunk} from './ReactServerStreamConfig';
export {
supportsRequestStorage,
requestStorage,
} from './ReactServerStreamConfig';
const stringify = JSON.stringify;
function serializeRowHeader(tag: string, id: number) {
return id.toString(16) + ':' + tag;
}
export function processErrorChunkProd(
request: Request,
id: number,
digest: string,
): Chunk {
if (__DEV__) {
// These errors should never make it into a build so we don't need to encode them in codes.json
// eslint-disable-next-line react-internal/prod-error-codes
throw new Error(
'processErrorChunkProd should never be called while in development mode. Use processErrorChunkDev instead. This is a bug in React.',
);
}
const errorInfo: any = {digest};
const row = serializeRowHeader('E', id) + stringify(errorInfo) + '\n';
return stringToChunk(row);
}
export function processErrorChunkDev(
request: Request,
id: number,
digest: string,
message: string,
stack: string,
): Chunk {
if (!__DEV__) {
// These errors should never make it into a build so we don't need to encode them in codes.json
// eslint-disable-next-line react-internal/prod-error-codes
throw new Error(
'processErrorChunkDev should never be called while in production mode. Use processErrorChunkProd instead. This is a bug in React.',
);
}
const errorInfo: any = {digest, message, stack};
const row = serializeRowHeader('E', id) + stringify(errorInfo) + '\n';
return stringToChunk(row);
}
export function processModelChunk(
request: Request,
id: number,
model: ReactClientValue,
): Chunk {
// $FlowFixMe[incompatible-type] stringify can return null
const json: string = stringify(model, request.toJSON);
const row = id.toString(16) + ':' + json + '\n';
return stringToChunk(row);
}
export function processReferenceChunk(
request: Request,
id: number,
reference: string,
): Chunk {
const json = stringify(reference);
const row = id.toString(16) + ':' + json + '\n';
return stringToChunk(row);
}
export function processImportChunk(
request: Request,
id: number,
clientReferenceMetadata: ReactClientValue,
): Chunk {
// $FlowFixMe[incompatible-type] stringify can return null
const json: string = stringify(clientReferenceMetadata);
const row = serializeRowHeader('I', id) + json + '\n';
return stringToChunk(row);
}
export {
scheduleWork,
flushBuffered,
beginWriting,
writeChunk,
writeChunkAndReturn,
completeWriting,
close,
closeWithError,
} from './ReactServerStreamConfig';