@tanstack/react-start-rsc 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/dist/esm/ClientSlot.js +19 -0
  2. package/dist/esm/ClientSlot.js.map +1 -0
  3. package/dist/esm/CompositeComponent.js +93 -0
  4. package/dist/esm/CompositeComponent.js.map +1 -0
  5. package/dist/esm/ReplayableStream.js +147 -0
  6. package/dist/esm/ReplayableStream.js.map +1 -0
  7. package/dist/esm/RscNodeRenderer.js +46 -0
  8. package/dist/esm/RscNodeRenderer.js.map +1 -0
  9. package/dist/esm/ServerComponentTypes.js +22 -0
  10. package/dist/esm/ServerComponentTypes.js.map +1 -0
  11. package/dist/esm/SlotContext.js +30 -0
  12. package/dist/esm/SlotContext.js.map +1 -0
  13. package/dist/esm/awaitLazyElements.js +41 -0
  14. package/dist/esm/awaitLazyElements.js.map +1 -0
  15. package/dist/esm/createCompositeComponent.js +205 -0
  16. package/dist/esm/createCompositeComponent.js.map +1 -0
  17. package/dist/esm/createCompositeComponent.stub.js +15 -0
  18. package/dist/esm/createCompositeComponent.stub.js.map +1 -0
  19. package/dist/esm/createRscProxy.js +138 -0
  20. package/dist/esm/createRscProxy.js.map +1 -0
  21. package/dist/esm/createServerComponentFromStream.js +74 -0
  22. package/dist/esm/createServerComponentFromStream.js.map +1 -0
  23. package/dist/esm/entry/rsc.js +21 -0
  24. package/dist/esm/entry/rsc.js.map +1 -0
  25. package/dist/esm/flight.js +56 -0
  26. package/dist/esm/flight.js.map +1 -0
  27. package/dist/esm/flight.rsc.js +2 -0
  28. package/dist/esm/flight.stub.js +15 -0
  29. package/dist/esm/flight.stub.js.map +1 -0
  30. package/dist/esm/index.js +7 -0
  31. package/dist/esm/index.rsc.js +6 -0
  32. package/dist/esm/plugin/vite.js +172 -0
  33. package/dist/esm/plugin/vite.js.map +1 -0
  34. package/dist/esm/reactSymbols.js +8 -0
  35. package/dist/esm/reactSymbols.js.map +1 -0
  36. package/dist/esm/renderServerComponent.js +58 -0
  37. package/dist/esm/renderServerComponent.js.map +1 -0
  38. package/dist/esm/renderServerComponent.stub.js +16 -0
  39. package/dist/esm/renderServerComponent.stub.js.map +1 -0
  40. package/dist/esm/serialization.client.js +21 -0
  41. package/dist/esm/serialization.client.js.map +1 -0
  42. package/dist/esm/serialization.server.js +121 -0
  43. package/dist/esm/serialization.server.js.map +1 -0
  44. package/dist/esm/slotUsageSanitizer.js +33 -0
  45. package/dist/esm/slotUsageSanitizer.js.map +1 -0
  46. package/dist/esm/src/ClientSlot.d.ts +5 -0
  47. package/dist/esm/src/CompositeComponent.d.ts +28 -0
  48. package/dist/esm/src/ReplayableStream.d.ts +76 -0
  49. package/dist/esm/src/RscNodeRenderer.d.ts +7 -0
  50. package/dist/esm/src/ServerComponentTypes.d.ts +99 -0
  51. package/dist/esm/src/SlotContext.d.ts +21 -0
  52. package/dist/esm/src/awaitLazyElements.d.ts +17 -0
  53. package/dist/esm/src/createCompositeComponent.d.ts +32 -0
  54. package/dist/esm/src/createCompositeComponent.stub.d.ts +9 -0
  55. package/dist/esm/src/createRscProxy.d.ts +18 -0
  56. package/dist/esm/src/createServerComponentFromStream.d.ts +24 -0
  57. package/dist/esm/src/entry/rsc.d.ts +7 -0
  58. package/dist/esm/src/flight.d.ts +41 -0
  59. package/dist/esm/src/flight.rsc.d.ts +17 -0
  60. package/dist/esm/src/flight.stub.d.ts +8 -0
  61. package/dist/esm/src/index.d.ts +7 -0
  62. package/dist/esm/src/index.rsc.d.ts +6 -0
  63. package/dist/esm/src/plugin/vite.d.ts +9 -0
  64. package/dist/esm/src/reactSymbols.d.ts +3 -0
  65. package/dist/esm/src/renderServerComponent.d.ts +33 -0
  66. package/dist/esm/src/renderServerComponent.stub.d.ts +9 -0
  67. package/dist/esm/src/rscSsrHandler.d.ts +24 -0
  68. package/dist/esm/src/serialization.client.d.ts +11 -0
  69. package/dist/esm/src/serialization.server.d.ts +10 -0
  70. package/dist/esm/src/slotUsageSanitizer.d.ts +1 -0
  71. package/dist/esm/src/types.d.ts +13 -0
  72. package/dist/plugin/entry/rsc.tsx +23 -0
  73. package/package.json +108 -0
  74. package/src/ClientSlot.tsx +34 -0
  75. package/src/CompositeComponent.tsx +165 -0
  76. package/src/ReplayableStream.ts +249 -0
  77. package/src/RscNodeRenderer.tsx +76 -0
  78. package/src/ServerComponentTypes.ts +226 -0
  79. package/src/SlotContext.tsx +42 -0
  80. package/src/awaitLazyElements.ts +91 -0
  81. package/src/createCompositeComponent.stub.ts +20 -0
  82. package/src/createCompositeComponent.ts +338 -0
  83. package/src/createRscProxy.tsx +294 -0
  84. package/src/createServerComponentFromStream.ts +105 -0
  85. package/src/entry/rsc.tsx +23 -0
  86. package/src/entry/virtual-modules.d.ts +12 -0
  87. package/src/flight.rsc.ts +17 -0
  88. package/src/flight.stub.ts +15 -0
  89. package/src/flight.ts +68 -0
  90. package/src/global.d.ts +75 -0
  91. package/src/index.rsc.ts +25 -0
  92. package/src/index.ts +26 -0
  93. package/src/plugin/vite.ts +241 -0
  94. package/src/reactSymbols.ts +6 -0
  95. package/src/renderServerComponent.stub.ts +26 -0
  96. package/src/renderServerComponent.ts +110 -0
  97. package/src/rscSsrHandler.ts +39 -0
  98. package/src/serialization.client.ts +43 -0
  99. package/src/serialization.server.ts +193 -0
  100. package/src/slotUsageSanitizer.ts +62 -0
  101. package/src/types.ts +15 -0
