vinext 1.0.0-beta.2 → 1.0.0-beta.4

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 (174) hide show
  1. package/README.md +6 -9
  2. package/dist/build/client-build-config.js +7 -1
  3. package/dist/build/precompress.js +1 -1
  4. package/dist/build/prerender.d.ts +2 -1
  5. package/dist/build/prerender.js +12 -2
  6. package/dist/check.js +4 -0
  7. package/dist/cli-args.d.ts +2 -1
  8. package/dist/cli-args.js +10 -0
  9. package/dist/cli.js +14 -8
  10. package/dist/client/navigation-runtime.d.ts +6 -0
  11. package/dist/client/navigation-runtime.js +1 -1
  12. package/dist/config/config-matchers.js +4 -1
  13. package/dist/config/dotenv.d.ts +3 -4
  14. package/dist/config/dotenv.js +30 -22
  15. package/dist/config/next-config.d.ts +16 -5
  16. package/dist/config/next-config.js +7 -0
  17. package/dist/entries/app-browser-entry.d.ts +4 -10
  18. package/dist/entries/app-browser-entry.js +20 -4
  19. package/dist/entries/app-rsc-entry.js +21 -3
  20. package/dist/entries/app-rsc-manifest.js +19 -0
  21. package/dist/entries/pages-client-entry.js +0 -1
  22. package/dist/entries/pages-server-entry.js +13 -3
  23. package/dist/index.js +122 -49
  24. package/dist/init-cloudflare.d.ts +3 -1
  25. package/dist/init-cloudflare.js +59 -5
  26. package/dist/plugins/client-reference-dedup.js +7 -5
  27. package/dist/plugins/extensionless-dynamic-import.js +23 -18
  28. package/dist/plugins/ignore-dynamic-requests.js +3 -1
  29. package/dist/plugins/import-meta-url.js +17 -6
  30. package/dist/plugins/require-context.js +20 -15
  31. package/dist/plugins/sass.js +3 -4
  32. package/dist/plugins/transform-cache.d.ts +19 -0
  33. package/dist/plugins/transform-cache.js +36 -0
  34. package/dist/routing/app-route-graph.d.ts +14 -6
  35. package/dist/routing/app-route-graph.js +106 -16
  36. package/dist/server/api-handler.d.ts +2 -0
  37. package/dist/server/api-handler.js +7 -6
  38. package/dist/server/app-bfcache-identity.js +28 -2
  39. package/dist/server/app-browser-entry.js +175 -75
  40. package/dist/server/app-browser-navigation-controller.d.ts +23 -21
  41. package/dist/server/app-browser-navigation-controller.js +30 -5
  42. package/dist/server/app-browser-prefetch-response.d.ts +9 -0
  43. package/dist/server/app-browser-prefetch-response.js +32 -0
  44. package/dist/server/app-browser-state.d.ts +8 -3
  45. package/dist/server/app-browser-state.js +9 -3
  46. package/dist/server/app-page-cache-finalizer.js +1 -1
  47. package/dist/server/app-page-cache.d.ts +1 -1
  48. package/dist/server/app-page-cache.js +16 -2
  49. package/dist/server/app-page-dispatch.d.ts +9 -1
  50. package/dist/server/app-page-dispatch.js +37 -8
  51. package/dist/server/app-page-element-builder.d.ts +4 -1
  52. package/dist/server/app-page-element-builder.js +34 -7
  53. package/dist/server/app-page-head.d.ts +3 -3
  54. package/dist/server/app-page-head.js +58 -13
  55. package/dist/server/app-page-http-access-fallback-metadata.d.ts +2 -2
  56. package/dist/server/app-page-http-access-fallback-metadata.js +9 -1
  57. package/dist/server/app-page-probe.d.ts +4 -0
  58. package/dist/server/app-page-probe.js +6 -2
  59. package/dist/server/app-page-render.d.ts +1 -1
  60. package/dist/server/app-page-render.js +13 -3
  61. package/dist/server/app-page-request.d.ts +3 -1
  62. package/dist/server/app-page-request.js +4 -13
  63. package/dist/server/app-page-response.d.ts +2 -0
  64. package/dist/server/app-page-response.js +7 -2
  65. package/dist/server/app-page-route-wiring.d.ts +10 -2
  66. package/dist/server/app-page-route-wiring.js +269 -59
  67. package/dist/server/app-pages-bridge.d.ts +2 -1
  68. package/dist/server/app-pages-bridge.js +3 -1
  69. package/dist/server/app-route-handler-cache.js +4 -0
  70. package/dist/server/app-route-handler-dispatch.js +9 -3
  71. package/dist/server/app-route-handler-response.js +1 -1
  72. package/dist/server/app-route-module-loader.d.ts +6 -0
  73. package/dist/server/app-route-module-loader.js +3 -0
  74. package/dist/server/app-router-entry.js +6 -3
  75. package/dist/server/app-rsc-cache-busting.d.ts +7 -0
  76. package/dist/server/app-rsc-cache-busting.js +6 -0
  77. package/dist/server/app-rsc-errors.js +10 -0
  78. package/dist/server/app-rsc-handler.d.ts +2 -0
  79. package/dist/server/app-rsc-handler.js +30 -13
  80. package/dist/server/app-rsc-render-mode.d.ts +3 -2
  81. package/dist/server/app-rsc-render-mode.js +4 -1
  82. package/dist/server/app-rsc-request-normalization.js +65 -4
  83. package/dist/server/app-rsc-route-matching.d.ts +9 -0
  84. package/dist/server/app-rsc-route-matching.js +6 -0
  85. package/dist/server/app-server-action-execution.d.ts +1 -1
  86. package/dist/server/app-ssr-entry.js +4 -4
  87. package/dist/server/app-visited-response-cache.d.ts +6 -1
  88. package/dist/server/app-visited-response-cache.js +49 -1
  89. package/dist/server/cache-control.d.ts +2 -2
  90. package/dist/server/cache-control.js +2 -1
  91. package/dist/server/dev-server.d.ts +3 -1
  92. package/dist/server/dev-server.js +204 -348
  93. package/dist/server/edge-api-runtime.d.ts +10 -1
  94. package/dist/server/edge-api-runtime.js +29 -1
  95. package/dist/server/headers.d.ts +4 -2
  96. package/dist/server/headers.js +6 -3
  97. package/dist/server/isr-cache.d.ts +10 -33
  98. package/dist/server/isr-cache.js +33 -43
  99. package/dist/server/isr-decision.d.ts +2 -2
  100. package/dist/server/pages-api-route.d.ts +4 -0
  101. package/dist/server/pages-api-route.js +6 -3
  102. package/dist/server/pages-asset-tags.d.ts +1 -0
  103. package/dist/server/pages-asset-tags.js +6 -4
  104. package/dist/server/pages-dev-hydration.js +0 -1
  105. package/dist/server/pages-document-asset-props.d.ts +26 -0
  106. package/dist/server/pages-document-asset-props.js +69 -0
  107. package/dist/server/pages-get-initial-props.d.ts +1 -1
  108. package/dist/server/pages-get-initial-props.js +1 -4
  109. package/dist/server/pages-i18n.js +64 -16
  110. package/dist/server/pages-node-compat.d.ts +2 -0
  111. package/dist/server/pages-node-compat.js +10 -6
  112. package/dist/server/pages-page-data.d.ts +61 -9
  113. package/dist/server/pages-page-data.js +334 -74
  114. package/dist/server/pages-page-handler.d.ts +6 -1
  115. package/dist/server/pages-page-handler.js +119 -20
  116. package/dist/server/pages-page-response.d.ts +7 -3
  117. package/dist/server/pages-page-response.js +41 -33
  118. package/dist/server/pages-request-pipeline.d.ts +7 -0
  119. package/dist/server/pages-request-pipeline.js +5 -1
  120. package/dist/server/pages-revalidate.d.ts +1 -1
  121. package/dist/server/pages-revalidate.js +54 -8
  122. package/dist/server/pages-router-entry.d.ts +1 -0
  123. package/dist/server/pages-router-entry.js +10 -4
  124. package/dist/server/prerender-manifest.d.ts +1 -0
  125. package/dist/server/prod-server.d.ts +2 -1
  126. package/dist/server/prod-server.js +38 -13
  127. package/dist/server/revalidation-host.d.ts +11 -0
  128. package/dist/server/revalidation-host.js +19 -0
  129. package/dist/server/seed-cache.js +1 -1
  130. package/dist/server/worker-revalidation-context.d.ts +13 -0
  131. package/dist/server/worker-revalidation-context.js +30 -0
  132. package/dist/shims/app-router-scroll-state.d.ts +2 -1
  133. package/dist/shims/app-router-scroll-state.js +7 -2
  134. package/dist/shims/cache-handler.d.ts +1 -1
  135. package/dist/shims/cache-handler.js +10 -7
  136. package/dist/shims/cache-runtime.d.ts +6 -0
  137. package/dist/shims/cache-runtime.js +4 -1
  138. package/dist/shims/cache.js +1 -1
  139. package/dist/shims/document.js +15 -2
  140. package/dist/shims/error.js +1 -1
  141. package/dist/shims/fetch-cache.js +1 -1
  142. package/dist/shims/font-google-base.js +17 -8
  143. package/dist/shims/font-local.js +41 -10
  144. package/dist/shims/hash-scroll.d.ts +1 -1
  145. package/dist/shims/hash-scroll.js +2 -1
  146. package/dist/shims/headers.d.ts +10 -13
  147. package/dist/shims/headers.js +85 -36
  148. package/dist/shims/internal/cookie-serialize.d.ts +10 -9
  149. package/dist/shims/internal/cookie-serialize.js +9 -8
  150. package/dist/shims/internal/interpolate-as.d.ts +15 -1
  151. package/dist/shims/internal/interpolate-as.js +27 -2
  152. package/dist/shims/link.d.ts +2 -0
  153. package/dist/shims/link.js +77 -24
  154. package/dist/shims/metadata.d.ts +18 -34
  155. package/dist/shims/metadata.js +98 -56
  156. package/dist/shims/navigation.d.ts +18 -2
  157. package/dist/shims/navigation.js +70 -21
  158. package/dist/shims/request-context.d.ts +6 -2
  159. package/dist/shims/router.js +18 -7
  160. package/dist/shims/script.js +1 -1
  161. package/dist/shims/server.d.ts +7 -6
  162. package/dist/shims/server.js +156 -57
  163. package/dist/shims/slot.d.ts +2 -1
  164. package/dist/shims/slot.js +6 -2
  165. package/dist/shims/streamed-icons.d.ts +9 -0
  166. package/dist/shims/streamed-icons.js +33 -0
  167. package/dist/shims/unified-request-context.d.ts +21 -2
  168. package/dist/shims/unified-request-context.js +82 -1
  169. package/dist/utils/cache-control-metadata.d.ts +2 -1
  170. package/dist/utils/cache-control-metadata.js +5 -1
  171. package/dist/utils/html-limited-bots.js +1 -1
  172. package/dist/utils/protocol-headers.d.ts +7 -1
  173. package/dist/utils/protocol-headers.js +7 -1
  174. package/package.json +1 -1
