Skip to content

Commit e74a199

Browse files
hi-ogawaclaude
andauthored
feat(rsc): provide types for RSC API options (#1154)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 87e505b commit e74a199

File tree

4 files changed

+101
-24
lines changed

4 files changed

+101
-24
lines changed

packages/plugin-rsc/src/react/browser.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
// @ts-ignore
22
import * as ReactClient from '@vitejs/plugin-rsc/vendor/react-server-dom/client.browser'
3-
import type { CallServerCallback } from '../types'
3+
import type {
4+
CallServerCallback,
5+
ClientTemporaryReferenceSet,
6+
CreateFromReadableStreamBrowserOptions,
7+
EncodeReplyFunction,
8+
} from '../types'
49

510
export { setRequireModule } from '../core/browser'
611

712
export function createFromReadableStream<T>(
813
stream: ReadableStream<Uint8Array>,
9-
options: object = {},
14+
options: CreateFromReadableStreamBrowserOptions = {},
1015
): Promise<T> {
1116
return ReactClient.createFromReadableStream(stream, {
1217
callServer,
@@ -17,7 +22,7 @@ export function createFromReadableStream<T>(
1722

1823
export function createFromFetch<T>(
1924
promiseForResponse: Promise<Response>,
20-
options: object = {},
25+
options: CreateFromReadableStreamBrowserOptions = {},
2126
): Promise<T> {
2227
return ReactClient.createFromFetch(promiseForResponse, {
2328
callServer,
@@ -26,10 +31,7 @@ export function createFromFetch<T>(
2631
})
2732
}
2833

29-
export const encodeReply: (
30-
v: unknown[],
31-
options?: unknown,
32-
) => Promise<string | FormData> = ReactClient.encodeReply
34+
export const encodeReply: EncodeReplyFunction = ReactClient.encodeReply
3335

3436
export const createServerReference: (...args: any[]) => unknown =
3537
ReactClient.createServerReference
@@ -47,7 +49,7 @@ export function setServerCallback(fn: CallServerCallback): void {
4749

4850
export type { CallServerCallback }
4951

50-
export const createTemporaryReferenceSet: () => unknown =
52+
export const createTemporaryReferenceSet: () => ClientTemporaryReferenceSet =
5153
ReactClient.createTemporaryReferenceSet
5254

5355
export function findSourceMapURL(

packages/plugin-rsc/src/react/rsc.ts

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,20 @@ import {
88
createServerDecodeClientManifest,
99
createServerManifest,
1010
} from '../core/rsc'
11+
import type {
12+
ClientTemporaryReferenceSet,
13+
CreateFromReadableStreamEdgeOptions,
14+
DecodeReplyFunction,
15+
EncodeReplyFunction,
16+
RenderToReadableStreamOptions,
17+
ServerTemporaryReferenceSet,
18+
} from '../types'
1119

1220
export { loadServerAction, setRequireModule } from '../core/rsc'
1321

1422
export function renderToReadableStream<T>(
1523
data: T,
16-
options?: object,
24+
options?: RenderToReadableStreamOptions,
1725
extraOptions?: {
1826
/**
1927
* @internal
@@ -32,7 +40,7 @@ export function renderToReadableStream<T>(
3240

3341
export function createFromReadableStream<T>(
3442
stream: ReadableStream<Uint8Array>,
35-
options: object = {},
43+
options: CreateFromReadableStreamEdgeOptions = {},
3644
): Promise<T> {
3745
return ReactClient.createFromReadableStream(stream, {
3846
serverConsumerManifest: {
@@ -59,12 +67,8 @@ export const registerServerReference: <T>(
5967
name: string,
6068
) => T = ReactServer.registerServerReference
6169

62-
export function decodeReply(
63-
body: string | FormData,
64-
options?: unknown,
65-
): Promise<unknown[]> {
66-
return ReactServer.decodeReply(body, createServerManifest(), options)
67-
}
70+
export const decodeReply: DecodeReplyFunction = (body, options) =>
71+
ReactServer.decodeReply(body, createServerManifest(), options)
6872

6973
export function decodeAction(body: FormData): Promise<() => Promise<void>> {
7074
return ReactServer.decodeAction(body, createServerManifest())
@@ -77,13 +81,10 @@ export function decodeFormState(
7781
return ReactServer.decodeFormState(actionResult, body, createServerManifest())
7882
}
7983

80-
export const createTemporaryReferenceSet: () => unknown =
84+
export const createTemporaryReferenceSet: () => ServerTemporaryReferenceSet =
8185
ReactServer.createTemporaryReferenceSet
8286

83-
export const encodeReply: (
84-
v: unknown[],
85-
options?: unknown,
86-
) => Promise<string | FormData> = ReactClient.encodeReply
87+
export const encodeReply: EncodeReplyFunction = ReactClient.encodeReply
8788

88-
export const createClientTemporaryReferenceSet: () => unknown =
89+
export const createClientTemporaryReferenceSet: () => ClientTemporaryReferenceSet =
8990
ReactClient.createTemporaryReferenceSet

packages/plugin-rsc/src/react/ssr.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
// @ts-ignore
22
import * as ReactClient from '@vitejs/plugin-rsc/vendor/react-server-dom/client.edge'
33
import { createServerConsumerManifest } from '../core/ssr'
4+
import type { CreateFromReadableStreamEdgeOptions } from '../types'
45

56
export { setRequireModule } from '../core/ssr'
67

78
export function createFromReadableStream<T>(
89
stream: ReadableStream<Uint8Array>,
9-
options: object = {},
10+
options: CreateFromReadableStreamEdgeOptions = {},
1011
): Promise<T> {
1112
return ReactClient.createFromReadableStream(stream, {
1213
serverConsumerManifest: createServerConsumerManifest(),

packages/plugin-rsc/src/types/index.ts

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,77 @@ export interface ServerConsumerManifest {
2424
}
2525
}
2626

27-
export type CallServerCallback = (id: string, args: unknown[]) => unknown
27+
export type CallServerCallback = (
28+
id: string,
29+
args: unknown[],
30+
) => Promise<unknown>
31+
32+
// Best-effort latest RSC API types
33+
// https://github.com/wakujs/waku/blob/2ce74ee2381f6c0593b8246f33043434706889fe/packages/waku/src/lib/react-types.d.ts
34+
35+
// https://github.com/facebook/react/blob/8b2e903a7447d370eb77bb117bc4c0ae240ce831/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerEdge.js#L64-L73
36+
export interface RenderToReadableStreamOptions {
37+
debugChannel?: DebugChannel
38+
environmentName?: string | (() => string)
39+
filterStackFrame?: (url: string, functionName: string) => boolean
40+
identifierPrefix?: string
41+
signal?: AbortSignal
42+
startTime?: number
43+
temporaryReferences?: ServerTemporaryReferenceSet
44+
onError?: (error: unknown) => void
45+
}
46+
47+
// https://github.com/facebook/react/blob/8b2e903a7447d370eb77bb117bc4c0ae240ce831/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientBrowser.js#L47-L57
48+
export interface CreateFromReadableStreamBrowserOptions {
49+
callServer?: CallServerCallback
50+
debugChannel?: DebugChannel
51+
endTime?: number
52+
environmentName?: string
53+
replayConsoleLogs?: boolean
54+
startTime?: number
55+
temporaryReferences?: ClientTemporaryReferenceSet
56+
}
57+
58+
// https://github.com/facebook/react/blob/8b2e903a7447d370eb77bb117bc4c0ae240ce831/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientEdge.js#L74-L87
59+
export interface CreateFromReadableStreamEdgeOptions {
60+
debugChannel?: DebugChannel
61+
endTime?: number
62+
environmentName?: string
63+
nonce?: string
64+
replayConsoleLogs?: boolean
65+
startTime?: number
66+
temporaryReferences?: ClientTemporaryReferenceSet
67+
}
68+
69+
// https://github.com/facebook/react/blob/8b2e903a7447d370eb77bb117bc4c0ae240ce831/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerEdge.js#L247-L253
70+
export interface DecodeReplyOptions {
71+
temporaryReferences?: ServerTemporaryReferenceSet
72+
arraySizeLimit?: number
73+
}
74+
75+
// https://github.com/facebook/react/blob/8b2e903a7447d370eb77bb117bc4c0ae240ce831/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientBrowser.js#L261-L263
76+
export interface EncodeReplyOptions {
77+
temporaryReferences?: ClientTemporaryReferenceSet
78+
signal?: AbortSignal
79+
}
80+
81+
// TODO: technically encode/decodeReply can serialize non-array values
82+
export type EncodeReplyFunction = (
83+
value: unknown[],
84+
options?: EncodeReplyOptions,
85+
) => Promise<string | FormData>
86+
export type DecodeReplyFunction = (
87+
body: string | FormData,
88+
options?: DecodeReplyOptions,
89+
) => Promise<unknown[]>
90+
91+
type DebugChannel = {
92+
readable?: ReadableStream<Uint8Array>
93+
writable?: WritableStream<Uint8Array>
94+
}
95+
96+
// TODO: for now keep them unknown
97+
// export type ServerTemporaryReferenceSet = WeakMap<object, string>
98+
// export type ClientTemporaryReferenceSet = Map<unknown, unknown>
99+
export type ServerTemporaryReferenceSet = unknown
100+
export type ClientTemporaryReferenceSet = unknown

0 commit comments

Comments
 (0)