@real-router/rsc-server-plugin 0.2.2 → 0.2.3
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/cjs/errors.d.ts.map +1 -1
- package/dist/cjs/errors.js.map +1 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/errors.d.mts.map +1 -1
- package/dist/esm/errors.mjs.map +1 -1
- package/dist/esm/index.d.mts.map +1 -1
- package/dist/esm/index.mjs.map +1 -1
- package/package.json +5 -6
- package/src/actionFactory.ts +0 -148
- package/src/buildRscPayload.ts +0 -64
- package/src/constants.ts +0 -16
- package/src/errors.ts +0 -6
- package/src/factory.ts +0 -56
- package/src/getSsrRscMode.ts +0 -41
- package/src/index.ts +0 -28
- package/src/invalidate.ts +0 -36
- package/src/types.ts +0 -122
package/src/getSsrRscMode.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { ALLOWED_RSC_MODES } from "./constants";
|
|
2
|
-
|
|
3
|
-
import type { RscSsrMode } from "./types";
|
|
4
|
-
import type { State } from "@real-router/types";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Returns the SSR mode resolved by `rsc-server-plugin` for the current state.
|
|
8
|
-
* Falls back to `"full"` when the route has no plugin entry.
|
|
9
|
-
*
|
|
10
|
-
* Read this from `entry-server.tsx` to branch on full vs client-only:
|
|
11
|
-
* - `"full"` — render the Server Component tree, pipe Flight stream.
|
|
12
|
-
* - `"client-only"` — ship shell HTML and let the client fetch via its own mechanism.
|
|
13
|
-
*
|
|
14
|
-
* The mode is written to `state.context.ssrRscMode` by the plugin's `start`
|
|
15
|
-
* interceptor for every route registered in the loaders map.
|
|
16
|
-
*
|
|
17
|
-
* Defensive read: if `state.context.ssrRscMode` was set to something outside
|
|
18
|
-
* `ALLOWED_RSC_MODES` by a TS-cast bypass or a foreign writer, the function
|
|
19
|
-
* collapses it to `"full"` rather than returning the bad value. Without this
|
|
20
|
-
* guard, a downstream `mode === "full"` branch would silently misbehave for
|
|
21
|
-
* `0`, `false`, `""`, `null`, or any unknown string.
|
|
22
|
-
*
|
|
23
|
-
* The read itself is wrapped in `try/catch` — a foreign writer that installs
|
|
24
|
-
* a throwing getter (`Object.defineProperty(ctx, "ssrRscMode", { get() { throw … } })`)
|
|
25
|
-
* cannot break the contract. The function NEVER throws, no matter how
|
|
26
|
-
* adversarial the context shape. `"full"` is the safe default for any error.
|
|
27
|
-
*/
|
|
28
|
-
export function getSsrRscMode(state: State): RscSsrMode {
|
|
29
|
-
let raw: unknown;
|
|
30
|
-
|
|
31
|
-
try {
|
|
32
|
-
raw = (state.context as { ssrRscMode?: unknown }).ssrRscMode;
|
|
33
|
-
} catch {
|
|
34
|
-
return "full";
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return typeof raw === "string" &&
|
|
38
|
-
ALLOWED_RSC_MODES.includes(raw as RscSsrMode)
|
|
39
|
-
? (raw as RscSsrMode)
|
|
40
|
-
: "full";
|
|
41
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
export type {
|
|
2
|
-
RscActionResult,
|
|
3
|
-
RscLoaderFn,
|
|
4
|
-
RscLoaderFactoryMap,
|
|
5
|
-
RscLoaderFnFactory,
|
|
6
|
-
RscPayload,
|
|
7
|
-
RscRouteEntry,
|
|
8
|
-
RscSsrMode,
|
|
9
|
-
SsrLoaderContext,
|
|
10
|
-
} from "./types";
|
|
11
|
-
|
|
12
|
-
export { rscServerPluginFactory } from "./factory";
|
|
13
|
-
|
|
14
|
-
export { rscActionPluginFactory } from "./actionFactory";
|
|
15
|
-
|
|
16
|
-
export { buildRscPayload } from "./buildRscPayload";
|
|
17
|
-
|
|
18
|
-
export { getSsrRscMode } from "./getSsrRscMode";
|
|
19
|
-
|
|
20
|
-
export { invalidate } from "./invalidate";
|
|
21
|
-
|
|
22
|
-
declare module "@real-router/types" {
|
|
23
|
-
interface StateContext {
|
|
24
|
-
rsc?: import("react").ReactNode;
|
|
25
|
-
rscAction?: import("./types").RscActionResult;
|
|
26
|
-
ssrRscMode?: import("./types").RscSsrMode;
|
|
27
|
-
}
|
|
28
|
-
}
|
package/src/invalidate.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { markStale } from "./shared-ssr";
|
|
2
|
-
|
|
3
|
-
import type { Router } from "@real-router/types";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Mark the `"rsc"` namespace as stale on the given router. The next
|
|
7
|
-
* navigation (including a same-route reload) re-runs the RSC loader for the
|
|
8
|
-
* destination route and overwrites `state.context.rsc` (and the mode marker)
|
|
9
|
-
* via the plugin's `subscribeLeave` listener.
|
|
10
|
-
*
|
|
11
|
-
* Honest fire-and-forget semantics — returns `void`. The flag is consumed in
|
|
12
|
-
* the awaited LEAVE_APPROVE phase of the next navigation, so subscribers see
|
|
13
|
-
* a fresh `ReactNode` when the navigation completes. Behaviour during an
|
|
14
|
-
* in-flight transition: the current transition completes unchanged; the flag
|
|
15
|
-
* is read by the *following* navigation. This keeps the invariant
|
|
16
|
-
* "one transition = one `state.context` snapshot" intact.
|
|
17
|
-
*
|
|
18
|
-
* Composability through the existing core API:
|
|
19
|
-
*
|
|
20
|
-
* ```ts
|
|
21
|
-
* // Fire-and-forget: stale until the user navigates somewhere
|
|
22
|
-
* invalidate(router, "rsc");
|
|
23
|
-
*
|
|
24
|
-
* // Explicit await — pair with a same-route reload
|
|
25
|
-
* invalidate(router, "rsc");
|
|
26
|
-
* await router.navigate(state.name, state.params, { reload: true });
|
|
27
|
-
* ```
|
|
28
|
-
*
|
|
29
|
-
* Surgical alternative to `router.navigate({ reload: true })` for multi-
|
|
30
|
-
* namespace routes: only the `"rsc"` namespace re-runs; a side-by-side
|
|
31
|
-
* `ssr-data-plugin` keeps its cached `state.context.data` on this transition
|
|
32
|
-
* unless its own `invalidate()` was also called.
|
|
33
|
-
*/
|
|
34
|
-
export function invalidate(router: Router, namespace: "rsc"): void {
|
|
35
|
-
markStale(router, namespace);
|
|
36
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
SsrLoaderFn,
|
|
3
|
-
SsrLoaderFnFactory,
|
|
4
|
-
SsrMode,
|
|
5
|
-
SsrRouteEntry,
|
|
6
|
-
} from "./shared-ssr";
|
|
7
|
-
import type { DefaultDependencies } from "@real-router/types";
|
|
8
|
-
import type { ReactNode } from "react";
|
|
9
|
-
|
|
10
|
-
export { type SsrLoaderContext } from "./shared-ssr";
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* SSR mode subset supported by `rsc-server-plugin`.
|
|
14
|
-
*
|
|
15
|
-
* `"data-only"` is intentionally excluded — RSC has no concept of "data
|
|
16
|
-
* without component" (the Flight payload IS the data + component). Using
|
|
17
|
-
* `"data-only"` with `rscServerPluginFactory` is a configuration error and
|
|
18
|
-
* is rejected at factory time.
|
|
19
|
-
*/
|
|
20
|
-
export type RscSsrMode = Exclude<SsrMode, "data-only">;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Compiled RSC loader signature.
|
|
24
|
-
*
|
|
25
|
-
* Receives the resolved route's `params` and returns a `ReactNode` (a Server
|
|
26
|
-
* Component element, sync or async). Synchronous return is permitted because
|
|
27
|
-
* many Server Components are synchronous — wrapping them in `Promise.resolve`
|
|
28
|
-
* would be ceremonial.
|
|
29
|
-
*/
|
|
30
|
-
export type RscLoaderFn = SsrLoaderFn<ReactNode>;
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Factory function for creating RSC loaders.
|
|
34
|
-
*
|
|
35
|
-
* Receives the router instance and a dependency getter (same pattern as
|
|
36
|
-
* `DataLoaderFnFactory`/`GuardFnFactory`). Factory runs once at
|
|
37
|
-
* `usePlugin()` time; the returned loader is cached.
|
|
38
|
-
*
|
|
39
|
-
* @template Dependencies - Router dependency map for typed `getDependency()`.
|
|
40
|
-
* Defaults to `DefaultDependencies`. Pass your app's dependency interface
|
|
41
|
-
* for type-safe DI: `RscLoaderFnFactory<AppDependencies>`.
|
|
42
|
-
*/
|
|
43
|
-
export type RscLoaderFnFactory<
|
|
44
|
-
Dependencies extends DefaultDependencies = DefaultDependencies,
|
|
45
|
-
> = SsrLoaderFnFactory<ReactNode, Dependencies>;
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Per-route entry: either a loader factory (short form) or
|
|
49
|
-
* `{ ssr?, loader? }` object form. Mode defaults to `"full"`.
|
|
50
|
-
*
|
|
51
|
-
* Allowed `ssr` values for RSC: `"full"` | `"client-only"` (and the
|
|
52
|
-
* `true` / `false` aliases). `"data-only"` is rejected at factory time.
|
|
53
|
-
*
|
|
54
|
-
* Function form `(state) => RscSsrMode` is resolved per-navigation,
|
|
55
|
-
* **before** the mode is written to context.
|
|
56
|
-
*/
|
|
57
|
-
export type RscRouteEntry<
|
|
58
|
-
Dependencies extends DefaultDependencies = DefaultDependencies,
|
|
59
|
-
> = SsrRouteEntry<ReactNode, RscSsrMode, Dependencies>;
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Map of route name → entry (factory or `{ ssr?, loader? }`).
|
|
63
|
-
*
|
|
64
|
-
* Pass to `rscServerPluginFactory()`. Keys are route names (e.g. `"users.profile"`);
|
|
65
|
-
* values are factory or object-form route entries.
|
|
66
|
-
*/
|
|
67
|
-
export type RscLoaderFactoryMap<
|
|
68
|
-
Dependencies extends DefaultDependencies = DefaultDependencies,
|
|
69
|
-
> = Record<string, RscRouteEntry<Dependencies>>;
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Server Action result published by `rscActionPluginFactory` to
|
|
73
|
-
* `state.context.rscAction`. Consumers read either field at render
|
|
74
|
-
* time. Both are optional — typical flows write one or the other:
|
|
75
|
-
*
|
|
76
|
-
* - `returnValue` — set when the action was invoked via the hydrated
|
|
77
|
-
* client path (`setServerCallback` → `loadServerAction` →
|
|
78
|
-
* `decodeReply` in the RSC entry). Threaded back into
|
|
79
|
-
* `useActionState` on the client.
|
|
80
|
-
* - `formState` — set when the action was invoked via progressive
|
|
81
|
-
* enhancement (`<form action={fn}>` POST without JS) and decoded
|
|
82
|
-
* via `decodeAction(formData)` + `decodeFormState(result, formData)`.
|
|
83
|
-
*
|
|
84
|
-
* Both type parameters default to `unknown` to keep the plugin
|
|
85
|
-
* runtime-only — consumers narrow them at the call site.
|
|
86
|
-
*/
|
|
87
|
-
export interface RscActionResult<TReturn = unknown, TFormState = unknown> {
|
|
88
|
-
returnValue?: { ok: boolean; data: TReturn };
|
|
89
|
-
formState?: TFormState;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Canonical Flight payload shape for RSC apps that ship Server Actions.
|
|
94
|
-
*
|
|
95
|
-
* The pipeline serializes this object via the bundler's RSC stream
|
|
96
|
-
* renderer (e.g. `@vitejs/plugin-rsc/rsc.renderToReadableStream`); the
|
|
97
|
-
* SSR + browser entries deserialize the same shape and thread
|
|
98
|
-
* `returnValue`/`formState` into `useActionState`.
|
|
99
|
-
*
|
|
100
|
-
* Apps without Server Actions can use `RscPayload` with all generics
|
|
101
|
-
* defaulted, or just type their payload as `{ root: ReactNode }`.
|
|
102
|
-
*
|
|
103
|
-
* Type parameters:
|
|
104
|
-
* - `TReturn` — narrowed shape of `returnValue.data` (e.g. mutation
|
|
105
|
-
* confirmation). Defaults to `unknown`.
|
|
106
|
-
* - `TFormState` — narrowed shape of `formState`. Defaults to
|
|
107
|
-
* `unknown` so the plugin stays free of `react-dom/client` import
|
|
108
|
-
* (which carries the canonical `ReactFormState` type). Consumers
|
|
109
|
-
* narrow at call site:
|
|
110
|
-
*
|
|
111
|
-
* ```ts
|
|
112
|
-
* import type { ReactFormState } from "react-dom/client";
|
|
113
|
-
* type AppPayload = RscPayload<{ id: string }, ReactFormState>;
|
|
114
|
-
* ```
|
|
115
|
-
*/
|
|
116
|
-
export interface RscPayload<
|
|
117
|
-
TReturn = unknown,
|
|
118
|
-
TFormState = unknown,
|
|
119
|
-
> extends RscActionResult<TReturn, TFormState> {
|
|
120
|
-
/** Server Component tree to render. */
|
|
121
|
-
root: ReactNode;
|
|
122
|
-
}
|