@@ -2,12 +2,13 @@
2
2
  import { stripBasePath } from "../utils/base-path.js";
3
3
  import { createRouteTrieCache, matchRouteWithTrie } from "../routing/route-matching.js";
4
4
  import { isDangerousScheme, reportBlockedDangerousNavigation } from "./url-safety.js";
5
+ import { RouterContext } from "./internal/router-context.js";
5
6
  import { addLocalePrefix, getDomainLocaleUrl } from "../utils/domain-locale.js";
6
7
  import { getPagesMiddlewareDataHref, prefetchPagesData, resolvePagesDataNavigationTarget } from "./internal/pages-data-target.js";
7
8
  import { markAppRouteDetectedOnPrefetch } from "./internal/app-route-detection.js";
8
9
  import { isAbsoluteOrProtocolRelativeUrl, normalizePathTrailingSlash, toBrowserNavigationHref, toSameOriginAppPath, withBasePath } from "./url-utils.js";
9
10
  import { appendSearchParamsToUrl, urlQueryToSearchParams } from "../utils/query.js";
10
- import { interpolateDynamicRouteHref } from "./internal/interpolate-as.js";
11
+ import { interpolateDynamicRouteHref, resolveDynamicRouteHref } from "./internal/interpolate-as.js";
11
12
  import { getCurrentBrowserLocale } from "./client-locale.js";
12
13
  import { getCurrentRoutePathnameForWarning } from "./internal/route-pattern-for-warning.js";
13
14
  import { isBotUserAgent } from "../utils/html-limited-bots.js";
@@ -29,6 +30,22 @@ import { jsx } from "react/jsx-runtime";
29
30
  */
30
31
  const HAS_PAGES_ROUTER = process.env.__VINEXT_HAS_PAGES_ROUTER !== "false";
31
32
  const HAS_CLIENT_REWRITES = process.env.__VINEXT_HAS_CLIENT_REWRITES !== "false";
33
+ let loadedNavigationModule = null;
34
+ let navigationModulePromise = null;
35
+ let loadedHybridClientRouteOwnerModule = null;
36
+ let hybridClientRouteOwnerModulePromise = null;
37
+ function loadNavigationModule() {
38
+ return navigationModulePromise ??= import("./navigation.js").then((module) => {
39
+ loadedNavigationModule = module;
40
+ return module;
41
+ });
42
+ }
43
+ function loadHybridClientRouteOwnerModule() {
44
+ return hybridClientRouteOwnerModulePromise ??= import("./internal/hybrid-client-route-owner.js").then((module) => {
45
+ loadedHybridClientRouteOwnerModule = module;
46
+ return module;
47
+ });
48
+ }
32
49
  const LinkStatusContext = createContext({ pending: false });
