@rangojs/router 0.16.0 → 0.18.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 +255 -89
- package/dist/testing/vitest.js +252 -0
- package/dist/types/browser/cookie-name.d.ts +6 -0
- package/dist/types/browser/history-state.d.ts +16 -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-key-utils.d.ts +17 -2
- package/dist/types/cache/cache-policy.d.ts +17 -0
- package/dist/types/cache/cache-scope.d.ts +132 -19
- package/dist/types/cache/cache-tag.d.ts +92 -7
- package/dist/types/cache/cf/cf-base64.d.ts +6 -0
- package/dist/types/cache/cf/cf-cache-constants.d.ts +11 -0
- package/dist/types/cache/cf/cf-cache-store.d.ts +185 -44
- package/dist/types/cache/cf/cf-cache-types.d.ts +31 -4
- package/dist/types/cache/cf/cf-shell-frame.d.ts +95 -0
- package/dist/types/cache/cf/cf-tag-marker-memo.d.ts +34 -0
- package/dist/types/cache/handle-capture.d.ts +41 -3
- package/dist/types/cache/handle-snapshot.d.ts +54 -13
- package/dist/types/cache/index.d.ts +1 -0
- package/dist/types/cache/isolate-tag-memo.d.ts +149 -0
- package/dist/types/cache/segment-codec.d.ts +10 -3
- package/dist/types/cache/shell-memo.d.ts +178 -0
- package/dist/types/cache/shell-snapshot.d.ts +110 -21
- package/dist/types/cache/tag-invalidation.d.ts +30 -3
- package/dist/types/cache/taint.d.ts +1 -1
- package/dist/types/cache/types.d.ts +220 -44
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +111 -13
- 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/prerender/build-shell-capture.d.ts +11 -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/instrument.d.ts +8 -0
- package/dist/types/router/match-middleware/background-revalidation.d.ts +46 -5
- package/dist/types/router/middleware-types.d.ts +9 -3
- 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 +66 -1
- package/dist/types/router/segment-resolution/loader-mask.d.ts +9 -19
- package/dist/types/router/segment-resolution/loader-snapshot.d.ts +23 -12
- package/dist/types/router/segment-resolution/mask-nested.d.ts +67 -26
- 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/full-payload.d.ts +14 -0
- package/dist/types/rsc/handler.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-build-manifest.d.ts +8 -0
- package/dist/types/rsc/shell-capture-constants.d.ts +61 -6
- package/dist/types/rsc/shell-capture.d.ts +151 -19
- package/dist/types/rsc/shell-serve.d.ts +140 -17
- package/dist/types/rsc/ssr-setup.d.ts +6 -6
- package/dist/types/rsc/types.d.ts +17 -0
- package/dist/types/server/context.d.ts +139 -15
- package/dist/types/server/cookie-store.d.ts +21 -0
- package/dist/types/server/handle-store.d.ts +26 -2
- package/dist/types/server/request-context.d.ts +182 -53
- package/dist/types/ssr/index.d.ts +24 -0
- package/dist/types/ssr/ssr-root.d.ts +9 -8
- package/dist/types/static-handler.d.ts +4 -1
- package/dist/types/testing/flight.entry.d.ts +7 -0
- 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/run-loader.d.ts +18 -3
- package/dist/types/testing/serve-shell-request.d.ts +132 -0
- package/dist/types/testing/shell-status.d.ts +23 -10
- 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 +28 -1
- package/dist/types/types/loader-types.d.ts +8 -6
- package/dist/types/urls/pattern-types.d.ts +22 -18
- 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/types/vite/router-discovery.d.ts +29 -2
- package/dist/vite/index.js +1420 -1348
- package/package.json +2 -2
- package/skills/api-client/SKILL.md +22 -10
- package/skills/breadcrumbs/SKILL.md +75 -22
- package/skills/bundle-analysis/SKILL.md +22 -22
- package/skills/cache-guide/SKILL.md +306 -124
- package/skills/caching/SKILL.md +530 -98
- package/skills/catalog.json +16 -16
- package/skills/client-urls/SKILL.md +65 -38
- package/skills/cloudflare/SKILL.md +87 -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 +75 -57
- 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 +52 -31
- package/skills/deployment-caching/SKILL.md +11 -3
- package/skills/document-cache/SKILL.md +98 -28
- package/skills/fonts/SKILL.md +16 -8
- package/skills/handler-use/SKILL.md +55 -17
- package/skills/hooks/SKILL.md +28 -20
- package/skills/hooks/data.md +23 -3
- package/skills/hooks/handle-and-actions.md +34 -17
- package/skills/hooks/navigation.md +39 -10
- package/skills/hooks/outlets.md +13 -6
- package/skills/hooks/state.md +39 -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 +386 -128
- package/skills/middleware/SKILL.md +129 -26
- package/skills/migrate-nextjs/SKILL.md +156 -70
- package/skills/migrate-nextjs/backend-host-swap.md +5 -2
- package/skills/migrate-react-router/SKILL.md +51 -39
- package/skills/migrate-react-router/component-migration.md +28 -7
- package/skills/migrate-react-router/data-and-actions.md +21 -6
- package/skills/migrate-react-router/route-mapping.md +19 -10
- package/skills/mime-routes/SKILL.md +12 -7
- package/skills/observability/SKILL.md +92 -14
- package/skills/parallel/SKILL.md +88 -47
- package/skills/ppr/SKILL.md +866 -379
- package/skills/prerender/SKILL.md +210 -108
- package/skills/rango/SKILL.md +115 -65
- package/skills/react-compiler/SKILL.md +6 -5
- package/skills/response-routes/SKILL.md +133 -25
- package/skills/route/SKILL.md +170 -60
- package/skills/router-setup/SKILL.md +420 -240
- package/skills/scripts/SKILL.md +39 -21
- package/skills/server-actions/SKILL.md +231 -59
- package/skills/shell-manifest/SKILL.md +28 -14
- package/skills/streams-and-websockets/SKILL.md +32 -14
- package/skills/tailwind/SKILL.md +37 -33
- package/skills/testing/SKILL.md +73 -33
- package/skills/testing/cache-prerender.md +60 -33
- 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 +26 -6
- 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/serve-shell-request.md +188 -0
- 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 +155 -30
- package/skills/typesafety/SKILL.md +20 -9
- package/skills/typesafety/env-and-bindings.md +137 -50
- 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 +224 -83
- package/skills/vercel/SKILL.md +35 -13
- package/skills/view-transitions/SKILL.md +42 -21
- package/src/__augment-tests__/augmented.check.ts +26 -1
- package/src/browser/cookie-name.ts +23 -0
- package/src/browser/history-state.ts +23 -0
- 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 +6 -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 +23 -8
- package/src/cache/cache-policy.ts +22 -0
- package/src/cache/cache-runtime.ts +264 -68
- package/src/cache/cache-scope.ts +419 -43
- package/src/cache/cache-tag.ts +375 -11
- package/src/cache/cf/cf-base64.ts +36 -4
- package/src/cache/cf/cf-cache-constants.ts +12 -0
- package/src/cache/cf/cf-cache-store.ts +990 -348
- package/src/cache/cf/cf-cache-types.ts +32 -4
- package/src/cache/cf/cf-shell-frame.ts +258 -0
- package/src/cache/cf/cf-tag-marker-memo.ts +143 -39
- package/src/cache/document-cache.ts +15 -0
- package/src/cache/handle-capture.ts +90 -10
- package/src/cache/handle-snapshot.ts +133 -28
- package/src/cache/index.ts +2 -0
- package/src/cache/isolate-tag-memo.ts +308 -0
- package/src/cache/segment-codec.ts +26 -7
- package/src/cache/shell-memo.ts +341 -0
- package/src/cache/shell-snapshot.ts +217 -27
- package/src/cache/tag-invalidation.ts +108 -22
- package/src/cache/taint.ts +1 -1
- package/src/cache/types.ts +225 -44
- package/src/cache/vercel/vercel-cache-store.ts +545 -61
- 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 +73 -22
- package/src/reverse.ts +44 -4
- package/src/route-definition/dsl-helpers.ts +121 -33
- 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 +71 -28
- package/src/router/instrument.ts +54 -2
- package/src/router/intercept-resolution.ts +141 -43
- package/src/router/loader-resolution.ts +115 -39
- package/src/router/match-api.ts +40 -26
- package/src/router/match-handlers.ts +5 -0
- package/src/router/match-middleware/background-revalidation.ts +161 -96
- package/src/router/match-middleware/cache-lookup.ts +110 -10
- package/src/router/match-middleware/cache-store.ts +48 -101
- package/src/router/middleware-types.ts +9 -6
- package/src/router/middleware.ts +75 -13
- package/src/router/prerender-match.ts +59 -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 +62 -21
- package/src/router/segment-resolution/helpers.ts +4 -2
- package/src/router/segment-resolution/loader-cache.ts +407 -76
- package/src/router/segment-resolution/loader-mask.ts +12 -22
- package/src/router/segment-resolution/loader-snapshot.ts +208 -56
- package/src/router/segment-resolution/mask-nested.ts +138 -44
- package/src/router/segment-resolution/revalidation.ts +61 -16
- package/src/router/segment-wrappers.ts +4 -0
- package/src/rsc/full-payload.ts +25 -1
- package/src/rsc/handler.ts +14 -2
- package/src/rsc/progressive-enhancement.ts +3 -2
- package/src/rsc/render-pipeline.ts +3 -0
- package/src/rsc/response-cache-serve.ts +9 -6
- package/src/rsc/response-route-handler.ts +11 -3
- package/src/rsc/rsc-rendering.ts +608 -225
- package/src/rsc/shell-build-manifest.ts +27 -9
- package/src/rsc/shell-capture-constants.ts +73 -6
- package/src/rsc/shell-capture.ts +1068 -296
- package/src/rsc/shell-serve.ts +316 -34
- package/src/rsc/ssr-setup.ts +14 -8
- package/src/rsc/types.ts +18 -0
- package/src/server/context.ts +300 -32
- package/src/server/cookie-store.ts +87 -61
- package/src/server/handle-store.ts +232 -7
- package/src/server/request-context.ts +297 -67
- package/src/ssr/index.tsx +136 -44
- package/src/ssr/ssr-root.tsx +9 -8
- package/src/static-handler.ts +4 -1
- package/src/testing/flight-runtime.d.ts +21 -0
- package/src/testing/flight.entry.ts +14 -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 +68 -6
- package/src/testing/serve-shell-request.ts +378 -0
- package/src/testing/shell-status.ts +34 -12
- package/src/testing/vitest-stubs/plugin-rsc.ts +123 -20
- package/src/testing/vitest.ts +62 -1
- package/src/theme/ThemeProvider.tsx +7 -6
- package/src/theme/ThemeScript.tsx +3 -3
- package/src/types/cache-types.ts +14 -10
- package/src/types/handler-context.ts +28 -1
- package/src/types/loader-types.ts +8 -6
- package/src/urls/pattern-types.ts +22 -18
- package/src/urls/response-types.ts +3 -23
- package/src/use-loader.tsx +12 -3
- package/src/vite/discovery/shell-prerender-phase.ts +9 -0
- package/src/vite/plugins/use-cache-transform.ts +118 -74
- package/src/vite/rango.ts +7 -3
- package/src/vite/router-discovery.ts +14 -4
package/src/client.rsc.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* RSC-environment version of client exports
|
|
3
3
|
*
|
|
4
|
-
* This file is used when importing "
|
|
4
|
+
* This file is used when importing "@rangojs/router/client" from RSC (server components).
|
|
5
5
|
* It re-exports the server's createLoader so that loader definitions work in both
|
|
6
6
|
* environments with the same import.
|
|
7
7
|
*
|
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
* in RSC context, while the regular client.tsx is used in client components.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
// From html.ts directly, never via ./client.js: every export of that
|
|
13
|
+
// "use client" module is an opaque client reference here.
|
|
14
|
+
import * as Html from "./html.js";
|
|
15
|
+
|
|
12
16
|
// Re-export everything from client.tsx (Outlet, useLoader, etc.)
|
|
13
17
|
// These are safe to use in RSC context
|
|
14
18
|
export {
|
|
@@ -64,7 +68,10 @@ export {
|
|
|
64
68
|
useLinkStatus,
|
|
65
69
|
type LinkStatus,
|
|
66
70
|
} from "./browser/react/use-link-status.js";
|
|
67
|
-
export {
|
|
71
|
+
export {
|
|
72
|
+
useScrollRestoration,
|
|
73
|
+
type ScrollRestorationProps,
|
|
74
|
+
} from "./browser/react/ScrollRestoration.js";
|
|
68
75
|
|
|
69
76
|
export {
|
|
70
77
|
Link,
|
|
@@ -72,11 +79,6 @@ export {
|
|
|
72
79
|
type PrefetchStrategy,
|
|
73
80
|
} from "./browser/react/Link.js";
|
|
74
81
|
|
|
75
|
-
export {
|
|
76
|
-
ScrollRestoration,
|
|
77
|
-
type ScrollRestorationProps,
|
|
78
|
-
} from "./browser/react/ScrollRestoration.js";
|
|
79
|
-
|
|
80
82
|
export {
|
|
81
83
|
NavigationProvider,
|
|
82
84
|
type NavigationProviderProps,
|
|
@@ -91,14 +93,13 @@ export { MountContext } from "./browser/react/mount-context.js";
|
|
|
91
93
|
export { createHandle, isHandle, type Handle } from "./handle.js";
|
|
92
94
|
|
|
93
95
|
export { Meta } from "./handles/meta.js";
|
|
94
|
-
export { MetaTags } from "./handles/MetaTags.js";
|
|
95
96
|
export type { MetaDescriptor, MetaDescriptorBase } from "./router/types.js";
|
|
96
97
|
export {
|
|
97
98
|
Script,
|
|
98
99
|
type ScriptConfig,
|
|
99
100
|
type ScriptAttributes,
|
|
100
101
|
} from "./handles/script.js";
|
|
101
|
-
export {
|
|
102
|
+
export { Html };
|
|
102
103
|
export { Breadcrumbs, type BreadcrumbItem } from "./handles/breadcrumbs.js";
|
|
103
104
|
|
|
104
105
|
export {
|
package/src/client.tsx
CHANGED
|
@@ -8,6 +8,9 @@ import {
|
|
|
8
8
|
Suspense,
|
|
9
9
|
type ReactNode,
|
|
10
10
|
} from "react";
|
|
11
|
+
// Not `export * as Html`: plugin-rsc's "use client" proxy transform only
|
|
12
|
+
// expands bare `export *` and throws on a named one.
|
|
13
|
+
import * as Html from "./html.js";
|
|
11
14
|
import { OutletContext, type OutletContextValue } from "./outlet-context.js";
|
|
12
15
|
import {
|
|
13
16
|
type ClientErrorBoundaryFallbackProps,
|
|
@@ -300,7 +303,7 @@ interface ErrorBoundaryState {
|
|
|
300
303
|
* @example
|
|
301
304
|
* ```tsx
|
|
302
305
|
* "use client";
|
|
303
|
-
* import { ErrorBoundary } from "
|
|
306
|
+
* import { ErrorBoundary } from "@rangojs/router/client";
|
|
304
307
|
*
|
|
305
308
|
* function MyComponent() {
|
|
306
309
|
* return (
|
|
@@ -427,7 +430,6 @@ export {
|
|
|
427
430
|
} from "./browser/react/use-link-status.js";
|
|
428
431
|
|
|
429
432
|
export {
|
|
430
|
-
ScrollRestoration,
|
|
431
433
|
useScrollRestoration,
|
|
432
434
|
type ScrollRestorationProps,
|
|
433
435
|
} from "./browser/react/ScrollRestoration.js";
|
|
@@ -436,14 +438,13 @@ export { type Handle } from "./handle.js";
|
|
|
436
438
|
export { useHandle } from "./browser/react/use-handle.js";
|
|
437
439
|
|
|
438
440
|
export { Meta } from "./handles/meta.js";
|
|
439
|
-
export { MetaTags } from "./handles/MetaTags.js";
|
|
440
441
|
export type { MetaDescriptor, MetaDescriptorBase } from "./router/types.js";
|
|
441
442
|
export {
|
|
442
443
|
Script,
|
|
443
444
|
type ScriptConfig,
|
|
444
445
|
type ScriptAttributes,
|
|
445
446
|
} from "./handles/script.js";
|
|
446
|
-
export {
|
|
447
|
+
export { Html };
|
|
447
448
|
export { Breadcrumbs, type BreadcrumbItem } from "./handles/breadcrumbs.js";
|
|
448
449
|
|
|
449
450
|
export {
|
|
@@ -3,12 +3,16 @@
|
|
|
3
3
|
import type { ReactNode, ReactElement } from "react";
|
|
4
4
|
import { MetaTags } from "../handles/MetaTags.js";
|
|
5
5
|
import { Scripts } from "../handles/Scripts.js";
|
|
6
|
+
import { ScrollRestoration } from "../browser/react/ScrollRestoration.js";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Default document component that provides a basic HTML structure.
|
|
9
10
|
* Used when no custom document is provided to createRouter.
|
|
10
|
-
*
|
|
11
|
-
*
|
|
11
|
+
* Renders every Html member: Html.Meta (charset, viewport, route meta), head +
|
|
12
|
+
* body Html.Scripts sites for the Script handle, and Html.ScrollRestoration.
|
|
13
|
+
* An app that wants a custom getKey or no scroll restoration passes its own
|
|
14
|
+
* document; rendering a second Html.ScrollRestoration under this one only
|
|
15
|
+
* warns ("[Scroll] Already initialized").
|
|
12
16
|
*
|
|
13
17
|
* Uses suppressHydrationWarning on <html> because the theme script
|
|
14
18
|
* may modify class/style attributes before React hydrates.
|
|
@@ -27,6 +31,7 @@ export function DefaultDocument({
|
|
|
27
31
|
<body>
|
|
28
32
|
<Scripts position="body" />
|
|
29
33
|
{children}
|
|
34
|
+
<ScrollRestoration />
|
|
30
35
|
</body>
|
|
31
36
|
</html>
|
|
32
37
|
);
|
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
|
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* Runs in the RSC realm of the build's temp server, AFTER all bundles are
|
|
5
5
|
* written (the prelude embeds built client asset URLs — bootstrap module,
|
|
6
6
|
* chunk preloads — that only exist post-client-build). The capture core is
|
|
7
|
-
* producer A's, verbatim: deriveShellCaptureContext (
|
|
8
|
-
*
|
|
9
|
-
* quiesce, tags union, putShell barrier). Build capture first replays global
|
|
7
|
+
* producer A's, verbatim: deriveShellCaptureContext (push funnel, snapshot
|
|
8
|
+
* recording, implicit doc-cache scope) + settleCaptureRecord (the record-first
|
|
9
|
+
* step) + captureAndStoreShell (gates, quiesce, tags union, putShell barrier). Build capture first replays global
|
|
10
10
|
* and route middleware with a synthetic build request context
|
|
11
11
|
* (`ctx.build === true`, inert `ctx.waitUntil()`); middleware can seed vars or
|
|
12
12
|
* call `ctx.dynamic()` to skip this URL. The sink is an entry collector instead
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
import type { ShellCacheEntry } from "../cache/types.js";
|
|
24
|
+
import type { MatchResult } from "../types.js";
|
|
24
25
|
import { MemorySegmentCacheStore } from "../cache/memory-segment-store.js";
|
|
25
26
|
import {
|
|
26
27
|
createRequestContext,
|
|
@@ -31,7 +32,10 @@ import {
|
|
|
31
32
|
import {
|
|
32
33
|
deriveShellCaptureContext,
|
|
33
34
|
captureAndStoreShell,
|
|
35
|
+
settleCaptureRecord,
|
|
36
|
+
withinDeadline,
|
|
34
37
|
delay,
|
|
38
|
+
SHELL_CAPTURE_MAX_WAIT_MS,
|
|
35
39
|
SHELL_CAPTURE_RETRY_DELAY_MS,
|
|
36
40
|
type ShellCaptureDescriptor,
|
|
37
41
|
} from "../rsc/shell-capture.js";
|
|
@@ -44,7 +48,7 @@ import { isRouteNotFoundError } from "../errors.js";
|
|
|
44
48
|
import { createReverseFunction } from "../router/handler-context.js";
|
|
45
49
|
import { executeMiddleware, matchMiddleware } from "../router/middleware.js";
|
|
46
50
|
import type { MiddlewareEntry } from "../router/middleware.js";
|
|
47
|
-
import { getGlobalRouteMap
|
|
51
|
+
import { getGlobalRouteMap } from "../route-map-builder.js";
|
|
48
52
|
import {
|
|
49
53
|
resolvePprConfig,
|
|
50
54
|
type ResolvedPprConfig,
|
|
@@ -134,18 +138,25 @@ export interface BuildShellCaptureResult {
|
|
|
134
138
|
tags?: string[];
|
|
135
139
|
/** On route-mismatch: what this router's match actually landed on. */
|
|
136
140
|
matchedRouteName?: string;
|
|
141
|
+
/**
|
|
142
|
+
* On no-shell: the attempt ran out of ppr.captureTimeout. It is not
|
|
143
|
+
* retried: its match may still be running, and the retry would start the
|
|
144
|
+
* same work beside it (runtime twin: shell-capture.ts runShellCapture).
|
|
145
|
+
*/
|
|
146
|
+
timedOut?: true;
|
|
137
147
|
}
|
|
138
148
|
|
|
139
149
|
/**
|
|
140
150
|
* Capture the PPR shell for one prerendered URL at build time. Retries once
|
|
141
151
|
* in place on `no-shell` (the first attempt warms the temp server's SSR/Flight
|
|
142
|
-
* transform graph, mirroring producer A's cold-start retry — same delay)
|
|
152
|
+
* transform graph, mirroring producer A's cold-start retry — same delay),
|
|
153
|
+
* unless the attempt ran out of ppr.captureTimeout (`timedOut`).
|
|
143
154
|
*/
|
|
144
155
|
export async function captureShellForBuild(
|
|
145
156
|
opts: BuildShellCaptureOptions,
|
|
146
157
|
): Promise<BuildShellCaptureResult> {
|
|
147
158
|
const first = await attemptBuildCapture(opts);
|
|
148
|
-
if (first.outcome !== "no-shell") return first;
|
|
159
|
+
if (first.outcome !== "no-shell" || first.timedOut) return first;
|
|
149
160
|
if (opts.debug) {
|
|
150
161
|
console.log(
|
|
151
162
|
`[rango] shell capture attempt 1/2 for ${opts.urlPath} produced no shell (cold graph?) — retrying`,
|
|
@@ -215,6 +226,7 @@ async function attemptBuildCapture(
|
|
|
215
226
|
};
|
|
216
227
|
|
|
217
228
|
let mismatchedRouteName: string | undefined;
|
|
229
|
+
let timedOut = false;
|
|
218
230
|
const result = await runWithRequestContext(baseCtx, async () => {
|
|
219
231
|
const preview =
|
|
220
232
|
typeof router.previewMatch === "function"
|
|
@@ -234,14 +246,11 @@ async function attemptBuildCapture(
|
|
|
234
246
|
setRequestContextParams(preview.params ?? {}, preview.routeKey);
|
|
235
247
|
}
|
|
236
248
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
? isRouteRootScoped(preview.routeKey, router.id)
|
|
243
|
-
: undefined,
|
|
244
|
-
);
|
|
249
|
+
// Global-only, like the live request's middleware reverse
|
|
250
|
+
// (rsc/handler.ts: createReverseFunction(getRequiredRouteMap())): no
|
|
251
|
+
// include() scope, no param auto-fill. A scoped reverse here resolved
|
|
252
|
+
// `.name` at build while the live request threw `Unknown route`.
|
|
253
|
+
const middlewareReverse = createReverseFunction(getGlobalRouteMap());
|
|
245
254
|
|
|
246
255
|
const runCapture = () =>
|
|
247
256
|
runBuildCaptureFinal({
|
|
@@ -255,6 +264,9 @@ async function attemptBuildCapture(
|
|
|
255
264
|
setMismatchedRouteName: (routeName) => {
|
|
256
265
|
mismatchedRouteName = routeName;
|
|
257
266
|
},
|
|
267
|
+
markTimedOut: () => {
|
|
268
|
+
timedOut = true;
|
|
269
|
+
},
|
|
258
270
|
});
|
|
259
271
|
|
|
260
272
|
const routeMiddleware =
|
|
@@ -268,7 +280,7 @@ async function attemptBuildCapture(
|
|
|
268
280
|
env,
|
|
269
281
|
variables,
|
|
270
282
|
runCapture,
|
|
271
|
-
|
|
283
|
+
middlewareReverse,
|
|
272
284
|
baseCtx,
|
|
273
285
|
);
|
|
274
286
|
|
|
@@ -281,7 +293,7 @@ async function attemptBuildCapture(
|
|
|
281
293
|
env,
|
|
282
294
|
variables,
|
|
283
295
|
runRouteMiddleware,
|
|
284
|
-
|
|
296
|
+
middlewareReverse,
|
|
285
297
|
baseCtx,
|
|
286
298
|
);
|
|
287
299
|
});
|
|
@@ -294,6 +306,7 @@ async function attemptBuildCapture(
|
|
|
294
306
|
if (outcome === "route-mismatch") {
|
|
295
307
|
return { outcome, matchedRouteName: mismatchedRouteName };
|
|
296
308
|
}
|
|
309
|
+
if (outcome === "no-shell" && timedOut) return { outcome, timedOut: true };
|
|
297
310
|
return { outcome };
|
|
298
311
|
}
|
|
299
312
|
|
|
@@ -313,6 +326,8 @@ interface BuildCaptureFinalOptions {
|
|
|
313
326
|
router: any;
|
|
314
327
|
url: URL;
|
|
315
328
|
setMismatchedRouteName(routeName: string | undefined): void;
|
|
329
|
+
/** The attempt ran out of ppr.captureTimeout (BuildShellCaptureResult.timedOut). */
|
|
330
|
+
markTimedOut(): void;
|
|
316
331
|
}
|
|
317
332
|
|
|
318
333
|
async function runBuildMiddlewareEnvelope<TEnv>(
|
|
@@ -372,15 +387,28 @@ async function runBuildCaptureFinal(
|
|
|
372
387
|
// invoking this when baseCtx._dynamic is set. A loader/handler opting out
|
|
373
388
|
// DURING the capture render is caught by the derivedCtx._dynamic check below.
|
|
374
389
|
|
|
375
|
-
const
|
|
390
|
+
const derivation = deriveShellCaptureContext(baseCtx, {
|
|
376
391
|
ttl: opts.ttl,
|
|
377
392
|
swr: opts.swr,
|
|
378
393
|
});
|
|
394
|
+
const { derivedCtx, freshHandleStore } = derivation;
|
|
379
395
|
|
|
380
396
|
const outcome = await runWithRequestContext(derivedCtx, async () => {
|
|
381
|
-
|
|
397
|
+
// Same one deadline as the runtime capture: the match, the record-first
|
|
398
|
+
// step, then the prerender with what is left.
|
|
399
|
+
const deadline =
|
|
400
|
+
Date.now() + (opts.captureTimeout ?? SHELL_CAPTURE_MAX_WAIT_MS);
|
|
401
|
+
let match: MatchResult;
|
|
382
402
|
try {
|
|
383
|
-
|
|
403
|
+
const matched = await withinDeadline<MatchResult>(
|
|
404
|
+
router.match(request, { env }),
|
|
405
|
+
deadline,
|
|
406
|
+
);
|
|
407
|
+
if (!matched.done) {
|
|
408
|
+
options.markTimedOut();
|
|
409
|
+
return "no-shell" as const;
|
|
410
|
+
}
|
|
411
|
+
match = matched.value;
|
|
384
412
|
} catch (error) {
|
|
385
413
|
if (isPlainPathMiss(error, opts.urlPath)) {
|
|
386
414
|
return "route-mismatch" as const;
|
|
@@ -395,8 +423,25 @@ async function runBuildCaptureFinal(
|
|
|
395
423
|
|
|
396
424
|
setRequestContextParams(match.params, match.routeName);
|
|
397
425
|
|
|
398
|
-
|
|
426
|
+
// Same record-first step as the runtime capture. A prerendered URL's
|
|
427
|
+
// match comes from the prerender store (no handler runs, no doc record),
|
|
428
|
+
// which settleCaptureRecord reports as `prerender`.
|
|
429
|
+
const settled = await settleCaptureRecord(
|
|
399
430
|
match,
|
|
431
|
+
derivation,
|
|
432
|
+
descriptor,
|
|
433
|
+
deadline,
|
|
434
|
+
);
|
|
435
|
+
if (settled.kind === "refused") {
|
|
436
|
+
return derivedCtx._dynamic ? ("dynamic" as const) : ("refused" as const);
|
|
437
|
+
}
|
|
438
|
+
if (settled.kind === "timeout") {
|
|
439
|
+
options.markTimedOut();
|
|
440
|
+
return "no-shell" as const;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
const payload = buildFullPayload(
|
|
444
|
+
settled.match,
|
|
400
445
|
// buildFullPayload reads only ctx.router.* and ctx.version.
|
|
401
446
|
{ router, version: opts.buildVersion } as unknown as HandlerContext<any>,
|
|
402
447
|
url,
|
|
@@ -419,9 +464,15 @@ async function runBuildCaptureFinal(
|
|
|
419
464
|
rscStream,
|
|
420
465
|
freshHandleStore,
|
|
421
466
|
derivedCtx,
|
|
422
|
-
descriptor,
|
|
467
|
+
{ ...descriptor, captureTimeout: Math.max(1, deadline - Date.now()) },
|
|
423
468
|
);
|
|
424
|
-
|
|
469
|
+
if (captureOutcome === "no-shell" && Date.now() >= deadline) {
|
|
470
|
+
options.markTimedOut();
|
|
471
|
+
}
|
|
472
|
+
if (derivedCtx._dynamic) return "dynamic";
|
|
473
|
+
// A route cache() record that ran out mid-capture: the in-place retry
|
|
474
|
+
// (captureShellForBuild) reads or renders a newer one.
|
|
475
|
+
return captureOutcome === "expired" ? "no-shell" : captureOutcome;
|
|
425
476
|
});
|
|
426
477
|
|
|
427
478
|
return {
|