vinext 0.1.6 → 0.1.8

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.
Files changed (114) hide show
  1. package/dist/build/client-build-config.d.ts +4 -6
  2. package/dist/build/client-build-config.js +27 -7
  3. package/dist/build/prerender.js +1 -2
  4. package/dist/check.d.ts +18 -0
  5. package/dist/check.js +37 -17
  6. package/dist/cli.js +2 -2
  7. package/dist/config/next-config.d.ts +2 -1
  8. package/dist/config/next-config.js +3 -0
  9. package/dist/config/server-external-packages.d.ts +4 -0
  10. package/dist/config/server-external-packages.js +91 -0
  11. package/dist/deploy.d.ts +7 -0
  12. package/dist/deploy.js +25 -18
  13. package/dist/entries/app-rsc-entry.d.ts +2 -1
  14. package/dist/entries/app-rsc-entry.js +89 -20
  15. package/dist/entries/app-rsc-manifest.js +8 -0
  16. package/dist/entries/pages-client-entry.js +1 -0
  17. package/dist/entries/pages-server-entry.js +1 -0
  18. package/dist/index.js +87 -34
  19. package/dist/init.js +2 -1
  20. package/dist/plugins/middleware-server-only.d.ts +8 -6
  21. package/dist/plugins/middleware-server-only.js +8 -7
  22. package/dist/plugins/og-assets.js +6 -6
  23. package/dist/plugins/optimize-imports.js +1 -1
  24. package/dist/plugins/remove-console.js +1 -1
  25. package/dist/plugins/strip-server-exports.js +2 -1
  26. package/dist/routing/app-route-graph.d.ts +6 -2
  27. package/dist/routing/app-route-graph.js +61 -13
  28. package/dist/routing/app-router.d.ts +5 -0
  29. package/dist/routing/app-router.js +5 -0
  30. package/dist/routing/file-matcher.d.ts +5 -0
  31. package/dist/routing/file-matcher.js +7 -1
  32. package/dist/server/app-action-request.d.ts +4 -0
  33. package/dist/server/app-action-request.js +9 -0
  34. package/dist/server/app-bfcache-identity.d.ts +12 -2
  35. package/dist/server/app-bfcache-identity.js +52 -23
  36. package/dist/server/app-browser-entry.js +42 -147
  37. package/dist/server/app-browser-history-controller.d.ts +2 -1
  38. package/dist/server/app-browser-history-controller.js +6 -2
  39. package/dist/server/app-browser-server-action-client.d.ts +32 -0
  40. package/dist/server/app-browser-server-action-client.js +128 -0
  41. package/dist/server/app-fallback-renderer.d.ts +3 -1
  42. package/dist/server/app-fallback-renderer.js +6 -2
  43. package/dist/server/app-history-state.d.ts +1 -2
  44. package/dist/server/app-history-state.js +1 -1
  45. package/dist/server/app-page-boundary-render.d.ts +3 -0
  46. package/dist/server/app-page-boundary-render.js +14 -3
  47. package/dist/server/app-page-cache-finalizer.d.ts +1 -0
  48. package/dist/server/app-page-cache-finalizer.js +8 -2
  49. package/dist/server/app-page-dispatch.d.ts +33 -4
  50. package/dist/server/app-page-dispatch.js +62 -90
  51. package/dist/server/app-page-element-builder.d.ts +7 -1
  52. package/dist/server/app-page-element-builder.js +56 -19
  53. package/dist/server/app-page-head.d.ts +16 -1
  54. package/dist/server/app-page-head.js +44 -22
  55. package/dist/server/app-page-method.js +1 -1
  56. package/dist/server/app-page-params.d.ts +2 -1
  57. package/dist/server/app-page-params.js +8 -1
  58. package/dist/server/app-page-ppr-runtime.d.ts +7 -0
  59. package/dist/server/app-page-ppr-runtime.js +70 -0
  60. package/dist/server/app-page-probe.d.ts +1 -0
  61. package/dist/server/app-page-probe.js +1 -1
  62. package/dist/server/app-page-render.d.ts +4 -1
  63. package/dist/server/app-page-render.js +8 -3
  64. package/dist/server/app-page-request.d.ts +8 -1
  65. package/dist/server/app-page-request.js +23 -11
  66. package/dist/server/app-page-route-wiring.d.ts +6 -1
  67. package/dist/server/app-page-route-wiring.js +30 -8
  68. package/dist/server/app-page-search-params-observation.d.ts +4 -2
  69. package/dist/server/app-page-search-params-observation.js +11 -7
  70. package/dist/server/app-page-stream.js +2 -1
  71. package/dist/server/app-ppr-fallback-shell-render.d.ts +4 -3
  72. package/dist/server/app-route-handler-cache.js +1 -1
  73. package/dist/server/app-route-handler-dispatch.js +3 -2
  74. package/dist/server/app-route-handler-execution.js +5 -3
  75. package/dist/server/app-route-handler-policy.d.ts +1 -1
  76. package/dist/server/app-route-handler-policy.js +1 -6
  77. package/dist/server/app-route-module-loader.d.ts +2 -0
  78. package/dist/server/app-route-module-loader.js +1 -0
  79. package/dist/server/app-router-entry.js +7 -6
  80. package/dist/server/app-rsc-errors.d.ts +12 -1
  81. package/dist/server/app-rsc-errors.js +29 -3
  82. package/dist/server/app-rsc-handler.d.ts +15 -13
  83. package/dist/server/app-rsc-handler.js +28 -33
  84. package/dist/server/app-rsc-response-finalizer.js +5 -1
  85. package/dist/server/app-rsc-route-matching.d.ts +7 -0
  86. package/dist/server/app-rsc-route-matching.js +36 -3
  87. package/dist/server/app-segment-config.d.ts +1 -0
  88. package/dist/server/app-segment-config.js +32 -2
  89. package/dist/server/app-server-action-execution.d.ts +4 -0
  90. package/dist/server/app-server-action-execution.js +42 -11
  91. package/dist/server/app-ssr-entry.js +11 -6
  92. package/dist/server/app-static-generation.d.ts +1 -0
  93. package/dist/server/app-static-generation.js +1 -0
  94. package/dist/server/headers.d.ts +3 -1
  95. package/dist/server/headers.js +3 -1
  96. package/dist/server/metadata-route-response.d.ts +1 -1
  97. package/dist/server/prod-server.js +15 -6
  98. package/dist/server/worker-utils.d.ts +2 -1
  99. package/dist/server/worker-utils.js +7 -1
  100. package/dist/shims/dynamic.js +1 -1
  101. package/dist/shims/error-boundary.d.ts +19 -1
  102. package/dist/shims/error-boundary.js +11 -1
  103. package/dist/shims/headers.d.ts +3 -1
  104. package/dist/shims/headers.js +16 -5
  105. package/dist/shims/link.js +16 -12
  106. package/dist/shims/metadata.d.ts +3 -2
  107. package/dist/shims/metadata.js +8 -4
  108. package/dist/shims/router.js +13 -2
  109. package/dist/typegen.js +6 -5
  110. package/dist/utils/path.d.ts +2 -1
  111. package/dist/utils/path.js +1 -1
  112. package/dist/utils/project.d.ts +4 -0
  113. package/dist/utils/project.js +5 -1
  114. package/package.json +7 -3
