@rangojs/router 0.16.0 → 0.17.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/README.md +254 -89
- package/dist/testing/vitest.js +252 -0
- package/dist/types/browser/navigation-transaction.d.ts +6 -0
- package/dist/types/browser/partial-update.d.ts +11 -0
- package/dist/types/browser/react/ScrollRestoration.d.ts +6 -6
- package/dist/types/browser/rsc-router.d.ts +1 -1
- package/dist/types/browser/scroll-restoration.d.ts +7 -0
- package/dist/types/cache/cache-exec-scope.d.ts +18 -1
- package/dist/types/cache/cache-scope.d.ts +34 -5
- package/dist/types/cache/handle-capture.d.ts +41 -3
- package/dist/types/cache/handle-snapshot.d.ts +53 -13
- package/dist/types/cache/segment-codec.d.ts +10 -3
- package/dist/types/cache/taint.d.ts +1 -1
- package/dist/types/cache/types.d.ts +15 -3
- package/dist/types/client.d.ts +4 -4
- package/dist/types/client.rsc.d.ts +4 -5
- package/dist/types/components/DefaultDocument.d.ts +5 -2
- package/dist/types/context-var.d.ts +6 -5
- package/dist/types/escape-script.d.ts +1 -1
- package/dist/types/handles/MetaTags.d.ts +5 -4
- package/dist/types/handles/Scripts.d.ts +8 -7
- package/dist/types/handles/meta.d.ts +2 -2
- package/dist/types/handles/script.d.ts +17 -16
- package/dist/types/href-client.d.ts +1 -1
- package/dist/types/html.d.ts +12 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.rsc.d.ts +3 -2
- package/dist/types/loader-store.d.ts +7 -4
- package/dist/types/reverse.d.ts +36 -4
- package/dist/types/route-definition/dsl-helpers.d.ts +3 -3
- package/dist/types/route-definition/helpers-types.d.ts +33 -9
- package/dist/types/route-definition/resolve-handler-use.d.ts +23 -1
- package/dist/types/route-types.d.ts +1 -1
- package/dist/types/router/debug-manifest.d.ts +3 -2
- package/dist/types/router/error-handling.d.ts +20 -0
- package/dist/types/router/handler-context.d.ts +6 -0
- package/dist/types/router/match-middleware/background-revalidation.d.ts +46 -5
- package/dist/types/router/middleware-types.d.ts +3 -2
- package/dist/types/router/router-context.d.ts +3 -1
- package/dist/types/router/router-interfaces.d.ts +24 -2
- package/dist/types/router/router-options.d.ts +8 -5
- package/dist/types/router/segment-resolution/fresh.d.ts +10 -0
- package/dist/types/router/segment-resolution/loader-cache.d.ts +37 -1
- package/dist/types/router/segment-resolution/loader-mask.d.ts +9 -19
- package/dist/types/router/segment-resolution/loader-snapshot.d.ts +3 -3
- package/dist/types/router/segment-resolution/mask-nested.d.ts +7 -7
- package/dist/types/router/segment-resolution/revalidation.d.ts +6 -2
- package/dist/types/router/segment-wrappers.d.ts +1 -1
- package/dist/types/rsc/response-route-handler.d.ts +1 -1
- package/dist/types/rsc/rsc-rendering.d.ts +1 -2
- package/dist/types/rsc/shell-capture-constants.d.ts +8 -0
- package/dist/types/rsc/shell-capture.d.ts +5 -4
- package/dist/types/rsc/ssr-setup.d.ts +6 -6
- package/dist/types/rsc/types.d.ts +10 -0
- package/dist/types/server/context.d.ts +33 -3
- package/dist/types/server/handle-store.d.ts +26 -2
- package/dist/types/server/request-context.d.ts +24 -21
- package/dist/types/ssr/index.d.ts +15 -0
- package/dist/types/static-handler.d.ts +4 -1
- package/dist/types/testing/generated-routes.d.ts +2 -2
- package/dist/types/testing/internal/context.d.ts +1 -1
- package/dist/types/testing/render-route.d.ts +32 -6
- package/dist/types/testing/vitest-stubs/plugin-rsc.d.ts +28 -5
- package/dist/types/testing/vitest.d.ts +35 -1
- package/dist/types/theme/ThemeScript.d.ts +3 -3
- package/dist/types/types/cache-types.d.ts +14 -10
- package/dist/types/types/handler-context.d.ts +14 -0
- package/dist/types/types/loader-types.d.ts +8 -6
- package/dist/types/urls/response-types.d.ts +3 -12
- package/dist/types/use-loader.d.ts +12 -3
- package/dist/types/vite/plugins/use-cache-transform.d.ts +33 -2
- package/dist/types/vite/rango.d.ts +1 -1
- package/dist/vite/index.js +1381 -1346
- package/package.json +2 -2
- package/skills/api-client/SKILL.md +22 -10
- package/skills/breadcrumbs/SKILL.md +65 -22
- package/skills/bundle-analysis/SKILL.md +22 -22
- package/skills/cache-guide/SKILL.md +207 -97
- package/skills/caching/SKILL.md +295 -93
- package/skills/catalog.json +16 -16
- package/skills/client-urls/SKILL.md +53 -31
- package/skills/cloudflare/SKILL.md +72 -20
- package/skills/cloudflare/references/d1-and-local-dev.md +15 -2
- package/skills/cloudflare/references/streaming-and-deploy.md +10 -3
- package/skills/cloudflare/references/webhooks-and-crypto.md +9 -2
- package/skills/comparison/SKILL.md +5 -0
- package/skills/comparison/references/framework-comparison.md +39 -33
- package/skills/composability/SKILL.md +38 -29
- package/skills/css/SKILL.md +10 -13
- package/skills/debug-manifest/SKILL.md +74 -31
- package/skills/defer-hydration/SKILL.md +2 -1
- package/skills/deployment-caching/SKILL.md +6 -1
- package/skills/document-cache/SKILL.md +92 -28
- package/skills/fonts/SKILL.md +16 -8
- package/skills/handler-use/SKILL.md +53 -17
- package/skills/hooks/SKILL.md +28 -20
- package/skills/hooks/data.md +23 -3
- package/skills/hooks/handle-and-actions.md +31 -16
- package/skills/hooks/navigation.md +39 -10
- package/skills/hooks/outlets.md +13 -6
- package/skills/hooks/state.md +37 -15
- package/skills/hooks/urls.md +7 -5
- package/skills/host-router/SKILL.md +64 -12
- package/skills/i18n/SKILL.md +60 -34
- package/skills/intercept/SKILL.md +161 -26
- package/skills/layout/SKILL.md +106 -50
- package/skills/links/SKILL.md +51 -19
- package/skills/loader/SKILL.md +242 -106
- package/skills/middleware/SKILL.md +119 -23
- package/skills/migrate-nextjs/SKILL.md +100 -45
- package/skills/migrate-nextjs/backend-host-swap.md +5 -2
- package/skills/migrate-react-router/SKILL.md +49 -38
- package/skills/migrate-react-router/component-migration.md +25 -6
- package/skills/migrate-react-router/data-and-actions.md +18 -5
- package/skills/migrate-react-router/route-mapping.md +12 -6
- package/skills/mime-routes/SKILL.md +12 -7
- package/skills/observability/SKILL.md +28 -14
- package/skills/parallel/SKILL.md +75 -39
- package/skills/ppr/SKILL.md +345 -150
- package/skills/prerender/SKILL.md +189 -100
- package/skills/rango/SKILL.md +65 -34
- package/skills/react-compiler/SKILL.md +6 -5
- package/skills/response-routes/SKILL.md +133 -25
- package/skills/route/SKILL.md +165 -60
- package/skills/router-setup/SKILL.md +418 -240
- package/skills/scripts/SKILL.md +31 -20
- package/skills/server-actions/SKILL.md +220 -59
- package/skills/shell-manifest/SKILL.md +12 -7
- package/skills/streams-and-websockets/SKILL.md +32 -14
- package/skills/tailwind/SKILL.md +37 -33
- package/skills/testing/SKILL.md +68 -32
- package/skills/testing/cache-prerender.md +55 -29
- package/skills/testing/client-components.md +59 -6
- package/skills/testing/e2e-parity.md +12 -2
- package/skills/testing/flight.md +19 -11
- package/skills/testing/handles.md +8 -5
- package/skills/testing/loader.md +8 -5
- package/skills/testing/middleware.md +8 -3
- package/skills/testing/predicates.md +120 -0
- package/skills/testing/render-handler.md +70 -22
- package/skills/testing/response-routes.md +11 -4
- package/skills/testing/reverse-and-types.md +20 -14
- package/skills/testing/server-actions.md +12 -3
- package/skills/testing/server-tree.md +9 -0
- package/skills/testing/setup.md +9 -5
- package/skills/theme/SKILL.md +106 -29
- package/skills/typesafety/SKILL.md +20 -9
- package/skills/typesafety/env-and-bindings.md +126 -47
- package/skills/typesafety/generated-files-and-cli.md +26 -14
- package/skills/typesafety/params-and-search.md +44 -19
- package/skills/typesafety/route-types.md +50 -14
- package/skills/use-cache/SKILL.md +200 -82
- package/skills/vercel/SKILL.md +21 -11
- package/skills/view-transitions/SKILL.md +41 -20
- package/src/__augment-tests__/augmented.check.ts +26 -1
- package/src/browser/index.ts +2 -2
- package/src/browser/navigation-bridge.ts +3 -4
- package/src/browser/navigation-transaction.ts +22 -2
- package/src/browser/partial-update.ts +35 -25
- package/src/browser/react/ScrollRestoration.tsx +6 -6
- package/src/browser/rsc-router.tsx +1 -1
- package/src/browser/scroll-restoration.ts +53 -6
- package/src/cache/cache-exec-scope.ts +37 -4
- package/src/cache/cache-key-utils.ts +1 -6
- package/src/cache/cache-runtime.ts +230 -61
- package/src/cache/cache-scope.ts +76 -12
- package/src/cache/document-cache.ts +15 -0
- package/src/cache/handle-capture.ts +90 -10
- package/src/cache/handle-snapshot.ts +132 -28
- package/src/cache/segment-codec.ts +26 -7
- package/src/cache/tag-invalidation.ts +4 -3
- package/src/cache/taint.ts +1 -1
- package/src/cache/types.ts +16 -3
- package/src/client.rsc.tsx +10 -9
- package/src/client.tsx +5 -4
- package/src/components/DefaultDocument.tsx +7 -2
- package/src/context-var.ts +6 -5
- package/src/escape-script.ts +1 -1
- package/src/handles/MetaTags.tsx +13 -11
- package/src/handles/Scripts.tsx +11 -10
- package/src/handles/meta.ts +2 -2
- package/src/handles/script.ts +17 -16
- package/src/href-client.ts +1 -1
- package/src/html.ts +12 -0
- package/src/index.rsc.ts +5 -0
- package/src/index.ts +1 -0
- package/src/loader-store.ts +7 -4
- package/src/prerender/build-shell-capture.ts +8 -11
- package/src/reverse.ts +44 -4
- package/src/route-definition/dsl-helpers.ts +117 -30
- package/src/route-definition/helpers-types.ts +33 -9
- package/src/route-definition/resolve-handler-use.ts +121 -6
- package/src/route-types.ts +0 -3
- package/src/router/debug-manifest.ts +10 -2
- package/src/router/error-handling.ts +51 -15
- package/src/router/handler-context.ts +34 -25
- package/src/router/intercept-resolution.ts +125 -39
- package/src/router/loader-resolution.ts +56 -11
- package/src/router/match-api.ts +12 -17
- package/src/router/match-middleware/background-revalidation.ts +161 -96
- package/src/router/match-middleware/cache-lookup.ts +93 -10
- package/src/router/match-middleware/cache-store.ts +17 -90
- package/src/router/middleware-types.ts +3 -5
- package/src/router/middleware.ts +52 -9
- package/src/router/prerender-match.ts +53 -19
- package/src/router/route-snapshot.ts +11 -1
- package/src/router/router-context.ts +2 -0
- package/src/router/router-interfaces.ts +25 -2
- package/src/router/router-options.ts +8 -5
- package/src/router/segment-resolution/fresh.ts +44 -12
- package/src/router/segment-resolution/loader-cache.ts +205 -45
- package/src/router/segment-resolution/loader-mask.ts +12 -22
- package/src/router/segment-resolution/loader-snapshot.ts +6 -6
- package/src/router/segment-resolution/mask-nested.ts +7 -7
- package/src/router/segment-resolution/revalidation.ts +34 -6
- package/src/router/segment-wrappers.ts +4 -0
- package/src/rsc/render-pipeline.ts +3 -0
- package/src/rsc/response-route-handler.ts +11 -3
- package/src/rsc/rsc-rendering.ts +8 -45
- package/src/rsc/shell-capture-constants.ts +13 -0
- package/src/rsc/shell-capture.ts +111 -90
- package/src/rsc/ssr-setup.ts +14 -8
- package/src/rsc/types.ts +11 -0
- package/src/server/context.ts +88 -11
- package/src/server/cookie-store.ts +5 -4
- package/src/server/handle-store.ts +232 -7
- package/src/server/request-context.ts +35 -30
- package/src/ssr/index.tsx +40 -7
- package/src/static-handler.ts +4 -1
- package/src/testing/flight-runtime.d.ts +21 -0
- package/src/testing/generated-routes.ts +2 -2
- package/src/testing/internal/context.ts +1 -1
- package/src/testing/internal/flight-client-globals.ts +7 -5
- package/src/testing/render-route.tsx +85 -24
- package/src/testing/run-loader.ts +5 -1
- package/src/testing/vitest-stubs/plugin-rsc.ts +123 -20
- package/src/testing/vitest.ts +62 -1
- package/src/theme/ThemeScript.tsx +3 -3
- package/src/types/cache-types.ts +14 -10
- package/src/types/handler-context.ts +14 -0
- package/src/types/loader-types.ts +8 -6
- package/src/urls/response-types.ts +3 -23
- package/src/use-loader.tsx +12 -3
- package/src/vite/plugins/use-cache-transform.ts +118 -74
- package/src/vite/rango.ts +7 -3
package/src/context-var.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* interface PaginationData { current: number; total: number }
|
|
13
13
|
* export const Pagination = createVar<PaginationData>();
|
|
14
14
|
*
|
|
15
|
-
* // Non-cacheable var — ctx.get(User) throws inside
|
|
15
|
+
* // Non-cacheable var — ctx.get(User) throws inside cache() or "use cache"
|
|
16
16
|
* export const User = createVar<UserData>({ cache: false });
|
|
17
17
|
*
|
|
18
18
|
* // handler
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
export interface ContextVar<T> {
|
|
27
27
|
readonly __brand: "context-var";
|
|
28
28
|
readonly key: symbol;
|
|
29
|
-
/** When false, ctx.get(var) throws inside
|
|
29
|
+
/** When false, ctx.get(var) throws inside cache() or "use cache". */
|
|
30
30
|
readonly cache: boolean;
|
|
31
31
|
/** Phantom field to carry the type parameter. Never set at runtime. */
|
|
32
32
|
readonly __type?: T;
|
|
@@ -35,9 +35,10 @@ export interface ContextVar<T> {
|
|
|
35
35
|
export interface ContextVarOptions {
|
|
36
36
|
/**
|
|
37
37
|
* When false, marks this variable as non-cacheable.
|
|
38
|
-
* Reading this var with ctx.get() inside a cache() boundary
|
|
39
|
-
* inherently request-specific data (user sessions,
|
|
40
|
-
* must never be baked into cached segments
|
|
38
|
+
* Reading this var with ctx.get() inside a cache() boundary or a "use cache"
|
|
39
|
+
* function throws. Use for inherently request-specific data (user sessions,
|
|
40
|
+
* auth tokens, etc.) that must never be baked into cached segments or
|
|
41
|
+
* entries; pass the value into a "use cache" function as an argument.
|
|
41
42
|
*
|
|
42
43
|
* @default true
|
|
43
44
|
*/
|
package/src/escape-script.ts
CHANGED
|
@@ -45,7 +45,7 @@ export function escapeJsonForScript(json: string): string {
|
|
|
45
45
|
* source; for untrusted dynamic data, JSON-encode it and read it back, rather than
|
|
46
46
|
* inlining it as code.
|
|
47
47
|
*
|
|
48
|
-
* Used by the Script handle's <Scripts> renderer for inline `children`.
|
|
48
|
+
* Used by the Script handle's <Html.Scripts> renderer for inline `children`.
|
|
49
49
|
*/
|
|
50
50
|
export function escapeScriptBody(js: string): string {
|
|
51
51
|
return js.replace(/<!--/g, "<\\u0021--").replace(/<\/(script)/gi, "<\\/$1");
|
package/src/handles/MetaTags.tsx
CHANGED
|
@@ -2,17 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Component to render collected meta descriptors in the document head.
|
|
5
|
+
* Public as `Html.Meta` (`@rangojs/router/client`).
|
|
5
6
|
*
|
|
6
|
-
* Deferred (Promise) meta descriptors are resolved before
|
|
7
|
+
* Deferred (Promise) meta descriptors are resolved before `<Html.Meta />` renders
|
|
7
8
|
* (server-side on the full render, client-side before apply on navigation), so
|
|
8
9
|
* it only ever receives resolved descriptors and never suspends.
|
|
9
10
|
*
|
|
10
|
-
* When theme is enabled in the router config,
|
|
11
|
+
* When theme is enabled in the router config, `<Html.Meta />` also renders
|
|
11
12
|
* the theme initialization script to prevent FOUC (flash of unstyled content).
|
|
12
|
-
* This makes
|
|
13
|
-
* the standalone `<ThemeScript />` is only needed when
|
|
14
|
-
* Rendering both is safe (the inline script guards listener registration)
|
|
15
|
-
* redundant.
|
|
13
|
+
* This makes `<Html.Meta />` the sole FOUC-script injector for apps that render
|
|
14
|
+
* it; the standalone `<ThemeScript />` is only needed when `<Html.Meta />` is not
|
|
15
|
+
* used. Rendering both is safe (the inline script guards listener registration)
|
|
16
|
+
* but redundant.
|
|
16
17
|
*
|
|
17
18
|
* @example
|
|
18
19
|
* ```tsx
|
|
@@ -20,7 +21,7 @@
|
|
|
20
21
|
* return (
|
|
21
22
|
* <html lang="en" suppressHydrationWarning>
|
|
22
23
|
* <head>
|
|
23
|
-
* <
|
|
24
|
+
* <Html.Meta />
|
|
24
25
|
* </head>
|
|
25
26
|
* <body>...</body>
|
|
26
27
|
* </html>
|
|
@@ -179,17 +180,18 @@ export function renderMetaDescriptor(
|
|
|
179
180
|
}
|
|
180
181
|
|
|
181
182
|
/**
|
|
182
|
-
* Renders all collected meta descriptors from route handlers.
|
|
183
|
+
* Renders all collected meta descriptors from route handlers. Public as
|
|
184
|
+
* `Html.Meta` (`@rangojs/router/client`).
|
|
183
185
|
*
|
|
184
|
-
* Place
|
|
186
|
+
* Place `<Html.Meta />` inside the `<head>` element of your document.
|
|
185
187
|
* It will automatically update when meta descriptors change during navigation.
|
|
186
188
|
*
|
|
187
189
|
* When theme is enabled in router config, also renders the theme initialization
|
|
188
190
|
* script to prevent FOUC (flash of unstyled content).
|
|
189
191
|
*
|
|
190
|
-
* Deferred (Promise) meta descriptors are resolved BEFORE
|
|
192
|
+
* Deferred (Promise) meta descriptors are resolved BEFORE this renders —
|
|
191
193
|
* server-side on the full/SSR render, client-side before apply on navigation
|
|
192
|
-
* (resolve-by-default) — so
|
|
194
|
+
* (resolve-by-default) — so it only ever receives resolved descriptors and
|
|
193
195
|
* never suspends.
|
|
194
196
|
*/
|
|
195
197
|
export function MetaTags(): React.ReactNode {
|
package/src/handles/Scripts.tsx
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Renders the scripts collected by the Script handle into the document.
|
|
4
|
+
* Renders the scripts collected by the Script handle into the document. Public
|
|
5
|
+
* as `Html.Scripts` (`@rangojs/router/client`).
|
|
5
6
|
*
|
|
6
|
-
* Place `<Scripts />` inside `<head>` (default) and, if you push body
|
|
7
|
-
* `<Scripts position="body" />` at the top of `<body>`. Each site
|
|
8
|
-
* configs whose `position` matches; the request CSP nonce is applied
|
|
7
|
+
* Place `<Html.Scripts />` inside `<head>` (default) and, if you push body
|
|
8
|
+
* scripts, `<Html.Scripts position="body" />` at the top of `<body>`. Each site
|
|
9
|
+
* renders the configs whose `position` matches; the request CSP nonce is applied
|
|
9
10
|
* automatically to every DOCUMENT-RENDERED <script> (consumers never pass it). An
|
|
10
11
|
* async script first encountered on a soft navigation is injected client-side
|
|
11
12
|
* where the nonce is unavailable, so it carries no nonce and relies on
|
|
@@ -24,11 +25,11 @@
|
|
|
24
25
|
* ```tsx
|
|
25
26
|
* <html>
|
|
26
27
|
* <head>
|
|
27
|
-
* <
|
|
28
|
-
* <Scripts />
|
|
28
|
+
* <Html.Meta />
|
|
29
|
+
* <Html.Scripts />
|
|
29
30
|
* </head>
|
|
30
31
|
* <body>
|
|
31
|
-
* <Scripts position="body" />
|
|
32
|
+
* <Html.Scripts position="body" />
|
|
32
33
|
* {children}
|
|
33
34
|
* </body>
|
|
34
35
|
* </html>
|
|
@@ -80,10 +81,10 @@ function passthroughAttributes(
|
|
|
80
81
|
if (dev) {
|
|
81
82
|
console.warn(
|
|
82
83
|
isHandler
|
|
83
|
-
? `[Scripts] event handler "${key}" in a script's attributes is ` +
|
|
84
|
+
? `[Html.Scripts] event handler "${key}" in a script's attributes is ` +
|
|
84
85
|
`dropped; callbacks cannot cross the server -> client handle ` +
|
|
85
86
|
`boundary. Use a "use client" component for load/error handling.`
|
|
86
|
-
: `[Scripts] managed field "${key}" in a script's attributes is ` +
|
|
87
|
+
: `[Html.Scripts] managed field "${key}" in a script's attributes is ` +
|
|
87
88
|
`dropped; set it via the ScriptConfig fields (the request nonce ` +
|
|
88
89
|
`is applied automatically).`,
|
|
89
90
|
);
|
|
@@ -129,7 +130,7 @@ function renderScript(
|
|
|
129
130
|
async
|
|
130
131
|
) {
|
|
131
132
|
console.warn(
|
|
132
|
-
`[Scripts] An async external script (src="${src}") is hoisted into ` +
|
|
133
|
+
`[Html.Scripts] An async external script (src="${src}") is hoisted into ` +
|
|
133
134
|
`<head> by React; position: "body" is ignored for it.`,
|
|
134
135
|
);
|
|
135
136
|
}
|
package/src/handles/meta.ts
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* return (
|
|
20
20
|
* <html>
|
|
21
21
|
* <head>
|
|
22
|
-
* <
|
|
22
|
+
* <Html.Meta />
|
|
23
23
|
* </head>
|
|
24
24
|
* ...
|
|
25
25
|
* </html>
|
|
@@ -225,7 +225,7 @@ function collectMeta(segments: MetaDescriptor[][]): MetaDescriptor[] {
|
|
|
225
225
|
* Built-in handle for managing document metadata.
|
|
226
226
|
*
|
|
227
227
|
* Use `ctx.use(Meta)` in route handlers to push meta descriptors.
|
|
228
|
-
* Use `<
|
|
228
|
+
* Use the `<Html.Meta />` component to render them in the document head.
|
|
229
229
|
*
|
|
230
230
|
* Deferred (Promise) descriptors are resolved before collectMeta runs
|
|
231
231
|
* (resolve-by-default), so they participate in deduplication and `%s`
|
package/src/handles/script.ts
CHANGED
|
@@ -3,22 +3,23 @@
|
|
|
3
3
|
* route/layout handlers.
|
|
4
4
|
*
|
|
5
5
|
* Push from a SERVER handler with `ctx.use(Script)(config)`; render with the
|
|
6
|
-
* `<Scripts />` component (from `@rangojs/router/client`) placed in the
|
|
7
|
-
* `<head>` (and optionally a second `<Scripts position="body" />`
|
|
8
|
-
* `<body>`). This mirrors the Meta / <
|
|
6
|
+
* `<Html.Scripts />` component (from `@rangojs/router/client`) placed in the
|
|
7
|
+
* Document `<head>` (and optionally a second `<Html.Scripts position="body" />`
|
|
8
|
+
* at the top of `<body>`). This mirrors the Meta / <Html.Meta> pair.
|
|
9
9
|
*
|
|
10
|
-
* The request CSP nonce is applied AUTOMATICALLY by <Scripts> to
|
|
11
|
-
* scripts; consumers never pass a nonce. (An async script
|
|
12
|
-
* navigation is injected client-side without a nonce —
|
|
13
|
-
* 'strict-dynamic' or a host allowance; see the EXECUTION CONTRACT
|
|
14
|
-
* /scripts skill.) A ScriptConfig is fully serializable (it
|
|
15
|
-
* server -> client handle-collection boundary), so callbacks like
|
|
16
|
-
* supported — a consumer needing them renders their own
|
|
10
|
+
* The request CSP nonce is applied AUTOMATICALLY by <Html.Scripts> to
|
|
11
|
+
* document-rendered scripts; consumers never pass a nonce. (An async script
|
|
12
|
+
* first loaded on a soft navigation is injected client-side without a nonce —
|
|
13
|
+
* it relies on 'strict-dynamic' or a host allowance; see the EXECUTION CONTRACT
|
|
14
|
+
* below and the /scripts skill.) A ScriptConfig is fully serializable (it
|
|
15
|
+
* crosses the server -> client handle-collection boundary), so callbacks like
|
|
16
|
+
* onLoad are NOT supported — a consumer needing them renders their own
|
|
17
|
+
* "use client" script.
|
|
17
18
|
*
|
|
18
19
|
* EXECUTION CONTRACT (see the /scripts skill for the full story):
|
|
19
20
|
* - Inline (`children`) and ordered external (`src`, optional `defer`) scripts
|
|
20
21
|
* are DOCUMENT-LOAD scripts: they execute only when present in the initial HTML
|
|
21
|
-
* response. <Scripts> freezes them after hydration, so a later client (soft)
|
|
22
|
+
* response. <Html.Scripts> freezes them after hydration, so a later client (soft)
|
|
22
23
|
* navigation never inserts an inert copy — React creates client-mounted
|
|
23
24
|
* <script> elements via innerHTML, which the HTML spec makes non-executing.
|
|
24
25
|
* - Async external scripts (`src` + `async: true`) are React RESOURCES: they load
|
|
@@ -78,9 +79,9 @@ export type ScriptAttributes = Omit<
|
|
|
78
79
|
/** Fields shared by every script shape. */
|
|
79
80
|
interface ScriptConfigBase {
|
|
80
81
|
/**
|
|
81
|
-
* Where <Scripts> renders this script.
|
|
82
|
-
* - "head" (default): the `<head>` <Scripts> site.
|
|
83
|
-
* - "body": the `<Scripts position="body" />` site at the top of <body>.
|
|
82
|
+
* Where <Html.Scripts> renders this script.
|
|
83
|
+
* - "head" (default): the `<head>` <Html.Scripts> site.
|
|
84
|
+
* - "body": the `<Html.Scripts position="body" />` site at the top of <body>.
|
|
84
85
|
* Note: an external `async` script is hoisted into <head> by React regardless.
|
|
85
86
|
*/
|
|
86
87
|
position?: "head" | "body";
|
|
@@ -96,7 +97,7 @@ interface ScriptConfigBase {
|
|
|
96
97
|
/**
|
|
97
98
|
* Inline script: a raw JS body rendered in place, escaped against `</script>`
|
|
98
99
|
* breakout. DOCUMENT-LOAD only (executes when present in the initial HTML;
|
|
99
|
-
* <Scripts> freezes it after hydration so navigation never inserts an inert
|
|
100
|
+
* <Html.Scripts> freezes it after hydration so navigation never inserts an inert
|
|
100
101
|
* copy). `id` is REQUIRED — inline scripts are never deduped by React, so a
|
|
101
102
|
* layout and a child pushing the same bootstrap would inject it twice. It is also
|
|
102
103
|
* rendered as the script's DOM `id`. Forbids `src`/`async`/`defer`. For analytics
|
|
@@ -146,7 +147,7 @@ export interface OrderedScriptConfig extends ScriptConfigBase {
|
|
|
146
147
|
* inline (`id` + `children`), external async (`src` + `async: true`), or external
|
|
147
148
|
* ordered (`src`, optional `defer`). Invalid combinations (both `src`+`children`,
|
|
148
149
|
* `async`+`defer`, inline without `id`) are compile errors. The CSP nonce is
|
|
149
|
-
* applied by <Scripts>, never here.
|
|
150
|
+
* applied by <Html.Scripts>, never here.
|
|
150
151
|
*/
|
|
151
152
|
export type ScriptConfig =
|
|
152
153
|
| InlineScriptConfig
|
package/src/href-client.ts
CHANGED
package/src/html.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Members of the `Html` namespace; client.tsx and client.rsc.tsx expose this
|
|
3
|
+
* module as `import * as Html`. A module namespace, not an object literal, so
|
|
4
|
+
* bundlers drop members an app never renders (a literal kept opt-in
|
|
5
|
+
* ScrollRestoration in every app: +313 B gzip, over the router-chunk ratchet).
|
|
6
|
+
* No "use client": each member stays its own module's client reference, so a
|
|
7
|
+
* server component can dot into `Html`. Pinned by __tests__/html.test.ts and
|
|
8
|
+
* testing/__tests__/html-namespace.rsc-test.tsx.
|
|
9
|
+
*/
|
|
10
|
+
export { MetaTags as Meta } from "./handles/MetaTags.js";
|
|
11
|
+
export { Scripts } from "./handles/Scripts.js";
|
|
12
|
+
export { ScrollRestoration } from "./browser/react/ScrollRestoration.js";
|
package/src/index.rsc.ts
CHANGED
|
@@ -51,6 +51,7 @@ export type {
|
|
|
51
51
|
LoaderDefinition,
|
|
52
52
|
LoaderFn,
|
|
53
53
|
LoaderContext,
|
|
54
|
+
LoaderOptions,
|
|
54
55
|
FetchableLoaderOptions,
|
|
55
56
|
LoadOptions,
|
|
56
57
|
// Error boundary types
|
|
@@ -188,6 +189,9 @@ export {
|
|
|
188
189
|
type RouterRequestInput,
|
|
189
190
|
} from "./router.js";
|
|
190
191
|
|
|
192
|
+
// Route manifest snapshot returned by router.debugManifest()
|
|
193
|
+
export type { SerializedManifest } from "./debug.js";
|
|
194
|
+
|
|
191
195
|
// RSC handler types (server-side)
|
|
192
196
|
export type { HandlerCacheConfig } from "./rsc/types.js";
|
|
193
197
|
export {
|
|
@@ -254,6 +258,7 @@ export type {
|
|
|
254
258
|
export type {
|
|
255
259
|
ScopedReverseFunction,
|
|
256
260
|
ReverseFunction,
|
|
261
|
+
GlobalReverseFunction,
|
|
257
262
|
ExtractLocalRoutes,
|
|
258
263
|
ParamsFor,
|
|
259
264
|
} from "./reverse.js";
|
package/src/index.ts
CHANGED
package/src/loader-store.ts
CHANGED
|
@@ -162,10 +162,13 @@ export class LoaderStore {
|
|
|
162
162
|
* browser/partial-update.ts calls INSIDE every transition commit, so a
|
|
163
163
|
* reader whose content is held on screen by that transition pins
|
|
164
164
|
* `isLoading: true` for the data it is still showing until the transition
|
|
165
|
-
* lands (use-loader.tsx).
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
165
|
+
* lands (use-loader.tsx). Family-keyed on purpose: a persisting layout
|
|
166
|
+
* reader of the same createLoader the child is re-running is pinned too
|
|
167
|
+
* (the loader is in flight; not "this segment's copy is being replaced" —
|
|
168
|
+
* issue #862, working as designed). The new tree's own read of the loader
|
|
169
|
+
* suspends at the read site and never observes the flag. A Set, not a
|
|
170
|
+
* flag: overlapping navigations (second click before the first stream
|
|
171
|
+
* lands) keep the family pending until the LAST stream settles.
|
|
169
172
|
*/
|
|
170
173
|
private readonly pendingStreams = new Map<string, Set<Promise<unknown>>>();
|
|
171
174
|
|
|
@@ -44,7 +44,7 @@ import { isRouteNotFoundError } from "../errors.js";
|
|
|
44
44
|
import { createReverseFunction } from "../router/handler-context.js";
|
|
45
45
|
import { executeMiddleware, matchMiddleware } from "../router/middleware.js";
|
|
46
46
|
import type { MiddlewareEntry } from "../router/middleware.js";
|
|
47
|
-
import { getGlobalRouteMap
|
|
47
|
+
import { getGlobalRouteMap } from "../route-map-builder.js";
|
|
48
48
|
import {
|
|
49
49
|
resolvePprConfig,
|
|
50
50
|
type ResolvedPprConfig,
|
|
@@ -234,14 +234,11 @@ async function attemptBuildCapture(
|
|
|
234
234
|
setRequestContextParams(preview.params ?? {}, preview.routeKey);
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
? isRouteRootScoped(preview.routeKey, router.id)
|
|
243
|
-
: undefined,
|
|
244
|
-
);
|
|
237
|
+
// Global-only, like the live request's middleware reverse
|
|
238
|
+
// (rsc/handler.ts: createReverseFunction(getRequiredRouteMap())): no
|
|
239
|
+
// include() scope, no param auto-fill. A scoped reverse here resolved
|
|
240
|
+
// `.name` at build while the live request threw `Unknown route`.
|
|
241
|
+
const middlewareReverse = createReverseFunction(getGlobalRouteMap());
|
|
245
242
|
|
|
246
243
|
const runCapture = () =>
|
|
247
244
|
runBuildCaptureFinal({
|
|
@@ -268,7 +265,7 @@ async function attemptBuildCapture(
|
|
|
268
265
|
env,
|
|
269
266
|
variables,
|
|
270
267
|
runCapture,
|
|
271
|
-
|
|
268
|
+
middlewareReverse,
|
|
272
269
|
baseCtx,
|
|
273
270
|
);
|
|
274
271
|
|
|
@@ -281,7 +278,7 @@ async function attemptBuildCapture(
|
|
|
281
278
|
env,
|
|
282
279
|
variables,
|
|
283
280
|
runRouteMiddleware,
|
|
284
|
-
|
|
281
|
+
middlewareReverse,
|
|
285
282
|
baseCtx,
|
|
286
283
|
);
|
|
287
284
|
});
|
package/src/reverse.ts
CHANGED
|
@@ -207,6 +207,43 @@ export type ScopedReverseFunction<
|
|
|
207
207
|
): string;
|
|
208
208
|
};
|
|
209
209
|
|
|
210
|
+
/**
|
|
211
|
+
* Reverse function that resolves global route names only: no include() scope,
|
|
212
|
+
* no param auto-fill.
|
|
213
|
+
*
|
|
214
|
+
* This is the `ctx.reverse` of middleware (`MiddlewareContext`) and
|
|
215
|
+
* response-route handlers (`ResponseHandlerContext`). On a live request both
|
|
216
|
+
* get `createReverseFunction(routeMap)` with no route name or params (the
|
|
217
|
+
* middleware callers in rsc/handler.ts and rsc/loader-fetch.ts,
|
|
218
|
+
* handleResponseRoute, router/intercept-resolution.ts; mirrored by
|
|
219
|
+
* testing/run-middleware.ts and testing/dispatch.ts), so a dot-local `.name`
|
|
220
|
+
* has no scope to resolve against and throws `Unknown route`. Build-time PPR
|
|
221
|
+
* shell capture (prerender/build-shell-capture.ts) gives global and route
|
|
222
|
+
* middleware the same global-only reverse.
|
|
223
|
+
*
|
|
224
|
+
* - Route map with a string index signature (no generated map, the permissive
|
|
225
|
+
* `Record<string, string>` fallback): any name except a dot-prefixed literal.
|
|
226
|
+
* `Exclude` is required because `keyof` collapses to `string` there, so the
|
|
227
|
+
* global overloads of `ScopedReverseFunction` would accept `.name` too.
|
|
228
|
+
* - Concrete route map: the global overloads of `ScopedReverseFunction`, with
|
|
229
|
+
* name and param validation. The empty local map (`{}`) leaves no dot-prefixed
|
|
230
|
+
* overload that can match.
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* ```typescript
|
|
234
|
+
* reverse("blog.post", { slug: "hello" }) // ok: global route + params
|
|
235
|
+
* reverse(".post", { slug: "hello" }) // compile error: no include() scope
|
|
236
|
+
* ```
|
|
237
|
+
*/
|
|
238
|
+
export type GlobalReverseFunction<TGlobalRoutes> =
|
|
239
|
+
string extends keyof TGlobalRoutes
|
|
240
|
+
? <TName extends string>(
|
|
241
|
+
name: Exclude<TName, `.${string}`>,
|
|
242
|
+
params?: Record<string, string>,
|
|
243
|
+
search?: Record<string, unknown>,
|
|
244
|
+
) => string
|
|
245
|
+
: ScopedReverseFunction<{}, TGlobalRoutes>;
|
|
246
|
+
|
|
210
247
|
/**
|
|
211
248
|
* Extract local routes type from UrlPatterns
|
|
212
249
|
* Used with scopedReverse() to get the routes type from patterns
|
|
@@ -290,11 +327,14 @@ export type { RouteResponse } from "./urls.js";
|
|
|
290
327
|
* Get a locally-typed reverse function from ctx.reverse for composable modules.
|
|
291
328
|
*
|
|
292
329
|
* This is a type-only cast - ctx.reverse already resolves names at runtime.
|
|
293
|
-
*
|
|
294
|
-
*
|
|
330
|
+
* Only the module's LOCAL routes are typed: `.name` and bare `name` both
|
|
331
|
+
* validate against the local map (the global map parameter defaults to it).
|
|
332
|
+
* Always dot-prefix local names — a bare name type-checks against the local
|
|
333
|
+
* map but resolves as a global name at runtime. For global names, call
|
|
334
|
+
* ctx.reverse directly.
|
|
295
335
|
*
|
|
296
336
|
* @param reverse - The ctx.reverse function from HandlerContext
|
|
297
|
-
* @returns The same reverse function, typed with
|
|
337
|
+
* @returns The same reverse function, typed with the module's local routes
|
|
298
338
|
*
|
|
299
339
|
* @example
|
|
300
340
|
* ```typescript
|
|
@@ -305,7 +345,7 @@ export type { RouteResponse } from "./urls.js";
|
|
|
305
345
|
*
|
|
306
346
|
* reverse(".index"); // ✓ Local route
|
|
307
347
|
* reverse(".post", { slug: "x" }); // ✓ Local with params
|
|
308
|
-
* reverse("shop.cart");
|
|
348
|
+
* ctx.reverse("shop.cart"); // Global route: use ctx.reverse
|
|
309
349
|
*
|
|
310
350
|
* return <BlogIndex />;
|
|
311
351
|
* }, { name: "index" }),
|