Stacked on #31299. We already have an option for resolving Client References to other Client References when consuming an RSC payload on the server. This lets you resolve Server References on the consuming side when the environment where you're consuming the RSC payload also has access to those Server References. Basically they becomes like Client References for this consumer but for another consumer they wouldn't be.
106 lines
2.8 KiB
JavaScript
106 lines
2.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
|
|
*/
|
|
|
|
import type {Thenable, ReactCustomFormAction} from 'shared/ReactTypes.js';
|
|
|
|
import type {
|
|
Response,
|
|
FindSourceMapURLCallback,
|
|
} from 'react-client/src/ReactFlightClient';
|
|
|
|
import type {
|
|
ServerConsumerModuleMap,
|
|
ModuleLoading,
|
|
ServerManifest,
|
|
} from 'react-client/src/ReactFlightClientConfig';
|
|
|
|
type ServerConsumerManifest = {
|
|
moduleMap: ServerConsumerModuleMap,
|
|
moduleLoading: ModuleLoading,
|
|
serverModuleMap: null | ServerManifest,
|
|
};
|
|
|
|
import type {Readable} from 'stream';
|
|
|
|
import {
|
|
createResponse,
|
|
getRoot,
|
|
reportGlobalError,
|
|
processStringChunk,
|
|
processBinaryChunk,
|
|
close,
|
|
} from 'react-client/src/ReactFlightClient';
|
|
|
|
import {createServerReference as createServerReferenceImpl} from 'react-client/src/ReactFlightReplyClient';
|
|
|
|
function noServerCall() {
|
|
throw new Error(
|
|
'Server Functions cannot be called during initial render. ' +
|
|
'This would create a fetch waterfall. Try to use a Server Component ' +
|
|
'to pass data to Client Components instead.',
|
|
);
|
|
}
|
|
|
|
export function createServerReference<A: Iterable<any>, T>(
|
|
id: any,
|
|
callServer: any,
|
|
): (...A) => Promise<T> {
|
|
return createServerReferenceImpl(id, noServerCall);
|
|
}
|
|
|
|
type EncodeFormActionCallback = <A>(
|
|
id: any,
|
|
args: Promise<A>,
|
|
) => ReactCustomFormAction;
|
|
|
|
export type Options = {
|
|
nonce?: string,
|
|
encodeFormAction?: EncodeFormActionCallback,
|
|
findSourceMapURL?: FindSourceMapURLCallback,
|
|
replayConsoleLogs?: boolean,
|
|
environmentName?: string,
|
|
};
|
|
|
|
function createFromNodeStream<T>(
|
|
stream: Readable,
|
|
serverConsumerManifest: ServerConsumerManifest,
|
|
options?: Options,
|
|
): Thenable<T> {
|
|
const response: Response = createResponse(
|
|
serverConsumerManifest.moduleMap,
|
|
serverConsumerManifest.serverModuleMap,
|
|
serverConsumerManifest.moduleLoading,
|
|
noServerCall,
|
|
options ? options.encodeFormAction : undefined,
|
|
options && typeof options.nonce === 'string' ? options.nonce : undefined,
|
|
undefined, // TODO: If encodeReply is supported, this should support temporaryReferences
|
|
__DEV__ && options && options.findSourceMapURL
|
|
? options.findSourceMapURL
|
|
: undefined,
|
|
__DEV__ && options ? options.replayConsoleLogs === true : false, // defaults to false
|
|
__DEV__ && options && options.environmentName
|
|
? options.environmentName
|
|
: undefined,
|
|
);
|
|
stream.on('data', chunk => {
|
|
if (typeof chunk === 'string') {
|
|
processStringChunk(response, chunk);
|
|
} else {
|
|
processBinaryChunk(response, chunk);
|
|
}
|
|
});
|
|
stream.on('error', error => {
|
|
reportGlobalError(response, error);
|
|
});
|
|
stream.on('end', () => close(response));
|
|
return getRoot(response);
|
|
}
|
|
|
|
export {createFromNodeStream};
|