33
50
  /**
34
51
  * useLinkStatus returns the pending state of the enclosing <Link>.
@@ -147,6 +164,8 @@ function getLinkPrefetchRouterMode() {
147
164
  function resolveMatchedAutoAppRoutePrefetch(route) {
148
165
  return {
149
166
  cacheForNavigation: !route.canPrefetchLoadingShell && route.requiresDynamicNavigationRequest !== true,
167
+ fallbackTtl: "static",
168
+ minimumTtlMs: route.isDynamic ? 0 : void 0,
150
169
  prefetchShellFirst: !route.isDynamic,
151
170
  shouldPrefetch: true
152
171
  };
@@ -163,24 +182,32 @@ function canAutoPrefetchFullAppRoute(href) {
163
182
  function resolveAutoAppRoutePrefetch(href) {
164
183
  if (typeof window === "undefined") return {
165
184
  cacheForNavigation: false,
185
+ fallbackTtl: "static",
186
+ minimumTtlMs: void 0,
166
187
  prefetchShellFirst: false,
167
188
  shouldPrefetch: false
168
189
  };
169
190
  const routes = window.__VINEXT_LINK_PREFETCH_ROUTES__;
170
191
  if (!routes) return {
171
192
  cacheForNavigation: false,
193
+ fallbackTtl: "static",
194
+ minimumTtlMs: void 0,
172
195
  prefetchShellFirst: false,
173
196
  shouldPrefetch: false
174
197
  };
175
198
  const routeHref = toSameOriginRouteHref(href);
176
199
  if (routeHref === null) return {
177
200
  cacheForNavigation: false,
201
+ fallbackTtl: "static",
202
+ minimumTtlMs: void 0,
178
203
  prefetchShellFirst: false,
179
204
  shouldPrefetch: false
180
205
  };
181
206
  const match = matchRouteWithTrie(routeHref, routes, linkPrefetchRouteTrieCache);
182
207
  if (!match) return {
183
208
  cacheForNavigation: false,
209
+ fallbackTtl: "static",
210
+ minimumTtlMs: void 0,
184
211
  prefetchShellFirst: false,
185
212
  shouldPrefetch: false
186
213
  };
@@ -195,6 +222,8 @@ function resolveAutoAppRoutePrefetch(href) {
195
222
  function resolveFullAppRoutePrefetch() {
196
223
  return {
197
224
  cacheForNavigation: true,
225
+ fallbackTtl: "static",
226
+ minimumTtlMs: void 0,
198
227
  prefetchShellFirst: true,
199
228
  shouldPrefetch: true
200
229
  };
@@ -228,27 +257,30 @@ function prefetchUrl(href, mode, priority = "low", pagesRouteHref, locale) {
228
257
  }) ?? prefetchHref, window.location.href, __basePath);
229
258
  const target = new URL(fullHref, window.location.href);
230
259
  if (target.origin === window.location.origin && target.pathname === window.location.pathname && target.search === window.location.search) return;
260
+ if (mode === "auto" && priority === "low" && target.origin === window.location.origin && target.pathname === window.location.pathname && target.search !== window.location.search && target.hash !== "") return;
231
261
  const runPrefetch = () => {
232
262
  (async () => {
233
263
  if (hasAppNavigationRuntime()) {
234
264
  if (isBotUserAgent(window.navigator?.userAgent ?? "")) return;
235
265
  const [navigation, { AppElementsWire }, rscCacheBusting, { APP_RSC_RENDER_MODE_PREFETCH_DYNAMIC_SHELL, APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL }, headersModule, hybridRouteOwner] = await Promise.all([
236
- import("./navigation.js"),
266
+ loadNavigationModule(),
237
267
  import("../server/app-elements.js"),
238
268
  import("../server/app-rsc-cache-busting.js"),
239
269
  import("../server/app-rsc-render-mode.js"),
240
270
  import("../server/headers.js"),
241
- HAS_PAGES_ROUTER || HAS_CLIENT_REWRITES ? import("./internal/hybrid-client-route-owner.js") : null
271
+ HAS_PAGES_ROUTER || HAS_CLIENT_REWRITES ? loadHybridClientRouteOwnerModule() : null
242
272
  ]);
243
273
  if (navigationEpoch !== linkPrefetchNavigationEpoch) return;
244
- const { getPrefetchInterceptionContext, getPrefetchCache, getPrefetchedUrls, getMountedSlotsHeader, hasSearchAgnosticPrefetchShellForRoute, hasPrefetchCacheEntryForNavigation, peekPrefetchResponseForNavigation, prefetchRscResponse, restoreRscResponse, PREFETCH_CACHE_TTL } = navigation;
245
- const { createRscRequestHeaders, createRscRequestUrl } = rscCacheBusting;
274
+ const { getPrefetchInterceptionContext, getPrefetchCache, getPrefetchedUrls, getMountedSlotsHeader, createAppPrefetchRequestHeaders, discardLearningOnlyPrefetchCacheEntry, hasSearchAgnosticPrefetchShellForRoute, hasPrefetchCacheEntryForNavigation, peekPrefetchResponseForNavigation, prefetchRscResponse, DYNAMIC_NAVIGATION_CACHE_TTL, restoreRscResponse, PREFETCH_CACHE_TTL } = navigation;
275
+ const { createRscRequestUrl } = rscCacheBusting;
246
276
  const { NEXT_ROUTER_PREFETCH_HEADER, NEXT_ROUTER_SEGMENT_PREFETCH_HEADER, VINEXT_MOUNTED_SLOTS_HEADER } = headersModule;
247
277
  const hybridOwner = HAS_PAGES_ROUTER ? hybridRouteOwner.resolveHybridClientRouteOwner(prefetchHref, __basePath) : null;
248
278
  if (hybridOwner === "pages" || hybridOwner === "document") return;
249
279
  const rewrittenPrefetchHref = HAS_CLIENT_REWRITES ? hybridRouteOwner.resolveHybridClientRewriteHref(fullHref, __basePath) : null;
250
280
  const autoPrefetch = mode === "auto" ? resolveAutoAppRoutePrefetch(rewrittenPrefetchHref ?? prefetchHref) : mode === "full-after-shell" ? {
251
281
  cacheForNavigation: true,
282
+ fallbackTtl: "static",
283
+ minimumTtlMs: void 0,
252
284
  prefetchShellFirst: true,
253
285
  shouldPrefetch: true
254
286
  } : resolveFullAppRoutePrefetch();
@@ -258,15 +290,16 @@ function prefetchUrl(href, mode, priority = "low", pagesRouteHref, locale) {
258
290
  const isOptimisticRouteShellPrefetch = !autoPrefetch.cacheForNavigation;
259
291
  const hasSearchParams = new URL(fullHref, window.location.href).search !== "";
260
292
  const isAutomaticSearchParamShell = mode === "auto" && isOptimisticRouteShellPrefetch && hasSearchParams;
261
- if (isOptimisticRouteShellPrefetch && interceptionContext !== null) return;
262
293
  const hasSearchAgnosticShell = isAutomaticSearchParamShell && hasSearchAgnosticPrefetchShellForRoute(await createRscRequestUrl(fullHref, new Headers()), interceptionContext, mountedSlotsHeader);
263
- const headers = createRscRequestHeaders({
294
+ const headers = createAppPrefetchRequestHeaders({
264
295
  interceptionContext,
296
+ fetchPriority: priority,
297
+ prefetchKind: mode === "full" ? "full" : "auto",
265
298
  renderMode: isOptimisticRouteShellPrefetch ? hasSearchAgnosticShell ? APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL : isAutomaticSearchParamShell ? APP_RSC_RENDER_MODE_PREFETCH_DYNAMIC_SHELL : APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL : void 0
266
299
  });
267
300
  if (mountedSlotsHeader) headers.set(VINEXT_MOUNTED_SLOTS_HEADER, mountedSlotsHeader);
268
301
  const shouldSendSegmentPrefetchHeaders = isOptimisticRouteShellPrefetch || mode === "auto";
269
- if (__prefetchInlining && autoPrefetch.cacheForNavigation) {
302
+ if (__prefetchInlining && mode === "auto" && autoPrefetch.cacheForNavigation) {
270
303
  headers.set(NEXT_ROUTER_PREFETCH_HEADER, "1");
271
304
  headers.set(NEXT_ROUTER_SEGMENT_PREFETCH_HEADER, "/__PAGE__");
272
305
  } else if (shouldSendSegmentPrefetchHeaders) {
@@ -277,10 +310,9 @@ function prefetchUrl(href, mode, priority = "low", pagesRouteHref, locale) {
277
310
  const additionalRscUrls = rewrittenPrefetchHref && rewrittenPrefetchHref !== fullHref ? [await createRscRequestUrl(rewrittenPrefetchHref, headers)] : [];
278
311
  const cacheKey = AppElementsWire.encodeCacheKey(rscUrl, interceptionContext);
279
312
  const prefetched = getPrefetchedUrls();
313
+ if (autoPrefetch.cacheForNavigation) discardLearningOnlyPrefetchCacheEntry(rscUrl, interceptionContext);
280
314
  if (prefetched.has(cacheKey)) {
281
315
  if (!autoPrefetch.cacheForNavigation) return;
282
- const existing = getPrefetchCache().get(cacheKey);
283
- if (existing?.cacheForNavigation === false) existing.cacheForNavigation = true;
284
316
  }
285
317
  const fetchFullRscPayload = () => scheduleAppPrefetchFetch(() => fetch(rscUrl, {
286
318
  headers,
@@ -289,8 +321,9 @@ function prefetchUrl(href, mode, priority = "low", pagesRouteHref, locale) {
289
321
  purpose: "prefetch"
290
322
  }), priority);
291
323
  const fetchLoadingShellForReuse = async () => {
292
- const shellHeaders = createRscRequestHeaders({
324
+ const shellHeaders = createAppPrefetchRequestHeaders({
293
325
  interceptionContext,
326
+ fetchPriority: priority,
294
327
  renderMode: APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL
295
328
  });
296
329
  shellHeaders.set(NEXT_ROUTER_PREFETCH_HEADER, "1");
@@ -317,8 +350,9 @@ function prefetchUrl(href, mode, priority = "low", pagesRouteHref, locale) {
317
350
  await shellEntry?.pending?.catch(() => {});
318
351
  };
319
352
  const fetchAliasCacheHitProbe = async () => {
320
- const probeHeaders = createRscRequestHeaders({
353
+ const probeHeaders = createAppPrefetchRequestHeaders({
321
354
  interceptionContext,
355
+ fetchPriority: priority,
322
356
  renderMode: APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL
323
357
  });
324
358
  probeHeaders.set(NEXT_ROUTER_PREFETCH_HEADER, "1");
@@ -350,8 +384,9 @@ function prefetchUrl(href, mode, priority = "low", pagesRouteHref, locale) {
350
384
  await fetchLoadingShellForReuse();
351
385
  return fetchFullRscPayload();
352
386
  }
353
- const shellHeaders = createRscRequestHeaders({
387
+ const shellHeaders = createAppPrefetchRequestHeaders({
354
388
  interceptionContext,
389
+ fetchPriority: priority,
355
390
  renderMode: void 0
356
391
  });
357
392
  shellHeaders.set(NEXT_ROUTER_PREFETCH_HEADER, "1");
@@ -389,12 +424,18 @@ function prefetchUrl(href, mode, priority = "low", pagesRouteHref, locale) {
389
424
  purpose: "prefetch"
390
425
  }), priority);
391
426
  })() : fetchFullRscPayload();
392
- if (mode === "full" && autoPrefetch.cacheForNavigation && autoPrefetch.prefetchShellFirst && mountedSlotsHeader === null && !gateViaExplicitSearchShell) fetchLoadingShellForReuse();
427
+ if (!__prefetchInlining && mode === "full" && autoPrefetch.cacheForNavigation && autoPrefetch.prefetchShellFirst && mountedSlotsHeader === null && !gateViaExplicitSearchShell) fetchLoadingShellForReuse();
393
428
  prefetchRscResponse(rscUrl, fetchPromise, interceptionContext, mountedSlotsHeader, void 0, {
394
429
  cacheForNavigation: autoPrefetch.cacheForNavigation,
395
- fallbackTtlMs: PREFETCH_CACHE_TTL,
430
+ fallbackTtlMs: autoPrefetch.fallbackTtl === "dynamic" ? DYNAMIC_NAVIGATION_CACHE_TTL : PREFETCH_CACHE_TTL,
431
+ minimumTtlMs: autoPrefetch.minimumTtlMs,
396
432
  optimisticRouteShell: isOptimisticRouteShellPrefetch,
397
433
  prefetchKind: isOptimisticRouteShellPrefetch ? "loading-shell" : "navigation",
434
+ prepareSnapshot: autoPrefetch.cacheForNavigation ? async (snapshot) => {
435
+ const preparePrefetchResponse = getNavigationRuntime()?.functions.preparePrefetchResponse;
436
+ if (!preparePrefetchResponse) throw new Error("App Router prefetch preparation is unavailable");
437
+ return await preparePrefetchResponse(restoreRscResponse(snapshot));
438
+ } : void 0,
398
439
  searchAgnosticShell: isAutomaticSearchParamShell && !hasSearchAgnosticShell
399
440
  });
400
441
  } else if (HAS_PAGES_ROUTER && window.__NEXT_DATA__) {
@@ -427,7 +468,7 @@ function prefetchUrl(href, mode, priority = "low", pagesRouteHref, locale) {
427
468
  async function promotePrefetchEntriesForNavigation(href) {
428
469
  if (typeof window === "undefined") return;
429
470
  if (!hasAppNavigationRuntime()) return;
430
- const [{ getPrefetchCache }, { stripRscCacheBustingSearchParam, stripRscSuffix }] = await Promise.all([import("./navigation.js"), import("../server/app-rsc-cache-busting.js")]);
471
+ const [{ getPrefetchCache }, { stripRscCacheBustingSearchParam, stripRscSuffix }] = await Promise.all([loadNavigationModule(), import("../server/app-rsc-cache-busting.js")]);
431
472
  let target;
432
473
  try {
433
474
  target = new URL(toBrowserNavigationHref(href, window.location.href, __basePath), window.location.href);
@@ -581,17 +622,29 @@ function resolveConcreteRouteHref(href, as) {
581
622
  return interpolateDynamicRouteHref(typeof href === "string" ? href : resolveHref(href), as, typeof href === "string" || !href.query || typeof href.query === "string" ? void 0 : href.query)?.href || null;
582
623
  }
583
624
  const Link = forwardRef(function Link({ href, as, replace = false, prefetch: prefetchProp, scroll = true, shallow = false, children: childrenProp, onClick, onMouseEnter, onTouchStart, onNavigate, unstable_dynamicOnHover = false, legacyBehavior = false, passHref = false, transitionTypes: _transitionTypes, ...rest }, forwardedRef) {
625
+ const pagesRouter = useContext(RouterContext);
584
626
  const asHref = as === void 0 ? void 0 : resolveHref(as);
627
+ const hrefStr = resolveHref(href);
585
628
  const { locale, ...restWithoutLocale } = rest;
586
629
  let children = childrenProp;
587
630
  if (legacyBehavior && (typeof childrenProp === "string" || typeof childrenProp === "number")) children = React.createElement("a", null, childrenProp);
588
- const unresolvedHref = asHref ?? resolveHref(href);
589
- const rawResolvedHref = typeof unresolvedHref === "string" && unresolvedHref.startsWith("#") ? resolvePagesQueryOnlyHref(unresolvedHref) : unresolvedHref;
590
- const routeHrefRaw = (HAS_PAGES_ROUTER ? resolveConcreteRouteHref(href, asHref) : null) ?? (typeof href === "string" ? href : resolveHref(href));
631
+ const hrefForImplicitInterpolation = isAbsoluteOrProtocolRelativeUrl(hrefStr) ? hrefStr.startsWith("//") ? null : toSameOriginAppPath(hrefStr, __basePath) : hrefStr;
632
+ const implicitDynamicRouteHref = HAS_PAGES_ROUTER && pagesRouter !== null && asHref === void 0 && hrefForImplicitInterpolation !== null ? resolveDynamicRouteHref(hrefForImplicitInterpolation) : null;
633
+ const dynamicRouteHref = implicitDynamicRouteHref ? {
634
+ ...implicitDynamicRouteHref,
635
+ href: hrefStr
636
+ } : null;
637
+ const pagesAsHref = asHref ?? dynamicRouteHref?.as;
638
+ const unresolvedHref = pagesAsHref ?? hrefStr;
639
+ const rawResolvedHref = typeof unresolvedHref === "string" && unresolvedHref.startsWith("#") && !getNavigationRuntime()?.functions.navigate ? resolvePagesQueryOnlyHref(unresolvedHref) : unresolvedHref;
640
+ const concreteRouteHref = HAS_PAGES_ROUTER ? resolveConcreteRouteHref(dynamicRouteHref ? hrefForImplicitInterpolation ?? href : href, pagesAsHref) : null;
641
+ const routeHrefRaw = dynamicRouteHref?.href ?? concreteRouteHref ?? hrefStr;
642
+ const prefetchRouteHrefRaw = concreteRouteHref ?? routeHrefRaw;
643
+ const hasPagesHrefAsPair = HAS_PAGES_ROUTER && typeof pagesAsHref === "string" && typeof routeHrefRaw === "string" && pagesAsHref !== routeHrefRaw;
591
644
  const resolvedHref = typeof rawResolvedHref === "string" ? warnAndNormalizeRepeatedSlashesInHref(rawResolvedHref) : rawResolvedHref;
592
645
  const isDangerous = typeof resolvedHref === "string" && isDangerousScheme(resolvedHref);
593
646
  const normalizedHref = normalizePathTrailingSlash(applyLocaleToHref(isDangerous ? "/" : resolvedHref, locale), __trailingSlash);
594
- const normalizedRouteHref = HAS_PAGES_ROUTER && typeof asHref === "string" && typeof routeHrefRaw === "string" && asHref !== routeHrefRaw ? normalizePathTrailingSlash(applyLocaleToHref(isDangerous ? "/" : routeHrefRaw, locale), __trailingSlash) : normalizedHref;
647
+ const normalizedRouteHref = hasPagesHrefAsPair ? normalizePathTrailingSlash(applyLocaleToHref(isDangerous ? "/" : prefetchRouteHrefRaw, locale), __trailingSlash) : normalizedHref;
595
648
  const fullHref = normalizePathTrailingSlash(withBasePath(normalizedHref, __basePath), __trailingSlash);
596
649
  const [pending, setPending] = useState(false);
597
650
  const mountedRef = useRef(true);
@@ -713,7 +766,7 @@ const Link = forwardRef(function Link({ href, as, replace = false, prefetch: pre
713
766
  e.preventDefault();
714
767
  const hasAppNavigationRuntime = Boolean(getNavigationRuntime()?.functions.navigate);
715
768
  const pagesNavigateHref = HAS_PAGES_ROUTER && resolvedHref.startsWith("?") ? resolvePagesLinkNavigationHref(resolvedHref, locale) : navigateHref;
716
- const pagesAsForLink = HAS_PAGES_ROUTER && typeof asHref === "string" && typeof routeHrefRaw === "string" && asHref !== routeHrefRaw ? pagesNavigateHref : void 0;
769
+ const pagesAsForLink = hasPagesHrefAsPair ? pagesNavigateHref : void 0;
717
770
  const pagesHrefForLink = pagesAsForLink === void 0 ? pagesNavigateHref : routeHrefRaw;
718
771
  const absoluteFullHref = toBrowserNavigationHref(hasAppNavigationRuntime ? navigateHref : pagesNavigateHref, window.location.href, __basePath);
719
772
  if (onNavigate) try {
@@ -731,19 +784,19 @@ const Link = forwardRef(function Link({ href, as, replace = false, prefetch: pre
731
784
  onNavigate(navEvent);
732
785
  if (navEvent.defaultPrevented) return;
733
786
  } catch {}
734
- const hybridOwner = HAS_PAGES_ROUTER && hasAppNavigationRuntime ? (await import("./internal/hybrid-client-route-owner.js")).resolveHybridClientRouteOwner(navigateHref, __basePath) : null;
787
+ const hybridOwner = (HAS_PAGES_ROUTER && hasAppNavigationRuntime ? loadedHybridClientRouteOwnerModule ?? await loadHybridClientRouteOwnerModule() : null)?.resolveHybridClientRouteOwner(navigateHref, __basePath);
735
788
  if (HAS_PAGES_ROUTER && hasAppNavigationRuntime && ["pages", "document"].includes(hybridOwner ?? "")) {
736
789
  if (replace) window.location.replace(absoluteFullHref);
737
790
  else window.location.assign(absoluteFullHref);
738
791
  return;
739
792
  }
740
793
  if (hasAppNavigationRuntime) {
741
- const { navigateClientSide } = await import("./navigation.js");
794
+ const { navigateClientSide } = loadedNavigationModule ?? await loadNavigationModule();
742
795
  const setter = setPendingRef.current;
743
796
  if (setter) setLinkForCurrentNavigation(setter);
744
797
  setPending(true);
745
798
  React.startTransition(() => {
746
- navigateClientSide(navigateHref, replace ? "replace" : "push", scroll, true).finally(() => {
799
+ navigateClientSide(navigateHref, replace ? "replace" : "push", scroll, false).finally(() => {
747
800
  if (mountedRef.current) setPending(false);
748
801
  if (setter) clearLinkForCurrentNavigation(setter);
749
802
  });
@@ -1,31 +1,21 @@
1
1
  import { ThenableParamsObserver } from "./thenable-params.js";
2
2
  import React from "react";
3
+ import { ResolvedViewport as ResolvedViewport$1, Viewport as Viewport$1 } from "@vinext/types/next/upstream/dist/lib/metadata/types/metadata-interface";
3
4
 
4
5
  //#region src/shims/metadata.d.ts
5
- type Viewport = {
6
- /** Viewport width (default: "device-width") */width?: string | number; /** Viewport height */
7
- height?: string | number; /** Initial scale */
8
- initialScale?: number; /** Minimum scale */
9
- minimumScale?: number; /** Maximum scale */
10
- maximumScale?: number; /** Whether user can scale */
11
- userScalable?: boolean; /** Theme color — single color or array of { media, color } */
12
- themeColor?: string | Array<{
13
- media?: string;
14
- color: string;
15
- }>; /** Color scheme: 'light' | 'dark' | 'light dark' | 'normal' */
16
- colorScheme?: string;
17
- };
6
+ type Viewport = Viewport$1;
7
+ type ResolvedViewport = ResolvedViewport$1;
18
8
  /**
19
9
  * Resolve viewport config from a module. Handles both static `viewport` export
20
10
  * and async `generateViewport()` function.
21
11
  */
