@rangojs/router 0.0.0-experimental.bd6e11bc → 0.0.0-experimental.bdaf10aa
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/AGENTS.md +8 -4
- package/README.md +296 -887
- package/dist/bin/rango.js +459 -91
- package/dist/testing/vitest.js +36 -2
- package/dist/vite/index.js +1708 -414
- package/package.json +35 -10
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +82 -5
- package/skills/bundle-analysis/SKILL.md +2 -2
- package/skills/cache-guide/SKILL.md +14 -9
- package/skills/caching/SKILL.md +221 -12
- package/skills/catalog.json +271 -0
- package/skills/comparison/SKILL.md +50 -0
- package/skills/comparison/agents/openai.yaml +4 -0
- package/skills/comparison/references/framework-comparison.md +837 -0
- package/skills/composability/SKILL.md +83 -2
- package/skills/css/SKILL.md +76 -0
- package/skills/debug-manifest/SKILL.md +5 -3
- package/skills/defer-hydration/SKILL.md +235 -0
- package/skills/document-cache/SKILL.md +11 -3
- package/skills/fonts/SKILL.md +1 -1
- package/skills/handler-use/SKILL.md +9 -9
- package/skills/hooks/SKILL.md +73 -900
- package/skills/hooks/data.md +273 -0
- package/skills/hooks/handle-and-actions.md +103 -0
- package/skills/hooks/navigation.md +110 -0
- package/skills/hooks/outlets.md +41 -0
- package/skills/hooks/state.md +228 -0
- package/skills/hooks/urls.md +135 -0
- package/skills/host-router/SKILL.md +84 -7
- package/skills/i18n/SKILL.md +1 -1
- package/skills/intercept/SKILL.md +51 -17
- package/skills/layout/SKILL.md +38 -16
- package/skills/links/SKILL.md +1 -1
- package/skills/loader/SKILL.md +48 -20
- package/skills/middleware/SKILL.md +11 -5
- package/skills/migrate-nextjs/SKILL.md +203 -20
- package/skills/migrate-react-router/SKILL.md +59 -675
- package/skills/migrate-react-router/cloudflare-workers.md +129 -0
- package/skills/migrate-react-router/component-migration.md +196 -0
- package/skills/migrate-react-router/data-and-actions.md +225 -0
- package/skills/migrate-react-router/route-mapping.md +271 -0
- package/skills/mime-routes/SKILL.md +3 -3
- package/skills/observability/SKILL.md +70 -5
- package/skills/parallel/SKILL.md +32 -8
- package/skills/ppr/SKILL.md +622 -0
- package/skills/prerender/SKILL.md +59 -28
- package/skills/rango/SKILL.md +124 -50
- package/skills/response-routes/SKILL.md +78 -46
- package/skills/route/SKILL.md +85 -6
- package/skills/router-setup/SKILL.md +41 -6
- package/skills/scripts/SKILL.md +179 -0
- package/skills/server-actions/SKILL.md +28 -3
- package/skills/shell-manifest/SKILL.md +185 -0
- package/skills/streams-and-websockets/SKILL.md +1 -1
- package/skills/tailwind/SKILL.md +28 -4
- package/skills/testing/SKILL.md +68 -654
- package/skills/testing/bindings.md +103 -0
- package/skills/testing/cache-prerender.md +127 -0
- package/skills/testing/client-components.md +124 -0
- package/skills/testing/e2e-parity.md +125 -0
- package/skills/testing/flight.md +91 -0
- package/skills/testing/handles.md +131 -0
- package/skills/testing/loader.md +128 -0
- package/skills/testing/middleware.md +99 -0
- package/skills/testing/render-handler.md +122 -0
- package/skills/testing/response-routes.md +95 -0
- package/skills/testing/reverse-and-types.md +85 -0
- package/skills/testing/server-actions.md +107 -0
- package/skills/testing/server-tree.md +128 -0
- package/skills/testing/setup.md +123 -0
- package/skills/theme/SKILL.md +1 -1
- package/skills/typesafety/SKILL.md +45 -918
- package/skills/typesafety/env-and-bindings.md +254 -0
- package/skills/typesafety/generated-files-and-cli.md +335 -0
- package/skills/typesafety/params-and-search.md +153 -0
- package/skills/typesafety/route-types.md +209 -0
- package/skills/use-cache/SKILL.md +47 -17
- package/skills/vercel/SKILL.md +128 -0
- package/skills/view-transitions/SKILL.md +44 -1
- package/src/__augment-tests__/augmented.check.ts +2 -3
- package/src/__internal.ts +0 -65
- package/src/browser/action-coordinator.ts +1 -1
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/app-shell.ts +14 -27
- package/src/browser/connection-warmup.ts +134 -0
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +178 -100
- package/src/browser/invalidate-client-cache.ts +52 -0
- package/src/browser/logging.ts +28 -0
- package/src/browser/merge-segment-loaders.ts +6 -4
- package/src/browser/navigation-bridge.ts +81 -68
- package/src/browser/navigation-client.ts +115 -70
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +153 -88
- package/src/browser/navigation-transaction.ts +0 -32
- package/src/browser/network-error-handler.ts +34 -7
- package/src/browser/partial-update.ts +157 -144
- package/src/browser/prefetch/cache.ts +148 -81
- package/src/browser/prefetch/fetch.ts +231 -51
- package/src/browser/prefetch/queue.ts +25 -7
- package/src/browser/rango-state.ts +157 -115
- package/src/browser/react/Link.tsx +40 -7
- package/src/browser/react/NavigationProvider.tsx +140 -99
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/filter-segment-order.ts +17 -2
- package/src/browser/react/index.ts +0 -51
- package/src/browser/react/location-state-shared.ts +14 -15
- package/src/browser/react/location-state.ts +0 -1
- package/src/browser/react/use-action.ts +6 -15
- package/src/browser/react/use-handle.ts +0 -5
- package/src/browser/react/use-href.tsx +8 -1
- package/src/browser/react/use-link-status.ts +33 -8
- package/src/browser/react/use-navigation.ts +10 -5
- package/src/browser/react/use-params.ts +0 -2
- package/src/browser/react/use-router.ts +6 -4
- package/src/browser/react/use-search-params.ts +0 -5
- package/src/browser/react/use-segments.ts +0 -13
- package/src/browser/response-adapter.ts +74 -8
- package/src/browser/rsc-router.tsx +97 -22
- package/src/browser/scroll-restoration.ts +15 -8
- package/src/browser/segment-reconciler.ts +31 -21
- package/src/browser/server-action-bridge.ts +216 -38
- package/src/browser/types.ts +94 -22
- package/src/browser/validate-redirect-origin.ts +43 -16
- package/src/build/generate-manifest.ts +155 -131
- package/src/build/generate-route-types.ts +1 -1
- package/src/build/index.ts +11 -5
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +152 -22
- package/src/build/route-types/ast-route-extraction.ts +15 -8
- package/src/build/route-types/codegen.ts +12 -1
- package/src/build/route-types/include-resolution.ts +455 -61
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/per-module-writer.ts +15 -2
- package/src/build/route-types/router-processing.ts +77 -41
- package/src/build/route-types/source-scan.ts +105 -7
- package/src/build/runtime-discovery.ts +4 -1
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-key-utils.ts +58 -13
- package/src/cache/cache-policy.ts +108 -34
- package/src/cache/cache-runtime.ts +454 -101
- package/src/cache/cache-scope.ts +159 -54
- package/src/cache/cache-tag.ts +149 -0
- package/src/cache/cf/cf-base64.ts +33 -0
- package/src/cache/cf/cf-cache-constants.ts +127 -0
- package/src/cache/cf/cf-cache-store.ts +2170 -377
- package/src/cache/cf/cf-cache-types.ts +349 -0
- package/src/cache/cf/cf-kv-utils.ts +46 -0
- package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
- package/src/cache/cf/index.ts +6 -16
- package/src/cache/document-cache.ts +126 -41
- package/src/cache/handle-snapshot.ts +70 -0
- package/src/cache/index.ts +23 -20
- package/src/cache/memory-segment-store.ts +243 -37
- package/src/cache/profile-registry.ts +46 -31
- package/src/cache/read-through-swr.ts +56 -12
- package/src/cache/segment-codec.ts +13 -21
- package/src/cache/shell-snapshot.ts +417 -0
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/types.ts +194 -99
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +1132 -0
- package/src/client.rsc.tsx +39 -22
- package/src/client.tsx +28 -58
- package/src/cloudflare/index.ts +11 -0
- package/src/cloudflare/tracing.ts +108 -0
- package/src/component-utils.ts +19 -0
- package/src/components/DefaultDocument.tsx +8 -2
- package/src/context-var.ts +13 -1
- package/src/decode-loader-results.ts +18 -2
- package/src/defer.ts +185 -0
- package/src/deps/ssr.ts +0 -1
- package/src/encode-kv.ts +49 -0
- package/src/errors.ts +0 -3
- package/src/escape-script.ts +52 -0
- package/src/handle.ts +57 -40
- package/src/handles/MetaTags.tsx +24 -53
- package/src/handles/Scripts.tsx +183 -0
- package/src/handles/breadcrumbs.ts +35 -8
- package/src/handles/deferred-resolution.ts +127 -0
- package/src/handles/is-thenable.ts +18 -0
- package/src/handles/meta.ts +14 -40
- package/src/handles/script.ts +244 -0
- package/src/host/cookie-handler.ts +9 -60
- package/src/host/errors.ts +13 -22
- package/src/host/index.ts +7 -0
- package/src/host/pattern-matcher.ts +23 -52
- package/src/host/router.ts +1 -65
- package/src/host/testing.ts +40 -27
- package/src/host/types.ts +6 -2
- package/src/href-client.ts +7 -12
- package/src/index.rsc.ts +88 -8
- package/src/index.ts +90 -16
- package/src/internal-debug.ts +11 -10
- package/src/loader.rsc.ts +19 -9
- package/src/loader.ts +12 -4
- package/src/outlet-provider.tsx +1 -5
- package/src/prerender/param-hash.ts +16 -16
- package/src/prerender/store.ts +32 -37
- package/src/prerender.ts +75 -7
- package/src/redirect-origin.ts +114 -0
- package/src/regex-escape.ts +8 -0
- package/src/render-error-thrower.tsx +20 -0
- package/src/response-utils.ts +25 -0
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +13 -49
- package/src/route-definition/dsl-helpers.ts +60 -53
- package/src/route-definition/helper-factories.ts +0 -2
- package/src/route-definition/helpers-types.ts +46 -46
- package/src/route-definition/index.ts +1 -2
- package/src/route-definition/redirect.ts +44 -11
- package/src/route-definition/resolve-handler-use.ts +6 -1
- package/src/route-definition/use-item-types.ts +3 -6
- package/src/route-map-builder.ts +41 -20
- package/src/route-types.ts +0 -5
- package/src/router/content-negotiation.ts +58 -23
- package/src/router/error-handling.ts +44 -17
- package/src/router/find-match.ts +129 -30
- package/src/router/handler-context.ts +6 -1
- package/src/router/instrument.ts +355 -0
- package/src/router/intercept-resolution.ts +35 -2
- package/src/router/lazy-includes.ts +79 -56
- package/src/router/loader-resolution.ts +151 -73
- package/src/router/logging.ts +0 -6
- package/src/router/manifest.ts +74 -40
- package/src/router/match-api.ts +76 -52
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +181 -178
- package/src/router/match-middleware/background-revalidation.ts +40 -24
- package/src/router/match-middleware/cache-lookup.ts +115 -194
- package/src/router/match-middleware/cache-store.ts +61 -50
- package/src/router/match-middleware/intercept-resolution.ts +0 -22
- package/src/router/match-middleware/segment-resolution.ts +0 -22
- package/src/router/match-pipelines.ts +1 -42
- package/src/router/match-result.ts +36 -67
- package/src/router/metrics.ts +0 -34
- package/src/router/middleware-types.ts +0 -116
- package/src/router/middleware.ts +231 -120
- package/src/router/navigation-snapshot.ts +7 -56
- package/src/router/params-util.ts +23 -0
- package/src/router/parse-pattern.ts +115 -0
- package/src/router/pattern-matching.ts +99 -152
- package/src/router/prefetch-cache-ttl.ts +51 -0
- package/src/router/prefetch-limits.ts +37 -0
- package/src/router/prerender-match.ts +111 -66
- package/src/router/preview-match.ts +3 -1
- package/src/router/request-classification.ts +47 -42
- package/src/router/revalidation.ts +75 -81
- package/src/router/route-snapshot.ts +14 -3
- package/src/router/router-context.ts +6 -29
- package/src/router/router-interfaces.ts +70 -8
- package/src/router/router-options.ts +126 -4
- package/src/router/segment-resolution/fresh.ts +104 -80
- package/src/router/segment-resolution/helpers.ts +86 -6
- package/src/router/segment-resolution/loader-cache.ts +155 -39
- package/src/router/segment-resolution/loader-mask.ts +60 -0
- package/src/router/segment-resolution/loader-snapshot.ts +259 -0
- package/src/router/segment-resolution/mask-nested.ts +83 -0
- package/src/router/segment-resolution/revalidation.ts +215 -304
- package/src/router/segment-resolution/static-store.ts +19 -5
- package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
- package/src/router/segment-resolution/view-transition-default.ts +35 -15
- package/src/router/segment-resolution.ts +5 -1
- package/src/router/segment-wrappers.ts +6 -5
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +54 -35
- package/src/router/telemetry-otel.ts +160 -200
- package/src/router/telemetry.ts +9 -23
- package/src/router/timeout.ts +0 -20
- package/src/router/tracing.ts +215 -0
- package/src/router/trie-matching.ts +171 -64
- package/src/router/types.ts +1 -63
- package/src/router/url-params.ts +13 -5
- package/src/router.ts +119 -48
- package/src/rsc/full-payload.ts +70 -0
- package/src/rsc/handler-context.ts +1 -0
- package/src/rsc/handler.ts +267 -152
- package/src/rsc/helpers.ts +78 -4
- package/src/rsc/index.ts +1 -4
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/loader-fetch.ts +114 -38
- package/src/rsc/manifest-init.ts +29 -42
- package/src/rsc/nonce.ts +10 -1
- package/src/rsc/origin-guard.ts +11 -15
- package/src/rsc/progressive-enhancement.ts +120 -13
- package/src/rsc/redirect-guard.ts +100 -0
- package/src/rsc/response-cache-serve.ts +238 -0
- package/src/rsc/response-error.ts +79 -12
- package/src/rsc/response-route-handler.ts +58 -141
- package/src/rsc/rsc-rendering.ts +492 -49
- package/src/rsc/runtime-warnings.ts +14 -0
- package/src/rsc/server-action.ts +268 -82
- package/src/rsc/shell-capture.ts +1190 -0
- package/src/rsc/shell-serve.ts +181 -0
- package/src/rsc/transition-gate.ts +89 -0
- package/src/rsc/types.ts +45 -3
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +31 -26
- package/src/segment-loader-promise.ts +49 -4
- package/src/segment-system.tsx +260 -95
- package/src/server/context.ts +99 -9
- package/src/server/cookie-parse.ts +32 -0
- package/src/server/cookie-store.ts +125 -2
- package/src/server/handle-store.ts +21 -38
- package/src/server/loader-registry.ts +33 -42
- package/src/server/request-context.ts +379 -138
- package/src/ssr/index.tsx +491 -182
- package/src/ssr/inject-rsc-eager.ts +167 -0
- package/src/ssr/ssr-root.tsx +228 -0
- package/src/static-handler.ts +10 -13
- package/src/testing/cache-status.ts +44 -48
- package/src/testing/collect-handle.ts +14 -31
- package/src/testing/dispatch.ts +533 -160
- package/src/testing/e2e/fixture.ts +45 -11
- package/src/testing/e2e/index.ts +1 -22
- package/src/testing/e2e/matchers.ts +0 -16
- package/src/testing/e2e/parity.ts +85 -4
- package/src/testing/e2e/server.ts +12 -0
- package/src/testing/flight-matchers.ts +7 -14
- package/src/testing/flight-normalize.ts +11 -0
- package/src/testing/flight-runtime.d.ts +36 -0
- package/src/testing/flight-tree.ts +682 -0
- package/src/testing/flight.entry.ts +30 -0
- package/src/testing/flight.ts +145 -70
- package/src/testing/generated-routes.ts +26 -50
- package/src/testing/index.ts +18 -19
- package/src/testing/internal/context.ts +184 -68
- package/src/testing/internal/flight-client-globals.ts +30 -0
- package/src/testing/internal/seed-vars.ts +54 -0
- package/src/testing/render-handler.ts +357 -0
- package/src/testing/render-route.tsx +134 -115
- package/src/testing/run-loader.ts +140 -51
- package/src/testing/run-middleware.ts +59 -33
- package/src/testing/run-transition-when.ts +164 -0
- package/src/testing/vitest-stubs/cloudflare-email.ts +1 -1
- package/src/testing/vitest-stubs/cloudflare-workers.ts +1 -1
- package/src/testing/vitest.ts +138 -16
- package/src/theme/ThemeProvider.tsx +56 -84
- package/src/theme/ThemeScript.tsx +7 -9
- package/src/theme/constants.ts +52 -13
- package/src/theme/index.ts +0 -7
- package/src/theme/theme-context.ts +1 -5
- package/src/theme/theme-script.ts +22 -21
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +0 -35
- package/src/types/cache-types.ts +13 -4
- package/src/types/error-types.ts +30 -90
- package/src/types/global-namespace.ts +15 -15
- package/src/types/handler-context.ts +45 -15
- package/src/types/index.ts +2 -10
- package/src/types/loader-types.ts +6 -3
- package/src/types/request-scope.ts +8 -22
- package/src/types/route-config.ts +20 -52
- package/src/types/route-entry.ts +0 -6
- package/src/types/segments.ts +100 -13
- package/src/urls/include-helper.ts +10 -12
- package/src/urls/include-provider.ts +71 -0
- package/src/urls/index.ts +2 -8
- package/src/urls/path-helper-types.ts +52 -14
- package/src/urls/path-helper.ts +5 -54
- package/src/urls/pattern-types.ts +36 -0
- package/src/urls/type-extraction.ts +76 -42
- package/src/urls/urls-function.ts +0 -14
- package/src/use-loader.tsx +0 -186
- package/src/vercel/index.ts +11 -0
- package/src/vercel/tracing.ts +88 -0
- package/src/vite/discovery/bundle-postprocess.ts +2 -1
- package/src/vite/discovery/dev-prerender-cache.ts +117 -0
- package/src/vite/discovery/discover-routers.ts +34 -43
- package/src/vite/discovery/discovery-errors.ts +61 -0
- package/src/vite/discovery/prerender-collection.ts +33 -46
- package/src/vite/discovery/state.ts +12 -1
- package/src/vite/discovery/virtual-module-codegen.ts +1 -11
- package/src/vite/index.ts +9 -0
- package/src/vite/inject-client-debug.ts +88 -0
- package/src/vite/plugin-types.ts +143 -10
- package/src/vite/plugins/cjs-to-esm.ts +8 -12
- package/src/vite/plugins/client-ref-dedup.ts +0 -11
- package/src/vite/plugins/client-ref-hashing.ts +0 -10
- package/src/vite/plugins/cloudflare-protocol-stub.ts +0 -20
- package/src/vite/plugins/expose-action-id.ts +2 -73
- package/src/vite/plugins/expose-id-utils.ts +85 -56
- package/src/vite/plugins/expose-ids/export-analysis.ts +30 -43
- package/src/vite/plugins/expose-ids/handler-transform.ts +5 -31
- package/src/vite/plugins/expose-ids/loader-transform.ts +12 -20
- package/src/vite/plugins/expose-ids/router-transform.ts +98 -26
- package/src/vite/plugins/expose-internal-ids.ts +10 -1
- package/src/vite/plugins/performance-tracks.ts +0 -3
- package/src/vite/plugins/refresh-cmd.ts +1 -1
- package/src/vite/plugins/use-cache-transform.ts +21 -46
- package/src/vite/plugins/vercel-output.ts +384 -0
- package/src/vite/plugins/version-injector.ts +22 -27
- package/src/vite/plugins/version-plugin.ts +6 -66
- package/src/vite/plugins/virtual-entries.ts +137 -26
- package/src/vite/rango.ts +146 -135
- package/src/vite/router-discovery.ts +189 -48
- package/src/vite/utils/ast-handler-extract.ts +11 -20
- package/src/vite/utils/bundle-analysis.ts +6 -13
- package/src/vite/utils/client-chunks.ts +0 -6
- package/src/vite/utils/directive-prologue.ts +40 -0
- package/src/vite/utils/forward-user-plugins.ts +0 -22
- package/src/vite/utils/manifest-utils.ts +4 -75
- package/src/vite/utils/package-resolution.ts +1 -73
- package/src/vite/utils/prerender-utils.ts +71 -44
- package/src/vite/utils/shared-utils.ts +55 -37
- package/src/browser/react/use-client-cache.ts +0 -58
- package/src/browser/shallow.ts +0 -40
- package/src/handles/index.ts +0 -7
- package/src/network-error-thrower.tsx +0 -23
- package/src/router/middleware-cookies.ts +0 -55
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
getParallelEntries,
|
|
15
15
|
getParallelSlotEntries,
|
|
16
16
|
type EntryData,
|
|
17
|
+
type ParallelEntryData,
|
|
17
18
|
} from "../../server/context";
|
|
18
19
|
import type {
|
|
19
20
|
HandlerContext,
|
|
@@ -34,62 +35,23 @@ import {
|
|
|
34
35
|
import { resolveLoaderData } from "./loader-cache.js";
|
|
35
36
|
import {
|
|
36
37
|
handleHandlerResult,
|
|
38
|
+
warnOnStreamedResponse,
|
|
37
39
|
tryStaticHandler,
|
|
38
40
|
tryStaticSlot,
|
|
39
41
|
resolveLayoutComponent,
|
|
40
42
|
resolveWithErrorBoundary,
|
|
43
|
+
buildLoaderErrorContext,
|
|
41
44
|
} from "./helpers.js";
|
|
42
45
|
import { applyViewTransitionDefault } from "./view-transition-default.js";
|
|
43
46
|
import { getRouterContext } from "../router-context.js";
|
|
44
|
-
import {
|
|
47
|
+
import { observeEvent, observeHandler } from "../instrument.js";
|
|
48
|
+
import { observeStreamedHandler } from "./streamed-handler-telemetry.js";
|
|
45
49
|
import {
|
|
46
50
|
track,
|
|
47
51
|
RangoContext,
|
|
48
52
|
runInsideLoaderScope,
|
|
49
53
|
} from "../../server/context.js";
|
|
50
54
|
|
|
51
|
-
// ---------------------------------------------------------------------------
|
|
52
|
-
// Telemetry helpers
|
|
53
|
-
// ---------------------------------------------------------------------------
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Attach a fire-and-forget rejection observer to a streamed handler promise.
|
|
57
|
-
* Silently no-ops when called outside RouterContext (e.g. in unit tests).
|
|
58
|
-
*/
|
|
59
|
-
function observeStreamedHandler(
|
|
60
|
-
promise: Promise<ReactNode>,
|
|
61
|
-
segmentId: string,
|
|
62
|
-
segmentType: string,
|
|
63
|
-
pathname?: string,
|
|
64
|
-
routeKey?: string,
|
|
65
|
-
params?: Record<string, string>,
|
|
66
|
-
): void {
|
|
67
|
-
let routerCtx;
|
|
68
|
-
try {
|
|
69
|
-
routerCtx = getRouterContext();
|
|
70
|
-
} catch {
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
if (!routerCtx?.telemetry) return;
|
|
74
|
-
const sink = resolveSink(routerCtx.telemetry);
|
|
75
|
-
const reqId = routerCtx.requestId;
|
|
76
|
-
promise.catch((err: unknown) => {
|
|
77
|
-
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
78
|
-
safeEmit(sink, {
|
|
79
|
-
type: "handler.error",
|
|
80
|
-
timestamp: performance.now(),
|
|
81
|
-
requestId: reqId,
|
|
82
|
-
segmentId,
|
|
83
|
-
segmentType,
|
|
84
|
-
error: errorObj,
|
|
85
|
-
handledByBoundary: true,
|
|
86
|
-
pathname,
|
|
87
|
-
routeKey,
|
|
88
|
-
params,
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
|
|
93
55
|
/**
|
|
94
56
|
* Trace a parallel slot that's being force-rendered on a full refetch (client
|
|
95
57
|
* has no cached state). User revalidate fns are bypassed in this case — see
|
|
@@ -126,23 +88,14 @@ function emitRevalidationDecision(
|
|
|
126
88
|
routeKey: string,
|
|
127
89
|
shouldRevalidate: boolean,
|
|
128
90
|
): void {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
type: "revalidation.decision",
|
|
138
|
-
timestamp: performance.now(),
|
|
139
|
-
requestId: routerCtx.requestId,
|
|
140
|
-
segmentId,
|
|
141
|
-
pathname,
|
|
142
|
-
routeKey,
|
|
143
|
-
shouldRevalidate,
|
|
144
|
-
});
|
|
145
|
-
}
|
|
91
|
+
observeEvent({
|
|
92
|
+
type: "revalidation.decision",
|
|
93
|
+
timestamp: performance.now(),
|
|
94
|
+
segmentId,
|
|
95
|
+
pathname,
|
|
96
|
+
routeKey,
|
|
97
|
+
shouldRevalidate,
|
|
98
|
+
});
|
|
146
99
|
}
|
|
147
100
|
|
|
148
101
|
// ---------------------------------------------------------------------------
|
|
@@ -247,6 +200,10 @@ export async function resolveLoadersWithRevalidation<TEnv>(
|
|
|
247
200
|
),
|
|
248
201
|
);
|
|
249
202
|
|
|
203
|
+
// Partial (revalidation) render path: a throwing DSL loader must still fire
|
|
204
|
+
// onError/loader.error. isPartial flags the reporting phase accordingly.
|
|
205
|
+
const errorContext = { ...buildLoaderErrorContext(ctx), isPartial: true };
|
|
206
|
+
|
|
250
207
|
const loadersToRun = revalidationChecks.filter((c) => c.shouldRun);
|
|
251
208
|
const segments: ResolvedSegment[] = loadersToRun.map(
|
|
252
209
|
({ loaderEntry, loader, segmentId, index }) => ({
|
|
@@ -264,6 +221,7 @@ export async function resolveLoadersWithRevalidation<TEnv>(
|
|
|
264
221
|
entry,
|
|
265
222
|
segmentId,
|
|
266
223
|
ctx.pathname,
|
|
224
|
+
errorContext,
|
|
267
225
|
),
|
|
268
226
|
belongsToRoute,
|
|
269
227
|
}),
|
|
@@ -426,6 +384,97 @@ export function buildEntryRevalidateMap(
|
|
|
426
384
|
return map;
|
|
427
385
|
}
|
|
428
386
|
|
|
387
|
+
/**
|
|
388
|
+
* Resolve the component for a single parallel slot on the revalidation path.
|
|
389
|
+
* Pure component resolution shared verbatim by
|
|
390
|
+
* resolveParallelSegmentsWithRevalidation and the orphan-inlined loop in
|
|
391
|
+
* resolveOrphanLayoutWithRevalidation: try the static slot cache, else run the
|
|
392
|
+
* slot handler (pinning _currentSegmentId to the slot id so handle pushes land
|
|
393
|
+
* in the slot's own bucket, and wrapping a streamed handler). Returns the
|
|
394
|
+
* resolved component and whether the handler actually ran. Does NOT touch the
|
|
395
|
+
* revalidate-default policy (the caller decides shouldResolve, including the
|
|
396
|
+
* orphan-vs-main defaultOverride divergence) or loader-resolution ordering.
|
|
397
|
+
*/
|
|
398
|
+
async function resolveParallelSlotComponent<TEnv>(args: {
|
|
399
|
+
shouldResolve: boolean;
|
|
400
|
+
parallelEntry: ParallelEntryData;
|
|
401
|
+
slot: string;
|
|
402
|
+
parallelId: string;
|
|
403
|
+
handler:
|
|
404
|
+
| ((ctx: HandlerContext<any, TEnv>) => ReactNode | Promise<ReactNode>)
|
|
405
|
+
| ReactNode
|
|
406
|
+
| undefined;
|
|
407
|
+
context: HandlerContext<any, TEnv>;
|
|
408
|
+
deps: SegmentResolutionDeps<TEnv>;
|
|
409
|
+
routeKey: string;
|
|
410
|
+
params: Record<string, string>;
|
|
411
|
+
}): Promise<{ component: ReactNode | undefined; handlerRan: boolean }> {
|
|
412
|
+
const {
|
|
413
|
+
shouldResolve,
|
|
414
|
+
parallelEntry,
|
|
415
|
+
slot,
|
|
416
|
+
parallelId,
|
|
417
|
+
handler,
|
|
418
|
+
context,
|
|
419
|
+
deps,
|
|
420
|
+
routeKey,
|
|
421
|
+
params,
|
|
422
|
+
} = args;
|
|
423
|
+
|
|
424
|
+
let component: ReactNode | undefined;
|
|
425
|
+
let handlerRan = false;
|
|
426
|
+
if (shouldResolve) {
|
|
427
|
+
component = await tryStaticSlot(parallelEntry, slot, parallelId);
|
|
428
|
+
// tryStaticSlot returning a value means the static cache supplied the
|
|
429
|
+
// component — handler did NOT run. handlerRan stays false.
|
|
430
|
+
}
|
|
431
|
+
if (component === undefined) {
|
|
432
|
+
const hasLoadingFallback =
|
|
433
|
+
parallelEntry.loading !== undefined && parallelEntry.loading !== false;
|
|
434
|
+
if (!shouldResolve) {
|
|
435
|
+
component = null;
|
|
436
|
+
} else if (handler === undefined) {
|
|
437
|
+
// Handler evicted (production static slot) but static lookup missed.
|
|
438
|
+
// Nothing to render — use null so the client keeps its cached version.
|
|
439
|
+
component = null;
|
|
440
|
+
} else {
|
|
441
|
+
// Slot-keyed pushes — slot owns its own bucket, parent layout owns its
|
|
442
|
+
// own. On slot-only revalidations the partial merge updates only the
|
|
443
|
+
// slot's bucket; the parent's bucket stays intact.
|
|
444
|
+
(context as InternalHandlerContext<any, TEnv>)._currentSegmentId =
|
|
445
|
+
parallelId;
|
|
446
|
+
handlerRan = true;
|
|
447
|
+
if (hasLoadingFallback) {
|
|
448
|
+
const result =
|
|
449
|
+
typeof handler === "function" ? handler(context) : handler;
|
|
450
|
+
if (result instanceof Promise) {
|
|
451
|
+
warnOnStreamedResponse(result, parallelId);
|
|
452
|
+
const tracked = deps.trackHandler(result, {
|
|
453
|
+
segmentId: parallelId,
|
|
454
|
+
segmentType: "parallel",
|
|
455
|
+
});
|
|
456
|
+
observeStreamedHandler(
|
|
457
|
+
tracked,
|
|
458
|
+
parallelId,
|
|
459
|
+
"parallel",
|
|
460
|
+
context.pathname,
|
|
461
|
+
routeKey,
|
|
462
|
+
params,
|
|
463
|
+
);
|
|
464
|
+
component = tracked as ReactNode;
|
|
465
|
+
} else {
|
|
466
|
+
component = result as ReactNode;
|
|
467
|
+
}
|
|
468
|
+
} else {
|
|
469
|
+
component =
|
|
470
|
+
typeof handler === "function" ? await handler(context) : handler;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
return { component, handlerRan };
|
|
476
|
+
}
|
|
477
|
+
|
|
429
478
|
/**
|
|
430
479
|
* Resolve parallel segments with revalidation.
|
|
431
480
|
*/
|
|
@@ -443,9 +492,30 @@ export async function resolveParallelSegmentsWithRevalidation<TEnv>(
|
|
|
443
492
|
deps: SegmentResolutionDeps<TEnv>,
|
|
444
493
|
actionContext?: ActionContext,
|
|
445
494
|
stale?: boolean,
|
|
495
|
+
options?: {
|
|
496
|
+
/**
|
|
497
|
+
* Seed for an unknown parent-chain slot (slot not in clientSegmentIds) when
|
|
498
|
+
* there are no deciding revalidate fns. "type-derived" (default, main path):
|
|
499
|
+
* `belongsToRoute || isNewParent`. "force-render" (orphan path): always
|
|
500
|
+
* `true` — orphan parallels always belong to the route and must render
|
|
501
|
+
* unless the user opts out via revalidate(); the #482 blank-parent-chain-
|
|
502
|
+
* slot guard.
|
|
503
|
+
*/
|
|
504
|
+
parentChainDefault?: "type-derived" | "force-render";
|
|
505
|
+
/**
|
|
506
|
+
* When a slot's loaders are resolved relative to the slot segment push.
|
|
507
|
+
* "after" (default, main path) pushes the slot segment first; "before"
|
|
508
|
+
* (orphan path) resolves loaders first. This only changes the
|
|
509
|
+
* segments/matchedIds emission ORDER (the client reconciler is insensitive
|
|
510
|
+
* to it: loader sub-ids are filtered out and slots are re-grouped by parent).
|
|
511
|
+
*/
|
|
512
|
+
loaderOrder?: "after" | "before";
|
|
513
|
+
},
|
|
446
514
|
): Promise<SegmentRevalidationResult> {
|
|
447
515
|
const segments: ResolvedSegment[] = [];
|
|
448
516
|
const matchedIds: string[] = [];
|
|
517
|
+
const parentChainDefault = options?.parentChainDefault ?? "type-derived";
|
|
518
|
+
const loaderOrder = options?.loaderOrder ?? "after";
|
|
449
519
|
|
|
450
520
|
const resolvedParallelEntries = new Set<string>();
|
|
451
521
|
for (const { slot, entry: parallelEntry } of getParallelSlotEntries(
|
|
@@ -470,6 +540,34 @@ export async function resolveParallelSegmentsWithRevalidation<TEnv>(
|
|
|
470
540
|
|
|
471
541
|
const isFullRefetch = clientSegmentIds.size === 0;
|
|
472
542
|
const isNewParent = !clientSegmentIds.has(entry.shortCode);
|
|
543
|
+
|
|
544
|
+
// A slot's loaders (never cached) are deduped per parallel entry and
|
|
545
|
+
// emitted either before or after the slot segment per loaderOrder.
|
|
546
|
+
const resolveSlotLoaders = async () => {
|
|
547
|
+
if (resolvedParallelEntries.has(parallelEntry.id)) return;
|
|
548
|
+
const loaderResult = await resolveLoadersWithRevalidation(
|
|
549
|
+
parallelEntry,
|
|
550
|
+
context,
|
|
551
|
+
belongsToRoute,
|
|
552
|
+
clientSegmentIds,
|
|
553
|
+
prevParams,
|
|
554
|
+
request,
|
|
555
|
+
prevUrl,
|
|
556
|
+
nextUrl,
|
|
557
|
+
routeKey,
|
|
558
|
+
deps,
|
|
559
|
+
actionContext,
|
|
560
|
+
entry.shortCode,
|
|
561
|
+
stale,
|
|
562
|
+
);
|
|
563
|
+
segments.push(...loaderResult.segments);
|
|
564
|
+
matchedIds.push(...loaderResult.matchedIds);
|
|
565
|
+
resolvedParallelEntries.add(parallelEntry.id);
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
if (loaderOrder === "before") {
|
|
569
|
+
await resolveSlotLoaders();
|
|
570
|
+
}
|
|
473
571
|
// Always announce the slot in matchedIds — it's unconditionally appended
|
|
474
572
|
// to `segments` below, and a segment present in segments but missing from
|
|
475
573
|
// matched lets the client prune it (then it's missing from clientSegmentIds
|
|
@@ -489,7 +587,10 @@ export async function resolveParallelSegmentsWithRevalidation<TEnv>(
|
|
|
489
587
|
// soft chain seeds with the right "new segment" / "parent-chain" value.
|
|
490
588
|
let defaultOverride: { value: boolean; reason: string } | undefined;
|
|
491
589
|
if (!clientSegmentIds.has(parallelId)) {
|
|
492
|
-
const value =
|
|
590
|
+
const value =
|
|
591
|
+
parentChainDefault === "force-render"
|
|
592
|
+
? true
|
|
593
|
+
: belongsToRoute || isNewParent;
|
|
493
594
|
defaultOverride = {
|
|
494
595
|
value,
|
|
495
596
|
reason: value ? "new-segment" : "skip-parent-chain",
|
|
@@ -537,55 +638,17 @@ export async function resolveParallelSegmentsWithRevalidation<TEnv>(
|
|
|
537
638
|
shouldResolve,
|
|
538
639
|
);
|
|
539
640
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
component = null;
|
|
552
|
-
} else if (handler === undefined) {
|
|
553
|
-
// Handler evicted (production static slot) but static lookup missed.
|
|
554
|
-
// Nothing to render — use null so the client keeps its cached version.
|
|
555
|
-
component = null;
|
|
556
|
-
} else {
|
|
557
|
-
// Slot-keyed pushes — slot owns its own bucket, parent layout owns
|
|
558
|
-
// its own. On slot-only revalidations the partial merge updates only
|
|
559
|
-
// the slot's bucket; the parent's bucket stays intact.
|
|
560
|
-
(context as InternalHandlerContext<any, TEnv>)._currentSegmentId =
|
|
561
|
-
parallelId;
|
|
562
|
-
handlerRan = true;
|
|
563
|
-
if (hasLoadingFallback) {
|
|
564
|
-
const result =
|
|
565
|
-
typeof handler === "function" ? handler(context) : handler;
|
|
566
|
-
if (result instanceof Promise) {
|
|
567
|
-
const tracked = deps.trackHandler(result, {
|
|
568
|
-
segmentId: parallelId,
|
|
569
|
-
segmentType: "parallel",
|
|
570
|
-
});
|
|
571
|
-
observeStreamedHandler(
|
|
572
|
-
tracked,
|
|
573
|
-
parallelId,
|
|
574
|
-
"parallel",
|
|
575
|
-
context.pathname,
|
|
576
|
-
routeKey,
|
|
577
|
-
params,
|
|
578
|
-
);
|
|
579
|
-
component = tracked as ReactNode;
|
|
580
|
-
} else {
|
|
581
|
-
component = result as ReactNode;
|
|
582
|
-
}
|
|
583
|
-
} else {
|
|
584
|
-
component =
|
|
585
|
-
typeof handler === "function" ? await handler(context) : handler;
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
}
|
|
641
|
+
const { component, handlerRan } = await resolveParallelSlotComponent({
|
|
642
|
+
shouldResolve,
|
|
643
|
+
parallelEntry,
|
|
644
|
+
slot,
|
|
645
|
+
parallelId,
|
|
646
|
+
handler,
|
|
647
|
+
context,
|
|
648
|
+
deps,
|
|
649
|
+
routeKey,
|
|
650
|
+
params,
|
|
651
|
+
});
|
|
589
652
|
|
|
590
653
|
segments.push({
|
|
591
654
|
id: parallelId,
|
|
@@ -597,6 +660,7 @@ export async function resolveParallelSegmentsWithRevalidation<TEnv>(
|
|
|
597
660
|
transition: applyViewTransitionDefault(
|
|
598
661
|
parallelEntry.transition,
|
|
599
662
|
deps.viewTransitionDefault,
|
|
663
|
+
parallelId,
|
|
600
664
|
),
|
|
601
665
|
params,
|
|
602
666
|
slot,
|
|
@@ -608,28 +672,9 @@ export async function resolveParallelSegmentsWithRevalidation<TEnv>(
|
|
|
608
672
|
: {}),
|
|
609
673
|
});
|
|
610
674
|
|
|
611
|
-
if (
|
|
612
|
-
|
|
675
|
+
if (loaderOrder === "after") {
|
|
676
|
+
await resolveSlotLoaders();
|
|
613
677
|
}
|
|
614
|
-
|
|
615
|
-
const loaderResult = await resolveLoadersWithRevalidation(
|
|
616
|
-
parallelEntry,
|
|
617
|
-
context,
|
|
618
|
-
belongsToRoute,
|
|
619
|
-
clientSegmentIds,
|
|
620
|
-
prevParams,
|
|
621
|
-
request,
|
|
622
|
-
prevUrl,
|
|
623
|
-
nextUrl,
|
|
624
|
-
routeKey,
|
|
625
|
-
deps,
|
|
626
|
-
actionContext,
|
|
627
|
-
entry.shortCode,
|
|
628
|
-
stale,
|
|
629
|
-
);
|
|
630
|
-
segments.push(...loaderResult.segments);
|
|
631
|
-
matchedIds.push(...loaderResult.matchedIds);
|
|
632
|
-
resolvedParallelEntries.add(parallelEntry.id);
|
|
633
678
|
}
|
|
634
679
|
|
|
635
680
|
return { segments, matchedIds };
|
|
@@ -755,13 +800,18 @@ export async function resolveEntryHandlerWithRevalidation<TEnv>(
|
|
|
755
800
|
? routeEntry.liveHandler
|
|
756
801
|
: routeEntry.handler;
|
|
757
802
|
if (!routeEntry.loading) {
|
|
758
|
-
const result = handleHandlerResult(
|
|
803
|
+
const result = handleHandlerResult(
|
|
804
|
+
await observeHandler(entry.id, handler, context),
|
|
805
|
+
);
|
|
759
806
|
doneHandler();
|
|
760
807
|
return result;
|
|
761
808
|
}
|
|
762
809
|
if (!actionContext) {
|
|
763
|
-
const result = handleHandlerResult(
|
|
810
|
+
const result = handleHandlerResult(
|
|
811
|
+
observeHandler(entry.id, handler, context),
|
|
812
|
+
);
|
|
764
813
|
if (result instanceof Promise) {
|
|
814
|
+
warnOnStreamedResponse(result, routeEntry.id);
|
|
765
815
|
result.finally(doneHandler).catch(() => {});
|
|
766
816
|
const tracked = deps.trackHandler(result, {
|
|
767
817
|
segmentId: entry.shortCode,
|
|
@@ -783,7 +833,9 @@ export async function resolveEntryHandlerWithRevalidation<TEnv>(
|
|
|
783
833
|
debugLog("segment.action", "resolving action route with awaited value", {
|
|
784
834
|
entryId: entry.id,
|
|
785
835
|
});
|
|
786
|
-
const actionResult = handleHandlerResult(
|
|
836
|
+
const actionResult = handleHandlerResult(
|
|
837
|
+
await observeHandler(entry.id, handler, context),
|
|
838
|
+
);
|
|
787
839
|
doneHandler();
|
|
788
840
|
return {
|
|
789
841
|
content: Promise.resolve(actionResult),
|
|
@@ -810,6 +862,7 @@ export async function resolveEntryHandlerWithRevalidation<TEnv>(
|
|
|
810
862
|
transition: applyViewTransitionDefault(
|
|
811
863
|
entry.transition,
|
|
812
864
|
deps.viewTransitionDefault,
|
|
865
|
+
entry.shortCode,
|
|
813
866
|
),
|
|
814
867
|
params,
|
|
815
868
|
belongsToRoute,
|
|
@@ -836,7 +889,6 @@ export async function resolveSegmentWithRevalidation<TEnv>(
|
|
|
836
889
|
request: Request,
|
|
837
890
|
prevUrl: URL,
|
|
838
891
|
nextUrl: URL,
|
|
839
|
-
loaderPromises: Map<string, Promise<any>>,
|
|
840
892
|
deps: SegmentResolutionDeps<TEnv>,
|
|
841
893
|
actionContext?: ActionContext,
|
|
842
894
|
stale?: boolean,
|
|
@@ -1147,177 +1199,38 @@ export async function resolveOrphanLayoutWithRevalidation<TEnv>(
|
|
|
1147
1199
|
transition: applyViewTransitionDefault(
|
|
1148
1200
|
orphan.transition,
|
|
1149
1201
|
deps.viewTransitionDefault,
|
|
1202
|
+
orphan.shortCode,
|
|
1150
1203
|
),
|
|
1151
1204
|
...(orphan.mountPath ? { mountPath: orphan.mountPath } : {}),
|
|
1152
1205
|
});
|
|
1153
1206
|
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
)
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
matchedIds.push(...loaderResult.matchedIds);
|
|
1182
|
-
resolvedParallelEntries.add(parallelEntry.id);
|
|
1183
|
-
}
|
|
1184
|
-
|
|
1185
|
-
const slots = parallelEntry.handler as Record<
|
|
1186
|
-
`@${string}`,
|
|
1187
|
-
| ((ctx: HandlerContext<any, TEnv>) => ReactNode | Promise<ReactNode>)
|
|
1188
|
-
| ReactNode
|
|
1189
|
-
>;
|
|
1190
|
-
// Handler may be undefined in production after static handler eviction.
|
|
1191
|
-
const handler = slots[slot];
|
|
1192
|
-
|
|
1193
|
-
// Use orphan.shortCode (the parent layout) to match the SSR path
|
|
1194
|
-
// (resolveParallelEntry receives parentShortCode = orphan.shortCode).
|
|
1195
|
-
// Using parallelEntry.shortCode would generate IDs the client doesn't know about.
|
|
1196
|
-
const parallelId = `${orphan.shortCode}.${slot}`;
|
|
1197
|
-
matchedIds.push(parallelId);
|
|
1198
|
-
|
|
1199
|
-
const isFullRefetch = clientSegmentIds.size === 0;
|
|
1200
|
-
let shouldResolve: boolean;
|
|
1201
|
-
if (isFullRefetch) {
|
|
1202
|
-
// Same load-bearing rationale as the main parallel path: full refetch
|
|
1203
|
-
// means the client has nothing to fall back to, so the slot must render.
|
|
1204
|
-
traceFullRefetchedParallelSlot(parallelId, belongsToRoute);
|
|
1205
|
-
shouldResolve = true;
|
|
1206
|
-
} else {
|
|
1207
|
-
// When slot is unknown to the client, seed the soft chain with `true`
|
|
1208
|
-
// (orphan parallels always belong to the route — we want them rendered
|
|
1209
|
-
// unless the user explicitly opts out via revalidate()).
|
|
1210
|
-
const defaultOverride = clientSegmentIds.has(parallelId)
|
|
1211
|
-
? undefined
|
|
1212
|
-
: { value: true, reason: "new-segment" };
|
|
1213
|
-
|
|
1214
|
-
const dummySegment: ResolvedSegment = {
|
|
1215
|
-
id: parallelId,
|
|
1216
|
-
namespace: parallelEntry.id,
|
|
1217
|
-
type: "parallel",
|
|
1218
|
-
index: 0,
|
|
1219
|
-
component: null as any,
|
|
1220
|
-
params,
|
|
1221
|
-
slot,
|
|
1222
|
-
belongsToRoute,
|
|
1223
|
-
parallelName: `${parallelEntry.id}.${slot}`,
|
|
1224
|
-
...(parallelEntry.mountPath
|
|
1225
|
-
? { mountPath: parallelEntry.mountPath }
|
|
1226
|
-
: {}),
|
|
1227
|
-
};
|
|
1228
|
-
|
|
1229
|
-
shouldResolve = await evaluateRevalidation({
|
|
1230
|
-
segment: dummySegment,
|
|
1231
|
-
prevParams,
|
|
1232
|
-
getPrevSegment: null,
|
|
1233
|
-
request,
|
|
1234
|
-
prevUrl,
|
|
1235
|
-
nextUrl,
|
|
1236
|
-
revalidations: parallelEntry.revalidate.map((fn, i) => ({
|
|
1237
|
-
name: `revalidate${i}`,
|
|
1238
|
-
fn,
|
|
1239
|
-
})),
|
|
1240
|
-
routeKey,
|
|
1241
|
-
context,
|
|
1242
|
-
actionContext,
|
|
1243
|
-
stale,
|
|
1244
|
-
traceSource: "parallel",
|
|
1245
|
-
defaultOverride,
|
|
1246
|
-
});
|
|
1247
|
-
}
|
|
1248
|
-
emitRevalidationDecision(
|
|
1249
|
-
parallelId,
|
|
1250
|
-
context.pathname,
|
|
1251
|
-
routeKey,
|
|
1252
|
-
shouldResolve,
|
|
1253
|
-
);
|
|
1254
|
-
|
|
1255
|
-
let component: ReactNode | undefined;
|
|
1256
|
-
let handlerRan = false;
|
|
1257
|
-
if (shouldResolve) {
|
|
1258
|
-
component = await tryStaticSlot(parallelEntry, slot, parallelId);
|
|
1259
|
-
}
|
|
1260
|
-
if (component === undefined) {
|
|
1261
|
-
const hasLoadingFallback =
|
|
1262
|
-
parallelEntry.loading !== undefined && parallelEntry.loading !== false;
|
|
1263
|
-
if (!shouldResolve) {
|
|
1264
|
-
component = null;
|
|
1265
|
-
} else if (handler === undefined) {
|
|
1266
|
-
// Handler evicted (production static slot) but static lookup missed.
|
|
1267
|
-
component = null;
|
|
1268
|
-
} else {
|
|
1269
|
-
// Slot-keyed pushes — see resolveParallelSegmentsWithRevalidation.
|
|
1270
|
-
(context as InternalHandlerContext<any, TEnv>)._currentSegmentId =
|
|
1271
|
-
parallelId;
|
|
1272
|
-
handlerRan = true;
|
|
1273
|
-
if (hasLoadingFallback) {
|
|
1274
|
-
const result =
|
|
1275
|
-
typeof handler === "function" ? handler(context) : handler;
|
|
1276
|
-
if (result instanceof Promise) {
|
|
1277
|
-
const tracked = deps.trackHandler(result, {
|
|
1278
|
-
segmentId: parallelId,
|
|
1279
|
-
segmentType: "parallel",
|
|
1280
|
-
});
|
|
1281
|
-
observeStreamedHandler(
|
|
1282
|
-
tracked,
|
|
1283
|
-
parallelId,
|
|
1284
|
-
"parallel",
|
|
1285
|
-
context.pathname,
|
|
1286
|
-
routeKey,
|
|
1287
|
-
params,
|
|
1288
|
-
);
|
|
1289
|
-
component = tracked as ReactNode;
|
|
1290
|
-
} else {
|
|
1291
|
-
component = result as ReactNode;
|
|
1292
|
-
}
|
|
1293
|
-
} else {
|
|
1294
|
-
component =
|
|
1295
|
-
typeof handler === "function" ? await handler(context) : handler;
|
|
1296
|
-
}
|
|
1297
|
-
}
|
|
1298
|
-
}
|
|
1299
|
-
|
|
1300
|
-
segments.push({
|
|
1301
|
-
id: parallelId,
|
|
1302
|
-
namespace: parallelEntry.id,
|
|
1303
|
-
type: "parallel",
|
|
1304
|
-
index: 0,
|
|
1305
|
-
component,
|
|
1306
|
-
loading: parallelEntry.loading === false ? null : parallelEntry.loading,
|
|
1307
|
-
transition: applyViewTransitionDefault(
|
|
1308
|
-
parallelEntry.transition,
|
|
1309
|
-
deps.viewTransitionDefault,
|
|
1310
|
-
),
|
|
1311
|
-
params,
|
|
1312
|
-
slot,
|
|
1313
|
-
_handlerRan: handlerRan,
|
|
1314
|
-
belongsToRoute,
|
|
1315
|
-
parallelName: `${parallelEntry.id}.${slot}`,
|
|
1316
|
-
...(parallelEntry.mountPath
|
|
1317
|
-
? { mountPath: parallelEntry.mountPath }
|
|
1318
|
-
: {}),
|
|
1319
|
-
});
|
|
1320
|
-
}
|
|
1207
|
+
// Resolve the orphan layout's parallel slots through the shared main-path
|
|
1208
|
+
// helper. The orphan policy is carried by explicit args, byte-for-byte:
|
|
1209
|
+
// - parentChainDefault "force-render": an unknown parent-chain slot seeds
|
|
1210
|
+
// `true` (orphan parallels always belong to the route — the #482 guard),
|
|
1211
|
+
// where the main path would seed `belongsToRoute || isNewParent`.
|
|
1212
|
+
// - loaderOrder "before": a slot's loaders are emitted before the slot
|
|
1213
|
+
// segment, matching the prior inlined order.
|
|
1214
|
+
// `entry.shortCode` inside the helper is `orphan.shortCode` (orphan is passed
|
|
1215
|
+
// as `entry`), so the parallel ids + loader shortCodeOverride are unchanged.
|
|
1216
|
+
const parallelResult = await resolveParallelSegmentsWithRevalidation(
|
|
1217
|
+
orphan,
|
|
1218
|
+
params,
|
|
1219
|
+
context,
|
|
1220
|
+
belongsToRoute,
|
|
1221
|
+
clientSegmentIds,
|
|
1222
|
+
prevParams,
|
|
1223
|
+
request,
|
|
1224
|
+
prevUrl,
|
|
1225
|
+
nextUrl,
|
|
1226
|
+
routeKey,
|
|
1227
|
+
deps,
|
|
1228
|
+
actionContext,
|
|
1229
|
+
stale,
|
|
1230
|
+
{ parentChainDefault: "force-render", loaderOrder: "before" },
|
|
1231
|
+
);
|
|
1232
|
+
segments.push(...parallelResult.segments);
|
|
1233
|
+
matchedIds.push(...parallelResult.matchedIds);
|
|
1321
1234
|
|
|
1322
1235
|
return { segments, matchedIds };
|
|
1323
1236
|
}
|
|
@@ -1335,7 +1248,6 @@ export async function resolveAllSegmentsWithRevalidation<TEnv>(
|
|
|
1335
1248
|
request: Request,
|
|
1336
1249
|
prevUrl: URL,
|
|
1337
1250
|
nextUrl: URL,
|
|
1338
|
-
loaderPromises: Map<string, Promise<any>>,
|
|
1339
1251
|
actionContext: ActionContext | undefined,
|
|
1340
1252
|
interceptResult: { intercept: any; entry: EntryData } | null,
|
|
1341
1253
|
localRouteName: string,
|
|
@@ -1387,7 +1299,6 @@ export async function resolveAllSegmentsWithRevalidation<TEnv>(
|
|
|
1387
1299
|
request,
|
|
1388
1300
|
prevUrl,
|
|
1389
1301
|
nextUrl,
|
|
1390
|
-
loaderPromises,
|
|
1391
1302
|
deps,
|
|
1392
1303
|
actionContext,
|
|
1393
1304
|
stale,
|