@@ -1,17 +1,27 @@
1
1
  import { matchRoutePattern } from "../routing/route-pattern.js";
2
2
  import { AppElementsWire } from "./app-elements-wire.js";
3
- import { APP_RSC_RENDER_MODE_NAVIGATION, shouldSuppressLoadingBoundaries } from "./app-rsc-render-mode.js";
3
+ import { APP_RSC_RENDER_MODE_NAVIGATION } from "./app-rsc-render-mode.js";
4
4
  import "./app-elements.js";
5
5
  import { createAppPageRenderIdentity } from "./app-page-render-identity.js";
6
6
  import { makeThenableParams } from "../shims/thenable-params.js";
7
+ import { resolveAppPageBranchParams } from "./app-page-params.js";
7
8
  import { resolveActiveParallelRouteHeadInputs, resolveAppPageHead } from "./app-page-head.js";
8
- import { makeObservedAppPageSearchParamsThenable } from "./app-page-search-params-observation.js";
9
+ import { createAppPageSearchParamsObserver, makeObservedAppPageSearchParamsThenable } from "./app-page-search-params-observation.js";
9
10
  import { buildAppPageElements, createAppPageSourcePage, createAppPageTreePath } from "./app-page-route-wiring.js";
10
11
  import { DEFAULT_GLOBAL_ERROR_MODULE } from "./default-global-error-module.js";
11
12
  import "./app-rsc-route-matching.js";
12
13
  import { shouldServeStreamingMetadata } from "./streaming-metadata.js";
13
14
  import { createElement } from "react";
14
15
  //#region src/server/app-page-element-builder.ts
16
+ function resolveInterceptLayoutParams(branchSegments, layoutSegments, params) {
17
+ return resolveAppPageBranchParams(branchSegments, layoutSegments.length, params, layoutSegments);
18
+ }
19
+ const REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference");
20
+ function isReactOwnedPageComponent(component) {
21
+ if (typeof component !== "function") return true;
22
+ const candidate = component;
23
+ return candidate.$$typeof === REACT_CLIENT_REFERENCE || candidate.prototype?.isReactComponent != null;
24
+ }
15
25
  /**
16
26
  * Build the App Router element tree for a matched route.
17
27
  *
@@ -30,7 +40,8 @@ import { createElement } from "react";
30
40
  */
31
41
  async function buildPageElements(options) {
32
42
  const { route, params, routePath, displayPathname = routePath, pageRequest, globalErrorModule, rootNotFoundModule, rootForbiddenModule, rootUnauthorizedModule, metadataRoutes } = options;
33
- const { opts, searchParams, isRscRequest, mountedSlotsHeader, renderMode = APP_RSC_RENDER_MODE_NAVIGATION } = pageRequest;
43
+ const slotParamOverrides = resolveSlotParamOverrides(route, routePath);
44
+ const { opts, searchParams, isRscRequest, mountedSlotsHeader, renderMode = APP_RSC_RENDER_MODE_NAVIGATION, observeMetadataSearchParamsAccess = false, observePageSearchParamsAccess = false } = pageRequest;
34
45
  const pageModule = route.page;
35
46
  const isSiblingIntercept = opts?.interceptSlotKey === "__vinext_page_intercept" && !!opts?.interceptPage;
36
47
  const effectivePageModule = isSiblingIntercept ? opts.interceptPage : pageModule;
@@ -64,44 +75,68 @@ async function buildPageElements(options) {
64
75
  };
65
76
  }
66
77
  const { hasDynamicMetadata, metadata: resolvedMetadata, pageSearchParams, viewport: resolvedViewport } = await resolveAppPageHead({
78
+ applyFileBasedMetadata: options.applyFileBasedMetadata,
67
79
  basePath: options.basePath ?? "",
68
80
  layoutModules: route.layouts,
69
81
  layoutTreePositions: route.layoutTreePositions,
70
82
  metadataRoutes,
71
- pageModule: effectivePageModule ?? null,
72
- parallelRoutes: resolveActiveParallelRouteHeadInputs({
83
+ pageModule: isSiblingIntercept ? null : effectivePageModule ?? null,
84
+ parallelRoutes: [...resolveActiveParallelRouteHeadInputs({
85
+ interceptBranchSegments: opts?.interceptBranchSegments ?? null,
73
86
  interceptLayouts: opts?.interceptLayouts ?? null,
87
+ interceptLayoutSegments: opts?.interceptLayoutSegments ?? null,
74
88
  interceptPage: opts?.interceptPage ?? null,
75
89
  interceptParams: opts?.interceptParams ?? null,
76
90
  interceptSlotKey: opts?.interceptSlotKey ?? null,
91
+ layoutTreePositions: route.layoutTreePositions,
77
92
  params,
78
93
  routeSegments: route.routeSegments ?? [],
94
+ slotParams: slotParamOverrides,
79
95
  slots: route.slots ?? null
80
- }),
96
+ }), ...isSiblingIntercept ? [{
97
+ layoutModules: opts?.interceptLayouts ?? [],
98
+ layoutParams: (opts?.interceptLayoutSegments ?? []).map((segments) => resolveInterceptLayoutParams(opts?.interceptBranchSegments ?? segments, segments, effectiveParams)),
99
+ pageModule: effectivePageModule ?? null,
100
+ params: effectiveParams,
101
+ routeSegments: opts?.interceptSourcePageSegments ?? route.routeSegments ?? []
102
+ }] : []],
81
103
  params: effectiveParams,
82
104
  routePath: route.pattern,
83
105
  routeSegments: route.routeSegments ?? null,
84
- searchParams
106
+ searchParams,
107
+ searchParamsObserver: observeMetadataSearchParamsAccess ? createAppPageSearchParamsObserver() : void 0
85
108
  });
86
109
  const pageProps = { params: makeThenableParams(effectiveParams) };