22
- declare function resolveModuleViewport(mod: Record<string, unknown>, params: Record<string, string | string[]>, searchParams?: Record<string, string | string[]>, searchParamsObserver?: ThenableParamsObserver): Promise<Viewport | null>;
12
+ declare function resolveModuleViewport(mod: Record<string, unknown>, params?: Record<string, string | string[]>, searchParams?: Record<string, string | string[]>, parent?: Promise<ResolvedViewport>, searchParamsObserver?: ThenableParamsObserver): Promise<Viewport | null>;
23
13
  /**
24
14
  * Merge viewport configs from multiple sources (layouts + page).
25
15
  * Later entries override earlier ones.
26
16
  */
27
- declare const DEFAULT_VIEWPORT: Viewport;
28
- declare function mergeViewport(viewportList: Viewport[]): Viewport;
17
+ declare const DEFAULT_VIEWPORT: ResolvedViewport;
18
+ declare function mergeViewport(viewportList: readonly Viewport[]): ResolvedViewport;
29
19
  /**
30
20
  * React component that renders viewport meta tags into <head>.
31
21
  */
@@ -191,28 +181,19 @@ type SocialImageDescriptor = {
191
181
  };
192
182
  type IconDescriptor = {
193
183
  url: string | URL;
194
- sizes?: string;
195
184
  type?: string;
196
- media?: string;
197
- };
198
- type AppleIconDescriptor = {
199
- url: string | URL;
200
185
  sizes?: string;
201
- type?: string;
186
+ color?: string;
187
+ rel?: string;
188
+ media?: string;
189
+ fetchPriority?: "high" | "low" | "auto";
202
190
  };
