diff --git a/packages/plugin-rsc/src/react/browser.ts b/packages/plugin-rsc/src/react/browser.ts index 3cf05a3f5..60c2d96ca 100644 --- a/packages/plugin-rsc/src/react/browser.ts +++ b/packages/plugin-rsc/src/react/browser.ts @@ -1,12 +1,17 @@ // @ts-ignore import * as ReactClient from '@vitejs/plugin-rsc/vendor/react-server-dom/client.browser' -import type { CallServerCallback } from '../types' +import type { + CallServerCallback, + ClientTemporaryReferenceSet, + CreateFromReadableStreamBrowserOptions, + EncodeReplyFunction, +} from '../types' export { setRequireModule } from '../core/browser' export function createFromReadableStream( stream: ReadableStream, - options: object = {}, + options: CreateFromReadableStreamBrowserOptions = {}, ): Promise { return ReactClient.createFromReadableStream(stream, { callServer, @@ -17,7 +22,7 @@ export function createFromReadableStream( export function createFromFetch( promiseForResponse: Promise, - options: object = {}, + options: CreateFromReadableStreamBrowserOptions = {}, ): Promise { return ReactClient.createFromFetch(promiseForResponse, { callServer, @@ -26,10 +31,7 @@ export function createFromFetch( }) } -export const encodeReply: ( - v: unknown[], - options?: unknown, -) => Promise = ReactClient.encodeReply +export const encodeReply: EncodeReplyFunction = ReactClient.encodeReply export const createServerReference: (...args: any[]) => unknown = ReactClient.createServerReference @@ -47,7 +49,7 @@ export function setServerCallback(fn: CallServerCallback): void { export type { CallServerCallback } -export const createTemporaryReferenceSet: () => unknown = +export const createTemporaryReferenceSet: () => ClientTemporaryReferenceSet = ReactClient.createTemporaryReferenceSet export function findSourceMapURL( diff --git a/packages/plugin-rsc/src/react/rsc.ts b/packages/plugin-rsc/src/react/rsc.ts index 1eecfc5ef..117fe15ec 100644 --- a/packages/plugin-rsc/src/react/rsc.ts +++ b/packages/plugin-rsc/src/react/rsc.ts @@ -8,12 +8,20 @@ import { createServerDecodeClientManifest, createServerManifest, } from '../core/rsc' +import type { + ClientTemporaryReferenceSet, + CreateFromReadableStreamEdgeOptions, + DecodeReplyFunction, + EncodeReplyFunction, + RenderToReadableStreamOptions, + ServerTemporaryReferenceSet, +} from '../types' export { loadServerAction, setRequireModule } from '../core/rsc' export function renderToReadableStream( data: T, - options?: object, + options?: RenderToReadableStreamOptions, extraOptions?: { /** * @internal @@ -32,7 +40,7 @@ export function renderToReadableStream( export function createFromReadableStream( stream: ReadableStream, - options: object = {}, + options: CreateFromReadableStreamEdgeOptions = {}, ): Promise { return ReactClient.createFromReadableStream(stream, { serverConsumerManifest: { @@ -59,12 +67,8 @@ export const registerServerReference: ( name: string, ) => T = ReactServer.registerServerReference -export function decodeReply( - body: string | FormData, - options?: unknown, -): Promise { - return ReactServer.decodeReply(body, createServerManifest(), options) -} +export const decodeReply: DecodeReplyFunction = (body, options) => + ReactServer.decodeReply(body, createServerManifest(), options) export function decodeAction(body: FormData): Promise<() => Promise> { return ReactServer.decodeAction(body, createServerManifest()) @@ -77,13 +81,10 @@ export function decodeFormState( return ReactServer.decodeFormState(actionResult, body, createServerManifest()) } -export const createTemporaryReferenceSet: () => unknown = +export const createTemporaryReferenceSet: () => ServerTemporaryReferenceSet = ReactServer.createTemporaryReferenceSet -export const encodeReply: ( - v: unknown[], - options?: unknown, -) => Promise = ReactClient.encodeReply +export const encodeReply: EncodeReplyFunction = ReactClient.encodeReply -export const createClientTemporaryReferenceSet: () => unknown = +export const createClientTemporaryReferenceSet: () => ClientTemporaryReferenceSet = ReactClient.createTemporaryReferenceSet diff --git a/packages/plugin-rsc/src/react/ssr.ts b/packages/plugin-rsc/src/react/ssr.ts index caa325750..906ed3aac 100644 --- a/packages/plugin-rsc/src/react/ssr.ts +++ b/packages/plugin-rsc/src/react/ssr.ts @@ -1,12 +1,13 @@ // @ts-ignore import * as ReactClient from '@vitejs/plugin-rsc/vendor/react-server-dom/client.edge' import { createServerConsumerManifest } from '../core/ssr' +import type { CreateFromReadableStreamEdgeOptions } from '../types' export { setRequireModule } from '../core/ssr' export function createFromReadableStream( stream: ReadableStream, - options: object = {}, + options: CreateFromReadableStreamEdgeOptions = {}, ): Promise { return ReactClient.createFromReadableStream(stream, { serverConsumerManifest: createServerConsumerManifest(), diff --git a/packages/plugin-rsc/src/types/index.ts b/packages/plugin-rsc/src/types/index.ts index aae722125..bb827a7b4 100644 --- a/packages/plugin-rsc/src/types/index.ts +++ b/packages/plugin-rsc/src/types/index.ts @@ -24,4 +24,77 @@ export interface ServerConsumerManifest { } } -export type CallServerCallback = (id: string, args: unknown[]) => unknown +export type CallServerCallback = ( + id: string, + args: unknown[], +) => Promise + +// Best-effort latest RSC API types +// https://github.com/wakujs/waku/blob/2ce74ee2381f6c0593b8246f33043434706889fe/packages/waku/src/lib/react-types.d.ts + +// https://github.com/facebook/react/blob/8b2e903a7447d370eb77bb117bc4c0ae240ce831/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerEdge.js#L64-L73 +export interface RenderToReadableStreamOptions { + debugChannel?: DebugChannel + environmentName?: string | (() => string) + filterStackFrame?: (url: string, functionName: string) => boolean + identifierPrefix?: string + signal?: AbortSignal + startTime?: number + temporaryReferences?: ServerTemporaryReferenceSet + onError?: (error: unknown) => void +} + +// https://github.com/facebook/react/blob/8b2e903a7447d370eb77bb117bc4c0ae240ce831/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientBrowser.js#L47-L57 +export interface CreateFromReadableStreamBrowserOptions { + callServer?: CallServerCallback + debugChannel?: DebugChannel + endTime?: number + environmentName?: string + replayConsoleLogs?: boolean + startTime?: number + temporaryReferences?: ClientTemporaryReferenceSet +} + +// https://github.com/facebook/react/blob/8b2e903a7447d370eb77bb117bc4c0ae240ce831/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientEdge.js#L74-L87 +export interface CreateFromReadableStreamEdgeOptions { + debugChannel?: DebugChannel + endTime?: number + environmentName?: string + nonce?: string + replayConsoleLogs?: boolean + startTime?: number + temporaryReferences?: ClientTemporaryReferenceSet +} + +// https://github.com/facebook/react/blob/8b2e903a7447d370eb77bb117bc4c0ae240ce831/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerEdge.js#L247-L253 +export interface DecodeReplyOptions { + temporaryReferences?: ServerTemporaryReferenceSet + arraySizeLimit?: number +} + +// https://github.com/facebook/react/blob/8b2e903a7447d370eb77bb117bc4c0ae240ce831/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientBrowser.js#L261-L263 +export interface EncodeReplyOptions { + temporaryReferences?: ClientTemporaryReferenceSet + signal?: AbortSignal +} + +// TODO: technically encode/decodeReply can serialize non-array values +export type EncodeReplyFunction = ( + value: unknown[], + options?: EncodeReplyOptions, +) => Promise +export type DecodeReplyFunction = ( + body: string | FormData, + options?: DecodeReplyOptions, +) => Promise + +type DebugChannel = { + readable?: ReadableStream + writable?: WritableStream +} + +// TODO: for now keep them unknown +// export type ServerTemporaryReferenceSet = WeakMap +// export type ClientTemporaryReferenceSet = Map +export type ServerTemporaryReferenceSet = unknown +export type ClientTemporaryReferenceSet = unknown