87
- let pageSearchParamsThenable;
88
- if (searchParams) {
89
- pageSearchParamsThenable = !shouldSuppressLoadingBoundaries(renderMode) && Boolean(route.loading?.default) ? makeObservedAppPageSearchParamsThenable(pageSearchParams) : makeThenableParams(pageSearchParams);
90
- pageProps.searchParams = pageSearchParamsThenable;
91
- }
110
+ const hasRequestSearchParams = Object.keys(pageSearchParams).length > 0;
111
+ const createPageElement = (PageComponent, props) => {
112
+ if (isReactOwnedPageComponent(PageComponent)) {
113
+ const invocationProps = { ...props };
114
+ if (searchParams) invocationProps.searchParams = observePageSearchParamsAccess ? makeObservedAppPageSearchParamsThenable(pageSearchParams, { markDynamic: hasRequestSearchParams }) : makeThenableParams(pageSearchParams);
115
+ return createElement(PageComponent, invocationProps);
116
+ }
117
+ const ServerPageComponent = PageComponent;
118
+ const PageInvoker = () => {
119
+ const invocationProps = { ...props };
120
+ if (searchParams) invocationProps.searchParams = observePageSearchParamsAccess ? makeObservedAppPageSearchParamsThenable(pageSearchParams) : makeThenableParams(pageSearchParams);
121
+ return ServerPageComponent(invocationProps);
122
+ };
123
+ return createElement(PageInvoker);
124
+ };
125
+ const pageSearchParamsThenable = searchParams ? makeThenableParams(pageSearchParams) : void 0;
92
126
  const mountedSlotIds = mountedSlotsHeader ? new Set(mountedSlotsHeader.split(" ")) : null;
93
127
  const slotOverrides = buildSlotOverrides(route, params, routePath, opts);
94
128
  const metadataPlacement = hasDynamicMetadata && shouldServeStreamingMetadata(pageRequest.request.headers.get("user-agent") ?? "", options.htmlLimitedBots) ? "body" : "head";