203
191
  type IconInput = string | URL | IconDescriptor;
204
- type AppleIconInput = string | URL | AppleIconDescriptor;
205
- type OtherIconDescriptor = {
206
- rel: string;
207
- url: string | URL;
208
- sizes?: string;
209
- type?: string;
210
- };
211
192
  type IconsMap = {
212
193
  icon?: IconInput | IconInput[];
213
- shortcut?: string | URL | Array<string | URL>;
214
- apple?: AppleIconInput | AppleIconInput[];
215
- other?: OtherIconDescriptor | OtherIconDescriptor[];
194
+ shortcut?: IconInput | IconInput[];
195
+ apple?: IconInput | IconInput[];
196
+ other?: IconDescriptor | IconDescriptor[];
216
197
  };
217
198
  type IconsMetadata = IconInput | IconInput[] | IconsMap;
218
199
  type MetadataMergeEntry = {
@@ -273,14 +254,17 @@ type MetadataHeadProps = {
273
254
  metadata: Metadata;
274
255
  pathname?: string;
275
256
  trailingSlash?: boolean;
257
+ streamedIconKey?: string;
276
258
  };
277
259
  declare function renderMetadataToHtml(metadata: Metadata, pathname?: string, options?: {
278
260
  trailingSlash?: boolean;
261
+ streamedIconKey?: string;
279
262
  }): string;
280
263
  declare function MetadataHead({
281
264
  metadata,
282
265
  pathname,
283
- trailingSlash
266
+ trailingSlash,
267
+ streamedIconKey
284
268
  }: MetadataHeadProps): React.JSX.Element;
285
269
  //#endregion
286
- export { DEFAULT_VIEWPORT, Metadata, MetadataHead, MetadataMergeEntry, Viewport, ViewportHead, mergeMetadata, mergeMetadataEntries, mergeViewport, postProcessMetadata, renderMetadataToHtml, resolveModuleMetadata, resolveModuleViewport };
270
+ export { DEFAULT_VIEWPORT, Metadata, MetadataHead, MetadataMergeEntry, ResolvedViewport, Viewport, ViewportHead, mergeMetadata, mergeMetadataEntries, mergeViewport, postProcessMetadata, renderMetadataToHtml, resolveModuleMetadata, resolveModuleViewport };
@@ -9,18 +9,20 @@ import { Fragment as Fragment$1, jsx } from "react/jsx-runtime";
9
9
  * Handles `export const metadata` and `export async function generateMetadata()`.
10
10
  * Resolves metadata from layouts and pages (pages override layouts).
11
11
  */
12
+ const USE_CACHE_FUNCTION_SYMBOL = Symbol.for("vinext.useCacheFunction");
13
+ const USE_CACHE_ACCEPTS_SECOND_ARGUMENT_SYMBOL = Symbol.for("vinext.useCacheAcceptsSecondArgument");
12
14
  /**
13
15
  * Resolve viewport config from a module. Handles both static `viewport` export
14
16
  * and async `generateViewport()` function.
15
17
  */
16
- async function resolveModuleViewport(mod, params, searchParams, searchParamsObserver) {
18
+ async function resolveModuleViewport(mod, params = {}, searchParams, parent = Promise.resolve(mergeViewport([])), searchParamsObserver) {
17
19
  if (typeof mod.generateViewport === "function") {
18
20
  const asyncParams = makeThenableParams(params);
19
21
  const props = searchParams === void 0 ? { params: asyncParams } : {
20
22
  params: asyncParams,
21
23
  searchParams: makeThenableParams(searchParams, searchParamsObserver)
22
24
  };
23
- return await mod.generateViewport(props);
25
+ return await mod.generateViewport(props, parent);
24
26
  }
25
27
  if (mod.viewport && typeof mod.viewport === "object") return mod.viewport;
26
28
  return null;
@@ -31,47 +33,92 @@ async function resolveModuleViewport(mod, params, searchParams, searchParamsObse
31
33
  */
32
34
  const DEFAULT_VIEWPORT = {
33
35
  width: "device-width",
34
- initialScale: 1
36
+ initialScale: 1,
37
+ themeColor: null,
38
+ colorScheme: null
35
39
  };
36
40
  function mergeViewport(viewportList) {
37
41
  const merged = { ...DEFAULT_VIEWPORT };
38
- for (const vp of viewportList) Object.assign(merged, vp);
42
+ for (const viewport of viewportList) for (const viewportKey in viewport) switch (viewportKey) {
43
+ case "themeColor":
44
+ merged.themeColor = resolveThemeColor(viewport.themeColor);
45
+ break;
46
+ case "colorScheme":
47
+ merged.colorScheme = viewport.colorScheme || null;
48
+ break;
49
+ case "width":
50
+ merged.width = viewport.width;
51
+ break;
52
+ case "height":
53
+ merged.height = viewport.height;
54
+ break;
55
+ case "initialScale":
56
+ merged.initialScale = viewport.initialScale;
57
+ break;
58
+ case "minimumScale":
59
+ merged.minimumScale = viewport.minimumScale;
60
+ break;
61
+ case "maximumScale":
62
+ merged.maximumScale = viewport.maximumScale;
63
+ break;
64
+ case "userScalable":
65
+ merged.userScalable = viewport.userScalable;
66
+ break;
67
+ case "viewportFit":
68
+ merged.viewportFit = viewport.viewportFit;
69
+ break;
70
+ case "interactiveWidget":
71
+ merged.interactiveWidget = viewport.interactiveWidget;
72
+ break;
73
+ default:
74
+ }
39
75
  return merged;
40
76
  }
77
+ const VIEWPORT_META_NAMES = {
78
+ width: "width",
79
+ height: "height",
80
+ initialScale: "initial-scale",
81
+ minimumScale: "minimum-scale",
82
+ maximumScale: "maximum-scale",
83
+ userScalable: "user-scalable",
84
+ viewportFit: "viewport-fit",
85
+ interactiveWidget: "interactive-widget"
86
+ };
41
87
  /**
42
88
  * React component that renders viewport meta tags into <head>.
43
89
  */
44
90
  function ViewportHead({ viewport }) {
91
+ const resolvedViewport = mergeViewport([viewport]);
45
92
  const elements = [];
46
93
  let key = 0;
47
94
  const parts = [];
48
- if (viewport.width !== void 0) parts.push(`width=${viewport.width}`);
49
- if (viewport.height !== void 0) parts.push(`height=${viewport.height}`);
50
- if (viewport.initialScale !== void 0) parts.push(`initial-scale=${viewport.initialScale}`);
51
- if (viewport.minimumScale !== void 0) parts.push(`minimum-scale=${viewport.minimumScale}`);
52
- if (viewport.maximumScale !== void 0) parts.push(`maximum-scale=${viewport.maximumScale}`);
53
- if (viewport.userScalable !== void 0) parts.push(`user-scalable=${viewport.userScalable ? "yes" : "no"}`);
95
+ for (const key of Object.keys(VIEWPORT_META_NAMES)) {
96
+ const value = resolvedViewport[key];
97
+ if (value == null) continue;
98
+ parts.push(`${VIEWPORT_META_NAMES[key]}=${key === "userScalable" ? value ? "yes" : "no" : value}`);
99
+ }
54
100
  if (parts.length > 0) elements.push(/* @__PURE__ */ jsx("meta", {
55
101
  name: "viewport",
56
102
  content: parts.join(", ")
57
103
  }, key++));
58
- if (viewport.themeColor) {
59
- if (typeof viewport.themeColor === "string") elements.push(/* @__PURE__ */ jsx("meta", {
60
- name: "theme-color",
61
- content: viewport.themeColor
62
- }, key++));
63
- else if (Array.isArray(viewport.themeColor)) for (const entry of viewport.themeColor) elements.push(/* @__PURE__ */ jsx("meta", {
64
- name: "theme-color",
65
- content: entry.color,
66
- ...entry.media ? { media: entry.media } : {}
67
- }, key++));
68
- }
69
- if (viewport.colorScheme) elements.push(/* @__PURE__ */ jsx("meta", {
104
+ if (resolvedViewport.themeColor) for (const entry of resolvedViewport.themeColor) elements.push(/* @__PURE__ */ jsx("meta", {
105
+ name: "theme-color",
106
+ content: entry.color,
107
+ ...entry.media ? { media: entry.media } : {}
108
+ }, key++));
109
+ if (resolvedViewport.colorScheme) elements.push(/* @__PURE__ */ jsx("meta", {
70
110
  name: "color-scheme",
71
- content: viewport.colorScheme
111
+ content: resolvedViewport.colorScheme
72
112
  }, key++));
73
113
  return /* @__PURE__ */ jsx(Fragment$1, { children: elements });
74
114
  }
115
+ function resolveThemeColor(themeColor) {
116
+ if (!themeColor) return null;
117
+ return (Array.isArray(themeColor) ? themeColor : [themeColor]).map((descriptor) => typeof descriptor === "string" ? { color: descriptor } : {
118
+ color: descriptor.color,
119
+ media: descriptor.media
120
+ });
121
+ }
75
122
  /**
76
123
  * Merge metadata from multiple sources (layouts + page).
77
124
  *
@@ -219,12 +266,15 @@ function mergeMetadataEntries(entries) {
219
266
  */
220
267
  async function resolveModuleMetadata(mod, params = {}, searchParams, parent = Promise.resolve({}), searchParamsObserver) {
221
268
  if (typeof mod.generateMetadata === "function") {
269
+ const generateMetadata = mod.generateMetadata;
222
270
  const asyncParams = makeThenableParams(params);
223
271
  const props = searchParams === void 0 ? { params: asyncParams } : {
224
272
  params: asyncParams,
225
273
  searchParams: makeThenableParams(searchParams, searchParamsObserver)
226
274
  };
227
- return await (mod.generateMetadata.length >= 2 ? mod.generateMetadata(props, parent) : mod.generateMetadata(props));
275
+ const isUseCacheFunction = Reflect.get(generateMetadata, USE_CACHE_FUNCTION_SYMBOL) === true;
276
+ const acceptsSecondArgument = Reflect.get(generateMetadata, USE_CACHE_ACCEPTS_SECOND_ARGUMENT_SYMBOL);
277
+ return await (!isUseCacheFunction || (typeof acceptsSecondArgument === "boolean" ? acceptsSecondArgument : generateMetadata.length >= 2) ? generateMetadata(props, parent) : generateMetadata(props));
228
278
  }
229
279
  if (mod.metadata && typeof mod.metadata === "object") return mod.metadata;
230
280
  return null;
@@ -370,12 +420,15 @@ function renderMetadataElementToHtml(node) {
370
420
  "content"
371
421
  ])}>`;
372
422
  case "link": return `<link${renderMetadataAttributes(props, [
423
+ "data-vinext-streamed-icon",
373
424
  "rel",
374
425
  "href",
375
426
  "hrefLang",
376
- "media",
377
427
  "type",
378
- "sizes"
428
+ "sizes",
429
+ "color",
430
+ "media",
431
+ "fetchPriority"
379
432
  ])}>`;
380
433
  default: return "";
381
434
  }
@@ -384,10 +437,11 @@ function renderMetadataToHtml(metadata, pathname = "/", options) {
384
437
  return renderMetadataElementToHtml(MetadataHead({
385
438
  metadata,
386
439
  pathname,
387
- trailingSlash: options?.trailingSlash
440
+ trailingSlash: options?.trailingSlash,
441
+ streamedIconKey: options?.streamedIconKey
388
442
  }));
389
443
  }
390
- function MetadataHead({ metadata, pathname = "/", trailingSlash }) {
444
+ function MetadataHead({ metadata, pathname = "/", trailingSlash, streamedIconKey }) {
391
445
  const elements = [];
392
446
  let key = 0;
393
447
  const base = metadata.metadataBase;
@@ -675,35 +729,23 @@ function MetadataHead({ metadata, pathname = "/", trailingSlash }) {
675
729
  }
676
730
  if (metadata.icons) {
677
731
  const iconEntries = isIconsMap(metadata.icons) ? normalizeUrlDescriptorEntries(metadata.icons.icon, (url) => ({ url })) : normalizeUrlDescriptorEntries(metadata.icons, (url) => ({ url }));
678
- if (isIconsMap(metadata.icons) && metadata.icons.shortcut) {
679
- const shortcuts = Array.isArray(metadata.icons.shortcut) ? metadata.icons.shortcut : [metadata.icons.shortcut];
680
- for (const s of shortcuts) elements.push(/* @__PURE__ */ jsx("link", {
681
- rel: "shortcut icon",
682
- href: stringifyUrl(s)
732
+ let streamedIconOrder = 0;
733
+ const appendIcons = (entries, defaultRel) => {
734
+ for (const { url, rel, type, sizes, color, media, fetchPriority } of entries) elements.push(/* @__PURE__ */ jsx("link", {
735
+ "data-vinext-streamed-icon": streamedIconKey ? `${streamedIconKey}:${streamedIconOrder++}` : void 0,
736
+ rel: rel || defaultRel,
737
+ href: stringifyUrl(url),
738
+ type,
739
+ sizes,
740
+ color,
741
+ media,
742
+ fetchPriority
683
743
  }, key++));
684
- }
685
- if (iconEntries.length > 0) for (const i of iconEntries) elements.push(/* @__PURE__ */ jsx("link", {
686
- rel: "icon",
687
- href: stringifyUrl(i.url),
688
- ...i.sizes ? { sizes: i.sizes } : {},
689
- ...i.type ? { type: i.type } : {},
690
- ...i.media ? { media: i.media } : {}
691
- }, key++));
692
- if (isIconsMap(metadata.icons) && metadata.icons.apple) for (const a of normalizeUrlDescriptorEntries(metadata.icons.apple, (url) => ({ url }))) elements.push(/* @__PURE__ */ jsx("link", {
693
- rel: "apple-touch-icon",
694
- href: stringifyUrl(a.url),
695
- ...a.sizes ? { sizes: a.sizes } : {},
696
- ...a.type ? { type: a.type } : {}
697
- }, key++));
698
- if (isIconsMap(metadata.icons) && metadata.icons.other) {
699
- const others = Array.isArray(metadata.icons.other) ? metadata.icons.other : [metadata.icons.other];
700
- for (const o of others) elements.push(/* @__PURE__ */ jsx("link", {
701
- rel: o.rel,
702
- href: stringifyUrl(o.url),
703
- ...o.sizes ? { sizes: o.sizes } : {},
704
- ...o.type ? { type: o.type } : {}
705
- }, key++));
706
- }
744
+ };
745
+ if (isIconsMap(metadata.icons) && metadata.icons.shortcut) appendIcons(normalizeUrlDescriptorEntries(metadata.icons.shortcut, (url) => ({ url })), "shortcut icon");
746
+ if (iconEntries.length > 0) appendIcons(iconEntries, "icon");
747
+ if (isIconsMap(metadata.icons) && metadata.icons.apple) appendIcons(normalizeUrlDescriptorEntries(metadata.icons.apple, (url) => ({ url })), "apple-touch-icon");
748
+ if (isIconsMap(metadata.icons) && metadata.icons.other) appendIcons(normalizeUrlDescriptorEntries(metadata.icons.other, (url) => ({ url })), "icon");
707
749
  }
708
750
  if (metadata.manifest) elements.push(/* @__PURE__ */ jsx("link", {
709
751
  rel: "manifest",