@@ -0,0 +1,99 @@
1
+ import { Constrain, LooseAsyncReturnType, LooseReturnType, ValidateSerializable } from '@tanstack/router-core';
2
+ import { ComponentProps, ComponentType } from 'react';
3
+ export interface ServerComponentStream {
4
+ createReplayStream: () => ReadableStream<Uint8Array>;
5
+ }
6
+ export declare const SERVER_COMPONENT_STREAM: unique symbol;
7
+ export declare const SERVER_COMPONENT_CSS_HREFS: unique symbol;
8
+ export declare const SERVER_COMPONENT_JS_PRELOADS: unique symbol;
9
+ export declare const RSC_PROXY_PATH: unique symbol;
10
+ export declare const RSC_PROXY_GET_TREE: unique symbol;
11
+ export declare const RENDERABLE_RSC: unique symbol;
12
+ export declare const RSC_SLOT_USAGES: unique symbol;
13
+ export declare const RSC_SLOT_USAGES_STREAM: unique symbol;
14
+ export type RscSlotUsageEvent = {
15
+ slot: string;
16
+ args?: Array<any>;
17
+ };
18
+ /**
19
+ * Type guard to check if a value is a ServerComponent (Proxy with attached stream).
20
+ * The value can be either an object (proxy target) or a function (stub for server functions).
21
+ */
22
+ export declare function isServerComponent(value: unknown): value is AnyCompositeComponent;
23
+ /**
24
+ * Type guard to check if a value is a RenderableRsc (renderable proxy from renderServerComponent).
25
+ * The value can be either an object (proxy target) or a function (stub for server functions).
26
+ */
27
+ export declare function isRenderableRsc(value: unknown): boolean;
28
+ export type ValidateCompositeComponent<TComp> = Constrain<TComp, (props: ValidateCompositeComponentProps<TComp>) => ValidateCompositeComponentReturnType<TComp>>;
29
+ export type ValidateCompositeComponentProps<TComp> = unknown extends TComp ? TComp : ValidateCompositeComponentPropsObject<CompositeComponentProps<TComp>>;
30
+ export type ValidateCompositeComponentPropsObject<TProps> = unknown extends TProps ? TProps : {
31
+ [TKey in keyof TProps]: ValidateCompositeComponentProp<TProps[TKey]>;
32
+ };
33
+ export type CompositeComponentProps<TComp> = TComp extends (props: infer TProps) => any ? TProps : unknown;
34
+ export type ValidateCompositeComponentProp<TProp> = TProp extends (...args: Array<any>) => any ? (...args: ValidateReactSerializable<Parameters<TProp>>) => React.ReactNode : TProp extends ComponentType<any> ? ComponentType<ValidateReactSerializable<ComponentProps<TProp>>> : TProp extends React.ReactNode ? TProp : React.ReactNode;
35
+ export type ValidateReactSerializable<T> = ValidateSerializable<T, ReactSerializable>;
36
+ export type ReactSerializable = number | string | bigint | boolean | null | undefined | React.ReactNode;
37
+ export type ValidateCompositeComponentReturnType<TComp> = unknown extends TComp ? React.ReactNode : ValidateCompositeComponentResult<LooseReturnType<TComp>>;
38
+ export type ValidateCompositeComponentResult<TNode> = ValidateServerComponentResult<TNode>;
39
+ export type ValidateServerComponentResult<TNode> = TNode extends Promise<any> ? ValidateCompositeComponentPromiseResult<TNode> : TNode extends React.ReactNode ? TNode : TNode extends (...args: Array<any>) => any ? React.ReactNode : TNode extends object ? ValidateCompositeComponentObjectResult<TNode> : React.ReactNode;
40
+ export type ValidateCompositeComponentPromiseResult<TPromise> = TPromise extends Promise<infer T> ? Promise<ValidateCompositeComponentResult<T>> : never;
41
+ export type ValidateCompositeComponentObjectResult<TObject> = {
42
+ [TKey in keyof TObject]: ValidateCompositeComponentResult<TObject[TKey]>;
43
+ };
44
+ export type CompositeComponentResult<TComp> = CompositeComponentBuilder<TComp, LooseAsyncReturnType<TComp>>;
45
+ export type CompositeComponentBuilder<TComp, TReturn> = TReturn extends React.ReactNode ? CompositeComponent<TComp, TReturn> : {
46
+ [TKey in keyof TReturn]: CompositeComponentBuilder<TComp, TReturn[TKey]>;
47
+ };
48
+ export interface CompositeComponent<in out TComp, in out TReturn> {
49
+ '~types': {
50
+ props: CompositeComponentProps<TComp>;
51
+ return: TReturn;
52
+ };
53
+ [SERVER_COMPONENT_STREAM]?: ServerComponentStream;
54
+ /**
55
+ * Root decoded tree getter.
56
+ */
57
+ [RSC_PROXY_GET_TREE]?: () => unknown;
58
+ /**
59
+ * Nested selection path (eg ['content','Stats']).
60
+ * Used by <CompositeComponent/> to render a sub-tree.
61
+ */
62
+ [RSC_PROXY_PATH]?: Array<string>;
63
+ /**
64
+ * CSS hrefs collected from the RSC stream.
65
+ * Can be used for preloading in <head> or emitting 103 Early Hints.
66
+ */
67
+ [SERVER_COMPONENT_CSS_HREFS]?: ReadonlySet<string>;
68
+ /**
69
+ * JS hrefs collected from the RSC stream.
70
+ * Emitted as modulepreload links only if the decoded tree is rendered in SSR.
71
+ */
72
+ [SERVER_COMPONENT_JS_PRELOADS]?: ReadonlySet<string>;
73
+ /**
74
+ * Dev-only: async stream of slot usage preview events.
75
+ * Used by devtools to show slot names and previewed call args without
76
+ * buffering/draining the Flight stream.
77
+ */
78
+ [RSC_SLOT_USAGES_STREAM]?: ReadableStream<RscSlotUsageEvent>;
79
+ }
80
+ export type ValidateRenderableServerComponent<TNode> = ValidateServerComponentResult<TNode>;
81
+ export type RenderableServerComponentBuilder<T> = T extends React.ReactNode ? RenderableServerComponent<T> : {
82
+ [TKey in keyof T]: RenderableServerComponentBuilder<T[TKey]>;
83
+ };
84
+ export type RenderableServerComponent<TNode extends React.ReactNode> = TNode & RenderableServerComponentAttributes<TNode>;
85
+ export interface RenderableServerComponentAttributes<TNode> {
86
+ '~types': {
87
+ node: TNode;
88
+ };
89
+ [SERVER_COMPONENT_STREAM]: ServerComponentStream;
90
+ [RENDERABLE_RSC]: true;
91
+ }
92
+ declare module '@tanstack/router-core' {
93
+ interface SerializableExtensions {
94
+ CompositeComponent: AnyCompositeComponent;
95
+ RenderableServerComponent: AnyRenderableServerComponent;
96
+ }
97
+ }
98
+ export type AnyCompositeComponent = CompositeComponent<any, any>;
99
+ export type AnyRenderableServerComponent = RenderableServerComponentAttributes<any>;
@@ -0,0 +1,21 @@
1
+ import { SlotImplementations } from './types.js';
2
+ export interface SlotContextValue {
3
+ implementations: SlotImplementations;
4
+ strict: boolean;
5
+ }
6
+ /**
7
+ * Hook to access slot implementations from within ClientSlot.
8
+ */
9
+ export declare function useSlotContext(): SlotContextValue | null;
10
+ export interface SlotProviderProps {
11
+ implementations: SlotImplementations;
12
+ strict?: boolean;
13
+ children?: React.ReactNode;
14
+ }
15
+ /**
16
+ * SlotProvider - makes slot implementations available to ClientSlot components.
17
+ *
18
+ * Must wrap the decoded RSC content so that ClientSlot components can
19
+ * access their slot implementations via React Context.
20
+ */
21
+ export declare function SlotProvider({ implementations, strict, children, }: SlotProviderProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Optional callback for collecting CSS hrefs during tree traversal.
3
+ * Only called server-side when processing <link rel="stylesheet" data-rsc-css-href>
4
+ */
5
+ export type CssHrefCollector = (href: string) => void;
6
+ /**
7
+ * Wait for all lazy elements in a tree to be resolved.
8
+ * This ensures client component chunks are fully loaded before rendering,
9
+ * preventing Suspense boundaries from flashing during SWR navigation.
10
+ *
11
+ * Also collects CSS hrefs from <link rel="stylesheet" data-rsc-css-href>
12
+ * elements for preloading in <head>.
13
+ *
14
+ * @param tree - The tree to process
15
+ * @param cssCollector - Optional callback to collect CSS hrefs (server-only)
16
+ */
17
+ export declare function awaitLazyElements(tree: unknown, cssCollector?: CssHrefCollector): Promise<void>;
@@ -0,0 +1,32 @@
1
+ import { CompositeComponentResult, ValidateCompositeComponent } from './ServerComponentTypes.js';
2
+ /**
3
+ * Creates a composite server component with slot support.
4
+ *
5
+ * Supports returning:
6
+ * - A ReactNode directly
7
+ * - An object structure with ReactNodes: accessed as `src.Foo`
8
+ * - Nested structures: accessed as `src.x.Bar`
9
+ *
10
+ * Props that are functions become slots - they render as ClientSlot placeholders
11
+ * in the RSC output, filled in by the consumer with actual implementations.
12
+ *
13
+ * The returned value is NOT directly renderable. Use `<CompositeComponent src={...} />`.
14
+ *
15
+ * @example
16
+ * ```tsx
17
+ * const src = await createCompositeComponent((props) => (
18
+ * <div>
19
+ * <header>{props.header('Dashboard')}</header>
20
+ * <main>{props.children}</main>
21
+ * </div>
22
+ * ))
23
+ *
24
+ * // In route component
25
+ * return (
26
+ * <CompositeComponent src={src} header={(title) => <h1>{title}</h1>}>
27
+ * <p>Main content</p>
28
+ * </CompositeComponent>
29
+ * )
30
+ * ```
31
+ */
32
+ export declare function createCompositeComponent<TComp>(component: ValidateCompositeComponent<TComp>): Promise<CompositeComponentResult<TComp>>;
@@ -0,0 +1,9 @@
1
+ import { CompositeComponentResult, ValidateCompositeComponent } from './ServerComponentTypes.js';
2
+ /**
3
+ * Client stub for createCompositeComponent.
4
+ *
5
+ * This function should never be called at runtime on the client.
6
+ * It exists only to satisfy bundler imports in client bundles.
7
+ * The real implementation only runs inside server functions.
8
+ */
9
+ export declare function createCompositeComponent<TComp>(_component: ValidateCompositeComponent<TComp>): Promise<CompositeComponentResult<TComp>>;
@@ -0,0 +1,18 @@
1
+ import { RscSlotUsageEvent } from './ServerComponentTypes.js';
2
+ export interface RscProxyOptions {
3
+ stream?: unknown;
4
+ cssHrefs?: ReadonlySet<string>;
5
+ jsPreloads?: ReadonlySet<string>;
6
+ renderable?: boolean;
7
+ slotUsagesStream?: ReadableStream<RscSlotUsageEvent>;
8
+ }
9
+ /**
10
+ * Creates a recursive Proxy for RSC data.
11
+ *
12
+ * If `renderable: true`, returns a React element that can be rendered as `{data}`.
13
+ * The element also has proxy-like behavior for nested access like `data.foo.bar`.
14
+ *
15
+ * If `renderable: false` (default), the proxy is NOT directly renderable and
16
+ * must be used with `<CompositeComponent src={...} />`.
17
+ */
18
+ export declare function createRscProxy<T>(getTree: () => T, options?: RscProxyOptions): any;
@@ -0,0 +1,24 @@
1
+ import { AnyCompositeComponent, RscSlotUsageEvent } from './ServerComponentTypes.js';
2
+ /**
3
+ * Creates a renderable RSC proxy from a raw Flight stream.
4
+ * Client-side only - used by the client serialization adapter for `renderServerComponent`.
5
+ *
6
+ * Returns a Proxy that:
7
+ * - Can be rendered directly as `{data}` in JSX
8
+ * - Supports nested access: `{data.foo.bar}`
9
+ * - Masquerades as a React element
10
+ */
11
+ export declare function createRenderableFromStream(stream: ReadableStream<Uint8Array>): any;
12
+ /**
13
+ * Creates a composite RSC proxy from a raw Flight stream.
14
+ * Client-side only - used by the client serialization adapter for `createCompositeComponent`.
15
+ *
16
+ * Returns a Proxy that:
17
+ * - NOT directly renderable
18
+ * - Supports nested access: `src.foo.bar`
19
+ * - Must be rendered via `<CompositeComponent src={...} />`
20
+ */
21
+ export declare function createCompositeFromStream(stream: ReadableStream<Uint8Array>, options?: {
22
+ slotUsagesStream?: ReadableStream<RscSlotUsageEvent>;
23
+ }): AnyCompositeComponent;
24
+ export declare const createServerComponentFromStream: typeof createCompositeFromStream;
@@ -0,0 +1,7 @@
1
+ import { default as React } from 'react';
2
+ export { getServerFnById } from '#tanstack-start-server-fn-resolver';
3
+ /**
4
+ * Renders a React node to an RSC Flight stream.
5
+ * Used internally for streaming server component output.
6
+ */
7
+ export declare function render(node: React.ReactNode): ReadableStream<Uint8Array>;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Low-level Flight stream APIs for decoding RSC streams.
3
+ *
4
+ * These functions provide direct access to RSC Flight stream decoding,
5
+ * allowing advanced use cases like:
6
+ * - Server functions returning raw Flight Response
7
+ * - API routes streaming Flight payloads
8
+ * - Custom Flight stream handling via RawStream
9
+ *
10
+ * `createFromReadableStream` works in both SSR and browser contexts.
11
+ * `createFromFetch` is browser-only.
12
+ *
13
+ * NOTE: Dynamic imports keep decode initialisation runtime-specific. The
14
+ * concrete implementation comes from bundler-owned virtual modules.
15
+ */
16
+ /**
17
+ * Decode a Flight stream into React elements.
18
+ * Works in both SSR and browser contexts.
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * const rawStream = await getRscRawStream()
23
+ * const tree = await createFromReadableStream(rawStream)
24
+ * return <>{tree}</>
25
+ * ```
26
+ */
27
+ export declare const createFromReadableStream: import('@tanstack/start-fn-stubs').IsomorphicFn<[stream: ReadableStream<Uint8Array<ArrayBufferLike>>], Promise<import('react').ReactNode>, Promise<import('react').ReactNode>>;
28
+ /**
29
+ * Decode a Flight stream from a fetch Response.
30
+ * Browser only - will throw if called on the server.
31
+ *
32
+ * @example
33
+ * ```tsx
34
+ * // From server function returning raw Response
35
+ * const tree = await createFromFetch(getFlightResponse())
36
+ *
37
+ * // From API route
38
+ * const tree = await createFromFetch(fetch('/api/rsc-flight'))
39
+ * ```
40
+ */
41
+ export declare const createFromFetch: (fetchPromise: Promise<Response>) => Promise<React.ReactNode>;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Low-level Flight stream API for RSC (React Server Components) environment.
3
+ *
4
+ * This exports renderToReadableStream which generates a Flight stream from
5
+ * React elements. Only available in RSC context (react-server condition).
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * import { renderToReadableStream } from '@tanstack/react-start/rsc'
10
+ *
11
+ * const stream = renderToReadableStream(<MyServerComponent />)
12
+ * return new Response(stream, {
13
+ * headers: { 'Content-Type': 'text/x-component' }
14
+ * })
15
+ * ```
16
+ */
17
+ export { renderToReadableStream } from 'virtual:tanstack-rsc-runtime';
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Client stub for renderToReadableStream.
3
+ *
4
+ * This function should never be called at runtime on the client.
5
+ * It exists only to provide types for bundler imports in client bundles.
6
+ * The real implementation only runs inside RSC context (server functions).
7
+ */
8
+ export declare function renderToReadableStream(_node: React.ReactNode): ReadableStream<Uint8Array>;
@@ -0,0 +1,7 @@
1
+ export type { AnyCompositeComponent } from './ServerComponentTypes.js';
2
+ export { SERVER_COMPONENT_CSS_HREFS } from './ServerComponentTypes.js';
3
+ export { renderServerComponent } from './renderServerComponent.stub.js';
4
+ export { createCompositeComponent } from './createCompositeComponent.stub.js';
5
+ export { CompositeComponent } from './CompositeComponent.js';
6
+ export { createFromReadableStream, createFromFetch } from './flight.js';
7
+ export { renderToReadableStream } from './flight.stub.js';
@@ -0,0 +1,6 @@
1
+ export type { AnyCompositeComponent } from './ServerComponentTypes.js';
2
+ export { renderServerComponent } from './renderServerComponent.js';
3
+ export { createCompositeComponent } from './createCompositeComponent.js';
4
+ export { CompositeComponent } from './CompositeComponent.js';
5
+ export { renderToReadableStream } from './flight.rsc.js';
6
+ export { createFromReadableStream, createFromFetch } from './flight.js';
@@ -0,0 +1,9 @@
1
+ import { TanStackStartVitePluginCoreOptions } from '@tanstack/start-plugin-core/vite/types';
2
+ import { PluginOption } from 'vite';
3
+ export declare function configureRsc(): {
4
+ envName: string;
5
+ providerEnvironmentName: TanStackStartVitePluginCoreOptions['providerEnvironmentName'];
6
+ ssrResolverStrategy: TanStackStartVitePluginCoreOptions['ssrResolverStrategy'];
7
+ serializationAdapters: TanStackStartVitePluginCoreOptions['serializationAdapters'];
8
+ };
9
+ export declare function reactStartRscVitePlugin(): PluginOption;
@@ -0,0 +1,3 @@
1
+ export declare const ReactElement: unique symbol;
2
+ export declare const ReactLazy: unique symbol;
3
+ export declare const ReactSuspense: unique symbol;
@@ -0,0 +1,33 @@
1
+ import { AnyRenderableServerComponent, RenderableServerComponentBuilder, ValidateRenderableServerComponent } from './ServerComponentTypes.js';
2
+ export type { RscSsrHandler, RscDecodeResult } from './rscSsrHandler.js';
3
+ /**
4
+ * Renderable RSC handle type - used for serialization detection.
5
+ */
6
+ /**
7
+ * Type guard for renderable RSC handle.
8
+ */
9
+ export declare function isRenderableRscHandle(value: unknown): value is AnyRenderableServerComponent;
10
+ /**
11
+ * Renders a React element to an RSC Flight stream.
12
+ *
13
+ * Returns a "renderable proxy" that can be:
14
+ * - Rendered directly as `{data}` in JSX
15
+ * - Accessed for nested selections: `{data.foo.bar.Hello}`
16
+ *
17
+ * No slot support - for slots use `createCompositeComponent`.
18
+ *
19
+ * @example
20
+ * ```tsx
21
+ * // In a loader or server function
22
+ * const data = await renderServerComponent(<MyServerComponent foo="bar" />)
23
+ *
24
+ * // In the route component
25
+ * return (
26
+ * <div>
27
+ * {data}
28
+ * {data.sidebar.Menu}
29
+ * </div>
30
+ * )
31
+ * ```
32
+ */
33
+ export declare function renderServerComponent<TNode>(node: ValidateRenderableServerComponent<TNode>): Promise<RenderableServerComponentBuilder<TNode>>;
@@ -0,0 +1,9 @@
1
+ import { RenderableServerComponentBuilder, ValidateRenderableServerComponent } from './ServerComponentTypes.js';
2
+ /**
3
+ * Client stub for renderServerComponent.
4
+ *
5
+ * This function should never be called at runtime on the client.
6
+ * It exists only to satisfy bundler imports in client bundles.
7
+ * The real implementation only runs inside server functions.
8
+ */
9
+ export declare function renderServerComponent<TNode>(_node: ValidateRenderableServerComponent<TNode>): Promise<RenderableServerComponentBuilder<TNode>>;
@@ -0,0 +1,24 @@
1
+ import { RscSlotUsageEvent, ServerComponentStream } from './ServerComponentTypes.js';
2
+ /**
3
+ * Result from decoding an RSC stream for SSR.
4
+ */
5
+ export interface RscDecodeResult {
6
+ tree: unknown;
7
+ cssHrefs?: Set<string>;
8
+ jsPreloads?: Set<string>;
9
+ }
10
+ /**
11
+ * SSR handler interface - registered by serialization.server.ts in SSR environment.
12
+ * Supports both renderable and composite proxy creation.
13
+ */
14
+ export interface RscSsrHandler {
15
+ /** Pre-decode the stream for synchronous SSR rendering */
16
+ decode: (stream: ServerComponentStream) => Promise<RscDecodeResult>;
17
+ /** Create a renderable proxy (for renderServerComponent) */
18
+ createRenderableProxy: (stream: ServerComponentStream, decoded: RscDecodeResult) => any;
19
+ /** Create a composite proxy (for createCompositeComponent) */
20
+ createCompositeProxy: (stream: ServerComponentStream, decoded: RscDecodeResult, slotUsagesStream?: ReadableStream<RscSlotUsageEvent>) => any;
21
+ }
22
+ declare global {
23
+ var __RSC_SSR__: RscSsrHandler | undefined;
24
+ }
@@ -0,0 +1,11 @@
1
+ import { AnyCompositeComponent, RscSlotUsageEvent } from './ServerComponentTypes.js';
2
+ /**
3
+ * Client-side serialization adapter for RSC (renderable + composite).
4
+ */
5
+ type SerializedRsc = {
6
+ kind: 'renderable' | 'composite';
7
+ stream: ReadableStream<Uint8Array>;
8
+ slotUsagesStream?: ReadableStream<RscSlotUsageEvent>;
9
+ };
10
+ export declare const rscSerializationAdapter: () => import('@tanstack/router-core').SerializationAdapter<AnyCompositeComponent, SerializedRsc, never>[];
11
+ export {};
@@ -0,0 +1,10 @@
1
+ import { RawStream } from '@tanstack/router-core';
2
+ import { AnyCompositeComponent } from './ServerComponentTypes.js';
3
+ /**
4
+ * Factory function for server-side RSC serialization adapter.
5
+ */
6
+ export declare const rscSerializationAdapter: () => import('@tanstack/router-core').SerializationAdapter<AnyCompositeComponent, {
7
+ kind: string;
8
+ stream: RawStream;
9
+ slotUsagesStream: ReadableStream<any> | undefined;
10
+ }, never>[];
@@ -0,0 +1 @@
1
+ export declare function sanitizeSlotArgs(args: Array<any>): Array<any>;
@@ -0,0 +1,13 @@
1
+ import { ServerComponentStream } from './ServerComponentTypes.js';
2
+ /**
3
+ * Handle returned by RSC helpers.
4
+ * Contains the RSC Flight stream that can be consumed by SSR and/or Client.
5
+ */
6
+ export interface ServerComponentHandle {
7
+ readonly stream: ServerComponentStream;
8
+ }
9
+ /**
10
+ * Slot implementations provided to ServerComponentRenderer.
11
+ * Keys are slot names, values are either React nodes (for children) or render functions.
12
+ */
13
+ export type SlotImplementations = Record<string, unknown>;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Shared RSC (React Server Components) entry point.
3
+ *
4
+ * This file exports the functions needed for the active RSC environment:
5
+ * - getServerFnById: Resolves server functions by their encoded ID
6
+ * - render: Renders a React node to an RSC Flight stream
7
+ */
8
+
9
+ import { renderToReadableStream } from 'virtual:tanstack-rsc-runtime'
10
+ import type React from 'react'
11
+
12
+ // Re-export getServerFnById from the virtual module which handles both dev and production
13
+ // In dev: dynamic import with base64url-decoded file path
14
+ // In production: manifest-based lookup with bundled chunks
15
+ export { getServerFnById } from '#tanstack-start-server-fn-resolver'
16
+
17
+ /**
18
+ * Renders a React node to an RSC Flight stream.
19
+ * Used internally for streaming server component output.
20
+ */
21
+ export function render(node: React.ReactNode): ReadableStream<Uint8Array> {
22
+ return renderToReadableStream(node)
23
+ }
package/package.json ADDED
@@ -0,0 +1,108 @@
1
+ {
2
+ "name": "@tanstack/react-start-rsc",
3
+ "version": "0.0.0",
4
+ "description": "React Server Components support for TanStack Start",
5
+ "author": "Tanner Linsley",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/TanStack/router.git",
10
+ "directory": "packages/react-start-rsc"
11
+ },
12
+ "homepage": "https://tanstack.com/start",
13
+ "funding": {
14
+ "type": "github",
15
+ "url": "https://github.com/sponsors/tannerlinsley"
16
+ },
17
+ "keywords": [
18
+ "react",
19
+ "rsc",
20
+ "server components",
21
+ "router",
22
+ "routing",
23
+ "typescript"
24
+ ],
25
+ "scripts": {
26
+ "clean": "rimraf ./dist && rimraf ./coverage",
27
+ "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit",
28
+ "test:unit": "vitest",
29
+ "test:unit:dev": "vitest --watch",
30
+ "test:eslint": "eslint ./src",
31
+ "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"",
32
+ "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js",
33
+ "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js",
34
+ "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js",
35
+ "test:types:ts58": "node ../../node_modules/typescript58/lib/tsc.js",
36
+ "test:types:ts59": "node ../../node_modules/typescript59/lib/tsc.js",
37
+ "test:types:ts60": "tsc",
38
+ "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .",
39
+ "build": "vite build"
40
+ },
41
+ "type": "module",
42
+ "types": "dist/esm/src/index.d.ts",
43
+ "exports": {
44
+ ".": {
45
+ "react-server": {
46
+ "types": "./dist/esm/src/index.rsc.d.ts",
47
+ "default": "./dist/esm/index.rsc.js"
48
+ },
49
+ "import": {
50
+ "types": "./dist/esm/src/index.d.ts",
51
+ "default": "./dist/esm/index.js"
52
+ }
53
+ },
54
+ "./serialization.client": {
55
+ "import": {
56
+ "types": "./dist/esm/src/serialization.client.d.ts",
57
+ "default": "./dist/esm/serialization.client.js"
58
+ }
59
+ },
60
+ "./serialization.server": {
61
+ "import": {
62
+ "types": "./dist/esm/src/serialization.server.d.ts",
63
+ "default": "./dist/esm/serialization.server.js"
64
+ }
65
+ },
66
+ "./plugin/vite": {
67
+ "import": {
68
+ "types": "./dist/esm/src/plugin/vite.d.ts",
69
+ "default": "./dist/esm/plugin/vite.js"
70
+ }
71
+ },
72
+ "./package.json": "./package.json"
73
+ },
74
+ "files": [
75
+ "dist",
76
+ "src"
77
+ ],
78
+ "engines": {
79
+ "node": ">=22.12.0"
80
+ },
81
+ "dependencies": {
82
+ "@tanstack/router-core": "workspace:*",
83
+ "@tanstack/react-router": "workspace:*",
84
+ "@tanstack/react-start-server": "workspace:*",
85
+ "@tanstack/start-client-core": "workspace:*",
86
+ "@tanstack/start-fn-stubs": "workspace:*",
87
+ "@tanstack/start-server-core": "workspace:*",
88
+ "@tanstack/start-storage-context": "workspace:*",
89
+ "pathe": "^2.0.3",
90
+ "@tanstack/start-plugin-core": "workspace:*",
91
+ "@tanstack/router-utils": "workspace:*"
92
+ },
93
+ "devDependencies": {
94
+ "@testing-library/react": "^16.2.0",
95
+ "@vitejs/plugin-react": "^4.3.4",
96
+ "@vitejs/plugin-rsc": "^0.5.20"
97
+ },
98
+ "peerDependencies": {
99
+ "@vitejs/plugin-rsc": ">=0.5.20",
100
+ "react": ">=18.0.0 || >=19.0.0",
101
+ "react-dom": ">=18.0.0 || >=19.0.0"
102
+ },
103
+ "peerDependenciesMeta": {
104
+ "@vitejs/plugin-rsc": {
105
+ "optional": true
106
+ }
107
+ }
108
+ }
@@ -0,0 +1,34 @@
1
+ 'use client'
2
+
3
+ import { useSlotContext } from './SlotContext'
4
+
5
+ export interface ClientSlotProps {
6
+ slot: string
7
+ args: Array<unknown>
8
+ }
9
+
10
+ export function ClientSlot({ slot, args }: ClientSlotProps) {
11
+ const ctx = useSlotContext()
12
+
13
+ if (!ctx) {
14
+ throw new Error('ClientSlot must be rendered within SlotProvider')
15
+ }
16
+
17
+ const impl = ctx.implementations[slot]
18
+
19
+ // No implementation provided
20
+ if (impl === undefined) {
21
+ if (ctx.strict) {
22
+ throw new Error(`Missing slot implementation for "${slot}"`)
23
+ }
24
+ return null
25
+ }
26
+
27
+ // For children slot or any non-function value, render directly
28
+ if (typeof impl !== 'function') {
29
+ return <>{impl}</>
30
+ }
31
+
32
+ // Render function with args
33
+ return <>{impl(...args)}</>
34
+ }