95
- let siblingInterceptElement = isSiblingIntercept && EffectivePageComponent ? createElement(EffectivePageComponent, pageProps) : null;
96
- if (isSiblingIntercept && siblingInterceptElement !== null && opts?.interceptLayouts?.length) {
97
- const siblingThenableParams = makeThenableParams(effectiveParams);
98
- for (let i = opts.interceptLayouts.length - 1; i >= 0; i--) {
99
- const LayoutComponent = opts.interceptLayouts[i]?.default;
100
- if (LayoutComponent) siblingInterceptElement = createElement(LayoutComponent, { params: siblingThenableParams }, siblingInterceptElement);
129
+ let siblingInterceptElement = isSiblingIntercept && EffectivePageComponent ? createPageElement(EffectivePageComponent, pageProps) : null;
130
+ if (isSiblingIntercept && siblingInterceptElement !== null && opts?.interceptLayouts?.length) for (let i = opts.interceptLayouts.length - 1; i >= 0; i--) {
131
+ const LayoutComponent = opts.interceptLayouts[i]?.default;
132
+ if (LayoutComponent) {
133
+ const interceptLayoutSegments = opts.interceptLayoutSegments?.[i] ?? [];
134
+ siblingInterceptElement = createElement(LayoutComponent, { params: makeThenableParams(resolveInterceptLayoutParams(opts.interceptBranchSegments ?? interceptLayoutSegments, interceptLayoutSegments, effectiveParams)) }, siblingInterceptElement);
101
135
  }
102
136
  }
103
137
  return buildAppPageElements({
104
- element: isSiblingIntercept ? siblingInterceptElement : EffectivePageComponent ? createElement(EffectivePageComponent, pageProps) : null,
138
+ element: isSiblingIntercept ? siblingInterceptElement : EffectivePageComponent ? createPageElement(EffectivePageComponent, pageProps) : null,
139
+ createPageElement,
105
140
  globalErrorModule: globalErrorModule ?? DEFAULT_GLOBAL_ERROR_MODULE,
106
141
  isRscRequest,
107
142
  layoutParamAccess: options.layoutParamAccess,
@@ -142,7 +177,9 @@ async function buildPageElements(options) {
142
177
  function buildSlotOverrides(route, routeParams, routePath, opts) {
143
178
  const overrides = {};
144
179
  if (opts && opts.interceptSlotKey && opts.interceptPage && opts.interceptSlotKey !== "__vinext_page_intercept") overrides[opts.interceptSlotKey] = {
180
+ branchSegments: opts.interceptBranchSegments ?? null,
145
181
  layoutModules: opts.interceptLayouts || null,
182
+ layoutSegments: opts.interceptLayoutSegments ?? null,
146
183
  pageModule: opts.interceptPage,
147
184
  params: opts.interceptParams || routeParams
148
185
  };
@@ -1,31 +1,45 @@
1
1
  import { MetadataFileRoute } from "./metadata-routes.js";
2
2
  import { AppPageParams } from "./app-page-boundary.js";
3
+ import { ThenableParamsObserver } from "../shims/thenable-params.js";
3
4
  import { Metadata, Viewport } from "../shims/metadata.js";
5
+ import { applyFileBasedMetadata } from "./file-based-metadata.js";
4
6
 
5
7
  //#region src/server/app-page-head.d.ts
6
8
  type AppPageSearchParams = Record<string, string | string[]>;
7
9
  type AppPageHeadModule = Record<string, unknown>;
10
+ type ApplyAppPageFileBasedMetadata = typeof applyFileBasedMetadata;
8
11
  type AppPageHeadParallelRoute<TModule extends AppPageHeadModule = AppPageHeadModule> = {
12
+ layoutParams?: readonly AppPageParams[] | null;
9
13
  layoutModule?: TModule | null;
10
14
  layoutModules?: readonly (TModule | null | undefined)[] | null;
15
+ layoutTreePositions?: readonly number[] | null;
11
16
  pageModule?: TModule | null;
12
17
  params?: AppPageParams | null;
13
18
  routeSegments?: readonly string[] | null;
14
19
  };
15
20
  type AppPageHeadSlot<TModule extends AppPageHeadModule = AppPageHeadModule> = {
21
+ configLayouts?: readonly (TModule | null | undefined)[] | null;
22
+ configLayoutTreePositions?: readonly number[] | null;
16
23
  layout?: TModule | null;
24
+ layoutIndex?: number;
17
25
  page?: TModule | null;
26
+ routeSegments?: readonly string[] | null;
18
27
  };
19
28
  type ResolveActiveParallelRouteHeadInputsOptions<TModule extends AppPageHeadModule = AppPageHeadModule> = {
20
29
  interceptLayouts?: readonly (TModule | null | undefined)[] | null;
30
+ interceptBranchSegments?: readonly string[] | null;
31
+ interceptLayoutSegments?: readonly (readonly string[])[] | null;
21
32
  interceptPage?: TModule | null;
22
33
  interceptParams?: AppPageParams | null;
23
34
  interceptSlotKey?: string | null;
35
+ layoutTreePositions?: readonly number[] | null;
24
36
  params: AppPageParams;
25
37
  routeSegments: readonly string[];
38
+ slotParams?: Readonly<Record<string, AppPageParams>> | null;
26
39
  slots?: Record<string, AppPageHeadSlot<TModule>> | null;
27
40
  };
28
41
  type ResolveAppPageHeadOptions<TModule extends AppPageHeadModule = AppPageHeadModule> = {
42
+ applyFileBasedMetadata?: ApplyAppPageFileBasedMetadata;
29
43
  /**
30
44
  * Configured next.config `basePath`. Threaded into `applyFileBasedMetadata`
31
45
  * so file-based metadata route URLs (icon, opengraph-image, manifest, ...)
@@ -43,6 +57,7 @@ type ResolveAppPageHeadOptions<TModule extends AppPageHeadModule = AppPageHeadMo
43
57
  routePath: string;
44
58
  routeSegments?: readonly string[] | null;
45
59
  searchParams?: URLSearchParams | null;
60
+ searchParamsObserver?: ThenableParamsObserver;
46
61
  };
47
62
  type ResolveAppPageHeadResult = {
48
63
  hasDynamicMetadata: boolean;
@@ -59,4 +74,4 @@ declare function resolveActiveParallelRouteHeadInputs<TModule extends AppPageHea
59
74
  declare function collectAppPageSearchParams(searchParams: URLSearchParams | null | undefined): AppPageSearchParamsCollection;
60
75
  declare function resolveAppPageHead<TModule extends AppPageHeadModule>(options: ResolveAppPageHeadOptions<TModule>): Promise<ResolveAppPageHeadResult>;
61
76
  //#endregion
62
- export { AppPageSearchParams, collectAppPageSearchParams, resolveActiveParallelRouteHeadInputs, resolveAppPageHead };
77
+ export { AppPageSearchParams, ApplyAppPageFileBasedMetadata, collectAppPageSearchParams, resolveActiveParallelRouteHeadInputs, resolveAppPageHead };
@@ -1,6 +1,6 @@
1
1
  import { runWithFetchDedupe } from "../shims/fetch-cache.js";
2
2
  import { mergeMetadataEntries, mergeViewport, postProcessMetadata, resolveModuleMetadata as resolveModuleMetadata$1, resolveModuleViewport } from "../shims/metadata.js";
3
- import { resolveAppPageSegmentParams } from "./app-page-params.js";
3
+ import { resolveAppPageBranchParams, resolveAppPageSegmentParams } from "./app-page-params.js";
4
4
  import { tagAppPageMetadataError } from "./app-page-execution.js";
5
5
  //#region src/server/app-page-head.ts
6
6
  /**
@@ -24,23 +24,44 @@ async function resolveModuleMetadata(...args) {
24
24
  }
25
25
  function resolveActiveParallelRouteHeadInputs(options) {
26
26
  return Object.entries(options.slots ?? {}).map(([slotKey, slot]) => {
27
- if (options.interceptSlotKey === slotKey && options.interceptPage) return {
28
- layoutModules: options.interceptLayouts ?? [],
29
- pageModule: options.interceptPage,
30
- params: options.interceptParams ?? options.params,
31
- routeSegments: options.routeSegments
32
- };
27
+ const ownerTreePosition = options.layoutTreePositions?.[slot.layoutIndex ?? 0] ?? 0;
28
+ const ownerParams = resolveAppPageSegmentParams(options.routeSegments, ownerTreePosition, options.params);
29
+ if (options.interceptSlotKey === slotKey && options.interceptPage) {
30
+ const interceptLayouts = options.interceptLayouts ?? [];
31
+ return {
32
+ layoutModules: [slot.layout, ...interceptLayouts].filter(isPresent),
33
+ layoutParams: [...slot.layout ? [ownerParams] : [], ...interceptLayouts.filter(isPresent).map((_, index) => {
34
+ const segments = options.interceptLayoutSegments?.[index] ?? [];
35
+ return {
36
+ ...ownerParams,
37
+ ...resolveParallelLayoutParams(options.interceptBranchSegments ?? segments, segments.length, options.interceptParams ?? options.params)
38
+ };
39
+ })],
40
+ layoutTreePositions: [...slot.layout ? [0] : [], ...interceptLayouts.filter(isPresent).map(() => options.routeSegments.length)],
41
+ pageModule: options.interceptPage,
42
+ params: options.interceptParams ?? options.params,
43
+ routeSegments: options.routeSegments
44
+ };
45
+ }
33
46
  return {
34
- layoutModules: slot.layout ? [slot.layout] : [],
47
+ layoutModules: [slot.layout, ...slot.configLayouts ?? []].filter(isPresent),
48
+ layoutParams: [...slot.layout ? [ownerParams] : [], ...(slot.configLayoutTreePositions ?? []).map((treePosition) => ({
49
+ ...ownerParams,
50
+ ...resolveParallelLayoutParams(slot.routeSegments ?? options.routeSegments, treePosition, options.slotParams?.[slotKey] ?? options.params)
51
+ }))],
52
+ layoutTreePositions: [...slot.layout ? [0] : [], ...slot.configLayoutTreePositions ?? []],
35
53
  pageModule: slot.page,
36
- params: options.params,
37
- routeSegments: options.routeSegments
54
+ params: options.slotParams?.[slotKey] ?? options.params,
55
+ routeSegments: slot.routeSegments ?? options.routeSegments
38
56
  };
39
57
  });
40
58
  }
41
59
  function isPresent(value) {
42
60
  return value !== null && value !== void 0;
43
61
  }
62
+ function resolveParallelLayoutParams(routeSegments, treePosition, params) {
63
+ return resolveAppPageBranchParams(routeSegments, treePosition, params);
64
+ }
44
65
  function hasGenerateMetadata(module) {
45
66
  return typeof module?.generateMetadata === "function";
46
67
  }
@@ -111,7 +132,7 @@ async function resolveLayoutViewport(layoutInputs, params, routeSegments) {
111
132
  return resolveModuleViewport(layoutInput.module, layoutParams);
112
133
  }));
113
134
  }
114
- async function resolveParallelRouteHead(parallelRoute, fallbackParams, fallbackRouteSegments, pageSearchParams, parent) {
135
+ async function resolveParallelRouteHead(parallelRoute, fallbackParams, fallbackRouteSegments, pageSearchParams, parent, searchParamsObserver) {
115
136
  const params = parallelRoute.params ?? fallbackParams;
116
137
  const routeSegments = parallelRoute.routeSegments ?? fallbackRouteSegments;
117
138
  const metadataResults = [];
@@ -119,13 +140,15 @@ async function resolveParallelRouteHead(parallelRoute, fallbackParams, fallbackR
119
140
  const metadataSources = [];
120
141
  let accumulatedMetadata = parent;
121
142
  const layoutModules = [...parallelRoute.layoutModules ?? [], parallelRoute.layoutModule].filter(isPresent);
143
+ const layoutTreePositions = parallelRoute.layoutTreePositions ?? [];
144
+ const layoutParams = parallelRoute.layoutParams ?? [];
122
145
  const hasDynamicMetadata = layoutModules.some(hasGenerateMetadata) || hasGenerateMetadata(parallelRoute.pageModule);
123
- const layoutViewportPromises = layoutModules.map((layoutModule) => resolveModuleViewport(layoutModule, params));
124
- const pageViewportPromise = parallelRoute.pageModule ? resolveModuleViewport(parallelRoute.pageModule, params) : Promise.resolve(null);
146
+ const layoutViewportPromises = layoutModules.map((layoutModule, index) => resolveModuleViewport(layoutModule, layoutParams[index] ?? resolveParallelLayoutParams(routeSegments, layoutTreePositions[index] ?? 0, params)));
147
+ const pageViewportPromise = parallelRoute.pageModule ? resolveModuleViewport(parallelRoute.pageModule, params, pageSearchParams, searchParamsObserver) : Promise.resolve(null);
125
148
  for (const layoutViewportPromise of layoutViewportPromises) layoutViewportPromise.catch(() => null);
126
149
  pageViewportPromise.catch(() => null);
127
- for (const layoutModule of layoutModules) {
128
- const layoutMetadata = await resolveModuleMetadata(layoutModule, params, void 0, accumulatedMetadata);
150
+ for (const [index, layoutModule] of layoutModules.entries()) {
151
+ const layoutMetadata = await resolveModuleMetadata(layoutModule, layoutParams[index] ?? resolveParallelLayoutParams(routeSegments, layoutTreePositions[index] ?? 0, params), void 0, accumulatedMetadata);
129
152
  metadataResults.push(layoutMetadata);
130
153
  metadataSources.push({
131
154
  metadata: layoutMetadata,
@@ -137,7 +160,7 @@ async function resolveParallelRouteHead(parallelRoute, fallbackParams, fallbackR
137
160
  }
138
161
  }
139
162
  if (parallelRoute.pageModule) {
140
- const pageMetadata = await resolveModuleMetadata(parallelRoute.pageModule, params, pageSearchParams, accumulatedMetadata);
163
+ const pageMetadata = await resolveModuleMetadata(parallelRoute.pageModule, params, pageSearchParams, accumulatedMetadata, searchParamsObserver);
141
164
  metadataResults.push(pageMetadata);
142
165
  metadataSources.push({
143
166
  metadata: pageMetadata,
@@ -170,9 +193,9 @@ async function resolveAppPageHeadInner(options) {
170
193
  layoutMetadataResultsForParent.catch(() => null);
171
194
  const pageParentPromise = layoutMetadataResultsForParent.then((metadataResults) => metadataResults.length > 0 ? mergeMetadataEntries(metadataResults.map((metadata) => ({ metadata }))) : {});
172
195
  pageParentPromise.catch(() => null);
173
- const pageMetadataPromise = options.pageModule ? resolveModuleMetadata(options.pageModule, options.params, pageSearchParams, pageParentPromise) : Promise.resolve(null);
174
- const pageViewportPromise = options.pageModule ? resolveModuleViewport(options.pageModule, options.params) : Promise.resolve(null);
175
- const parallelRouteHeadPromise = Promise.all((options.parallelRoutes ?? []).map((parallelRoute) => resolveParallelRouteHead(parallelRoute, options.params, routeSegments, pageSearchParams, pageParentPromise)));
196
+ const pageMetadataPromise = options.pageModule ? resolveModuleMetadata(options.pageModule, options.params, pageSearchParams, pageParentPromise, options.searchParamsObserver) : Promise.resolve(null);
197
+ const pageViewportPromise = options.pageModule ? resolveModuleViewport(options.pageModule, options.params, pageSearchParams, options.searchParamsObserver) : Promise.resolve(null);
198
+ const parallelRouteHeadPromise = Promise.all((options.parallelRoutes ?? []).map((parallelRoute) => resolveParallelRouteHead(parallelRoute, options.params, routeSegments, pageSearchParams, pageParentPromise, options.searchParamsObserver)));
176
199
  const [layoutMetadataResults, layoutViewportResults, pageMetadata, pageViewport, parallelRouteHeads] = await Promise.all([
177
200
  layoutMetadataPromise,
178
201
  layoutViewportPromise,
@@ -205,9 +228,8 @@ async function resolveAppPageHeadInner(options) {
205
228
  const metadataSources = createMetadataSources(layoutMetadataResults, routeSegments, layoutSourcePositions, pageMetadata, Boolean(options.pageModule));
206
229
  metadataSources.push(...parallelMetadataSources);
207
230
  let metadata = resolvedMetadataBase;
208
- if (options.metadataRoutes.length > 0) try {
209
- const { applyFileBasedMetadata } = await import("./file-based-metadata.js");
210
- metadata = await applyFileBasedMetadata(resolvedMetadataBase, options.routePath, options.params, options.metadataRoutes, {
231
+ if (options.applyFileBasedMetadata && options.metadataRoutes.length > 0) try {
232
+ metadata = await options.applyFileBasedMetadata(resolvedMetadataBase, options.routePath, options.params, options.metadataRoutes, {
211
233
  routeSegments,
212
234
  metadataSources,
213
235
  basePath: options.basePath ?? ""
@@ -1,6 +1,6 @@
1
1
  import { methodNotAllowedResponse } from "./http-error-responses.js";
2
2
  import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
3
- import { isPossibleAppRouteActionRequest } from "./app-route-handler-policy.js";
3
+ import { isPossibleAppRouteActionRequest } from "./app-action-request.js";
4
4
  //#region src/server/app-page-method.ts
5
5
  function isNonGetOrHead(method) {
6
6
  const normalizedMethod = method.toUpperCase();
@@ -4,5 +4,6 @@ import { AppPageParams } from "./app-page-boundary.js";
4
4
  declare function getAppPageSegmentParamName(segment: string): string | null;
5
5
  declare function resolveAppPageSegmentParamScopeKeys(routeSegments: readonly string[] | null | undefined, treePosition: number): readonly string[];
6
6
  declare function resolveAppPageSegmentParams(routeSegments: readonly string[] | null | undefined, treePosition: number, matchedParams: AppPageParams): AppPageParams;
7
+ declare function resolveAppPageBranchParams(branchSegments: readonly string[], treePosition: number, matchedParams: AppPageParams, scopedSegments?: readonly string[]): AppPageParams;
7
8
  //#endregion
8
- export { getAppPageSegmentParamName, resolveAppPageSegmentParamScopeKeys, resolveAppPageSegmentParams };
9
+ export { getAppPageSegmentParamName, resolveAppPageBranchParams, resolveAppPageSegmentParamScopeKeys, resolveAppPageSegmentParams };
@@ -35,5 +35,12 @@ function resolveAppPageSegmentParams(routeSegments, treePosition, matchedParams)
35
35
  }
36
36
  return segmentParams;
37
37
  }
38
+ function resolveAppPageBranchParams(branchSegments, treePosition, matchedParams, scopedSegments = branchSegments) {
39
+ const branchParamNames = new Set(branchSegments.map(getAppPageSegmentParamName).filter((name) => name !== null));
40
+ const scopedParams = {};
41
+ for (const [name, value] of Object.entries(matchedParams)) if (!branchParamNames.has(name)) scopedParams[name] = value;
42
+ Object.assign(scopedParams, resolveAppPageSegmentParams(scopedSegments, treePosition, matchedParams));
43
+ return scopedParams;
44
+ }
38
45
  //#endregion
39
- export { getAppPageSegmentParamName, resolveAppPageSegmentParamScopeKeys, resolveAppPageSegmentParams };
46
+ export { getAppPageSegmentParamName, resolveAppPageBranchParams, resolveAppPageSegmentParamScopeKeys, resolveAppPageSegmentParams };
@@ -0,0 +1,7 @@
1
+ import { createAppPprFallbackShells } from "./app-ppr-fallback-shell.js";
2
+ import { AppPageDispatchRoute, AppPagePprRuntime } from "./app-page-dispatch.js";
3
+
4
+ //#region src/server/app-page-ppr-runtime.d.ts
5
+ declare const appPagePprRuntime: AppPagePprRuntime<AppPageDispatchRoute>;
6
+ //#endregion
7
+ export { appPagePprRuntime, createAppPprFallbackShells };
@@ -0,0 +1,70 @@
1
+ import { beginPprFallbackShellFinalRender, createPprFallbackShellState, getPprFallbackShellState, runWithPprFallbackShellState } from "../shims/ppr-fallback-shell.js";
2
+ import { createAppPprFallbackShells } from "./app-ppr-fallback-shell.js";
3
+ import { hasSearchParams, shouldReadAppPageCache } from "./app-page-dispatch.js";
4
+ //#region src/server/app-page-ppr-runtime.ts
5
+ function classifyPprFallbackShellEligibility(options, currentRevalidateSeconds, isDraftMode, isForceStatic, isForceDynamic) {
6
+ if (options.renderedConcreteUrlPaths?.has(options.cleanPathname) === true) return { kind: "skip-known-pregenerated-route" };
7
+ const fallbackShells = options.pprFallbackCacheShells;
8
+ if (!fallbackShells || fallbackShells.length === 0) return { kind: "skip-no-fallback-shells" };
9
+ if (options.isRscRequest) return { kind: "skip-rsc-request" };
10
+ if (options.request.method !== "GET") return { kind: "skip-non-get" };
11
+ if (!isForceStatic && hasSearchParams(options.searchParams)) return { kind: "skip-search-params" };
12
+ if (!shouldReadAppPageCache({
13
+ isDraftMode,
14
+ isForceDynamic,
15
+ isProgressiveActionRender: options.isProgressiveActionRender === true,
16
+ isProduction: options.isProduction,
17
+ isRscRequest: false,
18
+ revalidateSeconds: currentRevalidateSeconds,
19
+ scriptNonce: options.scriptNonce
20
+ })) return { kind: "skip-cache-disabled" };
21
+ return {
22
+ kind: "probe-fallback-shells",
23
+ fallbackShells
24
+ };
25
+ }
26
+ async function probePprFallbackShellCache(options, fallbackShells, currentRevalidateSeconds) {
27
+ const { readAppPageFallbackShellCacheResponse } = await import("./app-page-cache.js");
28
+ const { rewriteAppPprFallbackShellHtmlNavigation } = await import("./app-ppr-fallback-shell.js");
29
+ for (const fallbackShell of fallbackShells) {
30
+ const fallbackShellResponse = await readAppPageFallbackShellCacheResponse({
31
+ clearRequestContext: options.clearRequestContext,
32
+ expireSeconds: options.expireSeconds,
33
+ fallbackPathname: fallbackShell.pathname,
34
+ isEdgeRuntime: options.isEdgeRuntime,
35
+ isrDebug: options.isrDebug,
36
+ isrGet: options.isrGet,
37
+ isrHtmlKey: options.isrHtmlKey,
38
+ middlewareHeaders: options.middlewareContext.headers,
39
+ middlewareStatus: options.middlewareContext.status,
40
+ revalidateSeconds: currentRevalidateSeconds ?? 0,
41
+ rewriteHtml(html) {
42
+ return rewriteAppPprFallbackShellHtmlNavigation({
43
+ html,
44
+ params: options.params,
45
+ pathname: options.cleanPathname,
46
+ searchParams: options.searchParams
47
+ });
48
+ }
49
+ });
50
+ if (fallbackShellResponse) return fallbackShellResponse;
51
+ }
52
+ return null;
53
+ }
54
+ const appPagePprRuntime = {
55
+ beginFinalRender: beginPprFallbackShellFinalRender,
56
+ getState: getPprFallbackShellState,
57
+ run(shell, fn) {
58
+ return runWithPprFallbackShellState(createPprFallbackShellState(shell), fn);
59
+ },
60
+ async tryServe(options, currentRevalidateSeconds, isDraftMode, isForceStatic, isForceDynamic) {
61
+ const decision = classifyPprFallbackShellEligibility(options, currentRevalidateSeconds, isDraftMode, isForceStatic, isForceDynamic);
62
+ return decision.kind === "probe-fallback-shells" ? probePprFallbackShellCache(options, decision.fallbackShells, currentRevalidateSeconds) : null;
63
+ },
64
+ async warm(options) {
65
+ const { warmPprFallbackShellCaches } = await import("./app-ppr-fallback-shell-render.js");
66
+ await warmPprFallbackShellCaches(options);
67
+ }
68
+ };
69
+ //#endregion
70
+ export { appPagePprRuntime, createAppPprFallbackShells };
@@ -119,6 +119,7 @@ type ProbeAppPageBeforeRenderResult = {
119
119
  };
120
120
  type ProbeAppPageBeforeRenderOptions = {
121
121
  hasLoadingBoundary: boolean;
122
+ probePageBeforeRender?: boolean;
122
123
  skipProbes?: boolean;
123
124
  layoutCount: number;
124
125
  probeLayoutAt: (layoutIndex: number) => unknown;
@@ -252,7 +252,7 @@ async function probeAppPageBeforeRender(options) {
252
252
  layoutFlags
253
253
  };
254
254
  }
255
- if (options.hasLoadingBoundary) return {
255
+ if (options.hasLoadingBoundary || options.probePageBeforeRender === false) return {
256
256
  response: null,
257
257
  layoutFlags
258
258
  };
@@ -37,6 +37,7 @@ type RenderAppPageLifecycleOptions = {
37
37
  cleanPathname: string;
38
38
  clearRequestContext: () => void;
39
39
  consumeDynamicUsage: () => boolean;
40
+ peekDynamicUsage?: () => boolean;
40
41
  consumeRenderObservationState?: () => AppPageRenderObservationState; /** Read and clear any invalid dynamic usage error recorded during render (dev-only). */
41
42
  consumeInvalidDynamicUsageError?: () => unknown;
42
43
  createRscOnErrorHandler: (pathname: string, routePath: string) => AppPageBoundaryOnError;
@@ -60,6 +61,8 @@ type RenderAppPageLifecycleOptions = {
60
61
  isProgressiveActionRender?: boolean;
61
62
  isPrerender?: boolean;
62
63
  isProduction: boolean;
64
+ probePageBeforeRender?: boolean;
65
+ omitPendingDynamicCacheState?: boolean;
63
66
  isRscRequest: boolean;
64
67
  isrDebug?: AppPageDebugLogger;
65
68
  isrHtmlKey: (pathname: string) => string;
@@ -81,7 +84,7 @@ type RenderAppPageLifecycleOptions = {
81
84
  expireSeconds?: number;
82
85
  formState?: ReactFormState | null;
83
86
  revalidateSeconds: number | null;
84
- renderErrorBoundaryResponse: (error: unknown) => Promise<Response | null>;
87
+ renderErrorBoundaryResponse: (error: unknown, errorOrigin: "rsc" | "ssr") => Promise<Response | null>;
85
88
  renderLayoutSpecialError: (specialError: AppPageSpecialError, layoutIndex: number) => Promise<Response>;
86
89
  renderPageSpecialError: (specialError: AppPageSpecialError) => Promise<Response>;
87
90
  renderToReadableStream: (element: ReactNode | AppOutgoingElements, options: {
@@ -248,8 +248,11 @@ function wrapRscResponseForDevErrorReporting(response, consumeInvalidDynamicUsag
248
248
  });
249
249
  }
250
250
  async function renderAppPageLifecycle(options) {
251
+ const configuredProbePageBeforeRender = options.probePageBeforeRender ?? options.isRscRequest;
252
+ const probePageBeforeRender = options.isRscRequest || configuredProbePageBeforeRender && !(options.peekDynamicUsage?.() ?? false);
251
253
  const preRenderResult = await probeAppPageBeforeRender({
252
254
  hasLoadingBoundary: options.hasLoadingBoundary,
255
+ probePageBeforeRender,
253
256
  skipProbes: options.pprFallbackShellSignal !== void 0,
254
257
  layoutCount: options.layoutCount,
255
258
  probeLayoutAt(layoutIndex) {
@@ -430,7 +433,8 @@ async function renderAppPageLifecycle(options) {
430
433
  if (!options.isProduction) renderEnd = performance.now();
431
434
  },
432
435
  renderErrorBoundaryResponse(error) {
433
- return options.renderErrorBoundaryResponse(rscErrorTracker.getCapturedError() ?? error);
436
+ const capturedRscError = rscErrorTracker.getCapturedError();
437
+ return options.renderErrorBoundaryResponse(capturedRscError ?? error, capturedRscError === null ? "ssr" : "rsc");
434
438
  },
435
439
  async renderHtmlStream() {
436
440
  const ssrHandler = await options.loadSsrHandler();
@@ -462,7 +466,7 @@ async function renderAppPageLifecycle(options) {
462
466
  if (!htmlStream) throw new Error("[vinext] Expected an HTML stream when no fallback response was returned");
463
467
  const linkHeader = buildAppPageLinkHeader(htmlRender.linkHeader, fontLinkHeader, options.reactMaxHeadersLength);
464
468
  if (options.isPrerender === true) await htmlRender.metadataReady;
465
- if (options.hasLoadingBoundary) {
469
+ if (options.hasLoadingBoundary || !probePageBeforeRender) {
466
470
  const captured = rscErrorTracker.getCapturedSpecialError();
467
471
  if (captured) {
468
472
  const specialError = resolveAppPageSpecialError(captured);
@@ -480,8 +484,8 @@ async function renderAppPageLifecycle(options) {
480
484
  revalidateSeconds
481
485
  }));
482
486
  }
487
+ let dynamicUsedDuringRender = options.consumeDynamicUsage();
483
488
  const draftCookie = options.getDraftModeCookieHeader();
484
- const dynamicUsedDuringRender = options.consumeDynamicUsage();
485
489
  let dynamicUsedBeforeContextCleanup = dynamicUsedDuringRender;
486
490
  const safeHtmlStream = deferUntilStreamConsumed(htmlStream, () => {
487
491
  dynamicUsedBeforeContextCleanup = dynamicUsedBeforeContextCleanup || options.consumeDynamicUsage();
@@ -575,6 +579,7 @@ async function renderAppPageLifecycle(options) {
575
579
  isrRscKey: options.isrRscKey,
576
580
  isrSet: options.isrSet,
577
581
  interceptionContext: options.interceptionContext,
582
+ omitPendingDynamicCacheState: options.omitPendingDynamicCacheState,
578
583
  preserveClientResponseHeaders: !htmlResponsePolicy.shouldWriteToCache,
579
584
  expireSeconds,
580
585
  revalidateSeconds,
@@ -40,8 +40,11 @@ type BuildAppPageElementResult<TElement> = {
40
40
  };
41
41
  type AppPageInterceptMatch<TPage = unknown> = {
42
42
  interceptLayouts?: readonly unknown[] | null;
43
+ interceptLayoutSegments?: readonly (readonly string[])[] | null;
44
+ interceptBranchSegments?: readonly string[] | null;
43
45
  __loadInterceptLayouts?: readonly (() => Promise<unknown>)[] | null;
44
46
  matchedParams: AppPageParams;
47
+ sourceMatchedParams?: AppPageParams;
45
48
  page: TPage;
46
49
  __pageLoader?: (() => Promise<TPage>) | null;
47
50
  __loadState?: {
@@ -88,7 +91,10 @@ type ResolveAppPageInterceptionRerenderTargetResult<TRoute, TInterceptOpts> = {
88
91
  type ResolveAppPageActionRerenderTargetOptions<TRoute, TPage, TInterceptOpts> = ResolveAppPageInterceptionRerenderTargetOptions<TRoute, TPage, TInterceptOpts>;
89
92
  type ResolveAppPageActionRerenderTargetResult<TRoute, TInterceptOpts> = ResolveAppPageInterceptionRerenderTargetResult<TRoute, TInterceptOpts>;
90
93
  type ResolveAppPageInterceptOptions<TRoute, TPage, TInterceptOpts, TElement> = {
91
- buildPageElement: (route: TRoute, params: AppPageParams, interceptOpts: TInterceptOpts | undefined, searchParams: URLSearchParams, layoutParamAccess?: AppLayoutParamAccessTracker) => Promise<TElement>;
94
+ buildPageElement: (route: TRoute, params: AppPageParams, interceptOpts: TInterceptOpts | undefined, searchParams: URLSearchParams, layoutParamAccess?: AppLayoutParamAccessTracker, buildOptions?: {
95
+ observeMetadataSearchParamsAccess?: boolean;
96
+ observePageSearchParamsAccess?: boolean;
97
+ }) => Promise<TElement>;
92
98
  cleanPathname: string;
93
99
  currentRoute: TRoute;
94
100
  findIntercept: (pathname: string) => AppPageInterceptMatch<TPage> | null;
@@ -98,6 +104,7 @@ type ResolveAppPageInterceptOptions<TRoute, TPage, TInterceptOpts, TElement> = {
98
104
  layoutParamAccess?: AppLayoutParamAccessTracker;
99
105
  resolveNavigationParams: (route: TRoute, params: AppPageParams, pathname: string, interceptOpts: TInterceptOpts) => AppPageParams;
100
106
  renderInterceptResponse: (route: TRoute, element: TElement) => Promise<Response> | Response;
107
+ resolveSearchParams?: (route: TRoute, searchParams: URLSearchParams) => Awaitable<URLSearchParams>;
101
108
  searchParams: URLSearchParams;
102
109
  setNavigationContext: (context: {
103
110
  params: AppPageParams;
@@ -97,7 +97,7 @@ async function resolveAppPageInterceptMatch(options) {
97
97
  return {
98
98
  interceptOpts: options.toInterceptOpts(interceptState.intercept),
99
99
  matchedParams: interceptState.intercept.matchedParams,
100
- sourceParams: pickRouteParams(interceptState.intercept.matchedParams, options.getRouteParamNames(interceptState.sourceRoute)),
100
+ sourceParams: pickRouteParams(interceptState.intercept.sourceMatchedParams ?? interceptState.intercept.matchedParams, options.getRouteParamNames(interceptState.sourceRoute)),
101
101
  sourceRoute: interceptState.sourceRoute
102
102
  };
103
103
  }
@@ -145,12 +145,18 @@ async function resolveAppPageInterceptionRerenderTarget(options) {
145
145
  isRscRequest: options.isRscRequest,
146
146
  toInterceptOpts: options.toInterceptOpts
147
147
  });
148
- if (interceptState.kind === "source-route") return {
149
- interceptOpts: options.toInterceptOpts(interceptState.intercept),
150
- navigationParams: interceptState.intercept.matchedParams,
151
- params: pickRouteParams(interceptState.intercept.matchedParams, options.getRouteParamNames(interceptState.sourceRoute)),
152
- route: interceptState.sourceRoute
153
- };
148
+ if (interceptState.kind === "source-route") {
149
+ const sourceMatchedParams = interceptState.intercept.sourceMatchedParams ?? interceptState.intercept.matchedParams;
150
+ return {
151
+ interceptOpts: options.toInterceptOpts(interceptState.intercept),
152
+ navigationParams: {
153
+ ...sourceMatchedParams,
154
+ ...interceptState.intercept.matchedParams
155
+ },
156
+ params: pickRouteParams(sourceMatchedParams, options.getRouteParamNames(interceptState.sourceRoute)),
157
+ route: interceptState.sourceRoute
158
+ };
159
+ }
154
160
  return {
155
161
  interceptOpts: interceptState.kind === "current-route" ? options.toInterceptOpts(interceptState.intercept) : void 0,
156
162
  navigationParams: options.currentParams,
@@ -174,13 +180,19 @@ async function resolveAppPageIntercept(options) {
174
180
  if (interceptState.kind === "source-route") {
175
181
  const renderRoute = interceptState.sourceRoute;
176
182
  const interceptOpts = options.toInterceptOpts(interceptState.intercept);
177
- const renderParams = pickRouteParams(interceptState.intercept.matchedParams, options.getRouteParamNames(interceptState.sourceRoute));
183
+ const sourceMatchedParams = interceptState.intercept.sourceMatchedParams ?? interceptState.intercept.matchedParams;
184
+ const navigationParams = {
185
+ ...sourceMatchedParams,
186
+ ...interceptState.intercept.matchedParams
187
+ };
188
+ const renderSearchParams = options.resolveSearchParams ? await options.resolveSearchParams(renderRoute, options.searchParams) : options.searchParams;
189
+ const renderParams = pickRouteParams(sourceMatchedParams, options.getRouteParamNames(interceptState.sourceRoute));
178
190
  options.setNavigationContext({
179
- params: options.resolveNavigationParams(renderRoute, interceptState.intercept.matchedParams, options.cleanPathname, interceptOpts),
191
+ params: options.resolveNavigationParams(renderRoute, navigationParams, options.cleanPathname, interceptOpts),
180
192
  pathname: options.cleanPathname,
181
- searchParams: options.searchParams
193
+ searchParams: renderSearchParams
182
194
  });
183
- const interceptElement = await options.buildPageElement(renderRoute, renderParams, interceptOpts, options.searchParams, options.layoutParamAccess);
195
+ const interceptElement = await options.buildPageElement(renderRoute, renderParams, interceptOpts, renderSearchParams, options.layoutParamAccess);
184
196
  return {
185
197
  interceptOpts: void 0,
186
198
  response: await options.renderInterceptResponse(renderRoute, interceptElement)