@rangojs/router 0.20.0 → 0.22.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/dist/bin/rango.js +39 -15
- package/dist/types/browser/event-controller.d.ts +49 -0
- package/dist/types/browser/history-state.d.ts +16 -4
- package/dist/types/browser/navigation-store.d.ts +9 -0
- package/dist/types/browser/navigation-transaction.d.ts +7 -0
- package/dist/types/browser/partial-update.d.ts +2 -1
- package/dist/types/browser/prefetch/default-strategy.d.ts +16 -20
- package/dist/types/browser/rango-state.d.ts +3 -1
- package/dist/types/browser/react/NavigationProvider.d.ts +14 -1
- package/dist/types/browser/react/context.d.ts +25 -0
- package/dist/types/browser/react/location-state-shared.d.ts +84 -10
- package/dist/types/browser/react/location-state.d.ts +7 -2
- package/dist/types/browser/rsc-router.d.ts +13 -2
- package/dist/types/browser/types.d.ts +10 -0
- package/dist/types/build/generate-manifest.d.ts +2 -0
- package/dist/types/cache/background-task.d.ts +22 -0
- package/dist/types/cache/cache-key-utils.d.ts +50 -5
- package/dist/types/cache/cache-policy.d.ts +17 -0
- package/dist/types/cache/cache-scope.d.ts +5 -6
- package/dist/types/cache/cf/cf-cache-store.d.ts +34 -7
- package/dist/types/cache/cf/cf-cache-types.d.ts +12 -4
- package/dist/types/cache/document-cache.d.ts +8 -5
- package/dist/types/cache/handle-snapshot.d.ts +59 -50
- package/dist/types/cache/index.d.ts +3 -1
- package/dist/types/cache/invalidation-order.d.ts +14 -0
- package/dist/types/cache/memory-segment-store.d.ts +33 -1
- package/dist/types/cache/shell-snapshot.d.ts +29 -4
- package/dist/types/cache/store-scope.d.ts +22 -0
- package/dist/types/cache/tag-invalidation.d.ts +7 -6
- package/dist/types/cache/types.d.ts +84 -24
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +35 -17
- package/dist/types/client-urls/navigation.d.ts +7 -1
- package/dist/types/client-urls/optimistic-location.d.ts +10 -4
- package/dist/types/errors.d.ts +6 -0
- package/dist/types/handles/deferred-resolution.d.ts +18 -1
- package/dist/types/internal-suspense-audit.d.ts +1 -0
- package/dist/types/loader-store.d.ts +4 -8
- package/dist/types/outlet-provider.d.ts +2 -1
- package/dist/types/prerender/build-shell-capture.d.ts +8 -6
- package/dist/types/prerender/cloudflare.d.ts +49 -0
- package/dist/types/prerender/create-prerender-trigger.d.ts +121 -0
- package/dist/types/prerender/index.d.ts +12 -0
- package/dist/types/prerender/memory-prerender-store.d.ts +29 -0
- package/dist/types/prerender/on-demand.d.ts +272 -0
- package/dist/types/prerender/producer-guard.d.ts +33 -0
- package/dist/types/prerender/shell-manifest-key.d.ts +1 -18
- package/dist/types/prerender/warm-request.d.ts +65 -0
- package/dist/types/prerender/warm.d.ts +65 -0
- package/dist/types/prerender/writable-store.d.ts +170 -0
- package/dist/types/prerender.d.ts +27 -0
- package/dist/types/reverse.d.ts +1 -1
- package/dist/types/route-content-wrapper.d.ts +3 -1
- package/dist/types/router/error-handling.d.ts +2 -0
- package/dist/types/router/handler-context.d.ts +1 -1
- package/dist/types/router/match-middleware/cache-lookup.d.ts +15 -1
- package/dist/types/router/navigation-snapshot.d.ts +8 -1
- package/dist/types/router/pattern-matching.d.ts +2 -0
- package/dist/types/router/prefetch-default.d.ts +4 -4
- package/dist/types/router/prerender-match.d.ts +23 -1
- package/dist/types/router/route-trie-builder.d.ts +8 -1
- package/dist/types/router/router-context.d.ts +1 -0
- package/dist/types/router/router-interfaces.d.ts +32 -1
- package/dist/types/router/router-options.d.ts +39 -5
- package/dist/types/router/segment-resolution/fresh.d.ts +7 -0
- package/dist/types/router/segment-resolution/loader-cache.d.ts +23 -10
- package/dist/types/router/segment-resolution/revalidation.d.ts +5 -1
- package/dist/types/router/segment-resolution/streamed-handler-boundary.d.ts +43 -0
- package/dist/types/router/trie-matching.d.ts +2 -0
- package/dist/types/router-versions.d.ts +39 -0
- package/dist/types/rsc/handler-context.d.ts +5 -0
- package/dist/types/rsc/shell-build-manifest.d.ts +9 -6
- package/dist/types/rsc/shell-capture-constants.d.ts +20 -5
- package/dist/types/rsc/shell-capture.d.ts +14 -1
- package/dist/types/rsc/shell-serve.d.ts +2 -2
- package/dist/types/rsc/ssr-module-loader.d.ts +15 -0
- package/dist/types/rsc/types.d.ts +12 -6
- package/dist/types/segment-boundary-content.d.ts +17 -0
- package/dist/types/segment-loader-promise.d.ts +2 -6
- package/dist/types/server/build-version-table.d.ts +53 -0
- package/dist/types/server/context.d.ts +12 -4
- package/dist/types/server/handle-store.d.ts +89 -46
- package/dist/types/server/request-context.d.ts +84 -9
- package/dist/types/suspense-audit-react.d.ts +26 -0
- package/dist/types/suspense-audit.d.ts +157 -0
- package/dist/types/testing/action-form.d.ts +34 -0
- package/dist/types/testing/build-versions.d.ts +32 -0
- package/dist/types/testing/dom.entry.d.ts +1 -1
- package/dist/types/testing/flight.entry.d.ts +3 -1
- package/dist/types/testing/index.d.ts +6 -0
- package/dist/types/testing/internal/seed-vars.d.ts +7 -2
- package/dist/types/testing/internal/server-modules.d.ts +8 -0
- package/dist/types/testing/location-state-key.d.ts +5 -1
- package/dist/types/testing/render-route.d.ts +77 -6
- package/dist/types/testing/serve-shell-request.d.ts +55 -4
- package/dist/types/testing/shell-status.d.ts +14 -6
- package/dist/types/testing/vitest-stubs/plugin-rsc.d.ts +9 -6
- package/dist/types/testing/vitest-stubs/version.d.ts +1 -0
- package/dist/types/thenable-status.d.ts +6 -0
- package/dist/types/types/handler-context.d.ts +15 -5
- package/dist/types/types/route-entry.d.ts +5 -0
- package/dist/types/urls/path-helper.d.ts +18 -0
- package/dist/types/vite/discovery/build-versions.d.ts +393 -0
- package/dist/types/vite/discovery/installed-packages.d.ts +26 -0
- package/dist/types/vite/discovery/router-versions-phase.d.ts +52 -0
- package/dist/types/vite/discovery/shell-prerender-phase.d.ts +7 -17
- package/dist/types/vite/discovery/state.d.ts +25 -0
- package/dist/types/vite/encryption-key.d.ts +18 -0
- package/dist/types/vite/inject-client-debug.d.ts +6 -25
- package/dist/types/vite/plugin-types.d.ts +27 -0
- package/dist/types/vite/plugins/{version-injector.d.ts → entry-bootstrap-injector.d.ts} +4 -6
- package/dist/types/vite/plugins/expose-ids/export-analysis.d.ts +1 -0
- package/dist/types/vite/plugins/expose-ids/router-transform.d.ts +14 -0
- package/dist/types/vite/plugins/stable-rsc-output.d.ts +51 -0
- package/dist/types/vite/plugins/version-plugin.d.ts +9 -11
- package/dist/types/vite/plugins/virtual-entries.d.ts +18 -1
- package/dist/types/vite/router-discovery.d.ts +6 -0
- package/dist/types/vite/utils/bundle-analysis.d.ts +6 -2
- package/dist/types/vite/utils/client-chunks.d.ts +2 -0
- package/dist/types/vite/utils/compare-strings.d.ts +7 -0
- package/dist/types/vite/utils/package-resolution.d.ts +8 -0
- package/dist/types/vite/utils/prerender-utils.d.ts +2 -0
- package/dist/vite/index.js +1707 -931
- package/package.json +12 -3
- package/skills/cache-guide/SKILL.md +102 -37
- package/skills/caching/SKILL.md +56 -9
- package/skills/catalog.json +1 -1
- package/skills/client-urls/SKILL.md +16 -0
- package/skills/cloudflare/SKILL.md +133 -1
- package/skills/comparison/references/framework-comparison.md +17 -13
- package/skills/deployment-caching/SKILL.md +33 -12
- package/skills/document-cache/SKILL.md +16 -14
- package/skills/hooks/SKILL.md +25 -0
- package/skills/hooks/handle-and-actions.md +5 -0
- package/skills/hooks/navigation.md +38 -0
- package/skills/hooks/state.md +213 -11
- package/skills/hooks/urls.md +40 -1
- package/skills/host-router/SKILL.md +31 -0
- package/skills/intercept/SKILL.md +6 -0
- package/skills/loader/SKILL.md +25 -5
- package/skills/middleware/SKILL.md +2 -0
- package/skills/migrate-nextjs/SKILL.md +82 -9
- package/skills/ppr/SKILL.md +150 -48
- package/skills/prerender/SKILL.md +651 -10
- package/skills/rango/SKILL.md +9 -7
- package/skills/response-routes/SKILL.md +5 -5
- package/skills/route/SKILL.md +29 -0
- package/skills/router-setup/SKILL.md +15 -1
- package/skills/testing/SKILL.md +32 -27
- package/skills/testing/cache-prerender.md +18 -17
- package/skills/testing/client-components.md +193 -8
- package/skills/testing/handles.md +2 -0
- package/skills/testing/loader.md +1 -1
- package/skills/testing/middleware.md +1 -1
- package/skills/testing/render-handler.md +18 -18
- package/skills/testing/serve-shell-request.md +167 -22
- package/skills/testing/server-actions.md +17 -17
- package/skills/testing/server-tree.md +1 -1
- package/skills/typesafety/generated-files-and-cli.md +1 -1
- package/skills/use-cache/SKILL.md +25 -10
- package/skills/vercel/SKILL.md +5 -3
- package/skills/view-transitions/SKILL.md +9 -4
- package/src/bin/rango.ts +1 -1
- package/src/browser/event-controller.ts +119 -2
- package/src/browser/history-state.ts +39 -17
- package/src/browser/link-interceptor.ts +2 -2
- package/src/browser/navigation-bridge.ts +104 -41
- package/src/browser/navigation-store.ts +26 -0
- package/src/browser/navigation-transaction.ts +24 -12
- package/src/browser/network-error-handler.ts +2 -0
- package/src/browser/partial-update.ts +58 -14
- package/src/browser/prefetch/default-strategy.ts +22 -42
- package/src/browser/rango-state.ts +3 -1
- package/src/browser/react/Link.tsx +37 -43
- package/src/browser/react/NavigationProvider.tsx +85 -1
- package/src/browser/react/context.ts +30 -0
- package/src/browser/react/location-state-shared.ts +200 -34
- package/src/browser/react/location-state.ts +28 -77
- package/src/browser/react/use-action.ts +4 -1
- package/src/browser/react/use-handle.ts +3 -0
- package/src/browser/react/use-link-status.ts +4 -3
- package/src/browser/react/use-navigation.ts +4 -1
- package/src/browser/react/use-params.ts +4 -1
- package/src/browser/react/use-pathname.ts +4 -1
- package/src/browser/react/use-search-params.ts +5 -3
- package/src/browser/react/use-segments.ts +36 -54
- package/src/browser/rsc-router.tsx +93 -31
- package/src/browser/segment-reconciler.ts +3 -3
- package/src/browser/server-action-bridge.ts +43 -7
- package/src/browser/types.ts +11 -0
- package/src/build/generate-manifest.ts +17 -0
- package/src/build/merge-full-manifests.ts +5 -0
- package/src/build/route-trie.ts +1 -0
- package/src/cache/background-task.ts +61 -0
- package/src/cache/cache-key-utils.ts +91 -12
- package/src/cache/cache-policy.ts +11 -2
- package/src/cache/cache-runtime.ts +23 -23
- package/src/cache/cache-scope.ts +48 -36
- package/src/cache/cf/cf-cache-store.ts +91 -66
- package/src/cache/cf/cf-cache-types.ts +12 -4
- package/src/cache/document-cache.ts +35 -14
- package/src/cache/handle-snapshot.ts +118 -86
- package/src/cache/index.ts +5 -0
- package/src/cache/invalidation-order.ts +53 -0
- package/src/cache/memory-segment-store.ts +52 -1
- package/src/cache/shell-snapshot.ts +52 -5
- package/src/cache/store-scope.ts +36 -0
- package/src/cache/tag-invalidation.ts +7 -5
- package/src/cache/types.ts +90 -24
- package/src/cache/vercel/vercel-cache-store.ts +68 -26
- package/src/client-urls/client-root.tsx +1 -0
- package/src/client-urls/navigation.ts +10 -0
- package/src/client-urls/optimistic-location.ts +10 -4
- package/src/client.tsx +40 -3
- package/src/errors.ts +13 -6
- package/src/handles/deferred-resolution.ts +36 -0
- package/src/internal-suspense-audit.ts +12 -0
- package/src/loader-store.ts +4 -9
- package/src/outlet-provider.tsx +25 -1
- package/src/prerender/build-shell-capture.ts +11 -9
- package/src/prerender/cloudflare.ts +130 -0
- package/src/prerender/create-prerender-trigger.ts +780 -0
- package/src/prerender/index.ts +39 -0
- package/src/prerender/memory-prerender-store.ts +115 -0
- package/src/prerender/on-demand.ts +339 -0
- package/src/prerender/producer-guard.ts +66 -0
- package/src/prerender/shell-manifest-key.ts +12 -17
- package/src/prerender/warm-request.ts +154 -0
- package/src/prerender/warm.ts +193 -0
- package/src/prerender/writable-store.ts +278 -0
- package/src/prerender.ts +29 -0
- package/src/reverse.ts +1 -1
- package/src/route-content-wrapper.tsx +107 -13
- package/src/router/error-handling.ts +12 -12
- package/src/router/find-match.ts +1 -0
- package/src/router/handler-context.ts +2 -0
- package/src/router/intercept-resolution.ts +15 -8
- package/src/router/loader-resolution.ts +2 -10
- package/src/router/manifest.ts +2 -0
- package/src/router/match-middleware/background-revalidation.ts +2 -0
- package/src/router/match-middleware/cache-lookup.ts +239 -54
- package/src/router/navigation-snapshot.ts +25 -6
- package/src/router/pattern-matching.ts +14 -0
- package/src/router/prefetch-default.ts +4 -4
- package/src/router/prerender-match.ts +460 -352
- package/src/router/request-classification.ts +15 -12
- package/src/router/route-trie-builder.ts +9 -0
- package/src/router/router-context.ts +1 -0
- package/src/router/router-interfaces.ts +35 -1
- package/src/router/router-options.ts +45 -5
- package/src/router/segment-resolution/fresh.ts +20 -19
- package/src/router/segment-resolution/loader-cache.ts +110 -77
- package/src/router/segment-resolution/revalidation.ts +34 -24
- package/src/router/segment-resolution/streamed-handler-boundary.ts +133 -0
- package/src/router/trie-matching.ts +3 -0
- package/src/router-versions.ts +60 -0
- package/src/router.ts +107 -1
- package/src/rsc/full-payload.ts +6 -2
- package/src/rsc/handler-context.ts +5 -0
- package/src/rsc/handler.ts +64 -7
- package/src/rsc/progressive-enhancement.ts +5 -1
- package/src/rsc/response-cache-serve.ts +10 -4
- package/src/rsc/rsc-rendering.ts +65 -12
- package/src/rsc/shell-build-manifest.ts +17 -12
- package/src/rsc/shell-capture-constants.ts +39 -7
- package/src/rsc/shell-capture.ts +144 -45
- package/src/rsc/shell-serve.ts +12 -6
- package/src/rsc/ssr-module-loader.ts +26 -0
- package/src/rsc/types.ts +12 -6
- package/src/segment-boundary-content.ts +25 -0
- package/src/segment-loader-promise.ts +28 -38
- package/src/segment-system.tsx +117 -57
- package/src/server/build-version-table.ts +130 -0
- package/src/server/context.ts +40 -17
- package/src/server/cookie-store.ts +5 -0
- package/src/server/handle-store.ts +357 -127
- package/src/server/request-context.ts +149 -12
- package/src/ssr/ssr-root.tsx +32 -13
- package/src/suspense-audit-react.tsx +98 -0
- package/src/suspense-audit.ts +1030 -0
- package/src/testing/action-form.ts +66 -0
- package/src/testing/build-versions.ts +64 -0
- package/src/testing/dispatch.ts +6 -0
- package/src/testing/dom.entry.ts +1 -0
- package/src/testing/flight-runtime.d.ts +27 -0
- package/src/testing/flight.entry.ts +4 -0
- package/src/testing/index.ts +22 -0
- package/src/testing/internal/context.ts +2 -1
- package/src/testing/internal/seed-vars.ts +14 -2
- package/src/testing/internal/server-modules.ts +32 -0
- package/src/testing/location-state-key.ts +18 -8
- package/src/testing/render-handler.ts +2 -1
- package/src/testing/render-route.tsx +293 -46
- package/src/testing/serve-shell-request.ts +262 -37
- package/src/testing/shell-status.ts +17 -6
- package/src/testing/vitest-stubs/plugin-rsc.ts +37 -11
- package/src/testing/vitest-stubs/version.ts +4 -1
- package/src/thenable-status.ts +10 -0
- package/src/types/handler-context.ts +15 -5
- package/src/types/route-entry.ts +6 -0
- package/src/urls/path-helper.ts +69 -9
- package/src/use-loader.tsx +57 -30
- package/src/vite/discovery/build-versions.ts +1281 -0
- package/src/vite/discovery/bundle-postprocess.ts +4 -0
- package/src/vite/discovery/discover-routers.ts +15 -0
- package/src/vite/discovery/installed-packages.ts +159 -0
- package/src/vite/discovery/prerender-collection.ts +38 -1
- package/src/vite/discovery/router-versions-phase.ts +336 -0
- package/src/vite/discovery/shell-prerender-phase.ts +33 -43
- package/src/vite/discovery/state.ts +36 -1
- package/src/vite/discovery/virtual-module-codegen.ts +7 -2
- package/src/vite/encryption-key.ts +101 -9
- package/src/vite/inject-client-debug.ts +42 -20
- package/src/vite/plugin-types.ts +28 -0
- package/src/vite/plugins/{version-injector.ts → entry-bootstrap-injector.ts} +7 -22
- package/src/vite/plugins/expose-ids/export-analysis.ts +1 -1
- package/src/vite/plugins/expose-ids/router-transform.ts +36 -15
- package/src/vite/plugins/expose-internal-ids.ts +12 -3
- package/src/vite/plugins/stable-rsc-output.ts +147 -0
- package/src/vite/plugins/version-plugin.ts +19 -24
- package/src/vite/plugins/version.d.ts +17 -2
- package/src/vite/plugins/virtual-entries.ts +39 -6
- package/src/vite/rango.ts +28 -3
- package/src/vite/router-discovery.ts +96 -13
- package/src/vite/utils/bundle-analysis.ts +39 -7
- package/src/vite/utils/client-chunks.ts +5 -1
- package/src/vite/utils/compare-strings.ts +9 -0
- package/src/vite/utils/package-resolution.ts +9 -0
- package/src/vite/utils/prerender-utils.ts +4 -1
- package/src/vite/utils/shared-utils.ts +1 -1
- package/dist/types/segment-content-promise.d.ts +0 -13
- package/src/segment-content-promise.ts +0 -67
|
@@ -46,7 +46,11 @@ import { withDefer } from "../defer.js";
|
|
|
46
46
|
import { type MetricsStore } from "./context.js";
|
|
47
47
|
import { observePhase, PHASES } from "../router/instrument.js";
|
|
48
48
|
import { getFetchableLoader } from "./fetchable-loader-store.js";
|
|
49
|
-
import type {
|
|
49
|
+
import type {
|
|
50
|
+
SegmentCacheStore,
|
|
51
|
+
ShellSnapshotHandlesValue,
|
|
52
|
+
} from "../cache/types.js";
|
|
53
|
+
import type { RouterVersions } from "../router-versions.js";
|
|
50
54
|
import type { Theme, ResolvedThemeConfig } from "../theme/types.js";
|
|
51
55
|
import type { ExecutionContext, RequestScope } from "../types/request-scope.js";
|
|
52
56
|
import type { TransitionWhenRecord } from "../router/transition-when.js";
|
|
@@ -288,6 +292,30 @@ export interface RequestContext<
|
|
|
288
292
|
/** @internal Cache store for segment caching (optional, used by CacheScope) */
|
|
289
293
|
_cacheStore?: SegmentCacheStore;
|
|
290
294
|
|
|
295
|
+
/**
|
|
296
|
+
* @internal Env-scoped writable prerender store (the durable overlay) plus the
|
|
297
|
+
* deployment identity for build-scoped keys, resolved per request from the
|
|
298
|
+
* `prerender` router option. Read by the serve-path overlay lookup before the
|
|
299
|
+
* bundled build manifest. Absent when no prerender store is configured.
|
|
300
|
+
*/
|
|
301
|
+
// ResolvedPrerender<any> (not <TEnv>): onRevalidate's contravariant `env` would
|
|
302
|
+
// otherwise make RequestContext invariant in TEnv, breaking existing
|
|
303
|
+
// RequestContext<{}> -> RequestContext<unknown> assignments.
|
|
304
|
+
_prerender?: import("../prerender/on-demand.js").ResolvedPrerender<any>;
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* @internal Set only on the requestless on-demand producer's context. When
|
|
308
|
+
* present, the standalone request-scoped READS — `cookies()`, `headers()`,
|
|
309
|
+
* `invalidateClientCache()`, `keepClientCache()` — throw a
|
|
310
|
+
* PrerenderPersonalizationError so a personalized render is skipped rather than
|
|
311
|
+
* baked into a shared payload. Response MUTATIONS on the producer context
|
|
312
|
+
* (`ctx.setStatus`/`header`/`setCookie`) stay silent no-op stubs, matching
|
|
313
|
+
* build-time prerender (the design's "throw or skip" contract permits skip):
|
|
314
|
+
* they write to a discarded synthetic response, so there is nothing to leak.
|
|
315
|
+
* Never set on the live request path.
|
|
316
|
+
*/
|
|
317
|
+
_onDemandProducer?: true;
|
|
318
|
+
|
|
291
319
|
/**
|
|
292
320
|
* @internal Compiled `cache.searchParams` filter for default cache-key
|
|
293
321
|
* generation (undefined = "all", the byte-stable unfiltered format). Set
|
|
@@ -364,6 +392,22 @@ export interface RequestContext<
|
|
|
364
392
|
*/
|
|
365
393
|
_shellForcedMiss?: true;
|
|
366
394
|
|
|
395
|
+
/**
|
|
396
|
+
* @internal This request is a router.prerender() warm
|
|
397
|
+
* (prerender/warm-request.ts). In `replace` mode every runtime cache read
|
|
398
|
+
* misses (isWarmReplace); the layers report into the record. A capture's
|
|
399
|
+
* derived context inherits it through the prototype.
|
|
400
|
+
*/
|
|
401
|
+
_prerenderWarm?: import("../prerender/warm-request.js").PrerenderWarmRecord;
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* @internal Runs a callback in the async context this request entered the
|
|
405
|
+
* handler with (captureRequestEntryContext). router.prerender() dispatches
|
|
406
|
+
* a warm through it when called from inside a request. Absent where the
|
|
407
|
+
* runtime has no AsyncLocalStorage.snapshot.
|
|
408
|
+
*/
|
|
409
|
+
_runAtRequestEntry?: <T>(fn: () => T) => T;
|
|
410
|
+
|
|
367
411
|
/**
|
|
368
412
|
* @internal The freshness window of the route cache() records this
|
|
369
413
|
* request read or wrote (cache-scope.ts noteRouteRecordWindow), as ms
|
|
@@ -377,7 +421,7 @@ export interface RequestContext<
|
|
|
377
421
|
|
|
378
422
|
/**
|
|
379
423
|
* @internal Loader-family snapshot seed for a shell HIT's tail render:
|
|
380
|
-
*
|
|
424
|
+
* loader id -> the capture's elided container (already Flight-deserialized
|
|
381
425
|
* by serveShellHit) plus its capture-computed hole bit. resolveLoaderData
|
|
382
426
|
* overlays it onto the fresh run's container (recorded paths pinned,
|
|
383
427
|
* hole-marker paths keep the fresh nested promises) so the payload's baked
|
|
@@ -385,7 +429,9 @@ export interface RequestContext<
|
|
|
385
429
|
* and does not run the loader. Two owners: serveShellHit sets it on the
|
|
386
430
|
* HIT tail's derived context, and matchPartialWithPprReplay sets it on the
|
|
387
431
|
* request context of a PPR partial replay once its doc record hits, and
|
|
388
|
-
* restores the previous value after the match.
|
|
432
|
+
* restores the previous value after the match. Read through servedPins
|
|
433
|
+
* (loader-cache.ts) only: it also decides which of the record's
|
|
434
|
+
* loader-owned handle pushes stand (loaderPins).
|
|
389
435
|
*/
|
|
390
436
|
_shellLoaderSeed?: Map<
|
|
391
437
|
string,
|
|
@@ -446,9 +492,7 @@ export interface RequestContext<
|
|
|
446
492
|
* scope replaces any route-derived cache() scope for the tail's match
|
|
447
493
|
* (resolveShellImplicitCacheScope), and a lookup that does not hit throws
|
|
448
494
|
* ShellRecordUnavailableError instead of resolving segments
|
|
449
|
-
* (withCacheLookup): a HIT never runs a handler.
|
|
450
|
-
* loader-owned handle pushes restore as authoritative
|
|
451
|
-
* (HandleStore.pushRestored): the prelude rendered them.
|
|
495
|
+
* (withCacheLookup): a HIT never runs a handler.
|
|
452
496
|
*/
|
|
453
497
|
docTail?: true;
|
|
454
498
|
/**
|
|
@@ -458,6 +502,8 @@ export interface RequestContext<
|
|
|
458
502
|
* host) and miss the record.
|
|
459
503
|
*/
|
|
460
504
|
fixedDocKey?: string;
|
|
505
|
+
/** @internal The snapshot's `handles` record (ShellSnapshotHandlesValue). */
|
|
506
|
+
prerenderHandles?: ShellSnapshotHandlesValue;
|
|
461
507
|
/**
|
|
462
508
|
* @internal Set ONLY by matchPartialWithPprReplay on the navigation-replay
|
|
463
509
|
* serve path. Its presence arms the explicit-scope composition in
|
|
@@ -807,6 +853,18 @@ export interface RequestContext<
|
|
|
807
853
|
*/
|
|
808
854
|
_renderErrors?: unknown[];
|
|
809
855
|
|
|
856
|
+
/**
|
|
857
|
+
* @internal Rejections of streamed (loading()) handlers that were recovered
|
|
858
|
+
* into a declared errorBoundary()/notFoundBoundary() fallback, by segment id.
|
|
859
|
+
* The recovered promise resolves, so Flight reports nothing; cacheRoute
|
|
860
|
+
* (cache-scope.ts) refuses a write only when one of ITS segments is listed,
|
|
861
|
+
* the granularity a Flight error row has. The same errors are also pushed to
|
|
862
|
+
* `_renderErrors` for the document cache and PPR shell capture. A render
|
|
863
|
+
* under a derived context (shell capture, SWR re-render) owns its own map.
|
|
864
|
+
* Allocated on the first recovery.
|
|
865
|
+
*/
|
|
866
|
+
_recoveredHandlerErrors?: Map<string, unknown>;
|
|
867
|
+
|
|
810
868
|
/**
|
|
811
869
|
* @internal Report a non-fatal background error through the router's
|
|
812
870
|
* onError callback. Wired by the RSC handler / router during request
|
|
@@ -857,6 +915,15 @@ export interface RequestContext<
|
|
|
857
915
|
* lookups per router (route-map-builder.ts) */
|
|
858
916
|
_routerId?: string;
|
|
859
917
|
|
|
918
|
+
/**
|
|
919
|
+
* @internal Cache versions of the router serving this request. The cache
|
|
920
|
+
* factory builds a store per request without knowing the router, so a store
|
|
921
|
+
* reads its key versions from here, lazily, the same way CFCacheStore
|
|
922
|
+
* resolves its base URL (getCacheVersions, server/build-version-table.ts).
|
|
923
|
+
* Unset on a context no router created; a store then uses the build version.
|
|
924
|
+
*/
|
|
925
|
+
_versions?: RouterVersions;
|
|
926
|
+
|
|
860
927
|
/**
|
|
861
928
|
* @internal RouteSnapshot from classifyRequest, reused by match/matchPartial
|
|
862
929
|
* to avoid a second resolveRoute call. Cleared on HMR invalidation.
|
|
@@ -916,6 +983,8 @@ export type PublicRequestContext<
|
|
|
916
983
|
| "_transitionWhenRefs"
|
|
917
984
|
| "_pprReplayPostMatchReason"
|
|
918
985
|
| "_cacheStore"
|
|
986
|
+
| "_prerender"
|
|
987
|
+
| "_onDemandProducer"
|
|
919
988
|
| "_searchParamsFilter"
|
|
920
989
|
| "_shellCaptureRun"
|
|
921
990
|
| "_shellImplicitCache"
|
|
@@ -926,6 +995,8 @@ export type PublicRequestContext<
|
|
|
926
995
|
| "_resolvedCacheKeys"
|
|
927
996
|
| "_shellKey"
|
|
928
997
|
| "_shellForcedMiss"
|
|
998
|
+
| "_prerenderWarm"
|
|
999
|
+
| "_runAtRequestEntry"
|
|
929
1000
|
| "_routeRecordWindow"
|
|
930
1001
|
| "_shellFragmentPayload"
|
|
931
1002
|
| "_shellCaptureGuardTripped"
|
|
@@ -947,6 +1018,7 @@ export type PublicRequestContext<
|
|
|
947
1018
|
| "_inActionRevalidation"
|
|
948
1019
|
| "_reportedErrors"
|
|
949
1020
|
| "_renderErrors"
|
|
1021
|
+
| "_recoveredHandlerErrors"
|
|
950
1022
|
| "_renderBarrier"
|
|
951
1023
|
| "_resolveRenderBarrier"
|
|
952
1024
|
| "_renderBarrierSegmentOrder"
|
|
@@ -966,6 +1038,7 @@ export type PublicRequestContext<
|
|
|
966
1038
|
| "_tracing"
|
|
967
1039
|
| "_basename"
|
|
968
1040
|
| "_routerId"
|
|
1041
|
+
| "_versions"
|
|
969
1042
|
| "_setStatus"
|
|
970
1043
|
| "_rotateStateCookie"
|
|
971
1044
|
| "_setKeepCacheDirective"
|
|
@@ -996,6 +1069,22 @@ export const UNTRACKED_BACKGROUND_TASK: unique symbol = Symbol.for(
|
|
|
996
1069
|
// AsyncLocalStorage instance for request context
|
|
997
1070
|
const requestContextStorage = new AsyncLocalStorage<RequestContext<any>>();
|
|
998
1071
|
|
|
1072
|
+
/**
|
|
1073
|
+
* Capture the current async context (RequestContext._runAtRequestEntry), taken
|
|
1074
|
+
* on handler entry before any router scope, so a nested dispatch (a
|
|
1075
|
+
* router.prerender() warm called from a handler, loader or action) does not
|
|
1076
|
+
* inherit the caller's route-definition, loader and cache-scope state. Per
|
|
1077
|
+
* request: workerd refuses a snapshot outside the request that created it.
|
|
1078
|
+
* See docs/design/prerender-every-route.md.
|
|
1079
|
+
*/
|
|
1080
|
+
export function captureRequestEntryContext():
|
|
1081
|
+
| (<T>(fn: () => T) => T)
|
|
1082
|
+
| undefined {
|
|
1083
|
+
return typeof AsyncLocalStorage.snapshot === "function"
|
|
1084
|
+
? AsyncLocalStorage.snapshot()
|
|
1085
|
+
: undefined;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
999
1088
|
/**
|
|
1000
1089
|
* Run a function within a request context
|
|
1001
1090
|
* Used by the RSC handler to provide context to server actions
|
|
@@ -1107,6 +1196,12 @@ export interface CreateRequestContextOptions<TEnv> {
|
|
|
1107
1196
|
initialResponse?: Response;
|
|
1108
1197
|
/** Optional cache store for segment caching (used by CacheScope) */
|
|
1109
1198
|
cacheStore?: SegmentCacheStore;
|
|
1199
|
+
/**
|
|
1200
|
+
* Optional env-scoped writable prerender store + deployment identity (the
|
|
1201
|
+
* durable overlay), resolved per request by the RSC handler from the
|
|
1202
|
+
* `prerender` router option.
|
|
1203
|
+
*/
|
|
1204
|
+
prerender?: import("../prerender/on-demand.js").ResolvedPrerender<any>;
|
|
1110
1205
|
/**
|
|
1111
1206
|
* Compiled `cache.searchParams` filter from the resolved handler cache
|
|
1112
1207
|
* config (handler.ts). Stored as _searchParamsFilter.
|
|
@@ -1130,8 +1225,13 @@ export interface CreateRequestContextOptions<TEnv> {
|
|
|
1130
1225
|
themeConfig?: ResolvedThemeConfig | null;
|
|
1131
1226
|
/** Resolved rango state cookie name, for the server seat of invalidateClientCache(). */
|
|
1132
1227
|
stateCookieName?: string;
|
|
1133
|
-
/**
|
|
1134
|
-
|
|
1228
|
+
/**
|
|
1229
|
+
* The versions of the router serving this request (resolveRouterVersions).
|
|
1230
|
+
* Stored as `_versions` for the cache stores; `document` is also the prefix
|
|
1231
|
+
* of a server-rotated rango state value, which the browser compares with the
|
|
1232
|
+
* payload's `metadata.version`.
|
|
1233
|
+
*/
|
|
1234
|
+
versions?: RouterVersions;
|
|
1135
1235
|
}
|
|
1136
1236
|
|
|
1137
1237
|
/**
|
|
@@ -1152,6 +1252,7 @@ export function createRequestContext<TEnv>(
|
|
|
1152
1252
|
variables,
|
|
1153
1253
|
initialResponse,
|
|
1154
1254
|
cacheStore,
|
|
1255
|
+
prerender,
|
|
1155
1256
|
searchParamsFilter,
|
|
1156
1257
|
explicitTaggedStores,
|
|
1157
1258
|
cacheProfiles,
|
|
@@ -1159,7 +1260,7 @@ export function createRequestContext<TEnv>(
|
|
|
1159
1260
|
build = false,
|
|
1160
1261
|
themeConfig,
|
|
1161
1262
|
stateCookieName,
|
|
1162
|
-
|
|
1263
|
+
versions,
|
|
1163
1264
|
} = options;
|
|
1164
1265
|
// ctx.request.headers is guarded like headers() (#976); every router read
|
|
1165
1266
|
// of this request's headers goes through requestHeaders().
|
|
@@ -1194,6 +1295,12 @@ export function createRequestContext<TEnv>(
|
|
|
1194
1295
|
// Set-Cookie drain (rsc/helpers.ts) run outside any latched funnel scope,
|
|
1195
1296
|
// where assertCachedHeaderWriteAllowed is a no-op.
|
|
1196
1297
|
let rawStubHeaders = stubResponse.headers;
|
|
1298
|
+
// Node's util.inspect unwraps this Proxy and calls undici's Headers hook
|
|
1299
|
+
// with the proxy as `this`. That reads `#headersList` and throws (#1000).
|
|
1300
|
+
// Inspect does not consult the get trap, so the hook is an own property of
|
|
1301
|
+
// the target and formats `rawStubHeaders`. Read on each call: setStatus
|
|
1302
|
+
// rebinds that let to a new Headers.
|
|
1303
|
+
const NODE_INSPECT = Symbol.for("nodejs.util.inspect.custom");
|
|
1197
1304
|
const guardedStubHeaders: Headers = new Proxy(new Headers(), {
|
|
1198
1305
|
get(_target, prop) {
|
|
1199
1306
|
const raw = rawStubHeaders;
|
|
@@ -1208,6 +1315,22 @@ export function createRequestContext<TEnv>(
|
|
|
1208
1315
|
return (value as (...a: unknown[]) => unknown).bind(raw);
|
|
1209
1316
|
},
|
|
1210
1317
|
});
|
|
1318
|
+
Object.defineProperty(guardedStubHeaders, NODE_INSPECT, {
|
|
1319
|
+
value(...args: unknown[]): unknown {
|
|
1320
|
+
const hook = (rawStubHeaders as unknown as Record<symbol, unknown>)[
|
|
1321
|
+
NODE_INSPECT
|
|
1322
|
+
];
|
|
1323
|
+
if (typeof hook === "function") return hook.apply(rawStubHeaders, args);
|
|
1324
|
+
// DOM Headers has forEach and not entries. Node always has the hook above.
|
|
1325
|
+
const listed: Record<string, string> = {};
|
|
1326
|
+
rawStubHeaders.forEach((value, key) => {
|
|
1327
|
+
listed[key] = value;
|
|
1328
|
+
});
|
|
1329
|
+
return listed;
|
|
1330
|
+
},
|
|
1331
|
+
configurable: true,
|
|
1332
|
+
writable: true,
|
|
1333
|
+
});
|
|
1211
1334
|
const shadowStubHeaders = (res: Response): void => {
|
|
1212
1335
|
Object.defineProperty(res, "headers", {
|
|
1213
1336
|
value: guardedStubHeaders,
|
|
@@ -1429,7 +1552,7 @@ export function createRequestContext<TEnv>(
|
|
|
1429
1552
|
const prevRaw =
|
|
1430
1553
|
(requestHeaders(request).get("x-rango-state") || null) ??
|
|
1431
1554
|
getRawCookieValue(cookieHeader, stateCookieName);
|
|
1432
|
-
const value = mintStateValue(
|
|
1555
|
+
const value = mintStateValue(versions?.document ?? "0", prevRaw);
|
|
1433
1556
|
// rawStubHeaders: guard-exempt internal writer — invalidateClientCache()
|
|
1434
1557
|
// is documented callable from loaders and during shell capture.
|
|
1435
1558
|
rawStubHeaders.append(
|
|
@@ -1505,6 +1628,8 @@ export function createRequestContext<TEnv>(
|
|
|
1505
1628
|
|
|
1506
1629
|
_handleStore: handleStore,
|
|
1507
1630
|
_cacheStore: cacheStore,
|
|
1631
|
+
_prerender: prerender,
|
|
1632
|
+
_versions: versions,
|
|
1508
1633
|
_searchParamsFilter: searchParamsFilter,
|
|
1509
1634
|
_explicitTaggedStores: explicitTaggedStores,
|
|
1510
1635
|
_requestTags: new Set<string>(),
|
|
@@ -1515,11 +1640,23 @@ export function createRequestContext<TEnv>(
|
|
|
1515
1640
|
|
|
1516
1641
|
waitUntil(fn: () => Promise<void>): void {
|
|
1517
1642
|
if (ctx.build) return;
|
|
1518
|
-
//
|
|
1643
|
+
// A deferred task does not rely on the platform carrying the request's
|
|
1644
|
+
// async context into it. Deployed workerd lost it once ("use cache"
|
|
1645
|
+
// background revalidation, cache-runtime.ts); Node and miniflare never
|
|
1646
|
+
// do, so no local run shows a loss. A cache store builds its key inside
|
|
1647
|
+
// the task and reads the serving router's versions and the request host
|
|
1648
|
+
// from the context: without it the write lands under the whole-build
|
|
1649
|
+
// pair, which no router with its own version reads. So the task
|
|
1650
|
+
// re-enters the context it was scheduled under: the store active then
|
|
1651
|
+
// (a derived context), else this one.
|
|
1652
|
+
const scheduledUnder = requestContextStorage.getStore() ?? ctx;
|
|
1653
|
+
// Wrap in Promise.resolve().then(...) so a SYNCHRONOUS throw in a
|
|
1519
1654
|
// non-async callback becomes a rejected promise handed to the host's
|
|
1520
1655
|
// waitUntil (logged as a background failure), instead of escaping into
|
|
1521
1656
|
// the request flow. Mirrors fireAndForgetWaitUntil's deferral.
|
|
1522
|
-
const task = Promise.resolve().then(
|
|
1657
|
+
const task = Promise.resolve().then(() =>
|
|
1658
|
+
requestContextStorage.run(scheduledUnder, fn),
|
|
1659
|
+
);
|
|
1523
1660
|
// Track the task promise so the PPR shell capture can settle the
|
|
1524
1661
|
// foreground's deferred cache writes before its own match/render (the
|
|
1525
1662
|
// ordering edge; see _pendingBackgroundTasks). The capture task itself
|
package/src/ssr/ssr-root.tsx
CHANGED
|
@@ -7,7 +7,11 @@ import {
|
|
|
7
7
|
} from "../browser/react/filter-segment-order.js";
|
|
8
8
|
import { ThemeProvider } from "../theme/ThemeProvider.js";
|
|
9
9
|
import { NonceContext } from "../browser/react/nonce-context.js";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
HydrationBarrierContext,
|
|
12
|
+
LocationStateContext,
|
|
13
|
+
NavigationStoreContext,
|
|
14
|
+
} from "../browser/react/context.js";
|
|
11
15
|
import type { NavigationStoreContextValue } from "../browser/react/context.js";
|
|
12
16
|
import type { HandleData } from "../browser/types.js";
|
|
13
17
|
import type { ResolvedSegment } from "../types.js";
|
|
@@ -119,11 +123,17 @@ function createSsrEventController(opts: {
|
|
|
119
123
|
flushRouteState: () => {},
|
|
120
124
|
setHandleData: () => {},
|
|
121
125
|
getHandleState: () => handleState,
|
|
126
|
+
lockHydration: () => {},
|
|
127
|
+
getHydrationSnapshot: () => undefined,
|
|
128
|
+
releaseHydrationLock: () => {},
|
|
122
129
|
setRouteSegmentIds: () => {},
|
|
123
130
|
setParams: (nextParams) => {
|
|
124
131
|
params = nextParams;
|
|
125
132
|
},
|
|
126
133
|
getParams: () => params,
|
|
134
|
+
commitLocationState: () => {},
|
|
135
|
+
getLocationState: () => undefined,
|
|
136
|
+
takeTreelessLocationState: () => false,
|
|
127
137
|
setLocation: () => {},
|
|
128
138
|
startNavigation: () => {
|
|
129
139
|
throw new Error("Navigation not supported during SSR");
|
|
@@ -277,24 +287,28 @@ export function createSsrRootComponent(opts: SsrRootOptions): React.FC {
|
|
|
277
287
|
}
|
|
278
288
|
|
|
279
289
|
// Create SSR context with request-local pathname/params/handles.
|
|
280
|
-
ssrContextValue
|
|
281
|
-
|
|
282
|
-
eventController: createSsrEventController({
|
|
290
|
+
if (!ssrContextValue) {
|
|
291
|
+
const eventController = createSsrEventController({
|
|
283
292
|
pathname,
|
|
284
293
|
search,
|
|
285
294
|
origin,
|
|
286
295
|
params: resolved.metadata?.params,
|
|
287
296
|
handleData,
|
|
288
297
|
matched: resolved.metadata?.matched,
|
|
289
|
-
})
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
298
|
+
});
|
|
299
|
+
ssrContextValue = {
|
|
300
|
+
store: null as any,
|
|
301
|
+
eventController,
|
|
302
|
+
navigate: async () => {},
|
|
303
|
+
refresh: async () => {},
|
|
304
|
+
version: resolved.metadata?.version,
|
|
305
|
+
basename: resolved.metadata?.basename,
|
|
306
|
+
origin: (eventController.getState().location as URL).origin,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
295
309
|
|
|
296
310
|
// Build content tree from segments.
|
|
297
|
-
// Order must match NavigationProvider: NavigationStoreContext > NonceContext > ThemeProvider > content
|
|
311
|
+
// Order must match NavigationProvider: NavigationStoreContext > LocationStateContext > NonceContext > ThemeProvider > content
|
|
298
312
|
// Memoize like payload/handles above: renderSegments is async, so
|
|
299
313
|
// React.use() on a fresh promise suspends and replays SsrRoot, which
|
|
300
314
|
// would re-run the entire segment-tree build on every initial render.
|
|
@@ -324,10 +338,15 @@ export function createSsrRootComponent(opts: SsrRootOptions): React.FC {
|
|
|
324
338
|
<NonceContext.Provider value={nonce}>{content}</NonceContext.Provider>
|
|
325
339
|
);
|
|
326
340
|
|
|
327
|
-
// Wrap with NavigationStoreContext for useNavigation hook
|
|
341
|
+
// Wrap with NavigationStoreContext for useNavigation hook. The server has
|
|
342
|
+
// no history entry: location state is undefined, as readers hydrate.
|
|
328
343
|
return (
|
|
329
344
|
<NavigationStoreContext.Provider value={ssrContextValue!}>
|
|
330
|
-
{
|
|
345
|
+
<LocationStateContext.Provider value={undefined}>
|
|
346
|
+
<HydrationBarrierContext.Provider value={0}>
|
|
347
|
+
{content}
|
|
348
|
+
</HydrationBarrierContext.Provider>
|
|
349
|
+
</LocationStateContext.Provider>
|
|
331
350
|
</NavigationStoreContext.Provider>
|
|
332
351
|
);
|
|
333
352
|
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { useEffect, useLayoutEffect, useRef, type ReactNode } from "react";
|
|
2
|
+
import {
|
|
3
|
+
auditCommit,
|
|
4
|
+
auditFallback,
|
|
5
|
+
auditHandover,
|
|
6
|
+
auditMount,
|
|
7
|
+
auditRead,
|
|
8
|
+
auditReveal,
|
|
9
|
+
auditUnmount,
|
|
10
|
+
createBoundaryAudit,
|
|
11
|
+
type BoundaryAudit,
|
|
12
|
+
} from "./suspense-audit.js";
|
|
13
|
+
|
|
14
|
+
// Hooks of the suspense audit (docs/internal/suspense-contract.md), called by
|
|
15
|
+
// dev-only components: React Compiler skips a component with a gated hook.
|
|
16
|
+
|
|
17
|
+
function useRecord(boundary: string, segmentId: string): BoundaryAudit {
|
|
18
|
+
const ref = useRef<BoundaryAudit | null>(null);
|
|
19
|
+
// One position can hold another segment's boundary: its Suspense is keyed.
|
|
20
|
+
if (ref.current === null || ref.current.boundary !== boundary) {
|
|
21
|
+
ref.current = createBoundaryAudit(boundary, segmentId);
|
|
22
|
+
}
|
|
23
|
+
return ref.current;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Passive, not layout: React disconnects the layout effects of content a
|
|
27
|
+
// Suspense boundary hides, and that is not an unmount.
|
|
28
|
+
function useMount(rec: BoundaryAudit): void {
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
auditMount(rec);
|
|
31
|
+
return () => auditUnmount(rec);
|
|
32
|
+
}, [rec]);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* One boundary: what each render hands it, what each commit carries, and its
|
|
37
|
+
* mount. Called above the Suspense, which commits while the content waits.
|
|
38
|
+
* `streams` and `nodes` are what else its content waits for (I3 only).
|
|
39
|
+
*/
|
|
40
|
+
export function useBoundaryAudit(
|
|
41
|
+
boundary: string,
|
|
42
|
+
segmentId: string,
|
|
43
|
+
value: unknown,
|
|
44
|
+
streams?: Record<string, unknown>,
|
|
45
|
+
nodes?: unknown,
|
|
46
|
+
): BoundaryAudit {
|
|
47
|
+
const rec = useRecord(boundary, segmentId);
|
|
48
|
+
auditHandover(rec, value);
|
|
49
|
+
useLayoutEffect(() => {
|
|
50
|
+
auditCommit(rec, value, streams, nodes);
|
|
51
|
+
}, [rec, value, streams, nodes]);
|
|
52
|
+
useMount(rec);
|
|
53
|
+
return rec;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The boundary's content is on screen. */
|
|
57
|
+
export function useRevealAudit(rec: BoundaryAudit): void {
|
|
58
|
+
useLayoutEffect(() => {
|
|
59
|
+
auditReveal(rec);
|
|
60
|
+
}, [rec]);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* One `useLoader` read of a per-loader stream (I1, I2 at the read site). A
|
|
65
|
+
* read that suspends while mounting keeps no record: only a reader on screen
|
|
66
|
+
* is audited.
|
|
67
|
+
*/
|
|
68
|
+
export function useReadAudit(loaderId: string, stream: unknown): void {
|
|
69
|
+
const rec = useRecord(`read:${loaderId}`, loaderId);
|
|
70
|
+
auditHandover(rec, stream);
|
|
71
|
+
useLayoutEffect(() => {
|
|
72
|
+
auditRead(rec, stream);
|
|
73
|
+
}, [rec, stream]);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Wraps a boundary's fallback: mounted means the fallback is on screen. */
|
|
77
|
+
export function AuditedFallback({
|
|
78
|
+
audit,
|
|
79
|
+
children,
|
|
80
|
+
}: {
|
|
81
|
+
audit: BoundaryAudit;
|
|
82
|
+
children: ReactNode;
|
|
83
|
+
}): ReactNode {
|
|
84
|
+
useLayoutEffect(() => auditFallback(audit), [audit]);
|
|
85
|
+
return children;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Wraps a segment's outlet children: the segment's mount (I4). */
|
|
89
|
+
export function AuditedOutlet({
|
|
90
|
+
segmentId,
|
|
91
|
+
children,
|
|
92
|
+
}: {
|
|
93
|
+
segmentId: string;
|
|
94
|
+
children: ReactNode;
|
|
95
|
+
}): ReactNode {
|
|
96
|
+
useMount(useRecord(`outlet:${segmentId}`, segmentId));
|
|
97
|
+
return children;
|
|
98
|
+
}
|