react-server-frame 0.0.1

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/README.md ADDED
@@ -0,0 +1,69 @@
1
+ # A new type of RSC routing based on `<Frame />`
2
+
3
+ New type of RSC routing inspired by iFrames and Remix 3.
4
+
5
+ ## How it works
6
+
7
+ ### Define your routes
8
+
9
+ ```ts
10
+ import { route } from "remix/fetch-router/routes";
11
+
12
+ export const routes = route({
13
+ frames: {
14
+ home: "/",
15
+ about: "/about",
16
+ partials: {
17
+ sidebar: "/frame/sidebar",
18
+ },
19
+ },
20
+ });
21
+ ```
22
+
23
+ ### Map your components and render a `<Frame />` for the current location
24
+
25
+ ```tsx
26
+ const router = createRouter();
27
+
28
+ router.route("ANY", "*", {
29
+ handler: ({ request }) => {
30
+ return render(
31
+ request,
32
+ <ProvideFrames
33
+ frames={routes.frames}
34
+ components={{
35
+ about: About,
36
+ home: Home,
37
+ partials: {
38
+ sidebar: Sidebar,
39
+ },
40
+ }}
41
+ >
42
+ <Frame src={request.url} />
43
+ </ProvideFrames>,
44
+ );
45
+ },
46
+ });
47
+ ```
48
+
49
+ ### Nest frames
50
+
51
+ ```tsx
52
+ <Suspense fallback={<p>Loading sidebar...</p>}>
53
+ <Frame src={routes.frames.partials.sidebar.href()} />
54
+ </Suspense>
55
+ ```
56
+
57
+ ### Revalidate frames
58
+
59
+ ```tsx
60
+ "use client";
61
+
62
+ import { useFrame } from "react-server-frame/client";
63
+
64
+ export function ReloadFrame() {
65
+ const { pending, reload } = useFrame();
66
+
67
+ return <button onClick={reload}>Reload{pending ? "ing..." : ""}</button>;
68
+ }
69
+ ```
@@ -0,0 +1,24 @@
1
+ import * as _$react_jsx_runtime0 from "react/jsx-runtime";
2
+
3
+ //#region src/frames.client.d.ts
4
+ type Frame = {
5
+ pending: boolean;
6
+ reload: () => void;
7
+ };
8
+ declare function FetchFrameProvider({
9
+ children,
10
+ fetchFrame
11
+ }: {
12
+ children: React.ReactNode;
13
+ fetchFrame?: (url: URL, signal: AbortSignal) => Promise<React.ReactNode>;
14
+ }): _$react_jsx_runtime0.JSX.Element;
15
+ declare function useFrame(): Frame;
16
+ declare function ClientFrame({
17
+ children,
18
+ src
19
+ }: {
20
+ children?: React.ReactNode;
21
+ src: string;
22
+ }): _$react_jsx_runtime0.JSX.Element;
23
+ //#endregion
24
+ export { ClientFrame, FetchFrameProvider, useFrame };
@@ -0,0 +1,52 @@
1
+ "use client";
2
+ import { createContext, use, useCallback, useMemo, useRef, useState, useTransition } from "react";
3
+ import { jsx } from "react/jsx-runtime";
4
+ //#region src/frames.client.tsx
5
+ const FrameContext = createContext(void 0);
6
+ FrameContext.displayName = "FrameContext";
7
+ const FetchFrameContext = createContext(void 0);
8
+ function FetchFrameProvider({ children, fetchFrame }) {
9
+ return /* @__PURE__ */ jsx(FetchFrameContext.Provider, {
10
+ value: fetchFrame,
11
+ children
12
+ });
13
+ }
14
+ function useFrame() {
15
+ let frame = use(FrameContext);
16
+ if (!frame) throw new Error("useFrame must be used within a Frame / ClientFrame");
17
+ return frame;
18
+ }
19
+ function isPromise(value) {
20
+ return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
21
+ }
22
+ function ClientFrame({ children, src }) {
23
+ const [_content, setContent] = useState(children);
24
+ const content = isPromise(_content) ? use(_content) : _content;
25
+ const [pending, startTransition] = useTransition();
26
+ const [lastChildren, setLastChildren] = useState(children);
27
+ if (lastChildren !== children) {
28
+ setLastChildren(children);
29
+ setContent(children);
30
+ }
31
+ const controllerRef = useRef(void 0);
32
+ const fetchFrame = use(FetchFrameContext);
33
+ const reload = useCallback(() => {
34
+ if (!fetchFrame) throw new Error("FetchFrameContext is not provided");
35
+ const thisController = new AbortController();
36
+ startTransition(() => setContent(fetchFrame(new URL(src, window.location.href), thisController.signal)));
37
+ controllerRef.current?.abort();
38
+ controllerRef.current = thisController;
39
+ }, [fetchFrame, src]);
40
+ const frame = useMemo(() => {
41
+ return {
42
+ pending,
43
+ reload
44
+ };
45
+ }, [pending, reload]);
46
+ return /* @__PURE__ */ jsx(FrameContext.Provider, {
47
+ value: frame,
48
+ children: content
49
+ });
50
+ }
51
+ //#endregion
52
+ export { ClientFrame, FetchFrameProvider, useFrame };
@@ -0,0 +1,57 @@
1
+ import * as _$react_jsx_runtime0 from "react/jsx-runtime";
2
+ import { ReactFormState } from "react-dom/client";
3
+ import { Route } from "remix/fetch-router/routes";
4
+
5
+ //#region src/frames.d.ts
6
+ declare class UseServerState {
7
+ formState?: ReactFormState;
8
+ returnValue?: Promise<unknown>;
9
+ temporaryReferences?: unknown;
10
+ status?: number;
11
+ constructor(formState: ReactFormState | undefined, returnValue: Promise<unknown> | undefined, temporaryReferences: unknown, status: number | undefined);
12
+ }
13
+ declare class RedirectState {
14
+ location: string;
15
+ constructor(location: string);
16
+ }
17
+ declare function redirect(location: string): void;
18
+ declare function render({
19
+ createTemporaryReferenceSet,
20
+ prerender,
21
+ renderToReadableStream,
22
+ request,
23
+ root
24
+ }: {
25
+ createTemporaryReferenceSet: () => unknown;
26
+ prerender: (body: ReadableStream<Uint8Array>) => Promise<Response>;
27
+ renderToReadableStream: (payload: any, options: {
28
+ temporaryReferences: unknown;
29
+ onError: (error: unknown) => string | undefined;
30
+ }) => ReadableStream<Uint8Array>;
31
+ request: Request;
32
+ root: React.ReactNode;
33
+ }): Promise<Response>;
34
+ declare class NotFoundError extends Error {
35
+ constructor(message: string);
36
+ }
37
+ interface Routes extends Record<string, Route | Routes> {}
38
+ type Components<R extends Record<any, any>> = { [K in keyof R]: (R[K] extends Record<any, any> ? Components<R[K]> : never) | React.ComponentType };
39
+ type ProvideFramesProps<Frames extends Routes> = {
40
+ children?: React.ReactNode;
41
+ components: Components<Frames>;
42
+ fetchFrame: (url: URL, signal: AbortSignal) => Promise<React.ReactNode>;
43
+ frames: Frames;
44
+ };
45
+ declare function ProvideFrames<Frames extends Routes>({
46
+ children,
47
+ components,
48
+ fetchFrame,
49
+ frames
50
+ }: ProvideFramesProps<Frames>): _$react_jsx_runtime0.JSX.Element;
51
+ declare function Frame({
52
+ src
53
+ }: {
54
+ src: string;
55
+ }): _$react_jsx_runtime0.JSX.Element;
56
+ //#endregion
57
+ export { Frame, NotFoundError, ProvideFrames, ProvideFramesProps, RedirectState, UseServerState, redirect, render };
package/dist/index.mjs ADDED
@@ -0,0 +1,106 @@
1
+ import { ClientFrame, FetchFrameProvider } from "./client.mjs";
2
+ import { cache } from "react";
3
+ import { getContext } from "remix/async-context-middleware";
4
+ import { jsx } from "react/jsx-runtime";
5
+ //#region src/frames.tsx
6
+ var UseServerState = class {
7
+ formState;
8
+ returnValue;
9
+ temporaryReferences;
10
+ status;
11
+ constructor(formState, returnValue, temporaryReferences, status) {
12
+ this.formState = formState;
13
+ this.returnValue = returnValue;
14
+ this.temporaryReferences = temporaryReferences;
15
+ this.status = status;
16
+ }
17
+ };
18
+ var RedirectState = class {
19
+ location;
20
+ constructor(location) {
21
+ this.location = location;
22
+ }
23
+ };
24
+ function redirect(location) {
25
+ getContext().set(RedirectState, new RedirectState(location));
26
+ }
27
+ async function render({ createTemporaryReferenceSet, prerender, renderToReadableStream, request, root }) {
28
+ const ctx = getContext();
29
+ let redirect;
30
+ try {
31
+ redirect = ctx.get(RedirectState);
32
+ } catch {}
33
+ let state;
34
+ try {
35
+ state = ctx.get(UseServerState);
36
+ } catch {}
37
+ try {
38
+ const body = renderToReadableStream(redirect ? {
39
+ type: "redirect",
40
+ redirect: redirect.location,
41
+ returnValue: state?.returnValue
42
+ } : {
43
+ type: "render",
44
+ root,
45
+ returnValue: state?.returnValue,
46
+ formState: state?.formState
47
+ }, {
48
+ temporaryReferences: state?.temporaryReferences ?? createTemporaryReferenceSet(),
49
+ onError(error) {
50
+ if (error instanceof NotFoundError) return "404";
51
+ if (request.signal.aborted) return;
52
+ console.error(error);
53
+ }
54
+ });
55
+ if (new URL(request.url).pathname.endsWith(".rsc")) return new Response(body, { headers: { "Content-Type": "text/x-component; charset=utf-8" } });
56
+ return await prerender(body);
57
+ } catch (reason) {
58
+ if (reason instanceof Error && reason.name === "NotFoundError") return new Response("Not Found", { status: 404 });
59
+ if (!request.signal.aborted) console.error(reason);
60
+ return new Response("Internal Server Error", { status: 500 });
61
+ }
62
+ }
63
+ const frameCache = cache(() => ({}));
64
+ var NotFoundError = class extends Error {
65
+ constructor(message) {
66
+ super(message);
67
+ this.name = "NotFoundError";
68
+ }
69
+ };
70
+ function ProvideFrames({ children, components, fetchFrame, frames }) {
71
+ const cache = frameCache();
72
+ cache.components = {
73
+ ...cache.components,
74
+ ...components
75
+ };
76
+ cache.frames = {
77
+ ...cache.frames,
78
+ ...frames
79
+ };
80
+ return /* @__PURE__ */ jsx(FetchFrameProvider, {
81
+ fetchFrame,
82
+ children
83
+ });
84
+ }
85
+ function Frame({ src }) {
86
+ const cache = frameCache();
87
+ if (!cache.components || !cache.frames) throw new Error("No frames provided");
88
+ const url = new URL(src, "http://react-server-frame/");
89
+ if (url.pathname.endsWith(".rsc")) url.pathname = url.pathname.slice(0, -4);
90
+ const Component = match(cache.frames, cache.components, url.href);
91
+ if (!Component) throw new NotFoundError("No matching frame found");
92
+ return /* @__PURE__ */ jsx(ClientFrame, {
93
+ src: url.pathname + url.search,
94
+ children: /* @__PURE__ */ jsx(Component, {})
95
+ });
96
+ }
97
+ function match(frames, components, href) {
98
+ for (const [id, route] of Object.entries(frames)) if (typeof route.pattern?.test === "function") {
99
+ if (route.pattern.test(href)) return components?.[id];
100
+ } else {
101
+ let matched = match(route, components?.[id], href);
102
+ if (matched) return matched;
103
+ }
104
+ }
105
+ //#endregion
106
+ export { Frame, NotFoundError, ProvideFrames, RedirectState, UseServerState, redirect, render };
@@ -0,0 +1,123 @@
1
+ import {
2
+ createFromFetch,
3
+ createFromReadableStream,
4
+ createTemporaryReferenceSet,
5
+ encodeReply,
6
+ setServerCallback,
7
+ } from "@vitejs/plugin-rsc/browser";
8
+ import { startTransition, StrictMode, use, useState } from "react";
9
+ import { hydrateRoot } from "react-dom/client";
10
+ import { rscStream } from "rsc-html-stream/client";
11
+
12
+ import type { Payload } from "../generic-payload.ts";
13
+
14
+ setServerCallback(async (id, args) => {
15
+ const url = new URL(window.location.href);
16
+ url.pathname += ".rsc";
17
+ const temporaryReferences = createTemporaryReferenceSet();
18
+ const payload = await createFromFetch<Payload>(
19
+ fetch(url, {
20
+ method: "POST",
21
+ body: await encodeReply(args, { temporaryReferences }),
22
+ headers: {
23
+ "x-rsc-action": id,
24
+ },
25
+ }),
26
+ { temporaryReferences },
27
+ );
28
+ if (payload.type === "render") {
29
+ startTransition(() => {
30
+ setPayload(Promise.resolve(payload));
31
+ });
32
+ }
33
+ if (payload.type === "redirect") {
34
+ if (window.navigation) {
35
+ navigate(payload.redirect);
36
+ } else {
37
+ window.location.href = payload.redirect;
38
+ }
39
+ }
40
+ return payload.returnValue;
41
+ });
42
+
43
+ createFromReadableStream<Payload>(rscStream).then(
44
+ (payload) =>
45
+ startTransition(() => {
46
+ hydrateRoot(
47
+ document,
48
+ <StrictMode>
49
+ <Content initialPayload={Promise.resolve(payload)} />
50
+ </StrictMode>,
51
+ {
52
+ formState: payload.formState,
53
+ },
54
+ );
55
+ }),
56
+ (reason) => console.error("Failed to hydrate root", reason),
57
+ );
58
+
59
+ let setPayload: (payload: Promise<Payload>) => void;
60
+
61
+ let seenPayloads = new WeakSet<Payload>();
62
+
63
+ function Content({ initialPayload }: { initialPayload: Promise<Payload> }) {
64
+ const [promise, _setPayload] = useState(initialPayload);
65
+ setPayload = _setPayload;
66
+
67
+ const payload = use(promise);
68
+
69
+ if (payload.type === "redirect") {
70
+ if (window.navigation) {
71
+ if (!seenPayloads) {
72
+ navigate(payload.redirect);
73
+ }
74
+ return null;
75
+ } else {
76
+ window.location.href = payload.redirect;
77
+ return null;
78
+ }
79
+ }
80
+
81
+ return payload.root;
82
+ }
83
+
84
+ let navigationController = new AbortController();
85
+ function navigate(to: string) {
86
+ const url = new URL(to, window.location.href);
87
+ url.pathname += ".rsc";
88
+
89
+ if (window.location.host !== url.host) {
90
+ window.location.href = url.href;
91
+ return;
92
+ }
93
+
94
+ let thisController = new AbortController();
95
+ startTransition(() =>
96
+ setPayload(createFromFetch<Payload>(fetch(url, { signal: thisController.signal }))),
97
+ );
98
+ navigationController.abort();
99
+ navigationController = thisController;
100
+ }
101
+
102
+ window.navigation?.addEventListener("navigate", (event) => {
103
+ if (!event.canIntercept) {
104
+ return;
105
+ }
106
+
107
+ if (event.hashChange || event.downloadRequest !== null) {
108
+ return;
109
+ }
110
+
111
+ event.intercept({
112
+ async handler() {
113
+ navigate(event.destination.url);
114
+ },
115
+ });
116
+ });
117
+
118
+ if (import.meta.hot) {
119
+ import.meta.hot.on("rsc:update", (e) => {
120
+ console.log("[vite-rsc:update]", e.file);
121
+ navigate(location.href);
122
+ });
123
+ }
@@ -0,0 +1,62 @@
1
+ import { createFromReadableStream } from "@vitejs/plugin-rsc/ssr";
2
+ import { use } from "react";
3
+ import { renderToReadableStream } from "react-dom/server";
4
+ import { injectRSCPayload } from "rsc-html-stream/server";
5
+
6
+ import type { Payload } from "../generic-payload.ts";
7
+
8
+ export async function prerender(body: ReadableStream<Uint8Array>) {
9
+ const [decodeBody, inlineBody] = body.tee();
10
+
11
+ let decode: Promise<Payload> | undefined;
12
+ function Content() {
13
+ decode ??= createFromReadableStream<Payload>(decodeBody);
14
+ const payload = use(decode);
15
+
16
+ if (payload.type === "redirect") {
17
+ return (
18
+ <html>
19
+ <head></head>
20
+ <body>
21
+ <meta http-equiv="refresh" content={`0; url=${payload.redirect}`} />
22
+ </body>
23
+ </html>
24
+ );
25
+ }
26
+
27
+ return <>{payload.root}</>;
28
+ }
29
+
30
+ let notFoundError = false;
31
+ try {
32
+ const bootstrapScriptContent = await import.meta.viteRsc.loadBootstrapScriptContent("index");
33
+
34
+ const html = await renderToReadableStream(<Content />, {
35
+ bootstrapScriptContent,
36
+ onError(reason: unknown) {
37
+ if (
38
+ typeof reason === "object" &&
39
+ reason !== null &&
40
+ "digest" in reason &&
41
+ reason.digest === "404"
42
+ ) {
43
+ notFoundError = true;
44
+ return reason.digest;
45
+ }
46
+ },
47
+ });
48
+
49
+ const payload = await decode;
50
+ return new Response(html.pipeThrough(injectRSCPayload(inlineBody)), {
51
+ status: payload!.type === "redirect" ? 302 : notFoundError ? 404 : 200,
52
+ headers: {
53
+ "Content-Type": "text/html; charset=utf-8",
54
+ },
55
+ });
56
+ } catch (reason) {
57
+ if (notFoundError) return new Response("Not Found", { status: 404 });
58
+
59
+ console.error("Failed to prerender", reason);
60
+ return new Response("Internal Server Error", { status: 500 });
61
+ }
62
+ }
@@ -0,0 +1,6 @@
1
+ import * as _$react from "react";
2
+
3
+ //#region src/vite/fetch-frame.d.ts
4
+ declare function fetchFrame(url: URL, signal: AbortSignal): Promise<string | number | bigint | boolean | Iterable<_$react.ReactNode> | _$react.ReactElement<unknown, string | _$react.JSXElementConstructor<any>> | _$react.ReactPortal | null | undefined>;
5
+ //#endregion
6
+ export { fetchFrame };
@@ -0,0 +1,18 @@
1
+ "use client";
2
+ //#region src/vite/fetch-frame.ts
3
+ if (typeof document !== "undefined") import("@vitejs/plugin-rsc/browser");
4
+ async function fetchFrame(url, signal) {
5
+ const { createFromFetch } = await import("@vitejs/plugin-rsc/browser");
6
+ url.pathname += ".rsc";
7
+ const payload = await createFromFetch(fetch(url, { signal }));
8
+ if (payload.type === "redirect") if (window.navigation) return Promise.resolve(window.navigation.navigate(payload.redirect, { history: "replace" }).finished).then(() => {
9
+ return null;
10
+ });
11
+ else {
12
+ window.location.href = payload.redirect;
13
+ return;
14
+ }
15
+ return payload.root;
16
+ }
17
+ //#endregion
18
+ export { fetchFrame };
@@ -0,0 +1,10 @@
1
+ import { ProvideFrames as ProvideFrames$1 } from "../index.mjs";
2
+ import * as _$react_jsx_runtime0 from "react/jsx-runtime";
3
+ import { Middleware } from "remix/fetch-router";
4
+
5
+ //#region src/vite/frames.d.ts
6
+ declare function useServerMiddleware(): Middleware;
7
+ declare function render(request: Request, root: React.ReactNode): Promise<Response>;
8
+ declare function ProvideFrames(props: Omit<React.ComponentProps<typeof ProvideFrames$1>, "fetchFrame">): _$react_jsx_runtime0.JSX.Element;
9
+ //#endregion
10
+ export { ProvideFrames, render, useServerMiddleware };
@@ -0,0 +1,56 @@
1
+ import { ProvideFrames as ProvideFrames$1, UseServerState, render as render$1 } from "../index.mjs";
2
+ import { fetchFrame } from "./fetch-frame.mjs";
3
+ import { jsx } from "react/jsx-runtime";
4
+ import { createTemporaryReferenceSet, decodeAction, decodeFormState, decodeReply, loadServerAction, renderToReadableStream } from "@vitejs/plugin-rsc/rsc";
5
+ //#region src/vite/frames.tsx
6
+ function useServerMiddleware() {
7
+ return async ({ request, set }, next) => {
8
+ let formState;
9
+ let returnValue;
10
+ let temporaryReferences;
11
+ let actionStatus;
12
+ if (request.method === "POST") {
13
+ const actionId = request.headers.get("x-rsc-action");
14
+ if (actionId) {
15
+ const body = request.headers.get("content-type")?.startsWith("multipart/form-data") ? await request.formData() : await request.text();
16
+ temporaryReferences = createTemporaryReferenceSet();
17
+ const args = await decodeReply(body, { temporaryReferences });
18
+ const action = await loadServerAction(actionId);
19
+ try {
20
+ returnValue = action.apply(null, args);
21
+ await returnValue;
22
+ } catch (e) {
23
+ actionStatus = 500;
24
+ returnValue = Promise.reject(e);
25
+ }
26
+ } else {
27
+ const formData = await request.formData();
28
+ const decodedAction = await decodeAction(formData);
29
+ try {
30
+ formState = await decodeFormState(await decodedAction(), formData);
31
+ } catch (e) {
32
+ console.error(e);
33
+ }
34
+ }
35
+ }
36
+ set(UseServerState, new UseServerState(formState, returnValue, temporaryReferences, actionStatus));
37
+ return next();
38
+ };
39
+ }
40
+ async function render(request, root) {
41
+ return render$1({
42
+ createTemporaryReferenceSet,
43
+ prerender: (await import.meta.viteRsc.import("./entry.ssr.tsx", { environment: "ssr" })).prerender,
44
+ renderToReadableStream,
45
+ request,
46
+ root
47
+ });
48
+ }
49
+ function ProvideFrames(props) {
50
+ return /* @__PURE__ */ jsx(ProvideFrames$1, {
51
+ ...props,
52
+ fetchFrame
53
+ });
54
+ }
55
+ //#endregion
56
+ export { ProvideFrames, render, useServerMiddleware };
@@ -0,0 +1,13 @@
1
+ import * as Vite from "vite";
2
+
3
+ //#region src/vite/plugin.d.ts
4
+ declare function framework({
5
+ entry
6
+ }?: {
7
+ entry?: string;
8
+ }): {
9
+ name: string;
10
+ config(this: Vite.ConfigPluginContext, userConfig: Vite.UserConfig): Record<string, any>;
11
+ };
12
+ //#endregion
13
+ export { framework };
@@ -0,0 +1,21 @@
1
+ import * as path from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ import * as Vite from "vite";
4
+ //#region src/vite/plugin.ts
5
+ function getEntry(file) {
6
+ return Vite.normalizePath(path.join(path.dirname(fileURLToPath(import.meta.url)), file));
7
+ }
8
+ function framework({ entry = "/src/entry.server" } = {}) {
9
+ return {
10
+ name: "framework",
11
+ config(userConfig) {
12
+ return Vite.mergeConfig({ environments: {
13
+ client: { build: { rolldownOptions: { input: { index: getEntry("entry.client.tsx") } } } },
14
+ rsc: { build: { rolldownOptions: { input: { index: entry } } } },
15
+ ssr: { build: { rolldownOptions: { input: { index: getEntry("entry.ssr.tsx") } } } }
16
+ } }, userConfig, true);
17
+ }
18
+ };
19
+ }
20
+ //#endregion
21
+ export { framework };
package/package.json ADDED
@@ -0,0 +1,81 @@
1
+ {
2
+ "name": "react-server-frame",
3
+ "version": "0.0.1",
4
+ "description": "A new type of RSC routing.",
5
+ "homepage": "https://github.com/jacob-ebey/react-server-frame#readme",
6
+ "bugs": {
7
+ "url": "https://github.com/jacob-ebey/react-server-frame/issues"
8
+ },
9
+ "license": "MIT",
10
+ "author": "Jacob Ebey <jacob.ebey@live.com>",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/jacob-ebey/react-server-frame.git"
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "README.md"
18
+ ],
19
+ "type": "module",
20
+ "exports": {
21
+ ".": "./dist/index.mjs",
22
+ "./client": "./dist/client.mjs",
23
+ "./vite/fetch-frame": "./dist/vite/fetch-frame.mjs",
24
+ "./vite/frames": "./dist/vite/frames.mjs",
25
+ "./vite/plugin": "./dist/vite/plugin.mjs",
26
+ "./package.json": "./package.json"
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "scripts": {
32
+ "build": "vp pack",
33
+ "dev": "vp pack --watch",
34
+ "test": "vp test",
35
+ "check": "vp check",
36
+ "prepublishOnly": "vp run build"
37
+ },
38
+ "dependencies": {
39
+ "rsc-html-stream": "0.0.7"
40
+ },
41
+ "devDependencies": {
42
+ "@types/dom-navigation": "^1.0.7",
43
+ "@types/node": "catalog:",
44
+ "@types/react": "catalog:",
45
+ "@types/react-dom": "catalog:",
46
+ "@typescript/native-preview": "catalog:",
47
+ "@vitejs/plugin-react": "^6.0.1",
48
+ "@vitejs/plugin-rsc": "^0.5.21",
49
+ "bumpp": "^11.0.1",
50
+ "react": "catalog:",
51
+ "react-dom": "catalog:",
52
+ "react-server-dom-webpack": "catalog:",
53
+ "remix": "catalog:",
54
+ "typescript": "catalog:",
55
+ "vite": "catalog:",
56
+ "vite-plus": "catalog:"
57
+ },
58
+ "peerDependencies": {
59
+ "@vitejs/plugin-react": "catalog:",
60
+ "@vitejs/plugin-rsc": "catalog:",
61
+ "react": "catalog:",
62
+ "react-dom": "catalog:",
63
+ "react-server-dom-webpack": "catalog:",
64
+ "remix": "*",
65
+ "vite": "*"
66
+ },
67
+ "peerDependenciesMeta": {
68
+ "@vitejs/plugin-react": {
69
+ "optional": true
70
+ },
71
+ "@vitejs/plugin-rsc": {
72
+ "optional": true
73
+ },
74
+ "react-server-dom-webpack": {
75
+ "optional": true
76
+ },
77
+ "vite": {
78
+ "optional": true
79
+ }
80
+ }
81
+ }