@funstack/static 0.0.1-alpha.0 → 0.0.2-alpha.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 (99) hide show
  1. package/LICENSE +21 -0
  2. package/dist/build/buildApp.mjs +34 -0
  3. package/dist/build/buildApp.mjs.map +1 -0
  4. package/dist/build/contentHash.mjs +14 -0
  5. package/dist/build/contentHash.mjs.map +1 -0
  6. package/dist/build/dependencyGraph.mjs +46 -0
  7. package/dist/build/dependencyGraph.mjs.map +1 -0
  8. package/dist/build/rscPath.mjs +17 -0
  9. package/dist/build/rscPath.mjs.map +1 -0
  10. package/dist/build/rscProcessor.mjs +66 -0
  11. package/dist/build/rscProcessor.mjs.map +1 -0
  12. package/dist/client/entry.mjs +53 -0
  13. package/dist/client/entry.mjs.map +1 -0
  14. package/dist/client/error-boundary.mjs +48 -0
  15. package/dist/client/error-boundary.mjs.map +1 -0
  16. package/dist/client/globals.mjs +10 -0
  17. package/dist/client/globals.mjs.map +1 -0
  18. package/dist/entries/client.d.mts +1 -0
  19. package/dist/entries/client.mjs +3 -0
  20. package/dist/entries/rsc-client.d.mts +3 -0
  21. package/dist/entries/rsc-client.mjs +6 -0
  22. package/dist/entries/rsc.d.mts +3 -0
  23. package/dist/entries/rsc.mjs +4 -0
  24. package/dist/entries/server.d.mts +2 -0
  25. package/dist/entries/server.mjs +3 -0
  26. package/dist/entries/ssr.d.mts +2 -0
  27. package/dist/entries/ssr.mjs +3 -0
  28. package/dist/index.d.mts +2 -30
  29. package/dist/index.mjs +2 -6082
  30. package/dist/plugin/getRSCEntryPoint.mjs +16 -0
  31. package/dist/plugin/getRSCEntryPoint.mjs.map +1 -0
  32. package/dist/plugin/index.d.mts +30 -0
  33. package/dist/plugin/index.d.mts.map +1 -0
  34. package/dist/plugin/index.mjs +61 -0
  35. package/dist/plugin/index.mjs.map +1 -0
  36. package/dist/plugin/server.mjs +64 -0
  37. package/dist/plugin/server.mjs.map +1 -0
  38. package/dist/rsc/defer.d.mts +50 -0
  39. package/dist/rsc/defer.d.mts.map +1 -0
  40. package/dist/rsc/defer.mjs +124 -0
  41. package/dist/rsc/defer.mjs.map +1 -0
  42. package/dist/rsc/entry.d.mts +30 -0
  43. package/dist/rsc/entry.d.mts.map +1 -0
  44. package/dist/rsc/entry.mjs +94 -0
  45. package/dist/rsc/entry.mjs.map +1 -0
  46. package/dist/rsc/marker.mjs +15 -0
  47. package/dist/rsc/marker.mjs.map +1 -0
  48. package/dist/rsc/request.mjs +9 -0
  49. package/dist/rsc/request.mjs.map +1 -0
  50. package/dist/rsc/rscModule.mjs +25 -0
  51. package/dist/rsc/rscModule.mjs.map +1 -0
  52. package/dist/rsc-client/clientWrapper.d.mts +12 -0
  53. package/dist/rsc-client/clientWrapper.d.mts.map +1 -0
  54. package/dist/rsc-client/clientWrapper.mjs +44 -0
  55. package/dist/rsc-client/clientWrapper.mjs.map +1 -0
  56. package/dist/rsc-client/entry.d.mts +1 -0
  57. package/dist/rsc-client/entry.mjs +5 -0
  58. package/dist/ssr/entry.d.mts +15 -0
  59. package/dist/ssr/entry.d.mts.map +1 -0
  60. package/dist/ssr/entry.mjs +53 -0
  61. package/dist/ssr/entry.mjs.map +1 -0
  62. package/dist/util/basePath.mjs +28 -0
  63. package/dist/util/basePath.mjs.map +1 -0
  64. package/dist/util/drainStream.mjs +12 -0
  65. package/dist/util/drainStream.mjs.map +1 -0
  66. package/package.json +22 -7
  67. package/dist/build-BhjMQ5b5.mjs +0 -5
  68. package/dist/build2-BFobw-wK.mjs +0 -5269
  69. package/dist/build2-BFobw-wK.mjs.map +0 -1
  70. package/dist/chunk-CVYhg9ik.mjs +0 -45
  71. package/dist/chunk-ezxmLbPQ-BTJgBwYB.mjs +0 -29
  72. package/dist/chunk-ezxmLbPQ-BTJgBwYB.mjs.map +0 -1
  73. package/dist/chunk-yG6w5hYl.mjs +0 -41
  74. package/dist/chunk-yG6w5hYl.mjs.map +0 -1
  75. package/dist/config-ChWWLT6T.mjs +0 -41331
  76. package/dist/config-ChWWLT6T.mjs.map +0 -1
  77. package/dist/dist-CijqjcI1.mjs +0 -6699
  78. package/dist/dist-CijqjcI1.mjs.map +0 -1
  79. package/dist/false-CW0Ab7Sy.mjs +0 -6
  80. package/dist/false-CW0Ab7Sy.mjs.map +0 -1
  81. package/dist/false-CoaQMKhH.mjs +0 -3
  82. package/dist/index.d.mts.map +0 -1
  83. package/dist/index.mjs.map +0 -1
  84. package/dist/lib-BY2rcZzh.mjs +0 -366
  85. package/dist/lib-BY2rcZzh.mjs.map +0 -1
  86. package/dist/node-entry-Elsz8XBx.mjs +0 -18443
  87. package/dist/node-entry-Elsz8XBx.mjs.map +0 -1
  88. package/dist/parseAst-C9pD5vU6.mjs +0 -2109
  89. package/dist/parseAst-C9pD5vU6.mjs.map +0 -1
  90. package/dist/picocolors-BxaHL81J-CyL9Yrra.mjs +0 -74
  91. package/dist/picocolors-BxaHL81J-CyL9Yrra.mjs.map +0 -1
  92. package/dist/postcss-CQ0jlpM-.mjs +0 -5439
  93. package/dist/postcss-CQ0jlpM-.mjs.map +0 -1
  94. package/dist/postcss-import-D8PxJXZF.mjs +0 -452
  95. package/dist/postcss-import-D8PxJXZF.mjs.map +0 -1
  96. package/dist/rollup-Cs2z7Zqk.mjs +0 -9
  97. package/dist/rollup-Cs2z7Zqk.mjs.map +0 -1
  98. package/dist/watch-70G_ECVN.mjs +0 -7044
  99. package/dist/watch-70G_ECVN.mjs.map +0 -1
