@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.
- package/dist/esm/ClientSlot.js +19 -0
- package/dist/esm/ClientSlot.js.map +1 -0
- package/dist/esm/CompositeComponent.js +93 -0
- package/dist/esm/CompositeComponent.js.map +1 -0
- package/dist/esm/ReplayableStream.js +147 -0
- package/dist/esm/ReplayableStream.js.map +1 -0
- package/dist/esm/RscNodeRenderer.js +46 -0
- package/dist/esm/RscNodeRenderer.js.map +1 -0
- package/dist/esm/ServerComponentTypes.js +22 -0
- package/dist/esm/ServerComponentTypes.js.map +1 -0
- package/dist/esm/SlotContext.js +30 -0
- package/dist/esm/SlotContext.js.map +1 -0
- package/dist/esm/awaitLazyElements.js +41 -0
- package/dist/esm/awaitLazyElements.js.map +1 -0
- package/dist/esm/createCompositeComponent.js +205 -0
- package/dist/esm/createCompositeComponent.js.map +1 -0
- package/dist/esm/createCompositeComponent.stub.js +15 -0
- package/dist/esm/createCompositeComponent.stub.js.map +1 -0
- package/dist/esm/createRscProxy.js +138 -0
- package/dist/esm/createRscProxy.js.map +1 -0
- package/dist/esm/createServerComponentFromStream.js +74 -0
- package/dist/esm/createServerComponentFromStream.js.map +1 -0
- package/dist/esm/entry/rsc.js +21 -0
- package/dist/esm/entry/rsc.js.map +1 -0
- package/dist/esm/flight.js +56 -0
- package/dist/esm/flight.js.map +1 -0
- package/dist/esm/flight.rsc.js +2 -0
- package/dist/esm/flight.stub.js +15 -0
- package/dist/esm/flight.stub.js.map +1 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.rsc.js +6 -0
- package/dist/esm/plugin/vite.js +172 -0
- package/dist/esm/plugin/vite.js.map +1 -0
- package/dist/esm/reactSymbols.js +8 -0
- package/dist/esm/reactSymbols.js.map +1 -0
- package/dist/esm/renderServerComponent.js +58 -0
- package/dist/esm/renderServerComponent.js.map +1 -0
- package/dist/esm/renderServerComponent.stub.js +16 -0
- package/dist/esm/renderServerComponent.stub.js.map +1 -0
- package/dist/esm/serialization.client.js +21 -0
- package/dist/esm/serialization.client.js.map +1 -0
- package/dist/esm/serialization.server.js +121 -0
- package/dist/esm/serialization.server.js.map +1 -0
- package/dist/esm/slotUsageSanitizer.js +33 -0
- package/dist/esm/slotUsageSanitizer.js.map +1 -0
- package/dist/esm/src/ClientSlot.d.ts +5 -0
- package/dist/esm/src/CompositeComponent.d.ts +28 -0
- package/dist/esm/src/ReplayableStream.d.ts +76 -0
- package/dist/esm/src/RscNodeRenderer.d.ts +7 -0
- package/dist/esm/src/ServerComponentTypes.d.ts +99 -0
- package/dist/esm/src/SlotContext.d.ts +21 -0
- package/dist/esm/src/awaitLazyElements.d.ts +17 -0
- package/dist/esm/src/createCompositeComponent.d.ts +32 -0
- package/dist/esm/src/createCompositeComponent.stub.d.ts +9 -0
- package/dist/esm/src/createRscProxy.d.ts +18 -0
- package/dist/esm/src/createServerComponentFromStream.d.ts +24 -0
- package/dist/esm/src/entry/rsc.d.ts +7 -0
- package/dist/esm/src/flight.d.ts +41 -0
- package/dist/esm/src/flight.rsc.d.ts +17 -0
- package/dist/esm/src/flight.stub.d.ts +8 -0
- package/dist/esm/src/index.d.ts +7 -0
- package/dist/esm/src/index.rsc.d.ts +6 -0
- package/dist/esm/src/plugin/vite.d.ts +9 -0
- package/dist/esm/src/reactSymbols.d.ts +3 -0
- package/dist/esm/src/renderServerComponent.d.ts +33 -0
- package/dist/esm/src/renderServerComponent.stub.d.ts +9 -0
- package/dist/esm/src/rscSsrHandler.d.ts +24 -0
- package/dist/esm/src/serialization.client.d.ts +11 -0
- package/dist/esm/src/serialization.server.d.ts +10 -0
- package/dist/esm/src/slotUsageSanitizer.d.ts +1 -0
- package/dist/esm/src/types.d.ts +13 -0
- package/dist/plugin/entry/rsc.tsx +23 -0
- package/package.json +108 -0
- package/src/ClientSlot.tsx +34 -0
- package/src/CompositeComponent.tsx +165 -0
- package/src/ReplayableStream.ts +249 -0
- package/src/RscNodeRenderer.tsx +76 -0
- package/src/ServerComponentTypes.ts +226 -0
- package/src/SlotContext.tsx +42 -0
- package/src/awaitLazyElements.ts +91 -0
- package/src/createCompositeComponent.stub.ts +20 -0
- package/src/createCompositeComponent.ts +338 -0
- package/src/createRscProxy.tsx +294 -0
- package/src/createServerComponentFromStream.ts +105 -0
- package/src/entry/rsc.tsx +23 -0
- package/src/entry/virtual-modules.d.ts +12 -0
- package/src/flight.rsc.ts +17 -0
- package/src/flight.stub.ts +15 -0
- package/src/flight.ts +68 -0
- package/src/global.d.ts +75 -0
- package/src/index.rsc.ts +25 -0
- package/src/index.ts +26 -0
- package/src/plugin/vite.ts +241 -0
- package/src/reactSymbols.ts +6 -0
- package/src/renderServerComponent.stub.ts +26 -0
- package/src/renderServerComponent.ts +110 -0
- package/src/rscSsrHandler.ts +39 -0
- package/src/serialization.client.ts +43 -0
- package/src/serialization.server.ts +193 -0
- package/src/slotUsageSanitizer.ts +62 -0
- package/src/types.ts +15 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
import path from "pathe";
|
|
3
|
+
import { resolveViteId } from "@tanstack/start-plugin-core/utils";
|
|
4
|
+
//#region src/plugin/vite.ts
|
|
5
|
+
var isClientEnvironment = (env) => env.config.consumer === "client";
|
|
6
|
+
function escapeRegExp(value) {
|
|
7
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
8
|
+
}
|
|
9
|
+
function createVirtualModule(opts) {
|
|
10
|
+
const resolvedId = resolveViteId(opts.moduleId);
|
|
11
|
+
const idFilter = { id: new RegExp(escapeRegExp(opts.moduleId)) };
|
|
12
|
+
return {
|
|
13
|
+
name: opts.name,
|
|
14
|
+
apply: opts.apply,
|
|
15
|
+
applyToEnvironment: opts.applyToEnvironment,
|
|
16
|
+
resolveId: {
|
|
17
|
+
filter: idFilter,
|
|
18
|
+
handler() {
|
|
19
|
+
return resolvedId;
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
load: {
|
|
23
|
+
filter: idFilter,
|
|
24
|
+
handler: opts.load
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
var RSC_HMR_VIRTUAL_ID = "virtual:tanstack-rsc-hmr";
|
|
29
|
+
var RSC_RUNTIME_VIRTUAL_ID = "virtual:tanstack-rsc-runtime";
|
|
30
|
+
var RSC_BROWSER_DECODE_VIRTUAL_ID = "virtual:tanstack-rsc-browser-decode";
|
|
31
|
+
var RSC_SSR_DECODE_VIRTUAL_ID = "virtual:tanstack-rsc-ssr-decode";
|
|
32
|
+
var RSC_ENV_NAME = "rsc";
|
|
33
|
+
var currentDir = path.dirname(fileURLToPath(import.meta.url));
|
|
34
|
+
var entryDir = path.resolve(currentDir, "..", "..", "plugin", "entry");
|
|
35
|
+
var rscEntryPath = path.resolve(entryDir, "rsc.tsx");
|
|
36
|
+
function configureRsc() {
|
|
37
|
+
return {
|
|
38
|
+
envName: RSC_ENV_NAME,
|
|
39
|
+
providerEnvironmentName: RSC_ENV_NAME,
|
|
40
|
+
ssrResolverStrategy: {
|
|
41
|
+
type: "vite-rsc-forward",
|
|
42
|
+
sourceEnvironmentName: RSC_ENV_NAME,
|
|
43
|
+
sourceEntry: "index",
|
|
44
|
+
exportName: "getServerFnById"
|
|
45
|
+
},
|
|
46
|
+
serializationAdapters: [{
|
|
47
|
+
client: {
|
|
48
|
+
module: "@tanstack/react-start/rsc/serialization/client",
|
|
49
|
+
export: "rscSerializationAdapter",
|
|
50
|
+
isFactory: true
|
|
51
|
+
},
|
|
52
|
+
server: {
|
|
53
|
+
module: "@tanstack/react-start/rsc/serialization/server",
|
|
54
|
+
export: "rscSerializationAdapter",
|
|
55
|
+
isFactory: true
|
|
56
|
+
}
|
|
57
|
+
}]
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function reactStartRscVitePlugin() {
|
|
61
|
+
return [
|
|
62
|
+
{
|
|
63
|
+
name: "tanstack-react-start:rsc-ssr-config",
|
|
64
|
+
config() {
|
|
65
|
+
return { ssr: { noExternal: true } };
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: "tanstack-react-start:rsc-env-config",
|
|
70
|
+
config() {
|
|
71
|
+
return {
|
|
72
|
+
rsc: {
|
|
73
|
+
serverHandler: false,
|
|
74
|
+
cssLinkPrecedence: false
|
|
75
|
+
},
|
|
76
|
+
environments: { [RSC_ENV_NAME]: {
|
|
77
|
+
consumer: "server",
|
|
78
|
+
resolve: { noExternal: [
|
|
79
|
+
"@tanstack/start**",
|
|
80
|
+
"@tanstack/react-start",
|
|
81
|
+
"@tanstack/react-start-rsc",
|
|
82
|
+
"@tanstack/react-router"
|
|
83
|
+
] },
|
|
84
|
+
build: { rollupOptions: { input: { index: rscEntryPath } } }
|
|
85
|
+
} }
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
createVirtualModule({
|
|
90
|
+
name: "tanstack-react-start:rsc-runtime-virtual",
|
|
91
|
+
moduleId: RSC_RUNTIME_VIRTUAL_ID,
|
|
92
|
+
load() {
|
|
93
|
+
if (this.environment.name === RSC_ENV_NAME) return `export { renderToReadableStream, createFromReadableStream, createTemporaryReferenceSet, decodeReply, loadServerAction, decodeAction, decodeFormState } from '@vitejs/plugin-rsc/rsc'`;
|
|
94
|
+
return `
|
|
95
|
+
export function renderToReadableStream() { throw new Error('renderToReadableStream can only be used in RSC environment'); }
|
|
96
|
+
export function createFromReadableStream() { throw new Error('createFromReadableStream can only be used in RSC environment'); }
|
|
97
|
+
export function createTemporaryReferenceSet() { throw new Error('createTemporaryReferenceSet can only be used in RSC environment'); }
|
|
98
|
+
export function decodeReply() { throw new Error('decodeReply can only be used in RSC environment'); }
|
|
99
|
+
export function loadServerAction() { throw new Error('loadServerAction can only be used in RSC environment'); }
|
|
100
|
+
export function decodeAction() { throw new Error('decodeAction can only be used in RSC environment'); }
|
|
101
|
+
export function decodeFormState() { throw new Error('decodeFormState can only be used in RSC environment'); }
|
|
102
|
+
`;
|
|
103
|
+
}
|
|
104
|
+
}),
|
|
105
|
+
createVirtualModule({
|
|
106
|
+
name: "tanstack-react-start:rsc-browser-decode-virtual",
|
|
107
|
+
moduleId: RSC_BROWSER_DECODE_VIRTUAL_ID,
|
|
108
|
+
load() {
|
|
109
|
+
return `export { createFromReadableStream, createFromFetch } from '@vitejs/plugin-rsc/browser'`;
|
|
110
|
+
}
|
|
111
|
+
}),
|
|
112
|
+
createVirtualModule({
|
|
113
|
+
name: "tanstack-react-start:rsc-ssr-decode-virtual",
|
|
114
|
+
moduleId: RSC_SSR_DECODE_VIRTUAL_ID,
|
|
115
|
+
load() {
|
|
116
|
+
return `export { setOnClientReference, createFromReadableStream } from '@vitejs/plugin-rsc/ssr'`;
|
|
117
|
+
}
|
|
118
|
+
}),
|
|
119
|
+
createVirtualModule({
|
|
120
|
+
name: "tanstack-react-start:rsc-hmr-virtual:dev",
|
|
121
|
+
moduleId: RSC_HMR_VIRTUAL_ID,
|
|
122
|
+
apply: "serve",
|
|
123
|
+
applyToEnvironment: isClientEnvironment,
|
|
124
|
+
load() {
|
|
125
|
+
return `
|
|
126
|
+
export function setupRscHmr() {
|
|
127
|
+
if (!import.meta.hot) {
|
|
128
|
+
return
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
let __invalidateQueued = false
|
|
132
|
+
|
|
133
|
+
function __queueInvalidate() {
|
|
134
|
+
if (__invalidateQueued) return
|
|
135
|
+
__invalidateQueued = true
|
|
136
|
+
queueMicrotask(async () => {
|
|
137
|
+
__invalidateQueued = false
|
|
138
|
+
try {
|
|
139
|
+
const router = window.__TSR_ROUTER__
|
|
140
|
+
if (!router) {
|
|
141
|
+
console.warn('[rsc:hmr] No router found on window.__TSR_ROUTER__')
|
|
142
|
+
return
|
|
143
|
+
}
|
|
144
|
+
await router.invalidate()
|
|
145
|
+
} catch (e) {
|
|
146
|
+
console.warn('[rsc:hmr] Failed to invalidate router:', e)
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
import.meta.hot.on('rsc:update', () => {
|
|
152
|
+
__queueInvalidate()
|
|
153
|
+
})
|
|
154
|
+
}
|
|
155
|
+
`;
|
|
156
|
+
}
|
|
157
|
+
}),
|
|
158
|
+
createVirtualModule({
|
|
159
|
+
name: "tanstack-react-start:rsc-hmr-virtual:prod",
|
|
160
|
+
moduleId: RSC_HMR_VIRTUAL_ID,
|
|
161
|
+
applyToEnvironment: isClientEnvironment,
|
|
162
|
+
apply: "build",
|
|
163
|
+
load() {
|
|
164
|
+
return "export function setupRscHmr() {} ";
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
];
|
|
168
|
+
}
|
|
169
|
+
//#endregion
|
|
170
|
+
export { configureRsc, reactStartRscVitePlugin };
|
|
171
|
+
|
|
172
|
+
//# sourceMappingURL=vite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite.js","names":[],"sources":["../../../src/plugin/vite.ts"],"sourcesContent":["import { fileURLToPath } from 'node:url'\nimport path from 'pathe'\nimport { resolveViteId } from '@tanstack/start-plugin-core/utils'\nimport type {\n TanStackStartVitePluginCoreOptions,\n ViteRscForwardSsrResolverStrategy,\n} from '@tanstack/start-plugin-core/vite/types'\nimport type { Plugin, PluginOption, UserConfig } from 'vite'\n\ntype VirtualModuleLoadHandler = (this: {\n environment: { name: string }\n}) => string\nconst isClientEnvironment = (env: { config: { consumer: string } }) =>\n env.config.consumer === 'client'\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\nfunction createVirtualModule(opts: {\n name: string\n moduleId: string\n load: VirtualModuleLoadHandler\n apply?: Plugin['apply']\n applyToEnvironment?: Plugin['applyToEnvironment']\n}): Plugin {\n const resolvedId = resolveViteId(opts.moduleId)\n const idFilter = { id: new RegExp(escapeRegExp(opts.moduleId)) }\n\n return {\n name: opts.name,\n apply: opts.apply,\n applyToEnvironment: opts.applyToEnvironment,\n resolveId: {\n filter: idFilter,\n handler() {\n return resolvedId\n },\n },\n load: {\n filter: idFilter,\n handler: opts.load,\n },\n }\n}\n\n// Virtual module ids used by the React Start RSC runtime.\nconst RSC_HMR_VIRTUAL_ID = 'virtual:tanstack-rsc-hmr'\nconst RSC_RUNTIME_VIRTUAL_ID = 'virtual:tanstack-rsc-runtime'\nconst RSC_BROWSER_DECODE_VIRTUAL_ID = 'virtual:tanstack-rsc-browser-decode'\nconst RSC_SSR_DECODE_VIRTUAL_ID = 'virtual:tanstack-rsc-ssr-decode'\nconst RSC_ENV_NAME = 'rsc'\n\nconst currentDir = path.dirname(fileURLToPath(import.meta.url))\nconst entryDir = path.resolve(currentDir, '..', '..', 'plugin', 'entry')\nconst rscEntryPath = path.resolve(entryDir, 'rsc.tsx')\n\nexport function configureRsc(): {\n envName: string\n providerEnvironmentName: TanStackStartVitePluginCoreOptions['providerEnvironmentName']\n ssrResolverStrategy: TanStackStartVitePluginCoreOptions['ssrResolverStrategy']\n serializationAdapters: TanStackStartVitePluginCoreOptions['serializationAdapters']\n} {\n const serializationAdapters: TanStackStartVitePluginCoreOptions['serializationAdapters'] =\n [\n // IMPORTANT: plugin-adapters-plugin only calls the top-level factory once.\n // That factory must return a flat array of adapters (not nested arrays),\n // otherwise router-core ends up with non-adapter entries and Seroval crashes.\n {\n client: {\n module: '@tanstack/react-start/rsc/serialization/client',\n export: 'rscSerializationAdapter',\n isFactory: true,\n },\n server: {\n module: '@tanstack/react-start/rsc/serialization/server',\n export: 'rscSerializationAdapter',\n isFactory: true,\n },\n },\n ]\n const ssrResolverStrategy = {\n type: 'vite-rsc-forward',\n sourceEnvironmentName: RSC_ENV_NAME,\n sourceEntry: 'index',\n exportName: 'getServerFnById',\n } satisfies ViteRscForwardSsrResolverStrategy\n return {\n envName: RSC_ENV_NAME,\n providerEnvironmentName: RSC_ENV_NAME,\n ssrResolverStrategy,\n serializationAdapters,\n }\n}\nexport function reactStartRscVitePlugin(): PluginOption {\n return [\n // When RSC is enabled, SSR needs noExternal: true to ensure single React instance.\n // The RSC decoder's dynamic imports for client components can cause module duplication\n // without this, leading to \"Invalid hook call\" errors.\n // We use the top-level `ssr` config option as `environments.ssr.resolve.noExternal`\n // doesn't have the same effect.\n {\n name: 'tanstack-react-start:rsc-ssr-config',\n config() {\n return {\n ssr: {\n noExternal: true,\n },\n }\n },\n },\n {\n name: 'tanstack-react-start:rsc-env-config',\n config() {\n return {\n rsc: {\n // Disable @vitejs/plugin-rsc's built-in server handler middleware.\n // TanStack Start has its own request handling via the SSR environment.\n serverHandler: false,\n // Disable CSS link precedence to prevent React 19 SSR suspension\n // TanStack Start handles CSS preloading via manifest injection instead\n cssLinkPrecedence: false,\n },\n environments: {\n [RSC_ENV_NAME]: {\n consumer: 'server',\n // Force @tanstack packages to be processed by Vite as source code\n // rather than treated as external modules. This ensures:\n // 1. createIsomorphicFn transforms are applied\n // 2. Imports are resolved within the RSC environment context\n // with proper react-server conditions and pre-bundled deps\n resolve: {\n noExternal: [\n '@tanstack/start**',\n '@tanstack/react-start',\n '@tanstack/react-start-rsc',\n '@tanstack/react-router',\n ],\n },\n build: {\n rollupOptions: {\n input: {\n index: rscEntryPath,\n },\n },\n },\n },\n },\n } satisfies UserConfig & {\n rsc: {\n serverHandler: false\n cssLinkPrecedence?: boolean\n }\n }\n },\n },\n\n // Runtime bridge into the Vite RSC environment.\n createVirtualModule({\n name: 'tanstack-react-start:rsc-runtime-virtual',\n moduleId: RSC_RUNTIME_VIRTUAL_ID,\n load() {\n const envName = this.environment.name\n if (envName === RSC_ENV_NAME) {\n return `export { renderToReadableStream, createFromReadableStream, createTemporaryReferenceSet, decodeReply, loadServerAction, decodeAction, decodeFormState } from '@vitejs/plugin-rsc/rsc'`\n }\n return `\nexport function renderToReadableStream() { throw new Error('renderToReadableStream can only be used in RSC environment'); }\nexport function createFromReadableStream() { throw new Error('createFromReadableStream can only be used in RSC environment'); }\nexport function createTemporaryReferenceSet() { throw new Error('createTemporaryReferenceSet can only be used in RSC environment'); }\nexport function decodeReply() { throw new Error('decodeReply can only be used in RSC environment'); }\nexport function loadServerAction() { throw new Error('loadServerAction can only be used in RSC environment'); }\nexport function decodeAction() { throw new Error('decodeAction can only be used in RSC environment'); }\nexport function decodeFormState() { throw new Error('decodeFormState can only be used in RSC environment'); }\n`\n },\n }),\n createVirtualModule({\n name: 'tanstack-react-start:rsc-browser-decode-virtual',\n moduleId: RSC_BROWSER_DECODE_VIRTUAL_ID,\n load() {\n return `export { createFromReadableStream, createFromFetch } from '@vitejs/plugin-rsc/browser'`\n },\n }),\n createVirtualModule({\n name: 'tanstack-react-start:rsc-ssr-decode-virtual',\n moduleId: RSC_SSR_DECODE_VIRTUAL_ID,\n load() {\n return `export { setOnClientReference, createFromReadableStream } from '@vitejs/plugin-rsc/ssr'`\n },\n }),\n createVirtualModule({\n name: 'tanstack-react-start:rsc-hmr-virtual:dev',\n moduleId: RSC_HMR_VIRTUAL_ID,\n apply: 'serve',\n applyToEnvironment: isClientEnvironment,\n load() {\n return `\nexport function setupRscHmr() {\nif (!import.meta.hot) {\n return\n}\n\n let __invalidateQueued = false\n\n function __queueInvalidate() {\n if (__invalidateQueued) return\n __invalidateQueued = true\n queueMicrotask(async () => {\n __invalidateQueued = false\n try {\n const router = window.__TSR_ROUTER__\n if (!router) {\n console.warn('[rsc:hmr] No router found on window.__TSR_ROUTER__')\n return\n }\n await router.invalidate()\n } catch (e) {\n console.warn('[rsc:hmr] Failed to invalidate router:', e)\n }\n })\n }\n\n import.meta.hot.on('rsc:update', () => {\n __queueInvalidate()\n })\n}\n`\n },\n }),\n createVirtualModule({\n name: 'tanstack-react-start:rsc-hmr-virtual:prod',\n moduleId: RSC_HMR_VIRTUAL_ID,\n applyToEnvironment: isClientEnvironment,\n apply: 'build',\n load() {\n return 'export function setupRscHmr() {} '\n },\n }),\n ]\n}\n"],"mappings":";;;;AAYA,IAAM,uBAAuB,QAC3B,IAAI,OAAO,aAAa;AAE1B,SAAS,aAAa,OAAuB;AAC3C,QAAO,MAAM,QAAQ,uBAAuB,OAAO;;AAGrD,SAAS,oBAAoB,MAMlB;CACT,MAAM,aAAa,cAAc,KAAK,SAAS;CAC/C,MAAM,WAAW,EAAE,IAAI,IAAI,OAAO,aAAa,KAAK,SAAS,CAAC,EAAE;AAEhE,QAAO;EACL,MAAM,KAAK;EACX,OAAO,KAAK;EACZ,oBAAoB,KAAK;EACzB,WAAW;GACT,QAAQ;GACR,UAAU;AACR,WAAO;;GAEV;EACD,MAAM;GACJ,QAAQ;GACR,SAAS,KAAK;GACf;EACF;;AAIH,IAAM,qBAAqB;AAC3B,IAAM,yBAAyB;AAC/B,IAAM,gCAAgC;AACtC,IAAM,4BAA4B;AAClC,IAAM,eAAe;AAErB,IAAM,aAAa,KAAK,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;AAC/D,IAAM,WAAW,KAAK,QAAQ,YAAY,MAAM,MAAM,UAAU,QAAQ;AACxE,IAAM,eAAe,KAAK,QAAQ,UAAU,UAAU;AAEtD,SAAgB,eAKd;AAyBA,QAAO;EACL,SAAS;EACT,yBAAyB;EACzB,qBAT0B;GAC1B,MAAM;GACN,uBAAuB;GACvB,aAAa;GACb,YAAY;GACb;EAKC,uBA3BA,CAIE;GACE,QAAQ;IACN,QAAQ;IACR,QAAQ;IACR,WAAW;IACZ;GACD,QAAQ;IACN,QAAQ;IACR,QAAQ;IACR,WAAW;IACZ;GACF,CACF;EAYF;;AAEH,SAAgB,0BAAwC;AACtD,QAAO;EAML;GACE,MAAM;GACN,SAAS;AACP,WAAO,EACL,KAAK,EACH,YAAY,MACb,EACF;;GAEJ;EACD;GACE,MAAM;GACN,SAAS;AACP,WAAO;KACL,KAAK;MAGH,eAAe;MAGf,mBAAmB;MACpB;KACD,cAAc,GACX,eAAe;MACd,UAAU;MAMV,SAAS,EACP,YAAY;OACV;OACA;OACA;OACA;OACD,EACF;MACD,OAAO,EACL,eAAe,EACb,OAAO,EACL,OAAO,cACR,EACF,EACF;MACF,EACF;KACF;;GAOJ;EAGD,oBAAoB;GAClB,MAAM;GACN,UAAU;GACV,OAAO;AAEL,QADgB,KAAK,YAAY,SACjB,aACd,QAAO;AAET,WAAO;;;;;;;;;;GAUV,CAAC;EACF,oBAAoB;GAClB,MAAM;GACN,UAAU;GACV,OAAO;AACL,WAAO;;GAEV,CAAC;EACF,oBAAoB;GAClB,MAAM;GACN,UAAU;GACV,OAAO;AACL,WAAO;;GAEV,CAAC;EACF,oBAAoB;GAClB,MAAM;GACN,UAAU;GACV,OAAO;GACP,oBAAoB;GACpB,OAAO;AACL,WAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCV,CAAC;EACF,oBAAoB;GAClB,MAAM;GACN,UAAU;GACV,oBAAoB;GACpB,OAAO;GACP,OAAO;AACL,WAAO;;GAEV,CAAC;EACH"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/reactSymbols.ts
|
|
2
|
+
var ReactElement = Symbol.for("react.transitional.element");
|
|
3
|
+
var ReactLazy = Symbol.for("react.lazy");
|
|
4
|
+
var ReactSuspense = Symbol.for("react.suspense");
|
|
5
|
+
//#endregion
|
|
6
|
+
export { ReactElement, ReactLazy, ReactSuspense };
|
|
7
|
+
|
|
8
|
+
//# sourceMappingURL=reactSymbols.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reactSymbols.js","names":[],"sources":["../../src/reactSymbols.ts"],"sourcesContent":["// Inline React 19 internal $$typeof symbols to avoid depending on `react-is`.\n// `react-is` is CJS-only, causing module resolution failures in strict pnpm\n// setups where it can't be resolved from the consumer's node_modules.\nexport const ReactElement = Symbol.for('react.transitional.element')\nexport const ReactLazy = Symbol.for('react.lazy')\nexport const ReactSuspense = Symbol.for('react.suspense')\n"],"mappings":";AAGA,IAAa,eAAe,OAAO,IAAI,6BAA6B;AACpE,IAAa,YAAY,OAAO,IAAI,aAAa;AACjD,IAAa,gBAAgB,OAAO,IAAI,iBAAiB"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { RENDERABLE_RSC, SERVER_COMPONENT_STREAM } from "./ServerComponentTypes.js";
|
|
2
|
+
import { ReplayableStream } from "./ReplayableStream.js";
|
|
3
|
+
import { renderToReadableStream } from "virtual:tanstack-rsc-runtime";
|
|
4
|
+
import { getRequest } from "@tanstack/start-server-core";
|
|
5
|
+
import { getStartContext } from "@tanstack/start-storage-context";
|
|
6
|
+
//#region src/renderServerComponent.ts
|
|
7
|
+
/**
|
|
8
|
+
* Renders a React element to an RSC Flight stream.
|
|
9
|
+
*
|
|
10
|
+
* Returns a "renderable proxy" that can be:
|
|
11
|
+
* - Rendered directly as `{data}` in JSX
|
|
12
|
+
* - Accessed for nested selections: `{data.foo.bar.Hello}`
|
|
13
|
+
*
|
|
14
|
+
* No slot support - for slots use `createCompositeComponent`.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```tsx
|
|
18
|
+
* // In a loader or server function
|
|
19
|
+
* const data = await renderServerComponent(<MyServerComponent foo="bar" />)
|
|
20
|
+
*
|
|
21
|
+
* // In the route component
|
|
22
|
+
* return (
|
|
23
|
+
* <div>
|
|
24
|
+
* {data}
|
|
25
|
+
* {data.sidebar.Menu}
|
|
26
|
+
* </div>
|
|
27
|
+
* )
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
async function renderServerComponent(node) {
|
|
31
|
+
const flightStream = renderToReadableStream(node);
|
|
32
|
+
const isRouterRequest = getStartContext({ throwIfNotFound: false })?.handlerType === "router";
|
|
33
|
+
const ssrHandler = globalThis.__RSC_SSR__;
|
|
34
|
+
if (isRouterRequest && ssrHandler) {
|
|
35
|
+
const signal = getRequest().signal;
|
|
36
|
+
const stream = new ReplayableStream(flightStream, { signal });
|
|
37
|
+
const decoded = await ssrHandler.decode(stream);
|
|
38
|
+
return ssrHandler.createRenderableProxy(stream, decoded);
|
|
39
|
+
}
|
|
40
|
+
return createRenderableHandle(flightStream);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Creates a renderable handle for server function responses.
|
|
44
|
+
* Tagged with RENDERABLE_RSC for the serialization adapter.
|
|
45
|
+
*/
|
|
46
|
+
function createRenderableHandle(flightStream) {
|
|
47
|
+
const streamWrapper = { createReplayStream: () => flightStream };
|
|
48
|
+
const stub = function RenderableRscStub() {
|
|
49
|
+
throw new Error("Renderable RSC from server function cannot be rendered on server. It should be serialized and sent to the client.");
|
|
50
|
+
};
|
|
51
|
+
stub[SERVER_COMPONENT_STREAM] = streamWrapper;
|
|
52
|
+
stub[RENDERABLE_RSC] = true;
|
|
53
|
+
return stub;
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
export { renderServerComponent };
|
|
57
|
+
|
|
58
|
+
//# sourceMappingURL=renderServerComponent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderServerComponent.js","names":[],"sources":["../../src/renderServerComponent.ts"],"sourcesContent":["import { renderToReadableStream } from 'virtual:tanstack-rsc-runtime'\nimport { getRequest } from '@tanstack/start-server-core'\nimport { getStartContext } from '@tanstack/start-storage-context'\n\nimport { ReplayableStream } from './ReplayableStream'\nimport { RENDERABLE_RSC, SERVER_COMPONENT_STREAM } from './ServerComponentTypes'\nimport type {\n AnyRenderableServerComponent,\n RenderableServerComponentBuilder,\n ServerComponentStream,\n ValidateRenderableServerComponent,\n} from './ServerComponentTypes'\n\nimport './rscSsrHandler'\n// Import for global declaration side effect\nexport type { RscSsrHandler, RscDecodeResult } from './rscSsrHandler'\n\n/**\n * Renderable RSC handle type - used for serialization detection.\n */\n\n/**\n * Type guard for renderable RSC handle.\n */\nexport function isRenderableRscHandle(\n value: unknown,\n): value is AnyRenderableServerComponent {\n return (\n typeof value === 'function' &&\n SERVER_COMPONENT_STREAM in value &&\n RENDERABLE_RSC in value &&\n (value as any)[RENDERABLE_RSC] === true\n )\n}\n\n/**\n * Renders a React element to an RSC Flight stream.\n *\n * Returns a \"renderable proxy\" that can be:\n * - Rendered directly as `{data}` in JSX\n * - Accessed for nested selections: `{data.foo.bar.Hello}`\n *\n * No slot support - for slots use `createCompositeComponent`.\n *\n * @example\n * ```tsx\n * // In a loader or server function\n * const data = await renderServerComponent(<MyServerComponent foo=\"bar\" />)\n *\n * // In the route component\n * return (\n * <div>\n * {data}\n * {data.sidebar.Menu}\n * </div>\n * )\n * ```\n */\nexport async function renderServerComponent<TNode>(\n node: ValidateRenderableServerComponent<TNode>,\n): Promise<RenderableServerComponentBuilder<TNode>> {\n // Render the element directly to a Flight stream\n const flightStream = renderToReadableStream(node)\n\n // Check if this is an SSR request (router) or a direct server function call\n const ctx = getStartContext({ throwIfNotFound: false })\n const isRouterRequest = ctx?.handlerType === 'router'\n const ssrHandler = globalThis.__RSC_SSR__\n\n // SSR path: buffer stream for replay, pre-decode for synchronous rendering\n if (isRouterRequest && ssrHandler) {\n const signal = getRequest().signal\n const stream = new ReplayableStream(flightStream, { signal })\n\n // Pre-decode during loader phase for synchronous SSR rendering\n const decoded = await ssrHandler.decode(stream)\n return ssrHandler.createRenderableProxy(\n stream,\n decoded,\n ) as RenderableServerComponentBuilder<TNode>\n }\n\n // Server function call path: return a handle for serialization\n return createRenderableHandle(\n flightStream,\n ) as unknown as RenderableServerComponentBuilder<TNode>\n}\n\n/**\n * Creates a renderable handle for server function responses.\n * Tagged with RENDERABLE_RSC for the serialization adapter.\n */\nfunction createRenderableHandle(\n flightStream: ReadableStream<Uint8Array>,\n): AnyRenderableServerComponent {\n const streamWrapper: ServerComponentStream = {\n createReplayStream: () => flightStream,\n }\n\n const stub = function RenderableRscStub(): never {\n throw new Error(\n 'Renderable RSC from server function cannot be rendered on server. ' +\n 'It should be serialized and sent to the client.',\n )\n }\n\n ;(stub as any)[SERVER_COMPONENT_STREAM] = streamWrapper\n ;(stub as any)[RENDERABLE_RSC] = true\n return stub as unknown as AnyRenderableServerComponent\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0DA,eAAsB,sBACpB,MACkD;CAElD,MAAM,eAAe,uBAAuB,KAAK;CAIjD,MAAM,kBADM,gBAAgB,EAAE,iBAAiB,OAAO,CAAC,EAC1B,gBAAgB;CAC7C,MAAM,aAAa,WAAW;AAG9B,KAAI,mBAAmB,YAAY;EACjC,MAAM,SAAS,YAAY,CAAC;EAC5B,MAAM,SAAS,IAAI,iBAAiB,cAAc,EAAE,QAAQ,CAAC;EAG7D,MAAM,UAAU,MAAM,WAAW,OAAO,OAAO;AAC/C,SAAO,WAAW,sBAChB,QACA,QACD;;AAIH,QAAO,uBACL,aACD;;;;;;AAOH,SAAS,uBACP,cAC8B;CAC9B,MAAM,gBAAuC,EAC3C,0BAA0B,cAC3B;CAED,MAAM,OAAO,SAAS,oBAA2B;AAC/C,QAAM,IAAI,MACR,oHAED;;AAGD,MAAa,2BAA2B;AACxC,MAAa,kBAAkB;AACjC,QAAO"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/renderServerComponent.stub.ts
|
|
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
|
+
function renderServerComponent(_node) {
|
|
10
|
+
if (process.env.NODE_ENV === "test") return Promise.resolve(null);
|
|
11
|
+
throw new Error("renderServerComponent cannot be called on the client. This function should only be called inside a server function or route loader.");
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { renderServerComponent };
|
|
15
|
+
|
|
16
|
+
//# sourceMappingURL=renderServerComponent.stub.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderServerComponent.stub.js","names":[],"sources":["../../src/renderServerComponent.stub.ts"],"sourcesContent":["import type {\n RenderableServerComponentBuilder,\n ValidateRenderableServerComponent,\n} from './ServerComponentTypes'\n\n/**\n * Client stub for renderServerComponent.\n *\n * This function should never be called at runtime on the client.\n * It exists only to satisfy bundler imports in client bundles.\n * The real implementation only runs inside server functions.\n */\nexport function renderServerComponent<TNode>(\n _node: ValidateRenderableServerComponent<TNode>,\n): Promise<RenderableServerComponentBuilder<TNode>> {\n // Unit/type tests import this stub directly and call it.\n // Avoid throwing in that environment while keeping a hard runtime guard elsewhere.\n if (process.env.NODE_ENV === 'test') {\n return Promise.resolve(null as any)\n }\n\n throw new Error(\n 'renderServerComponent cannot be called on the client. ' +\n 'This function should only be called inside a server function or route loader.',\n )\n}\n"],"mappings":";;;;;;;;AAYA,SAAgB,sBACd,OACkD;AAGlD,KAAA,QAAA,IAAA,aAA6B,OAC3B,QAAO,QAAQ,QAAQ,KAAY;AAGrC,OAAM,IAAI,MACR,sIAED"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createCompositeFromStream, createRenderableFromStream } from "./createServerComponentFromStream.js";
|
|
2
|
+
import { createSerializationAdapter } from "@tanstack/react-router";
|
|
3
|
+
import { setupRscHmr } from "virtual:tanstack-rsc-hmr";
|
|
4
|
+
//#region src/serialization.client.ts
|
|
5
|
+
if (process.env.NODE_ENV === "development") setupRscHmr();
|
|
6
|
+
var adapter = createSerializationAdapter({
|
|
7
|
+
key: "$RSC",
|
|
8
|
+
test: (_value) => false,
|
|
9
|
+
toSerializable: () => {
|
|
10
|
+
throw new Error("RSC cannot be serialized on client");
|
|
11
|
+
},
|
|
12
|
+
fromSerializable: (value) => {
|
|
13
|
+
if (value.kind === "renderable") return createRenderableFromStream(value.stream);
|
|
14
|
+
return createCompositeFromStream(value.stream, { slotUsagesStream: value.slotUsagesStream });
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
var rscSerializationAdapter = () => [adapter];
|
|
18
|
+
//#endregion
|
|
19
|
+
export { rscSerializationAdapter };
|
|
20
|
+
|
|
21
|
+
//# sourceMappingURL=serialization.client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialization.client.js","names":[],"sources":["../../src/serialization.client.ts"],"sourcesContent":["import { createSerializationAdapter } from '@tanstack/react-router'\n// RSC HMR setup (dev-only, provided by the active Start bundler adapter).\nimport { setupRscHmr } from 'virtual:tanstack-rsc-hmr'\nimport {\n createCompositeFromStream,\n createRenderableFromStream,\n} from './createServerComponentFromStream'\nimport type {\n AnyCompositeComponent,\n RscSlotUsageEvent,\n} from './ServerComponentTypes'\n\nif (process.env.NODE_ENV === 'development') {\n setupRscHmr()\n}\n\n/**\n * Client-side serialization adapter for RSC (renderable + composite).\n */\ntype SerializedRsc = {\n kind: 'renderable' | 'composite'\n stream: ReadableStream<Uint8Array>\n slotUsagesStream?: ReadableStream<RscSlotUsageEvent>\n}\n\nconst adapter = createSerializationAdapter({\n key: '$RSC',\n test: (_value: unknown): _value is never => false,\n toSerializable: (): never => {\n throw new Error('RSC cannot be serialized on client')\n },\n fromSerializable: (value: SerializedRsc): AnyCompositeComponent => {\n if (value.kind === 'renderable') {\n return createRenderableFromStream(value.stream)\n }\n\n return createCompositeFromStream(value.stream, {\n slotUsagesStream: value.slotUsagesStream,\n })\n },\n})\n\nexport const rscSerializationAdapter = () => [adapter]\n"],"mappings":";;;;AAYA,IAAA,QAAA,IAAA,aAA6B,cAC3B,cAAa;AAYf,IAAM,UAAU,2BAA2B;CACzC,KAAK;CACL,OAAO,WAAqC;CAC5C,sBAA6B;AAC3B,QAAM,IAAI,MAAM,qCAAqC;;CAEvD,mBAAmB,UAAgD;AACjE,MAAI,MAAM,SAAS,aACjB,QAAO,2BAA2B,MAAM,OAAO;AAGjD,SAAO,0BAA0B,MAAM,QAAQ,EAC7C,kBAAkB,MAAM,kBACzB,CAAC;;CAEL,CAAC;AAEF,IAAa,gCAAgC,CAAC,QAAQ"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { RENDERABLE_RSC, RSC_SLOT_USAGES_STREAM, SERVER_COMPONENT_STREAM, isServerComponent } from "./ServerComponentTypes.js";
|
|
2
|
+
import { awaitLazyElements } from "./awaitLazyElements.js";
|
|
3
|
+
import { createRscProxy } from "./createRscProxy.js";
|
|
4
|
+
import { getStartContext } from "@tanstack/start-storage-context";
|
|
5
|
+
import { createSerializationAdapter } from "@tanstack/react-router";
|
|
6
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
7
|
+
import { RawStream } from "@tanstack/router-core";
|
|
8
|
+
import { createFromReadableStream, setOnClientReference } from "virtual:tanstack-rsc-ssr-decode";
|
|
9
|
+
//#region src/serialization.server.ts
|
|
10
|
+
var decodeCollectorStorage = new AsyncLocalStorage();
|
|
11
|
+
var jsCollectorStorage = new AsyncLocalStorage();
|
|
12
|
+
setOnClientReference(({ deps, runtime }) => {
|
|
13
|
+
const ctx = getStartContext({ throwIfNotFound: false });
|
|
14
|
+
const cssCollector = decodeCollectorStorage.getStore();
|
|
15
|
+
if (cssCollector) for (const href of deps.css) cssCollector.add(href);
|
|
16
|
+
const jsCollector = jsCollectorStorage.getStore();
|
|
17
|
+
if (jsCollector) for (const href of deps.js) jsCollector.add(href);
|
|
18
|
+
if (!ctx || runtime === "rsbuild") return;
|
|
19
|
+
if (!ctx.requestAssets) ctx.requestAssets = [];
|
|
20
|
+
const seenHrefs = new Set(ctx.requestAssets.filter((a) => a.tag === "link" && a.attrs?.href).map((a) => a.attrs.href));
|
|
21
|
+
for (const href of deps.js) {
|
|
22
|
+
if (seenHrefs.has(href)) continue;
|
|
23
|
+
seenHrefs.add(href);
|
|
24
|
+
ctx.requestAssets.push({
|
|
25
|
+
tag: "link",
|
|
26
|
+
attrs: {
|
|
27
|
+
rel: "modulepreload",
|
|
28
|
+
href
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
for (const href of deps.css) {
|
|
33
|
+
if (seenHrefs.has(href)) continue;
|
|
34
|
+
seenHrefs.add(href);
|
|
35
|
+
ctx.requestAssets.push({
|
|
36
|
+
tag: "link",
|
|
37
|
+
attrs: {
|
|
38
|
+
rel: "preload",
|
|
39
|
+
href,
|
|
40
|
+
as: "style"
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
var ssrHandler = {
|
|
46
|
+
async decode(stream) {
|
|
47
|
+
const readableStream = stream.createReplayStream();
|
|
48
|
+
const cssCollector = /* @__PURE__ */ new Set();
|
|
49
|
+
const jsCollector = /* @__PURE__ */ new Set();
|
|
50
|
+
return decodeCollectorStorage.run(cssCollector, async () => {
|
|
51
|
+
return jsCollectorStorage.run(jsCollector, async () => {
|
|
52
|
+
const tree = await createFromReadableStream(readableStream);
|
|
53
|
+
await awaitLazyElements(tree, (href) => {
|
|
54
|
+
cssCollector.add(href);
|
|
55
|
+
});
|
|
56
|
+
return {
|
|
57
|
+
tree,
|
|
58
|
+
cssHrefs: cssCollector.size > 0 ? cssCollector : void 0,
|
|
59
|
+
jsPreloads: jsCollector.size > 0 ? jsCollector : void 0
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
createRenderableProxy(stream, decoded) {
|
|
65
|
+
return createRscProxy(() => decoded.tree, {
|
|
66
|
+
stream,
|
|
67
|
+
cssHrefs: decoded.cssHrefs,
|
|
68
|
+
jsPreloads: decoded.jsPreloads,
|
|
69
|
+
renderable: true
|
|
70
|
+
});
|
|
71
|
+
},
|
|
72
|
+
createCompositeProxy(stream, decoded, slotUsagesStream) {
|
|
73
|
+
return createRscProxy(() => decoded.tree, {
|
|
74
|
+
stream,
|
|
75
|
+
cssHrefs: decoded.cssHrefs,
|
|
76
|
+
jsPreloads: decoded.jsPreloads,
|
|
77
|
+
renderable: false,
|
|
78
|
+
slotUsagesStream
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
globalThis.__RSC_SSR__ = ssrHandler;
|
|
83
|
+
/**
|
|
84
|
+
* Helper to check if a value is a renderable RSC (from renderServerComponent).
|
|
85
|
+
* The value can be either an object (proxy target) or a function (stub for server functions).
|
|
86
|
+
*/
|
|
87
|
+
function isRenderableRsc(value) {
|
|
88
|
+
if (value === null || value === void 0) return false;
|
|
89
|
+
if (typeof value !== "object" && typeof value !== "function") return false;
|
|
90
|
+
return RENDERABLE_RSC in value && value[RENDERABLE_RSC] === true;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Server-side serialization adapter for RSC (renderable + composite).
|
|
94
|
+
*/
|
|
95
|
+
var adapter = createSerializationAdapter({
|
|
96
|
+
key: "$RSC",
|
|
97
|
+
test: (value) => {
|
|
98
|
+
return isServerComponent(value);
|
|
99
|
+
},
|
|
100
|
+
toSerializable: (component) => {
|
|
101
|
+
const stream = component[SERVER_COMPONENT_STREAM].createReplayStream();
|
|
102
|
+
const kind = isRenderableRsc(component) ? "renderable" : "composite";
|
|
103
|
+
const slotUsagesStream = kind === "composite" && process.env.NODE_ENV === "development" && RSC_SLOT_USAGES_STREAM in component ? component[RSC_SLOT_USAGES_STREAM] : void 0;
|
|
104
|
+
return {
|
|
105
|
+
kind,
|
|
106
|
+
stream: new RawStream(stream, { hint: "text" }),
|
|
107
|
+
slotUsagesStream
|
|
108
|
+
};
|
|
109
|
+
},
|
|
110
|
+
fromSerializable: () => {
|
|
111
|
+
throw new Error("Server should never deserialize RSC data");
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
/**
|
|
115
|
+
* Factory function for server-side RSC serialization adapter.
|
|
116
|
+
*/
|
|
117
|
+
var rscSerializationAdapter = () => [adapter];
|
|
118
|
+
//#endregion
|
|
119
|
+
export { rscSerializationAdapter };
|
|
120
|
+
|
|
121
|
+
//# sourceMappingURL=serialization.server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialization.server.js","names":[],"sources":["../../src/serialization.server.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks'\nimport { createSerializationAdapter } from '@tanstack/react-router'\nimport { RawStream } from '@tanstack/router-core'\nimport { getStartContext } from '@tanstack/start-storage-context'\nimport {\n setOnClientReference,\n createFromReadableStream as ssrDecode,\n} from 'virtual:tanstack-rsc-ssr-decode'\nimport {\n RENDERABLE_RSC,\n RSC_SLOT_USAGES_STREAM,\n SERVER_COMPONENT_STREAM,\n isServerComponent,\n} from './ServerComponentTypes'\nimport { createRscProxy } from './createRscProxy'\nimport { awaitLazyElements } from './awaitLazyElements'\nimport type {\n AnyCompositeComponent,\n ServerComponentStream,\n} from './ServerComponentTypes'\nimport type { RscDecodeResult, RscSsrHandler } from './rscSsrHandler'\n\n// ===== SSR Handler Registration =====\n// This handler is registered on globalThis for the RSC environment to access.\n// The RSC env calls these functions during loader execution to pre-decode streams\n// and create renderable proxies.\n//\n// This MUST happen in a module without 'use client' directive.\n// Modules with 'use client' may be transformed to client references in the\n// SSR environment when RSC is enabled, preventing the side effect from running.\n\n// AsyncLocalStorage for decode-scoped CSS collector.\n// Each decode() runs in its own async context with its own collector.\n// The onClientReference callback reads from this to write CSS hrefs.\nconst decodeCollectorStorage = new AsyncLocalStorage<Set<string>>()\nconst jsCollectorStorage = new AsyncLocalStorage<Set<string>>()\n\nsetOnClientReference(\n ({\n deps,\n runtime,\n }: {\n deps: { js: Array<string>; css: Array<string> }\n runtime?: 'rsbuild'\n }) => {\n const ctx = getStartContext({ throwIfNotFound: false })\n\n const cssCollector = decodeCollectorStorage.getStore()\n if (cssCollector) {\n for (const href of deps.css) {\n cssCollector.add(href)\n }\n }\n\n const jsCollector = jsCollectorStorage.getStore()\n if (jsCollector) {\n for (const href of deps.js) {\n jsCollector.add(href)\n }\n }\n\n if (!ctx || runtime === 'rsbuild') return\n\n if (!ctx.requestAssets) ctx.requestAssets = []\n const seenHrefs = new Set(\n ctx.requestAssets\n .filter((a) => a.tag === 'link' && a.attrs?.href)\n .map((a) => a.attrs!.href as string),\n )\n\n for (const href of deps.js) {\n if (seenHrefs.has(href)) continue\n seenHrefs.add(href)\n ctx.requestAssets.push({\n tag: 'link',\n attrs: { rel: 'modulepreload', href },\n })\n }\n\n for (const href of deps.css) {\n if (seenHrefs.has(href)) continue\n seenHrefs.add(href)\n ctx.requestAssets.push({\n tag: 'link',\n attrs: { rel: 'preload', href, as: 'style' },\n })\n }\n },\n)\n\nconst ssrHandler: RscSsrHandler = {\n async decode(stream: ServerComponentStream): Promise<RscDecodeResult> {\n const readableStream = stream.createReplayStream()\n\n // Create a collector for this decode operation.\n // Run the decode in an AsyncLocalStorage context so the onClientReference\n // callback can write to this specific collector even with parallel decodes.\n const cssCollector = new Set<string>()\n const jsCollector = new Set<string>()\n\n return decodeCollectorStorage.run(cssCollector, async () => {\n return jsCollectorStorage.run(jsCollector, async () => {\n const tree = await ssrDecode(readableStream)\n await awaitLazyElements(tree, (href) => {\n cssCollector.add(href)\n })\n\n return {\n tree,\n cssHrefs: cssCollector.size > 0 ? cssCollector : undefined,\n jsPreloads: jsCollector.size > 0 ? jsCollector : undefined,\n }\n })\n })\n },\n\n createRenderableProxy(stream, decoded): any {\n return createRscProxy(() => decoded.tree, {\n stream,\n cssHrefs: decoded.cssHrefs,\n jsPreloads: decoded.jsPreloads,\n renderable: true,\n })\n },\n\n createCompositeProxy(\n stream,\n decoded,\n slotUsagesStream,\n ): AnyCompositeComponent {\n const proxy = createRscProxy(() => decoded.tree, {\n stream,\n cssHrefs: decoded.cssHrefs,\n jsPreloads: decoded.jsPreloads,\n renderable: false,\n slotUsagesStream,\n })\n return proxy\n },\n}\n\n// Register SSR handler on globalThis for RSC environment to access.\nglobalThis.__RSC_SSR__ = ssrHandler\n\n// ===== End SSR Handler Registration =====\n\n/**\n * Helper to check if a value is a renderable RSC (from renderServerComponent).\n * The value can be either an object (proxy target) or a function (stub for server functions).\n */\nfunction isRenderableRsc(value: unknown): boolean {\n if (value === null || value === undefined) return false\n if (typeof value !== 'object' && typeof value !== 'function') return false\n return RENDERABLE_RSC in value && (value as any)[RENDERABLE_RSC] === true\n}\n\n/**\n * Server-side serialization adapter for RSC (renderable + composite).\n */\nconst adapter = createSerializationAdapter({\n key: '$RSC',\n test: (value: unknown): value is AnyCompositeComponent => {\n return isServerComponent(value)\n },\n toSerializable: (component: AnyCompositeComponent) => {\n const stream = component[SERVER_COMPONENT_STREAM]!.createReplayStream()\n\n const kind = isRenderableRsc(component) ? 'renderable' : 'composite'\n\n const slotUsagesStream =\n kind === 'composite' &&\n process.env.NODE_ENV === 'development' &&\n RSC_SLOT_USAGES_STREAM in component\n ? ((component as any)[RSC_SLOT_USAGES_STREAM] as unknown as\n | ReadableStream<any>\n | undefined)\n : undefined\n\n return {\n kind,\n stream: new RawStream(stream, { hint: 'text' }),\n slotUsagesStream,\n }\n },\n fromSerializable: (): never => {\n throw new Error('Server should never deserialize RSC data')\n },\n})\n\n/**\n * Factory function for server-side RSC serialization adapter.\n */\nexport const rscSerializationAdapter = () => [adapter]\n"],"mappings":";;;;;;;;;AAkCA,IAAM,yBAAyB,IAAI,mBAAgC;AACnE,IAAM,qBAAqB,IAAI,mBAAgC;AAE/D,sBACG,EACC,MACA,cAII;CACJ,MAAM,MAAM,gBAAgB,EAAE,iBAAiB,OAAO,CAAC;CAEvD,MAAM,eAAe,uBAAuB,UAAU;AACtD,KAAI,aACF,MAAK,MAAM,QAAQ,KAAK,IACtB,cAAa,IAAI,KAAK;CAI1B,MAAM,cAAc,mBAAmB,UAAU;AACjD,KAAI,YACF,MAAK,MAAM,QAAQ,KAAK,GACtB,aAAY,IAAI,KAAK;AAIzB,KAAI,CAAC,OAAO,YAAY,UAAW;AAEnC,KAAI,CAAC,IAAI,cAAe,KAAI,gBAAgB,EAAE;CAC9C,MAAM,YAAY,IAAI,IACpB,IAAI,cACD,QAAQ,MAAM,EAAE,QAAQ,UAAU,EAAE,OAAO,KAAK,CAChD,KAAK,MAAM,EAAE,MAAO,KAAe,CACvC;AAED,MAAK,MAAM,QAAQ,KAAK,IAAI;AAC1B,MAAI,UAAU,IAAI,KAAK,CAAE;AACzB,YAAU,IAAI,KAAK;AACnB,MAAI,cAAc,KAAK;GACrB,KAAK;GACL,OAAO;IAAE,KAAK;IAAiB;IAAM;GACtC,CAAC;;AAGJ,MAAK,MAAM,QAAQ,KAAK,KAAK;AAC3B,MAAI,UAAU,IAAI,KAAK,CAAE;AACzB,YAAU,IAAI,KAAK;AACnB,MAAI,cAAc,KAAK;GACrB,KAAK;GACL,OAAO;IAAE,KAAK;IAAW;IAAM,IAAI;IAAS;GAC7C,CAAC;;EAGP;AAED,IAAM,aAA4B;CAChC,MAAM,OAAO,QAAyD;EACpE,MAAM,iBAAiB,OAAO,oBAAoB;EAKlD,MAAM,+BAAe,IAAI,KAAa;EACtC,MAAM,8BAAc,IAAI,KAAa;AAErC,SAAO,uBAAuB,IAAI,cAAc,YAAY;AAC1D,UAAO,mBAAmB,IAAI,aAAa,YAAY;IACrD,MAAM,OAAO,MAAM,yBAAU,eAAe;AAC5C,UAAM,kBAAkB,OAAO,SAAS;AACtC,kBAAa,IAAI,KAAK;MACtB;AAEF,WAAO;KACL;KACA,UAAU,aAAa,OAAO,IAAI,eAAe,KAAA;KACjD,YAAY,YAAY,OAAO,IAAI,cAAc,KAAA;KAClD;KACD;IACF;;CAGJ,sBAAsB,QAAQ,SAAc;AAC1C,SAAO,qBAAqB,QAAQ,MAAM;GACxC;GACA,UAAU,QAAQ;GAClB,YAAY,QAAQ;GACpB,YAAY;GACb,CAAC;;CAGJ,qBACE,QACA,SACA,kBACuB;AAQvB,SAPc,qBAAqB,QAAQ,MAAM;GAC/C;GACA,UAAU,QAAQ;GAClB,YAAY,QAAQ;GACpB,YAAY;GACZ;GACD,CAAC;;CAGL;AAGD,WAAW,cAAc;;;;;AAQzB,SAAS,gBAAgB,OAAyB;AAChD,KAAI,UAAU,QAAQ,UAAU,KAAA,EAAW,QAAO;AAClD,KAAI,OAAO,UAAU,YAAY,OAAO,UAAU,WAAY,QAAO;AACrE,QAAO,kBAAkB,SAAU,MAAc,oBAAoB;;;;;AAMvE,IAAM,UAAU,2BAA2B;CACzC,KAAK;CACL,OAAO,UAAmD;AACxD,SAAO,kBAAkB,MAAM;;CAEjC,iBAAiB,cAAqC;EACpD,MAAM,SAAS,UAAU,yBAA0B,oBAAoB;EAEvE,MAAM,OAAO,gBAAgB,UAAU,GAAG,eAAe;EAEzD,MAAM,mBACJ,SAAS,eAAA,QAAA,IAAA,aACgB,iBACzB,0BAA0B,YACpB,UAAkB,0BAGpB,KAAA;AAEN,SAAO;GACL;GACA,QAAQ,IAAI,UAAU,QAAQ,EAAE,MAAM,QAAQ,CAAC;GAC/C;GACD;;CAEH,wBAA+B;AAC7B,QAAM,IAAI,MAAM,2CAA2C;;CAE9D,CAAC;;;;AAKF,IAAa,gCAAgC,CAAC,QAAQ"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { isValidElement } from "react";
|
|
2
|
+
//#region src/slotUsageSanitizer.ts
|
|
3
|
+
var REACT_ELEMENT_TYPE = Symbol.for("react.element");
|
|
4
|
+
var REACT_TRANSITIONAL_ELEMENT_TYPE = Symbol.for("react.transitional.element");
|
|
5
|
+
var REACT_PORTAL_TYPE = Symbol.for("react.portal");
|
|
6
|
+
function isReactElementLike(value) {
|
|
7
|
+
if (!value || typeof value !== "object" && typeof value !== "function") return false;
|
|
8
|
+
if (isValidElement(value)) return true;
|
|
9
|
+
const t = value.$$typeof;
|
|
10
|
+
return t === REACT_ELEMENT_TYPE || t === REACT_TRANSITIONAL_ELEMENT_TYPE || t === REACT_PORTAL_TYPE;
|
|
11
|
+
}
|
|
12
|
+
var REACT_ELEMENT_PLACEHOLDER = "React element";
|
|
13
|
+
function sanitizeSlotArg(value, seen, depth) {
|
|
14
|
+
if (isReactElementLike(value)) return REACT_ELEMENT_PLACEHOLDER;
|
|
15
|
+
if (value === null || value === void 0) return value;
|
|
16
|
+
if (typeof value !== "object" && typeof value !== "function") return value;
|
|
17
|
+
if (Array.isArray(value)) return value.map((d) => sanitizeSlotArg(d, seen, depth + 1));
|
|
18
|
+
const proto = Object.getPrototypeOf(value);
|
|
19
|
+
if (proto === Object.prototype || proto === null) {
|
|
20
|
+
const out = {};
|
|
21
|
+
for (const [k, v] of Object.entries(value)) out[k] = sanitizeSlotArg(v, seen, depth + 1);
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
function sanitizeSlotArgs(args) {
|
|
27
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
28
|
+
return args.map((d) => sanitizeSlotArg(d, seen, 0));
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { sanitizeSlotArgs };
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=slotUsageSanitizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slotUsageSanitizer.js","names":[],"sources":["../../src/slotUsageSanitizer.ts"],"sourcesContent":["import { isValidElement } from 'react'\n\nconst REACT_ELEMENT_TYPE = Symbol.for('react.element')\nconst REACT_TRANSITIONAL_ELEMENT_TYPE = Symbol.for('react.transitional.element')\nconst REACT_PORTAL_TYPE = Symbol.for('react.portal')\n\nfunction isReactElementLike(value: unknown): boolean {\n if (!value || (typeof value !== 'object' && typeof value !== 'function')) {\n return false\n }\n\n // Prefer React's own check when available.\n if (isValidElement(value)) return true\n\n // Fallback: direct $$typeof detection (covers React 19 transitional elements).\n const t = (value as any).$$typeof\n return (\n t === REACT_ELEMENT_TYPE ||\n t === REACT_TRANSITIONAL_ELEMENT_TYPE ||\n t === REACT_PORTAL_TYPE\n )\n}\n\nconst REACT_ELEMENT_PLACEHOLDER = 'React element'\n\nfunction sanitizeSlotArg(\n value: unknown,\n seen: WeakSet<object>,\n depth: number,\n): unknown {\n if (isReactElementLike(value)) {\n return REACT_ELEMENT_PLACEHOLDER\n }\n\n if (value === null || value === undefined) {\n return value\n }\n\n if (typeof value !== 'object' && typeof value !== 'function') {\n return value\n }\n\n if (Array.isArray(value)) {\n return value.map((d) => sanitizeSlotArg(d, seen, depth + 1))\n }\n\n const proto = Object.getPrototypeOf(value)\n if (proto === Object.prototype || proto === null) {\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n out[k] = sanitizeSlotArg(v, seen, depth + 1)\n }\n return out\n }\n\n return value\n}\n\nexport function sanitizeSlotArgs(args: Array<any>): Array<any> {\n const seen = new WeakSet<object>()\n return args.map((d) => sanitizeSlotArg(d, seen, 0))\n}\n"],"mappings":";;AAEA,IAAM,qBAAqB,OAAO,IAAI,gBAAgB;AACtD,IAAM,kCAAkC,OAAO,IAAI,6BAA6B;AAChF,IAAM,oBAAoB,OAAO,IAAI,eAAe;AAEpD,SAAS,mBAAmB,OAAyB;AACnD,KAAI,CAAC,SAAU,OAAO,UAAU,YAAY,OAAO,UAAU,WAC3D,QAAO;AAIT,KAAI,eAAe,MAAM,CAAE,QAAO;CAGlC,MAAM,IAAK,MAAc;AACzB,QACE,MAAM,sBACN,MAAM,mCACN,MAAM;;AAIV,IAAM,4BAA4B;AAElC,SAAS,gBACP,OACA,MACA,OACS;AACT,KAAI,mBAAmB,MAAM,CAC3B,QAAO;AAGT,KAAI,UAAU,QAAQ,UAAU,KAAA,EAC9B,QAAO;AAGT,KAAI,OAAO,UAAU,YAAY,OAAO,UAAU,WAChD,QAAO;AAGT,KAAI,MAAM,QAAQ,MAAM,CACtB,QAAO,MAAM,KAAK,MAAM,gBAAgB,GAAG,MAAM,QAAQ,EAAE,CAAC;CAG9D,MAAM,QAAQ,OAAO,eAAe,MAAM;AAC1C,KAAI,UAAU,OAAO,aAAa,UAAU,MAAM;EAChD,MAAM,MAA+B,EAAE;AACvC,OAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,MAAiC,CACnE,KAAI,KAAK,gBAAgB,GAAG,MAAM,QAAQ,EAAE;AAE9C,SAAO;;AAGT,QAAO;;AAGT,SAAgB,iBAAiB,MAA8B;CAC7D,MAAM,uBAAO,IAAI,SAAiB;AAClC,QAAO,KAAK,KAAK,MAAM,gBAAgB,GAAG,MAAM,EAAE,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { AnyCompositeComponent } from './ServerComponentTypes.js';
|
|
2
|
+
/**
|
|
3
|
+
* Renders composite RSC data with slot support.
|
|
4
|
+
*
|
|
5
|
+
* Use this component to render data from `createCompositeComponent`.
|
|
6
|
+
* Pass slot implementations as props to fill in ClientSlot placeholders.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* const src = await createCompositeComponent((props) => (
|
|
11
|
+
* <div>
|
|
12
|
+
* <header>{props.header('Dashboard')}</header>
|
|
13
|
+
* <main>{props.children}</main>
|
|
14
|
+
* </div>
|
|
15
|
+
* ))
|
|
16
|
+
*
|
|
17
|
+
* // In route component
|
|
18
|
+
* return (
|
|
19
|
+
* <CompositeComponent src={src} header={(title) => <h1>{title}</h1>}>
|
|
20
|
+
* <p>Main content</p>
|
|
21
|
+
* </CompositeComponent>
|
|
22
|
+
* )
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function CompositeComponent<TComp extends AnyCompositeComponent>(props: CompositeComponentProps<TComp>): TComp['~types']['return'];
|
|
26
|
+
export type CompositeComponentProps<TComp extends AnyCompositeComponent> = {
|
|
27
|
+
src: TComp;
|
|
28
|
+
} & TComp['~types']['props'];
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ReplayableStream is used for React Server Components (RSC) / Flight streams.
|
|
3
|
+
*
|
|
4
|
+
* In this package the same Flight payload may need to be:
|
|
5
|
+
* - decoded for SSR (render path), and/or
|
|
6
|
+
* - serialized for transport to the client for client-side decoding.
|
|
7
|
+
*
|
|
8
|
+
* Call sites:
|
|
9
|
+
* - `src/createServerComponent.ts`: wraps the produced Flight stream once.
|
|
10
|
+
* - `src/serialization.ts`: uses `createReplayStream()` to transport a fresh stream
|
|
11
|
+
* to the client via `RawStream`.
|
|
12
|
+
*
|
|
13
|
+
* Constraints:
|
|
14
|
+
* - Consumption order isn't fixed: SSR decode might start first or transport might
|
|
15
|
+
* start first depending on the request path.
|
|
16
|
+
* - Sometimes only one happens (e.g. when client calls server function directly).
|
|
17
|
+
*
|
|
18
|
+
* Why not just `ReadableStream.tee()`?
|
|
19
|
+
* - tee() must be called up-front before the stream is consumed/locked and only
|
|
20
|
+
* creates two live branches (no late "replay from byte 0").
|
|
21
|
+
* - If one branch is slower or never consumed, the runtime may buffer internally
|
|
22
|
+
* to keep branches consistent, which can retain large Flight payloads longer
|
|
23
|
+
* than intended and makes cleanup less explicit.
|
|
24
|
+
*
|
|
25
|
+
* ReplayableStream reads once, buffers explicitly, can mint replay streams on
|
|
26
|
+
* demand, and centralizes cancellation so aborting can stop upstream work and
|
|
27
|
+
* free buffered data deterministically.
|
|
28
|
+
*
|
|
29
|
+
* Memory Management:
|
|
30
|
+
* - Memory is released when the abort signal fires (request cancelled)
|
|
31
|
+
* - Call `release()` to force immediate cleanup if no more replays are needed
|
|
32
|
+
* - No automatic release: replays can be created at unpredictable times (SSR decode
|
|
33
|
+
* finishes before serialization starts), so we can't safely auto-release
|
|
34
|
+
*/
|
|
35
|
+
export interface ReplayableStreamOptions {
|
|
36
|
+
signal?: AbortSignal;
|
|
37
|
+
}
|
|
38
|
+
export declare const REPLAYABLE_STREAM_MARKER: unique symbol;
|
|
39
|
+
export declare class ReplayableStream<T = Uint8Array> {
|
|
40
|
+
private source;
|
|
41
|
+
private options;
|
|
42
|
+
readonly [REPLAYABLE_STREAM_MARKER] = true;
|
|
43
|
+
private chunks;
|
|
44
|
+
private done;
|
|
45
|
+
private error;
|
|
46
|
+
private waiter;
|
|
47
|
+
private aborted;
|
|
48
|
+
private released;
|
|
49
|
+
private sourceReader;
|
|
50
|
+
private abortSignal;
|
|
51
|
+
private abortListener;
|
|
52
|
+
constructor(source: ReadableStream<T>, options?: ReplayableStreamOptions);
|
|
53
|
+
private start;
|
|
54
|
+
private detachAbortListener;
|
|
55
|
+
private cancelSource;
|
|
56
|
+
private handleAbort;
|
|
57
|
+
private notify;
|
|
58
|
+
private wait;
|
|
59
|
+
/**
|
|
60
|
+
* Explicitly release buffered chunks.
|
|
61
|
+
* Call this when you know no more replay streams will be created.
|
|
62
|
+
* After calling release(), createReplayStream() will return empty streams.
|
|
63
|
+
*/
|
|
64
|
+
release(): void;
|
|
65
|
+
/**
|
|
66
|
+
* Check if the stream data has been released
|
|
67
|
+
*/
|
|
68
|
+
isReleased(): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Create an independent replay stream. Each call returns a fresh reader
|
|
71
|
+
* that starts from the beginning of the buffered data.
|
|
72
|
+
*
|
|
73
|
+
* If the stream has been released, returns a stream that closes immediately.
|
|
74
|
+
*/
|
|
75
|
+
createReplayStream(): ReadableStream<T>;
|
|
76
|
+
}
|