@@ -0,0 +1,16 @@
1
+ //#region src/plugin/getRSCEntryPoint.ts
2
+ /**
3
+ * Get the entry point module of the RSC environment.
4
+ */
5
+ async function getRSCEntryPoint(environment) {
6
+ const rscInput = environment.config.build.rollupOptions?.input;
7
+ const source = rscInput !== void 0 && typeof rscInput !== "string" && !Array.isArray(rscInput) ? rscInput.index : void 0;
8
+ if (source === void 0) throw new Error("Cannot determine RSC entry point");
9
+ const resolved = await environment.pluginContainer.resolveId(source);
10
+ if (!resolved) throw new Error(`Cannot resolve RSC entry: ${source}`);
11
+ return await environment.runner.import(resolved.id);
12
+ }
13
+
14
+ //#endregion
15
+ export { getRSCEntryPoint };
16
+ //# sourceMappingURL=getRSCEntryPoint.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getRSCEntryPoint.mjs","names":[],"sources":["../../src/plugin/getRSCEntryPoint.ts"],"sourcesContent":["import type { RunnableDevEnvironment } from \"vite\";\n\n/**\n * Get the entry point module of the RSC environment.\n */\nexport async function getRSCEntryPoint(environment: RunnableDevEnvironment) {\n const rscInput = environment.config.build.rollupOptions?.input;\n const source =\n rscInput !== undefined &&\n typeof rscInput !== \"string\" &&\n !Array.isArray(rscInput)\n ? rscInput.index\n : undefined;\n if (source === undefined) {\n throw new Error(\"Cannot determine RSC entry point\");\n }\n const resolved = await environment.pluginContainer.resolveId(source);\n if (!resolved) {\n throw new Error(`Cannot resolve RSC entry: ${source}`);\n }\n const rscEntry = await environment.runner.import<\n typeof import(\"../rsc/entry\")\n >(resolved.id);\n return rscEntry;\n}\n"],"mappings":";;;;AAKA,eAAsB,iBAAiB,aAAqC;CAC1E,MAAM,WAAW,YAAY,OAAO,MAAM,eAAe;CACzD,MAAM,SACJ,aAAa,UACb,OAAO,aAAa,YACpB,CAAC,MAAM,QAAQ,SAAS,GACpB,SAAS,QACT;AACN,KAAI,WAAW,OACb,OAAM,IAAI,MAAM,mCAAmC;CAErD,MAAM,WAAW,MAAM,YAAY,gBAAgB,UAAU,OAAO;AACpE,KAAI,CAAC,SACH,OAAM,IAAI,MAAM,6BAA6B,SAAS;AAKxD,QAHiB,MAAM,YAAY,OAAO,OAExC,SAAS,GAAG"}
@@ -0,0 +1,30 @@
1
+ import { Plugin } from "vite";
2
+
3
+ //#region src/plugin/index.d.ts
4
+ interface FunstackStaticOptions {
5
+ /**
6
+ * Root component of the page.
7
+ * The file should `export default` a React component that renders the whole page.
8
+ * (`<html>...</html>`).
9
+ */
10
+ root: string;
11
+ /**
12
+ * Entry point of your application.
13
+ * The file should `export default` a React component that renders the application content.
14
+ */
15
+ app: string;
16
+ /**
17
+ * Output directory for build.
18
+ *
19
+ * @default dist/public
20
+ */
21
+ publicOutDir?: string;
22
+ }
23
+ declare function funstackStatic({
24
+ root,
25
+ app,
26
+ publicOutDir
27
+ }: FunstackStaticOptions): (Plugin | Plugin[])[];
28
+ //#endregion
29
+ export { FunstackStaticOptions, funstackStatic };
30
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/plugin/index.ts"],"sourcesContent":[],"mappings":";;;UAMiB,qBAAA;;AAAjB;AAkBC;;;EAKC,IAAA,EAAA,MAAA;EACC;;;;;;;;;;;;iBAJqB,cAAA;;;;GAIrB,yBAAyB,SAAS"}
@@ -0,0 +1,61 @@
1
+ import { buildApp } from "../build/buildApp.mjs";
2
+ import { serverPlugin } from "./server.mjs";
3
+ import path from "node:path";
4
+ import rsc from "@vitejs/plugin-rsc";
5
+
6
+ //#region src/plugin/index.ts
7
+ function funstackStatic({ root, app, publicOutDir = "dist/public" }) {
8
+ let resolvedRootEntry = "__uninitialized__";
9
+ let resolvedAppEntry = "__uninitialized__";
10
+ return [
11
+ {
12
+ name: "@funstack/static:config-pre",
13
+ config(config) {
14
+ return { environments: { client: { build: { outDir: config.environments?.client?.build?.outDir ?? publicOutDir } } } };
15
+ }
16
+ },
17
+ serverPlugin(),
18
+ rsc({
19
+ entries: {
20
+ rsc: "@funstack/static/entries/rsc",
21
+ ssr: "@funstack/static/entries/ssr",
22
+ client: "@funstack/static/entries/client"
23
+ },
24
+ serverHandler: false
25
+ }),
26
+ {
27
+ name: "@funstack/static:config",
28
+ configResolved(config) {
29
+ resolvedRootEntry = path.resolve(config.root, root);
30
+ resolvedAppEntry = path.resolve(config.root, app);
31
+ },
32
+ configEnvironment(_name, config) {
33
+ if (config.optimizeDeps?.include) config.optimizeDeps.include = config.optimizeDeps.include.map((entry) => {
34
+ if (entry.startsWith("@vitejs/plugin-rsc")) entry = `@funstack/static > ${entry}`;
35
+ return entry;
36
+ });
37
+ }
38
+ },
39
+ {
40
+ name: "@funstack/static:virtual-entry",
41
+ resolveId(id) {
42
+ if (id === "virtual:funstack/root") return "\0virtual:funstack/root";
43
+ if (id === "virtual:funstack/app") return "\0virtual:funstack/app";
44
+ },
45
+ load(id) {
46
+ if (id === "\0virtual:funstack/root") return `export { default } from "${resolvedRootEntry}";`;
47
+ if (id === "\0virtual:funstack/app") return `export { default } from "${resolvedAppEntry}";`;
48
+ }
49
+ },
50
+ {
51
+ name: "@funstack/static:build",
52
+ async buildApp(builder) {
53
+ await buildApp(builder, this);
54
+ }
55
+ }
56
+ ];
57
+ }
58
+
59
+ //#endregion
60
+ export { funstackStatic as default };
61
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/plugin/index.ts"],"sourcesContent":["import path from \"node:path\";\nimport type { Plugin } from \"vite\";\nimport rsc from \"@vitejs/plugin-rsc\";\nimport { buildApp } from \"../build/buildApp\";\nimport { serverPlugin } from \"./server\";\n\nexport interface FunstackStaticOptions {\n /**\n * Root component of the page.\n * The file should `export default` a React component that renders the whole page.\n * (`<html>...</html>`).\n */\n root: string;\n /**\n * Entry point of your application.\n * The file should `export default` a React component that renders the application content.\n */\n app: string;\n /**\n * Output directory for build.\n *\n * @default dist/public\n */\n publicOutDir?: string;\n}\n\nexport default function funstackStatic({\n root,\n app,\n publicOutDir = \"dist/public\",\n}: FunstackStaticOptions): (Plugin | Plugin[])[] {\n let resolvedRootEntry: string = \"__uninitialized__\";\n let resolvedAppEntry: string = \"__uninitialized__\";\n\n return [\n {\n name: \"@funstack/static:config-pre\",\n // Placed early because the rsc plugin sets the outDir to the default value\n config(config) {\n return {\n environments: {\n client: {\n build: {\n outDir:\n config.environments?.client?.build?.outDir ?? publicOutDir,\n },\n },\n },\n };\n },\n },\n serverPlugin(),\n rsc({\n entries: {\n rsc: \"@funstack/static/entries/rsc\",\n ssr: \"@funstack/static/entries/ssr\",\n client: \"@funstack/static/entries/client\",\n },\n serverHandler: false,\n }),\n {\n name: \"@funstack/static:config\",\n configResolved(config) {\n resolvedRootEntry = path.resolve(config.root, root);\n resolvedAppEntry = path.resolve(config.root, app);\n },\n // Needed for properly bundling @vitejs/plugin-rsc for browser.\n // See: https://github.com/vitejs/vite-plugin-react/tree/79bf57cc8b9c77e33970ec2e876bd6d2f1568d5d/packages/plugin-rsc#using-vitejsplugin-rsc-as-a-framework-packages-dependencies\n configEnvironment(_name, config) {\n if (config.optimizeDeps?.include) {\n config.optimizeDeps.include = config.optimizeDeps.include.map(\n (entry) => {\n if (entry.startsWith(\"@vitejs/plugin-rsc\")) {\n entry = `@funstack/static > ${entry}`;\n }\n return entry;\n },\n );\n }\n },\n },\n {\n name: \"@funstack/static:virtual-entry\",\n resolveId(id) {\n if (id === \"virtual:funstack/root\") {\n return \"\\0virtual:funstack/root\";\n }\n if (id === \"virtual:funstack/app\") {\n return \"\\0virtual:funstack/app\";\n }\n },\n load(id) {\n if (id === \"\\0virtual:funstack/root\") {\n return `export { default } from \"${resolvedRootEntry}\";`;\n }\n if (id === \"\\0virtual:funstack/app\") {\n return `export { default } from \"${resolvedAppEntry}\";`;\n }\n },\n },\n {\n name: \"@funstack/static:build\",\n async buildApp(builder) {\n await buildApp(builder, this);\n },\n },\n ];\n}\n"],"mappings":";;;;;;AA0BA,SAAwB,eAAe,EACrC,MACA,KACA,eAAe,iBACgC;CAC/C,IAAI,oBAA4B;CAChC,IAAI,mBAA2B;AAE/B,QAAO;EACL;GACE,MAAM;GAEN,OAAO,QAAQ;AACb,WAAO,EACL,cAAc,EACZ,QAAQ,EACN,OAAO,EACL,QACE,OAAO,cAAc,QAAQ,OAAO,UAAU,cACjD,EACF,EACF,EACF;;GAEJ;EACD,cAAc;EACd,IAAI;GACF,SAAS;IACP,KAAK;IACL,KAAK;IACL,QAAQ;IACT;GACD,eAAe;GAChB,CAAC;EACF;GACE,MAAM;GACN,eAAe,QAAQ;AACrB,wBAAoB,KAAK,QAAQ,OAAO,MAAM,KAAK;AACnD,uBAAmB,KAAK,QAAQ,OAAO,MAAM,IAAI;;GAInD,kBAAkB,OAAO,QAAQ;AAC/B,QAAI,OAAO,cAAc,QACvB,QAAO,aAAa,UAAU,OAAO,aAAa,QAAQ,KACvD,UAAU;AACT,SAAI,MAAM,WAAW,qBAAqB,CACxC,SAAQ,sBAAsB;AAEhC,YAAO;MAEV;;GAGN;EACD;GACE,MAAM;GACN,UAAU,IAAI;AACZ,QAAI,OAAO,wBACT,QAAO;AAET,QAAI,OAAO,uBACT,QAAO;;GAGX,KAAK,IAAI;AACP,QAAI,OAAO,0BACT,QAAO,4BAA4B,kBAAkB;AAEvD,QAAI,OAAO,yBACT,QAAO,4BAA4B,iBAAiB;;GAGzD;EACD;GACE,MAAM;GACN,MAAM,SAAS,SAAS;AACtB,UAAM,SAAS,SAAS,KAAK;;GAEhC;EACF"}
@@ -0,0 +1,64 @@
1
+ import { getRSCEntryPoint } from "./getRSCEntryPoint.mjs";
2
+ import path from "node:path";
3
+ import { readFile } from "node:fs/promises";
4
+ import { isRunnableDevEnvironment } from "vite";
5
+ import { toNodeHandler } from "srvx/node";
6
+
7
+ //#region src/plugin/server.ts
8
+ const serverPlugin = () => {
9
+ let resolvedOutDir = "__uninitialized__";
10
+ return {
11
+ name: "@funstack/static:server",
12
+ configResolved(config) {
13
+ resolvedOutDir = path.resolve(config.root, config.environments.client.build.outDir);
14
+ },
15
+ configureServer(server) {
16
+ const rscEnv = server.environments.rsc;
17
+ if (!isRunnableDevEnvironment(rscEnv)) throw new Error("The rsc environment is not runnable");
18
+ return () => {
19
+ server.middlewares.use(async (req, res, next) => {
20
+ try {
21
+ const rscEntry = await getRSCEntryPoint(rscEnv);
22
+ if (req.headers.accept?.includes("text/html")) {
23
+ await toNodeHandler(rscEntry.serveHTML)(req, res);
24
+ return;
25
+ }
26
+ const fetchHandler = toNodeHandler(rscEntry.serveRSC);
27
+ try {
28
+ await fetchHandler(req, res);
29
+ } catch (error) {
30
+ if (rscEntry.isServeRSCError(error) && error.status === 404) {
31
+ next();
32
+ return;
33
+ }
34
+ next(error);
35
+ }
36
+ } catch (error) {
37
+ next(error);
38
+ }
39
+ });
40
+ };
41
+ },
42
+ configurePreviewServer(server) {
43
+ return () => {
44
+ server.middlewares.use(async (req, res, next) => {
45
+ try {
46
+ if (req.headers.accept?.includes("text/html")) {
47
+ const html = await readFile(path.join(resolvedOutDir, "index.html"), "utf-8");
48
+ res.end(html);
49
+ return;
50
+ }
51
+ } catch (error) {
52
+ next(error);
53
+ return;
54
+ }
55
+ next();
56
+ });
57
+ };
58
+ }
59
+ };
60
+ };
61
+
62
+ //#endregion
63
+ export { serverPlugin };
64
+ //# sourceMappingURL=server.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.mjs","names":[],"sources":["../../src/plugin/server.ts"],"sourcesContent":["import { isRunnableDevEnvironment, type Plugin } from \"vite\";\nimport { readFile } from \"node:fs/promises\";\nimport { toNodeHandler } from \"srvx/node\";\nimport path from \"node:path\";\nimport { getRSCEntryPoint } from \"./getRSCEntryPoint\";\n\nexport const serverPlugin = (): Plugin => {\n let resolvedOutDir = \"__uninitialized__\";\n return {\n name: \"@funstack/static:server\",\n configResolved(config) {\n resolvedOutDir = path.resolve(\n config.root,\n config.environments.client.build.outDir,\n );\n },\n configureServer(server) {\n const rscEnv = server.environments.rsc;\n if (!isRunnableDevEnvironment(rscEnv)) {\n throw new Error(\"The rsc environment is not runnable\");\n }\n\n return () => {\n server.middlewares.use(async (req, res, next) => {\n try {\n const rscEntry = await getRSCEntryPoint(rscEnv);\n if (req.headers.accept?.includes(\"text/html\")) {\n const fetchHandler = toNodeHandler(rscEntry.serveHTML);\n await fetchHandler(req as any, res as any);\n return;\n }\n const fetchHandler = toNodeHandler(rscEntry.serveRSC);\n try {\n await fetchHandler(req as any, res as any);\n } catch (error) {\n if (rscEntry.isServeRSCError(error) && error.status === 404) {\n next();\n return;\n }\n next(error);\n }\n } catch (error) {\n next(error);\n }\n });\n };\n },\n configurePreviewServer(server) {\n return () => {\n server.middlewares.use(async (req, res, next) => {\n try {\n if (req.headers.accept?.includes(\"text/html\")) {\n const html = await readFile(\n path.join(resolvedOutDir, \"index.html\"),\n \"utf-8\",\n );\n res.end(html);\n return;\n }\n } catch (error) {\n next(error);\n return;\n }\n next();\n });\n };\n },\n };\n};\n"],"mappings":";;;;;;;AAMA,MAAa,qBAA6B;CACxC,IAAI,iBAAiB;AACrB,QAAO;EACL,MAAM;EACN,eAAe,QAAQ;AACrB,oBAAiB,KAAK,QACpB,OAAO,MACP,OAAO,aAAa,OAAO,MAAM,OAClC;;EAEH,gBAAgB,QAAQ;GACtB,MAAM,SAAS,OAAO,aAAa;AACnC,OAAI,CAAC,yBAAyB,OAAO,CACnC,OAAM,IAAI,MAAM,sCAAsC;AAGxD,gBAAa;AACX,WAAO,YAAY,IAAI,OAAO,KAAK,KAAK,SAAS;AAC/C,SAAI;MACF,MAAM,WAAW,MAAM,iBAAiB,OAAO;AAC/C,UAAI,IAAI,QAAQ,QAAQ,SAAS,YAAY,EAAE;AAE7C,aADqB,cAAc,SAAS,UAAU,CACnC,KAAY,IAAW;AAC1C;;MAEF,MAAM,eAAe,cAAc,SAAS,SAAS;AACrD,UAAI;AACF,aAAM,aAAa,KAAY,IAAW;eACnC,OAAO;AACd,WAAI,SAAS,gBAAgB,MAAM,IAAI,MAAM,WAAW,KAAK;AAC3D,cAAM;AACN;;AAEF,YAAK,MAAM;;cAEN,OAAO;AACd,WAAK,MAAM;;MAEb;;;EAGN,uBAAuB,QAAQ;AAC7B,gBAAa;AACX,WAAO,YAAY,IAAI,OAAO,KAAK,KAAK,SAAS;AAC/C,SAAI;AACF,UAAI,IAAI,QAAQ,QAAQ,SAAS,YAAY,EAAE;OAC7C,MAAM,OAAO,MAAM,SACjB,KAAK,KAAK,gBAAgB,aAAa,EACvC,QACD;AACD,WAAI,IAAI,KAAK;AACb;;cAEK,OAAO;AACd,WAAK,MAAM;AACX;;AAEF,WAAM;MACN;;;EAGP"}
@@ -0,0 +1,50 @@
1
+ import { ReactElement, ReactNode } from "react";
2
+
3
+ //#region src/rsc/defer.d.ts
4
+ interface DeferEntry {
5
+ state: DeferEntryState;
6
+ }
7
+ interface LoadedDeferEntry extends DeferEntry {
8
+ state: Exclude<DeferEntryState, {
9
+ state: "pending";
10
+ }>;
11
+ }
12
+ type DeferEntryState = {
13
+ state: "pending";
14
+ element: ReactElement;
15
+ } | {
16
+ state: "streaming";
17
+ stream: ReadableStream<Uint8Array>;
18
+ } | {
19
+ state: "ready";
20
+ data: string;
21
+ } | {
22
+ state: "error";
23
+ error: unknown;
24
+ };
25
+ declare class DeferRegistry {
26
+ #private;
27
+ register(element: ReactElement, id: string): void;
28
+ load(id: string): LoadedDeferEntry | undefined;
29
+ has(id: string): boolean;
30
+ /**
31
+ * Iterates over all entries in parallel.
32
+ * Yields results as each stream completes.
33
+ */
34
+ loadAll(): AsyncGenerator<{
35
+ id: string;
36
+ data: string;
37
+ }, void, unknown>;
38
+ }
39
+ /**
40
+ * Renders given Server Component into a separate RSC payload.
41
+ *
42
+ * During the client side rendering, fetching of the payload will be
43
+ * deferred until the returned ReactNode is actually rendered.
44
+ *
45
+ * @returns A ReactNode that virtually contains the result of rendering the given component.
46
+ */
47
+ declare function defer(element: ReactElement): ReactNode;
48
+ //#endregion
49
+ export { DeferRegistry, defer };
50
+ //# sourceMappingURL=defer.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defer.d.mts","names":[],"sources":["../../src/rsc/defer.tsx"],"sourcesContent":[],"mappings":";;;UAMiB,UAAA;SACR;AADT;AAIiB,UAAA,gBAAA,SAAyB,UAAR,CAAA;EACjB,KAAA,EAAR,OAAQ,CAAA,eAAA,EAAA;IAAR,KAAA,EAAA,SAAA;EADiC,CAAA,CAAA;;AAEzC,KAEI,eAAA,GAAe;EAGL,KAAA,EAAA,SAAA;EAIc,OAAA,EAJd,YAIc;CAAf,GAAA;EAAc,KAAA,EAAA,WAAA;EAWf,MAAA,EAXC,cAWY,CAXG,UAWH,CAAA;CAGN,GAAA;EAIA,KAAA,EAAA,OAAA;EAgDJ,IAAA,EAAA,MAAA;CAAA,GAAA;EAiFA,KAAA,EAAA,OAAK;;;cAxIR,aAAA;;oBAGO;oBAIA;;;;;;aAgDJ;;;;;;;;;;;;;iBAiFA,KAAA,UAAe,eAAe"}
@@ -0,0 +1,124 @@
1
+ import { getPayloadIDFor } from "./rscModule.mjs";
2
+ import { drainStream } from "../util/drainStream.mjs";
3
+ import { jsx } from "react/jsx-runtime";
4
+ import { renderToReadableStream } from "@vitejs/plugin-rsc/react/rsc";
5
+ import { ClientWrapper } from "#rsc-client";
6
+
7
+ //#region src/rsc/defer.tsx
8
+ var DeferRegistry = class {
9
+ #registry = /* @__PURE__ */ new Map();
10
+ register(element, id) {
11
+ this.#registry.set(id, { state: {
12
+ element,
13
+ state: "pending"
14
+ } });
15
+ }
16
+ load(id) {
17
+ const entry = this.#registry.get(id);
18
+ if (!entry) return;
19
+ return this.#loadEntry(entry);
20
+ }
21
+ #loadEntry(entry) {
22
+ const { state } = entry;
23
+ switch (state.state) {
24
+ case "pending": {
25
+ const [stream1, stream2] = renderToReadableStream(state.element).tee();
26
+ entry.state = {
27
+ state: "streaming",
28
+ stream: stream1
29
+ };
30
+ (async () => {
31
+ const chunks = [];
32
+ const decoder = new TextDecoder();
33
+ for await (const chunk of stream2) chunks.push(decoder.decode(chunk, { stream: true }));
34
+ chunks.push(decoder.decode());
35
+ entry.state = {
36
+ state: "ready",
37
+ data: chunks.join("")
38
+ };
39
+ })().catch((error) => {
40
+ entry.state = {
41
+ state: "error",
42
+ error
43
+ };
44
+ });
45
+ return entry;
46
+ }
47
+ case "streaming":
48
+ case "ready":
49
+ case "error": return entry;
50
+ }
51
+ }
52
+ has(id) {
53
+ return this.#registry.has(id);
54
+ }
55
+ /**
56
+ * Iterates over all entries in parallel.
57
+ * Yields results as each stream completes.
58
+ */
59
+ async *loadAll() {
60
+ const errors = [];
61
+ const loadedEntries = Array.from(this.#registry, ([id, entry]) => [id, this.#loadEntry(entry)]);
62
+ if (loadedEntries.length === 0) return;
63
+ const completed = [];
64
+ let waiting;
65
+ let remainingCount = loadedEntries.length;
66
+ const onComplete = (result) => {
67
+ completed.push(result);
68
+ remainingCount--;
69
+ waiting?.();
70
+ };
71
+ for (const [id, loadedEntry] of loadedEntries) (async () => {
72
+ try {
73
+ switch (loadedEntry.state.state) {
74
+ case "streaming":
75
+ onComplete({
76
+ id,
77
+ data: await drainStream(loadedEntry.state.stream)
78
+ });
79
+ break;
80
+ case "ready":
81
+ onComplete({
82
+ id,
83
+ data: loadedEntry.state.data
84
+ });
85
+ break;
86
+ case "error":
87
+ onComplete({ error: loadedEntry.state.error });
88
+ break;
89
+ }
90
+ } catch (error) {
91
+ onComplete({ error });
92
+ }
93
+ })();
94
+ while (remainingCount > 0 || completed.length > 0) {
95
+ if (completed.length === 0) {
96
+ await new Promise((r) => {
97
+ waiting = r;
98
+ });
99
+ waiting = void 0;
100
+ }
101
+ for (const result of completed.splice(0)) if ("error" in result) errors.push(result.error);
102
+ else yield result;
103
+ }
104
+ if (errors.length > 0) throw new AggregateError(errors);
105
+ }
106
+ };
107
+ const deferRegistry = new DeferRegistry();
108
+ /**
109
+ * Renders given Server Component into a separate RSC payload.
110
+ *
111
+ * During the client side rendering, fetching of the payload will be
112
+ * deferred until the returned ReactNode is actually rendered.
113
+ *
114
+ * @returns A ReactNode that virtually contains the result of rendering the given component.
115
+ */
116
+ function defer(element) {
117
+ const id = getPayloadIDFor(crypto.randomUUID());
118
+ deferRegistry.register(element, id);
119
+ return /* @__PURE__ */ jsx(ClientWrapper, { moduleID: id });
120
+ }
121
+
122
+ //#endregion
123
+ export { defer, deferRegistry };
124
+ //# sourceMappingURL=defer.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defer.mjs","names":["#registry","#loadEntry"],"sources":["../../src/rsc/defer.tsx"],"sourcesContent":["import type { ReactElement, ReactNode } from \"react\";\nimport { renderToReadableStream } from \"@vitejs/plugin-rsc/react/rsc\";\nimport { ClientWrapper } from \"#rsc-client\";\nimport { drainStream } from \"../util/drainStream\";\nimport { getPayloadIDFor } from \"./rscModule\";\n\nexport interface DeferEntry {\n state: DeferEntryState;\n}\n\nexport interface LoadedDeferEntry extends DeferEntry {\n state: Exclude<DeferEntryState, { state: \"pending\" }>;\n}\n\ntype DeferEntryState =\n | {\n state: \"pending\";\n element: ReactElement;\n }\n | {\n state: \"streaming\";\n stream: ReadableStream<Uint8Array>;\n }\n | {\n state: \"ready\";\n data: string;\n }\n | {\n state: \"error\";\n error: unknown;\n };\n\nexport class DeferRegistry {\n #registry = new Map<string, DeferEntry>();\n\n register(element: ReactElement, id: string) {\n this.#registry.set(id, { state: { element, state: \"pending\" } });\n }\n\n load(id: string): LoadedDeferEntry | undefined {\n const entry = this.#registry.get(id);\n if (!entry) {\n return undefined;\n }\n return this.#loadEntry(entry);\n }\n\n #loadEntry(entry: DeferEntry): LoadedDeferEntry {\n const { state } = entry;\n switch (state.state) {\n case \"pending\": {\n const stream = renderToReadableStream<ReactNode>(state.element);\n const [stream1, stream2] = stream.tee();\n entry.state = { state: \"streaming\", stream: stream1 };\n (async () => {\n const chunks: string[] = [];\n const decoder = new TextDecoder();\n for await (const chunk of stream2) {\n chunks.push(decoder.decode(chunk, { stream: true }));\n }\n chunks.push(decoder.decode());\n entry.state = {\n state: \"ready\",\n data: chunks.join(\"\"),\n };\n })().catch((error) => {\n entry.state = { state: \"error\", error };\n });\n return entry as LoadedDeferEntry;\n }\n case \"streaming\":\n case \"ready\":\n case \"error\": {\n return entry as LoadedDeferEntry;\n }\n }\n state satisfies never;\n }\n\n has(id: string): boolean {\n return this.#registry.has(id);\n }\n\n /**\n * Iterates over all entries in parallel.\n * Yields results as each stream completes.\n */\n async *loadAll() {\n const errors: unknown[] = [];\n\n // Phase 1: Start all entries loading\n const loadedEntries = Array.from(\n this.#registry,\n ([id, entry]) => [id, this.#loadEntry(entry)] as const,\n );\n\n if (loadedEntries.length === 0) return;\n\n type Result = { id: string; data: string };\n\n // Completion queue\n const completed: Array<Result | { error: unknown }> = [];\n let waiting: (() => void) | undefined;\n let remainingCount = loadedEntries.length;\n\n const onComplete = (result: Result | { error: unknown }) => {\n completed.push(result);\n remainingCount--;\n waiting?.();\n };\n\n // Phase 2: Start all operations (each pushes to queue when done)\n for (const [id, loadedEntry] of loadedEntries) {\n (async () => {\n try {\n switch (loadedEntry.state.state) {\n case \"streaming\":\n onComplete({\n id,\n data: await drainStream(loadedEntry.state.stream),\n });\n break;\n case \"ready\":\n onComplete({ id, data: loadedEntry.state.data });\n break;\n case \"error\":\n onComplete({ error: loadedEntry.state.error });\n break;\n }\n } catch (error) {\n onComplete({ error });\n }\n })();\n }\n\n // Phase 3: Yield from queue as results arrive\n while (remainingCount > 0 || completed.length > 0) {\n if (completed.length === 0) {\n await new Promise<void>((r) => {\n waiting = r;\n });\n waiting = undefined;\n }\n for (const result of completed.splice(0)) {\n if (\"error\" in result) {\n errors.push(result.error);\n } else {\n yield result;\n }\n }\n }\n\n if (errors.length > 0) {\n throw new AggregateError(errors);\n }\n }\n}\n\nexport const deferRegistry = new DeferRegistry();\n\n/**\n * Renders given Server Component into a separate RSC payload.\n *\n * During the client side rendering, fetching of the payload will be\n * deferred until the returned ReactNode is actually rendered.\n *\n * @returns A ReactNode that virtually contains the result of rendering the given component.\n */\nexport function defer(element: ReactElement): ReactNode {\n const id = getPayloadIDFor(crypto.randomUUID());\n deferRegistry.register(element, id);\n\n return <ClientWrapper moduleID={id} />;\n}\n"],"mappings":";;;;;;;AAgCA,IAAa,gBAAb,MAA2B;CACzB,4BAAY,IAAI,KAAyB;CAEzC,SAAS,SAAuB,IAAY;AAC1C,QAAKA,SAAU,IAAI,IAAI,EAAE,OAAO;GAAE;GAAS,OAAO;GAAW,EAAE,CAAC;;CAGlE,KAAK,IAA0C;EAC7C,MAAM,QAAQ,MAAKA,SAAU,IAAI,GAAG;AACpC,MAAI,CAAC,MACH;AAEF,SAAO,MAAKC,UAAW,MAAM;;CAG/B,WAAW,OAAqC;EAC9C,MAAM,EAAE,UAAU;AAClB,UAAQ,MAAM,OAAd;GACE,KAAK,WAAW;IAEd,MAAM,CAAC,SAAS,WADD,uBAAkC,MAAM,QAAQ,CAC7B,KAAK;AACvC,UAAM,QAAQ;KAAE,OAAO;KAAa,QAAQ;KAAS;AACrD,KAAC,YAAY;KACX,MAAM,SAAmB,EAAE;KAC3B,MAAM,UAAU,IAAI,aAAa;AACjC,gBAAW,MAAM,SAAS,QACxB,QAAO,KAAK,QAAQ,OAAO,OAAO,EAAE,QAAQ,MAAM,CAAC,CAAC;AAEtD,YAAO,KAAK,QAAQ,QAAQ,CAAC;AAC7B,WAAM,QAAQ;MACZ,OAAO;MACP,MAAM,OAAO,KAAK,GAAG;MACtB;QACC,CAAC,OAAO,UAAU;AACpB,WAAM,QAAQ;MAAE,OAAO;MAAS;MAAO;MACvC;AACF,WAAO;;GAET,KAAK;GACL,KAAK;GACL,KAAK,QACH,QAAO;;;CAMb,IAAI,IAAqB;AACvB,SAAO,MAAKD,SAAU,IAAI,GAAG;;;;;;CAO/B,OAAO,UAAU;EACf,MAAM,SAAoB,EAAE;EAG5B,MAAM,gBAAgB,MAAM,KAC1B,MAAKA,WACJ,CAAC,IAAI,WAAW,CAAC,IAAI,MAAKC,UAAW,MAAM,CAAC,CAC9C;AAED,MAAI,cAAc,WAAW,EAAG;EAKhC,MAAM,YAAgD,EAAE;EACxD,IAAI;EACJ,IAAI,iBAAiB,cAAc;EAEnC,MAAM,cAAc,WAAwC;AAC1D,aAAU,KAAK,OAAO;AACtB;AACA,cAAW;;AAIb,OAAK,MAAM,CAAC,IAAI,gBAAgB,cAC9B,EAAC,YAAY;AACX,OAAI;AACF,YAAQ,YAAY,MAAM,OAA1B;KACE,KAAK;AACH,iBAAW;OACT;OACA,MAAM,MAAM,YAAY,YAAY,MAAM,OAAO;OAClD,CAAC;AACF;KACF,KAAK;AACH,iBAAW;OAAE;OAAI,MAAM,YAAY,MAAM;OAAM,CAAC;AAChD;KACF,KAAK;AACH,iBAAW,EAAE,OAAO,YAAY,MAAM,OAAO,CAAC;AAC9C;;YAEG,OAAO;AACd,eAAW,EAAE,OAAO,CAAC;;MAErB;AAIN,SAAO,iBAAiB,KAAK,UAAU,SAAS,GAAG;AACjD,OAAI,UAAU,WAAW,GAAG;AAC1B,UAAM,IAAI,SAAe,MAAM;AAC7B,eAAU;MACV;AACF,cAAU;;AAEZ,QAAK,MAAM,UAAU,UAAU,OAAO,EAAE,CACtC,KAAI,WAAW,OACb,QAAO,KAAK,OAAO,MAAM;OAEzB,OAAM;;AAKZ,MAAI,OAAO,SAAS,EAClB,OAAM,IAAI,eAAe,OAAO;;;AAKtC,MAAa,gBAAgB,IAAI,eAAe;;;;;;;;;AAUhD,SAAgB,MAAM,SAAkC;CACtD,MAAM,KAAK,gBAAgB,OAAO,YAAY,CAAC;AAC/C,eAAc,SAAS,SAAS,GAAG;AAEnC,QAAO,oBAAC,iBAAc,UAAU,KAAM"}
@@ -0,0 +1,30 @@
1
+ import { DeferRegistry, defer } from "./defer.mjs";
2
+
3
+ //#region src/rsc/entry.d.ts
4
+ type RscPayload = {
5
+ root: React.ReactNode;
6
+ };
7
+ /**
8
+ * Entrypoint to serve HTML response in dev environment
9
+ */
10
+ declare function serveHTML(): Promise<Response>;
11
+ declare class ServeRSCError extends Error {
12
+ status: 404 | 500;
13
+ constructor(message: string, status: 404 | 500);
14
+ }
15
+ declare function isServeRSCError(error: unknown): error is ServeRSCError;
16
+ /**
17
+ * Servers an RSC stream response
18
+ */
19
+ declare function serveRSC(request: Request): Promise<Response>;
20
+ /**
21
+ * Build handler
22
+ */
23
+ declare function build(): Promise<{
24
+ html: ReadableStream<Uint8Array<ArrayBufferLike>>;
25
+ appRsc: ReadableStream<Uint8Array<ArrayBufferLike>>;
26
+ deferRegistry: DeferRegistry;
27
+ }>;
28
+ //#endregion
29
+ export { RscPayload, build, isServeRSCError, serveHTML, serveRSC };
30
+ //# sourceMappingURL=entry.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry.d.mts","names":[],"sources":["../../src/rsc/entry.tsx"],"sourcesContent":[],"mappings":";;;KAQY,UAAA;QACJ,KAAA,CAAM;AADd,CAAA;AAkCA;AAoBC;AAWD;AAOsB,iBAtCA,SAAA,CAAA,CAsCQ,EAtCK,OAsCL,CAtCa,QAsCb,CAAA;cAhBxB,aAAA,SAAsB,KAAA,CAgBY;EAAkB,MAAA,EAAA,GAAA,GAAA,GAAA;EAAR,WAAA,CAAA,OAAA,EAAA,MAAA,EAAA,MAAA,EAAA,GAAA,GAAA,GAAA;;AAqD5B,iBA5DN,eAAA,CA4DW,KAAA,EAAA,OAAA,CAAA,EAAA,KAAA,IA5D+B,aA4D/B;;;;iBArDL,QAAA,UAAkB,UAAU,QAAQ;;;;AAqD/B,iBAAL,KAAA,CAAA,CAAK,EAAA,OAAA,CAAA;EAAA,IAAA,gBAAA,WAAA,gBAAA,CAAA,CAAA"}
@@ -0,0 +1,94 @@
1
+ import { extractIDFromModulePath } from "./rscModule.mjs";
2
+ import { devMainRscPath } from "./request.mjs";
3
+ import { stripBasePath } from "../util/basePath.mjs";
4
+ import { defer, deferRegistry } from "./defer.mjs";
5
+ import { generateAppMarker } from "./marker.mjs";
6
+ import { jsx } from "react/jsx-runtime";
7
+ import { renderToReadableStream } from "@vitejs/plugin-rsc/rsc";
8
+
9
+ //#region src/rsc/entry.tsx
10
+ async function devMainRSCStream() {
11
+ const Root = (await import("virtual:funstack/root")).default;
12
+ const App = (await import("virtual:funstack/app")).default;
13
+ if (Root === void 0) throw new Error("Failed to load RSC root entry module. Check your entry file to ensure it has a default export.");
14
+ if (App === void 0) throw new Error("Failed to load RSC app entry module. Check your entry file to ensure it has a default export.");
15
+ return renderToReadableStream({ root: /* @__PURE__ */ jsx(Root, { children: /* @__PURE__ */ jsx(App, {}) }) });
16
+ }
17
+ /**
18
+ * Entrypoint to serve HTML response in dev environment
19
+ */
20
+ async function serveHTML() {
21
+ const marker = generateAppMarker();
22
+ const rootRscStream = await devMainRSCStream();
23
+ const ssrResult = await (await import.meta.viteRsc.loadModule("ssr")).renderHTML(rootRscStream, {
24
+ appEntryMarker: marker,
25
+ build: false
26
+ });
27
+ return new Response(ssrResult.stream, {
28
+ status: ssrResult.status,
29
+ headers: { "Content-type": "text/html" }
30
+ });
31
+ }
32
+ var ServeRSCError = class extends Error {
33
+ status;
34
+ constructor(message, status) {
35
+ super(message);
36
+ this.name = "ServeRSCError";
37
+ this.status = status;
38
+ }
39
+ };
40
+ function isServeRSCError(error) {
41
+ return error instanceof Error && error.name === "ServeRSCError";
42
+ }
43
+ /**
44
+ * Servers an RSC stream response
45
+ */
46
+ async function serveRSC(request) {
47
+ const pathname = stripBasePath(new URL(request.url).pathname);
48
+ if (pathname === devMainRscPath) {
49
+ const rootRscStream = await devMainRSCStream();
50
+ return new Response(rootRscStream, {
51
+ status: 200,
52
+ headers: { "content-type": "text/x-component;charset=utf-8" }
53
+ });
54
+ }
55
+ const moduleId = extractIDFromModulePath(pathname);
56
+ if (!moduleId) throw new ServeRSCError(`Invalid RSC module path: ${pathname}`, 404);
57
+ const entry = deferRegistry.load(moduleId);
58
+ if (!entry) throw new ServeRSCError(`RSC component not found: ${moduleId}`, 404);
59
+ const { state } = entry;
60
+ switch (state.state) {
61
+ case "streaming": return new Response(state.stream, {
62
+ status: 200,
63
+ headers: { "content-type": "text/x-component;charset=utf-8" }
64
+ });
65
+ case "ready": return new Response(state.data, {
66
+ status: 200,
67
+ headers: { "content-type": "text/x-component;charset=utf-8" }
68
+ });
69
+ case "error": throw new ServeRSCError(`Failed to load RSC component: ${state.error}`, 500);
70
+ }
71
+ }
72
+ /**
73
+ * Build handler
74
+ */
75
+ async function build() {
76
+ const marker = generateAppMarker();
77
+ const Root = (await import("virtual:funstack/root")).default;
78
+ const App = (await import("virtual:funstack/app")).default;
79
+ const rootRscStream = renderToReadableStream({ root: /* @__PURE__ */ jsx(Root, { children: /* @__PURE__ */ jsx("span", { id: marker }) }) });
80
+ const appRscStream = renderToReadableStream({ root: /* @__PURE__ */ jsx(App, {}) });
81
+ return {
82
+ html: (await (await import.meta.viteRsc.loadModule("ssr")).renderHTML(rootRscStream, {
83
+ appEntryMarker: marker,
84
+ build: true
85
+ })).stream,
86
+ appRsc: appRscStream,
87
+ deferRegistry
88
+ };
89
+ }
90
+ if (import.meta.hot) import.meta.hot.accept();
91
+
92
+ //#endregion
93
+ export { build, isServeRSCError, serveHTML, serveRSC };
94
+ //# sourceMappingURL=entry.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry.mjs","names":[],"sources":["../../src/rsc/entry.tsx"],"sourcesContent":["import \"./defer\";\nimport { renderToReadableStream } from \"@vitejs/plugin-rsc/rsc\";\nimport { devMainRscPath } from \"./request\";\nimport { generateAppMarker } from \"./marker\";\nimport { deferRegistry } from \"./defer\";\nimport { extractIDFromModulePath } from \"./rscModule\";\nimport { stripBasePath } from \"../util/basePath\";\n\nexport type RscPayload = {\n root: React.ReactNode;\n};\n\nasync function devMainRSCStream() {\n const Root = (await import(\"virtual:funstack/root\")).default;\n const App = (await import(\"virtual:funstack/app\")).default;\n\n // Sanity check; this may happen when user-provided entry file\n // does not have a default export.\n if (Root === undefined) {\n throw new Error(\n \"Failed to load RSC root entry module. Check your entry file to ensure it has a default export.\",\n );\n }\n if (App === undefined) {\n throw new Error(\n \"Failed to load RSC app entry module. Check your entry file to ensure it has a default export.\",\n );\n }\n\n const rootRscStream = renderToReadableStream<RscPayload>({\n root: (\n <Root>\n <App />\n </Root>\n ),\n });\n return rootRscStream;\n}\n\n/**\n * Entrypoint to serve HTML response in dev environment\n */\nexport async function serveHTML(): Promise<Response> {\n const marker = generateAppMarker();\n\n const rootRscStream = await devMainRSCStream();\n\n const ssrEntryModule = await import.meta.viteRsc.loadModule<\n typeof import(\"../ssr/entry\")\n >(\"ssr\");\n const ssrResult = await ssrEntryModule.renderHTML(rootRscStream, {\n appEntryMarker: marker,\n build: false,\n });\n\n // respond html\n return new Response(ssrResult.stream, {\n status: ssrResult.status,\n headers: {\n \"Content-type\": \"text/html\",\n },\n });\n}\n\nclass ServeRSCError extends Error {\n status: 404 | 500;\n constructor(message: string, status: 404 | 500) {\n super(message);\n this.name = \"ServeRSCError\";\n this.status = status;\n }\n}\n\nexport function isServeRSCError(error: unknown): error is ServeRSCError {\n return error instanceof Error && error.name === \"ServeRSCError\";\n}\n\n/**\n * Servers an RSC stream response\n */\nexport async function serveRSC(request: Request): Promise<Response> {\n const url = new URL(request.url);\n const pathname = stripBasePath(url.pathname);\n if (pathname === devMainRscPath) {\n // root RSC stream is requested\n const rootRscStream = await devMainRSCStream();\n return new Response(rootRscStream, {\n status: 200,\n headers: {\n \"content-type\": \"text/x-component;charset=utf-8\",\n },\n });\n }\n\n const moduleId = extractIDFromModulePath(pathname);\n if (!moduleId) {\n throw new ServeRSCError(`Invalid RSC module path: ${pathname}`, 404);\n }\n\n const entry = deferRegistry.load(moduleId);\n if (!entry) {\n throw new ServeRSCError(`RSC component not found: ${moduleId}`, 404);\n }\n const { state } = entry;\n switch (state.state) {\n case \"streaming\": {\n return new Response(state.stream, {\n status: 200,\n headers: {\n \"content-type\": \"text/x-component;charset=utf-8\",\n },\n });\n }\n case \"ready\": {\n return new Response(state.data, {\n status: 200,\n headers: {\n \"content-type\": \"text/x-component;charset=utf-8\",\n },\n });\n }\n case \"error\": {\n throw new ServeRSCError(\n `Failed to load RSC component: ${state.error}`,\n 500,\n );\n }\n }\n}\n\n/**\n * Build handler\n */\nexport async function build() {\n const marker = generateAppMarker();\n\n const Root = (await import(\"virtual:funstack/root\")).default;\n const App = (await import(\"virtual:funstack/app\")).default;\n\n const rootRscStream = renderToReadableStream<RscPayload>({\n root: (\n <Root>\n <span id={marker} />\n </Root>\n ),\n });\n\n const appRscStream = renderToReadableStream<RscPayload>({\n root: <App />,\n });\n\n const ssrEntryModule = await import.meta.viteRsc.loadModule<\n typeof import(\"../ssr/entry\")\n >(\"ssr\");\n\n const ssrResult = await ssrEntryModule.renderHTML(rootRscStream, {\n appEntryMarker: marker,\n build: true,\n });\n\n return {\n html: ssrResult.stream,\n appRsc: appRscStream,\n deferRegistry,\n };\n}\n\nexport { defer } from \"./defer\";\n\nif (import.meta.hot) {\n import.meta.hot.accept();\n}\n"],"mappings":";;;;;;;;;AAYA,eAAe,mBAAmB;CAChC,MAAM,QAAQ,MAAM,OAAO,0BAA0B;CACrD,MAAM,OAAO,MAAM,OAAO,yBAAyB;AAInD,KAAI,SAAS,OACX,OAAM,IAAI,MACR,iGACD;AAEH,KAAI,QAAQ,OACV,OAAM,IAAI,MACR,gGACD;AAUH,QAPsB,uBAAmC,EACvD,MACE,oBAAC,kBACC,oBAAC,QAAM,GACF,EAEV,CAAC;;;;;AAOJ,eAAsB,YAA+B;CACnD,MAAM,SAAS,mBAAmB;CAElC,MAAM,gBAAgB,MAAM,kBAAkB;CAK9C,MAAM,YAAY,OAHK,MAAM,OAAO,KAAK,QAAQ,WAE/C,MAAM,EAC+B,WAAW,eAAe;EAC/D,gBAAgB;EAChB,OAAO;EACR,CAAC;AAGF,QAAO,IAAI,SAAS,UAAU,QAAQ;EACpC,QAAQ,UAAU;EAClB,SAAS,EACP,gBAAgB,aACjB;EACF,CAAC;;AAGJ,IAAM,gBAAN,cAA4B,MAAM;CAChC;CACA,YAAY,SAAiB,QAAmB;AAC9C,QAAM,QAAQ;AACd,OAAK,OAAO;AACZ,OAAK,SAAS;;;AAIlB,SAAgB,gBAAgB,OAAwC;AACtE,QAAO,iBAAiB,SAAS,MAAM,SAAS;;;;;AAMlD,eAAsB,SAAS,SAAqC;CAElE,MAAM,WAAW,cADL,IAAI,IAAI,QAAQ,IAAI,CACG,SAAS;AAC5C,KAAI,aAAa,gBAAgB;EAE/B,MAAM,gBAAgB,MAAM,kBAAkB;AAC9C,SAAO,IAAI,SAAS,eAAe;GACjC,QAAQ;GACR,SAAS,EACP,gBAAgB,kCACjB;GACF,CAAC;;CAGJ,MAAM,WAAW,wBAAwB,SAAS;AAClD,KAAI,CAAC,SACH,OAAM,IAAI,cAAc,4BAA4B,YAAY,IAAI;CAGtE,MAAM,QAAQ,cAAc,KAAK,SAAS;AAC1C,KAAI,CAAC,MACH,OAAM,IAAI,cAAc,4BAA4B,YAAY,IAAI;CAEtE,MAAM,EAAE,UAAU;AAClB,SAAQ,MAAM,OAAd;EACE,KAAK,YACH,QAAO,IAAI,SAAS,MAAM,QAAQ;GAChC,QAAQ;GACR,SAAS,EACP,gBAAgB,kCACjB;GACF,CAAC;EAEJ,KAAK,QACH,QAAO,IAAI,SAAS,MAAM,MAAM;GAC9B,QAAQ;GACR,SAAS,EACP,gBAAgB,kCACjB;GACF,CAAC;EAEJ,KAAK,QACH,OAAM,IAAI,cACR,iCAAiC,MAAM,SACvC,IACD;;;;;;AAQP,eAAsB,QAAQ;CAC5B,MAAM,SAAS,mBAAmB;CAElC,MAAM,QAAQ,MAAM,OAAO,0BAA0B;CACrD,MAAM,OAAO,MAAM,OAAO,yBAAyB;CAEnD,MAAM,gBAAgB,uBAAmC,EACvD,MACE,oBAAC,kBACC,oBAAC,UAAK,IAAI,SAAU,GACf,EAEV,CAAC;CAEF,MAAM,eAAe,uBAAmC,EACtD,MAAM,oBAAC,QAAM,EACd,CAAC;AAWF,QAAO;EACL,OANgB,OAJK,MAAM,OAAO,KAAK,QAAQ,WAE/C,MAAM,EAE+B,WAAW,eAAe;GAC/D,gBAAgB;GAChB,OAAO;GACR,CAAC,EAGgB;EAChB,QAAQ;EACR;EACD;;AAKH,IAAI,OAAO,KAAK,IACd,QAAO,KAAK,IAAI,QAAQ"}
@@ -0,0 +1,15 @@
1
+ //#region src/rsc/marker.ts
2
+ /**
3
+ * Prefix of marker for App entry point.
4
+ */
5
+ const markerPrefix = "__FUNSTACK_APP_ENTRY__";
6
+ /**
7
+ * Generates an HTML ID for marking App entry point.
8
+ */
9
+ function generateAppMarker() {
10
+ return `${markerPrefix}${crypto.randomUUID()}`;
11
+ }
12
+
13
+ //#endregion
14
+ export { generateAppMarker };
15
+ //# sourceMappingURL=marker.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"marker.mjs","names":[],"sources":["../../src/rsc/marker.ts"],"sourcesContent":["/**\n * Prefix of marker for App entry point.\n */\nconst markerPrefix = \"__FUNSTACK_APP_ENTRY__\";\n\n/**\n * Generates an HTML ID for marking App entry point.\n */\nexport function generateAppMarker(): string {\n return `${markerPrefix}${crypto.randomUUID()}`;\n}\n"],"mappings":";;;;AAGA,MAAM,eAAe;;;;AAKrB,SAAgB,oBAA4B;AAC1C,QAAO,GAAG,eAAe,OAAO,YAAY"}
@@ -0,0 +1,9 @@
1
+ //#region src/rsc/request.tsx
2
+ /**
3
+ * Path of RSC stream endpoint in development environment.
4
+ */
5
+ const devMainRscPath = "/funstack__/rsc";
6
+
7
+ //#endregion
8
+ export { devMainRscPath };
9
+ //# sourceMappingURL=request.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request.mjs","names":[],"sources":["../../src/rsc/request.tsx"],"sourcesContent":["/**\n * Path of RSC stream endpoint in development environment.\n */\nexport const devMainRscPath = \"/funstack__/rsc\";\n"],"mappings":";;;;AAGA,MAAa,iBAAiB"}
@@ -0,0 +1,25 @@
1
+ //#region src/rsc/rscModule.ts
2
+ /**
3
+ * ID is prefixed with this string to form module path.
4
+ */
5
+ const rscPayloadIDPrefix = "fun:rsc-payload/";
6
+ /**
7
+ * Add prefix to raw ID to form payload ID so that the ID is
8
+ * distinguishable from other possible IDs.
9
+ */
10
+ function getPayloadIDFor(rawId) {
11
+ return `${rscPayloadIDPrefix}${rawId}`;
12
+ }
13
+ const rscModulePathPrefix = "/funstack__/";
14
+ const rscModulePathSuffix = ".txt";
15
+ function getModulePathFor(id) {
16
+ return `${rscModulePathPrefix}${id}${rscModulePathSuffix}`;
17
+ }
18
+ function extractIDFromModulePath(modulePath) {
19
+ if (!modulePath.startsWith(rscModulePathPrefix) || !modulePath.endsWith(rscModulePathSuffix)) return;
20
+ return modulePath.slice(12, -4);
21
+ }
22
+
23
+ //#endregion
24
+ export { extractIDFromModulePath, getModulePathFor, getPayloadIDFor };
25
+ //# sourceMappingURL=rscModule.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rscModule.mjs","names":[],"sources":["../../src/rsc/rscModule.ts"],"sourcesContent":["/**\n * ID is prefixed with this string to form module path.\n */\nconst rscPayloadIDPrefix = \"fun:rsc-payload/\";\n\n/**\n * Add prefix to raw ID to form payload ID so that the ID is\n * distinguishable from other possible IDs.\n */\nexport function getPayloadIDFor(rawId: string): string {\n return `${rscPayloadIDPrefix}${rawId}`;\n}\n\nconst rscModulePathPrefix = \"/funstack__/\";\nconst rscModulePathSuffix = \".txt\";\n\nexport function getModulePathFor(id: string): string {\n return `${rscModulePathPrefix}${id}${rscModulePathSuffix}`;\n}\n\nexport function extractIDFromModulePath(\n modulePath: string,\n): string | undefined {\n if (\n !modulePath.startsWith(rscModulePathPrefix) ||\n !modulePath.endsWith(rscModulePathSuffix)\n ) {\n return undefined;\n }\n return modulePath.slice(\n rscModulePathPrefix.length,\n -rscModulePathSuffix.length,\n );\n}\n"],"mappings":";;;;AAGA,MAAM,qBAAqB;;;;;AAM3B,SAAgB,gBAAgB,OAAuB;AACrD,QAAO,GAAG,qBAAqB;;AAGjC,MAAM,sBAAsB;AAC5B,MAAM,sBAAsB;AAE5B,SAAgB,iBAAiB,IAAoB;AACnD,QAAO,GAAG,sBAAsB,KAAK;;AAGvC,SAAgB,wBACd,YACoB;AACpB,KACE,CAAC,WAAW,WAAW,oBAAoB,IAC3C,CAAC,WAAW,SAAS,oBAAoB,CAEzC;AAEF,QAAO,WAAW,MAChB,IACA,GACD"}
@@ -0,0 +1,12 @@
1
+ import { DeferRegistry } from "../rsc/defer.mjs";
2
+ import React from "react";
3
+
4
+ //#region src/rsc-client/clientWrapper.d.ts
5
+ declare const RegistryContext: React.Context<DeferRegistry | undefined>;
6
+ interface ClientWrapperProps {
7
+ moduleID: string;
8
+ }
9
+ declare const ClientWrapper: React.FC<ClientWrapperProps>;
10
+ //#endregion
11
+ export { ClientWrapper, RegistryContext };
12
+ //# sourceMappingURL=clientWrapper.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clientWrapper.d.mts","names":[],"sources":["../../src/rsc-client/clientWrapper.tsx"],"sourcesContent":[],"mappings":";;;;cAUa,iBAAe,KAAA,CAAA,QAAA;UAIlB,kBAAA;EAJG,QAAA,EAAA,MAAA;AAEX;AAMW,cAAA,aAAwB,EAAT,KAAA,CAAM,EAAG,CAAA,kBAAD,CAAA"}