vinext 0.0.44 → 0.0.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build/google-fonts/build-url.d.ts +10 -0
- package/dist/build/google-fonts/build-url.js +30 -0
- package/dist/build/google-fonts/build-url.js.map +1 -0
- package/dist/build/google-fonts/font-data.js +24985 -0
- package/dist/build/google-fonts/font-data.js.map +1 -0
- package/dist/build/google-fonts/font-metadata.d.ts +17 -0
- package/dist/build/google-fonts/font-metadata.js +7 -0
- package/dist/build/google-fonts/font-metadata.js.map +1 -0
- package/dist/build/google-fonts/get-axes.d.ts +7 -0
- package/dist/build/google-fonts/get-axes.js +39 -0
- package/dist/build/google-fonts/get-axes.js.map +1 -0
- package/dist/build/google-fonts/sort-variants.d.ts +5 -0
- package/dist/build/google-fonts/sort-variants.js +14 -0
- package/dist/build/google-fonts/sort-variants.js.map +1 -0
- package/dist/build/google-fonts/validate.d.ts +28 -0
- package/dist/build/google-fonts/validate.js +56 -0
- package/dist/build/google-fonts/validate.js.map +1 -0
- package/dist/build/layout-classification.d.ts +1 -1
- package/dist/build/layout-classification.js.map +1 -1
- package/dist/build/nitro-route-rules.d.ts +1 -1
- package/dist/build/nitro-route-rules.js.map +1 -1
- package/dist/build/precompress.d.ts +1 -1
- package/dist/build/precompress.js.map +1 -1
- package/dist/build/prerender.d.ts +1 -7
- package/dist/build/prerender.js +7 -3
- package/dist/build/prerender.js.map +1 -1
- package/dist/build/run-prerender.d.ts +1 -13
- package/dist/build/run-prerender.js +5 -1
- package/dist/build/run-prerender.js.map +1 -1
- package/dist/build/standalone.d.ts +1 -1
- package/dist/build/standalone.js.map +1 -1
- package/dist/cloudflare/kv-cache-handler.d.ts +5 -0
- package/dist/cloudflare/kv-cache-handler.js +56 -35
- package/dist/cloudflare/kv-cache-handler.js.map +1 -1
- package/dist/cloudflare/tpr.d.ts +1 -16
- package/dist/cloudflare/tpr.js +1 -1
- package/dist/cloudflare/tpr.js.map +1 -1
- package/dist/config/dotenv.d.ts +1 -1
- package/dist/config/dotenv.js.map +1 -1
- package/dist/deploy.d.ts +1 -1
- package/dist/deploy.js.map +1 -1
- package/dist/entries/app-rsc-entry.js +83 -13
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +1 -1
- package/dist/init.js.map +1 -1
- package/dist/plugins/async-hooks-stub.d.ts +1 -2
- package/dist/plugins/async-hooks-stub.js +2 -2
- package/dist/plugins/async-hooks-stub.js.map +1 -1
- package/dist/plugins/fonts.d.ts +1 -20
- package/dist/plugins/fonts.js +42 -21
- package/dist/plugins/fonts.js.map +1 -1
- package/dist/plugins/server-externals-manifest.d.ts +1 -11
- package/dist/plugins/server-externals-manifest.js +1 -1
- package/dist/plugins/server-externals-manifest.js.map +1 -1
- package/dist/routing/app-router.js +7 -4
- package/dist/routing/app-router.js.map +1 -1
- package/dist/routing/file-matcher.d.ts +1 -3
- package/dist/routing/file-matcher.js +1 -1
- package/dist/routing/file-matcher.js.map +1 -1
- package/dist/routing/utils.d.ts +1 -29
- package/dist/routing/utils.js +1 -1
- package/dist/routing/utils.js.map +1 -1
- package/dist/server/app-browser-entry.js +33 -3
- package/dist/server/app-browser-entry.js.map +1 -1
- package/dist/server/app-browser-state.d.ts +1 -1
- package/dist/server/app-browser-state.js.map +1 -1
- package/dist/server/app-browser-stream.d.ts +1 -1
- package/dist/server/app-browser-stream.js.map +1 -1
- package/dist/server/app-elements.d.ts +1 -2
- package/dist/server/app-elements.js +1 -1
- package/dist/server/app-elements.js.map +1 -1
- package/dist/server/app-page-boundary-render.d.ts +3 -1
- package/dist/server/app-page-boundary-render.js +2 -0
- package/dist/server/app-page-boundary-render.js.map +1 -1
- package/dist/server/app-page-boundary.d.ts +2 -1
- package/dist/server/app-page-boundary.js +10 -5
- package/dist/server/app-page-boundary.js.map +1 -1
- package/dist/server/app-page-cache.d.ts +1 -1
- package/dist/server/app-page-cache.js.map +1 -1
- package/dist/server/app-page-execution.d.ts +4 -2
- package/dist/server/app-page-execution.js +19 -4
- package/dist/server/app-page-execution.js.map +1 -1
- package/dist/server/app-page-probe.d.ts +1 -1
- package/dist/server/app-page-probe.js.map +1 -1
- package/dist/server/app-page-render.d.ts +2 -2
- package/dist/server/app-page-render.js.map +1 -1
- package/dist/server/app-page-request.d.ts +1 -1
- package/dist/server/app-page-request.js.map +1 -1
- package/dist/server/app-page-response.d.ts +1 -1
- package/dist/server/app-page-response.js.map +1 -1
- package/dist/server/app-page-route-wiring.d.ts +1 -8
- package/dist/server/app-page-route-wiring.js +1 -1
- package/dist/server/app-page-route-wiring.js.map +1 -1
- package/dist/server/app-page-stream.d.ts +2 -1
- package/dist/server/app-page-stream.js +5 -3
- package/dist/server/app-page-stream.js.map +1 -1
- package/dist/server/app-route-handler-cache.d.ts +1 -1
- package/dist/server/app-route-handler-cache.js.map +1 -1
- package/dist/server/app-route-handler-execution.d.ts +1 -1
- package/dist/server/app-route-handler-execution.js +9 -4
- package/dist/server/app-route-handler-execution.js.map +1 -1
- package/dist/server/app-route-handler-policy.d.ts +6 -2
- package/dist/server/app-route-handler-policy.js +8 -3
- package/dist/server/app-route-handler-policy.js.map +1 -1
- package/dist/server/app-route-handler-response.d.ts +1 -1
- package/dist/server/app-route-handler-response.js.map +1 -1
- package/dist/server/app-route-handler-runtime.d.ts +1 -1
- package/dist/server/app-route-handler-runtime.js +1 -1
- package/dist/server/app-route-handler-runtime.js.map +1 -1
- package/dist/server/app-server-action-execution.d.ts +35 -0
- package/dist/server/app-server-action-execution.js +105 -0
- package/dist/server/app-server-action-execution.js.map +1 -0
- package/dist/server/app-ssr-stream.d.ts +1 -1
- package/dist/server/app-ssr-stream.js.map +1 -1
- package/dist/server/csp.d.ts +1 -2
- package/dist/server/csp.js +1 -1
- package/dist/server/csp.js.map +1 -1
- package/dist/server/dev-module-runner.d.ts +1 -1
- package/dist/server/dev-module-runner.js.map +1 -1
- package/dist/server/middleware-request-headers.d.ts +1 -3
- package/dist/server/middleware-request-headers.js +4 -4
- package/dist/server/middleware-request-headers.js.map +1 -1
- package/dist/server/middleware.d.ts +1 -1
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/pages-api-route.d.ts +1 -1
- package/dist/server/pages-api-route.js.map +1 -1
- package/dist/server/pages-i18n.d.ts +2 -3
- package/dist/server/pages-i18n.js +1 -1
- package/dist/server/pages-i18n.js.map +1 -1
- package/dist/server/pages-node-compat.d.ts +1 -2
- package/dist/server/pages-node-compat.js +1 -1
- package/dist/server/pages-node-compat.js.map +1 -1
- package/dist/server/pages-page-data.d.ts +1 -1
- package/dist/server/pages-page-data.js.map +1 -1
- package/dist/server/pages-page-response.d.ts +1 -1
- package/dist/server/pages-page-response.js.map +1 -1
- package/dist/server/prod-server.js +2 -0
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/socket-error-backstop.d.ts +17 -0
- package/dist/server/socket-error-backstop.js +129 -0
- package/dist/server/socket-error-backstop.js.map +1 -0
- package/dist/server/static-file-cache.d.ts +1 -1
- package/dist/server/static-file-cache.js.map +1 -1
- package/dist/shims/cache-runtime.js +16 -3
- package/dist/shims/cache-runtime.js.map +1 -1
- package/dist/shims/cache.d.ts +3 -1
- package/dist/shims/cache.js +83 -22
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/error-boundary.d.ts +1 -1
- package/dist/shims/fetch-cache.d.ts +10 -1
- package/dist/shims/fetch-cache.js +24 -4
- package/dist/shims/fetch-cache.js.map +1 -1
- package/dist/shims/font-google-base.d.ts +16 -18
- package/dist/shims/font-google-base.js +25 -16
- package/dist/shims/font-google-base.js.map +1 -1
- package/dist/shims/form.js +1 -1
- package/dist/shims/link.js +1 -1
- package/dist/shims/navigation.d.ts +7 -3
- package/dist/shims/navigation.js +11 -5
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/server.d.ts +2 -0
- package/dist/shims/server.js +18 -5
- package/dist/shims/server.js.map +1 -1
- package/dist/shims/unified-request-context.js +2 -0
- package/dist/shims/unified-request-context.js.map +1 -1
- package/dist/shims/url-safety.d.ts +3 -1
- package/dist/shims/url-safety.js +5 -1
- package/dist/shims/url-safety.js.map +1 -1
- package/dist/utils/error-cause.d.ts +5 -0
- package/dist/utils/error-cause.js +97 -0
- package/dist/utils/error-cause.js.map +1 -0
- package/dist/utils/lazy-chunks.d.ts +1 -1
- package/dist/utils/lazy-chunks.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"font-google-base.js","names":[],"sources":["../../src/shims/font-google-base.ts"],"sourcesContent":["/**\n * next/font/google shim\n *\n * Provides a compatible shim for Next.js Google Fonts.\n *\n * Two modes:\n * 1. **Dev / CDN mode** (default): Loads fonts from Google Fonts CDN via <link> tags.\n * 2. **Self-hosted mode** (production build): The vinext:google-fonts Vite plugin\n * fetches font CSS + .woff2 files at build time, caches them locally, and injects\n * @font-face CSS pointing at local assets. No requests to Google at runtime.\n *\n * Usage:\n * import { Inter } from 'next/font/google';\n * const inter = Inter({ subsets: ['latin'], weight: ['400', '700'] });\n * // inter.className -> unique CSS class\n * // inter.style -> { fontFamily: \"'Inter', sans-serif\" }\n * // inter.variable -> CSS variable name like '--font-inter'\n */\n\n/**\n * Escape a string for safe interpolation inside a CSS single-quoted string.\n *\n * Prevents CSS injection by escaping characters that could break out of\n * a `'...'` CSS string context: backslashes, single quotes, and newlines.\n */\nfunction escapeCSSString(value: string): string {\n return value\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/'/g, \"\\\\'\")\n .replace(/\\n/g, \"\\\\a \")\n .replace(/\\r/g, \"\\\\d \");\n}\n\n/**\n * Validate a CSS custom property name (e.g. `--font-inter`).\n *\n * Custom properties must start with `--` and only contain alphanumeric\n * characters, hyphens, and underscores. Anything else could be used to\n * break out of the CSS declaration and inject arbitrary rules.\n *\n * Returns the name if valid, undefined otherwise.\n */\nfunction sanitizeCSSVarName(name: string): string | undefined {\n if (/^--[a-zA-Z0-9_-]+$/.test(name)) return name;\n return undefined;\n}\n\n/**\n * Sanitize a CSS font-family fallback name.\n *\n * Generic family names (sans-serif, serif, monospace, etc.) are used as-is.\n * Named families are wrapped in escaped quotes. This prevents injection via\n * crafted fallback values like `); } body { color: red; } .x {`.\n */\nfunction sanitizeFallback(name: string): string {\n // CSS generic font families — safe to use unquoted\n const generics = new Set([\n \"serif\",\n \"sans-serif\",\n \"monospace\",\n \"cursive\",\n \"fantasy\",\n \"system-ui\",\n \"ui-serif\",\n \"ui-sans-serif\",\n \"ui-monospace\",\n \"ui-rounded\",\n \"emoji\",\n \"math\",\n \"fangsong\",\n ]);\n const trimmed = name.trim();\n if (generics.has(trimmed)) return trimmed;\n // Wrap in single quotes with escaping to prevent CSS injection\n return `'${escapeCSSString(trimmed)}'`;\n}\n\n// Counter for generating unique class names\nlet classCounter = 0;\n\n// Track which font stylesheets have been injected (SSR + client)\nconst injectedFonts = new Set<string>();\n\nexport type FontOptions = {\n weight?: string | string[];\n style?: string | string[];\n subsets?: string[];\n display?: string;\n preload?: boolean;\n fallback?: string[];\n adjustFontFallback?: boolean | string;\n variable?: string;\n axes?: string[];\n};\n\nexport type FontResult = {\n className: string;\n style: { fontFamily: string };\n variable?: string;\n};\n\n/**\n * Convert a font family name to a CSS variable name.\n * e.g., \"Inter\" -> \"--font-inter\", \"Roboto Mono\" -> \"--font-roboto-mono\"\n */\nfunction toVarName(family: string): string {\n return \"--font-\" + family.toLowerCase().replace(/\\s+/g, \"-\");\n}\n\n/**\n * Build a Google Fonts CSS URL.\n */\nexport function buildGoogleFontsUrl(family: string, options: FontOptions): string {\n const params = new URLSearchParams();\n // Don't pre-replace spaces with \"+\". URLSearchParams handles encoding:\n // spaces become \"+\" in application/x-www-form-urlencoded format.\n // Pre-replacing would cause double-encoding: \"+\" -> \"%2B\" (400 error).\n let spec = family;\n\n // Build weight/style specs\n const weights = options.weight\n ? Array.isArray(options.weight)\n ? options.weight\n : [options.weight]\n : [];\n const styles = options.style\n ? Array.isArray(options.style)\n ? options.style\n : [options.style]\n : [];\n\n if (weights.length > 0 || styles.length > 0) {\n const hasItalic = styles.includes(\"italic\");\n if (weights.length > 0) {\n if (hasItalic) {\n // Use ital axis: ital,wght@0,400;0,700;1,400;1,700\n const pairs: string[] = [];\n for (const w of weights) {\n pairs.push(`0,${w}`);\n pairs.push(`1,${w}`);\n }\n spec += `:ital,wght@${pairs.join(\";\")}`;\n } else {\n spec += `:wght@${weights.join(\";\")}`;\n }\n }\n } else {\n // When no weight is specified, request the full variable weight range.\n // Without this, Google Fonts returns only weight 400 (the default).\n // Next.js loads the full variable font by default, so we match that\n // behavior to ensure all font weights render correctly.\n spec += `:wght@100..900`;\n }\n\n params.set(\"family\", spec);\n params.set(\"display\", options.display ?? \"swap\");\n\n return `https://fonts.googleapis.com/css2?${params.toString()}`;\n}\n\n/**\n * Inject a <link> tag for the font (client-side only).\n * On the server, we track font URLs for SSR head injection.\n */\nfunction injectFontStylesheet(url: string): void {\n if (injectedFonts.has(url)) return;\n injectedFonts.add(url);\n\n if (typeof document !== \"undefined\") {\n const link = document.createElement(\"link\");\n link.rel = \"stylesheet\";\n link.href = url;\n document.head.appendChild(link);\n }\n}\n\n/** Track which className CSS rules have been injected. */\nconst injectedClassRules = new Set<string>();\n\n/**\n * Inject a CSS rule that maps a className to a font-family.\n *\n * This is what makes `<div className={inter.className}>` apply the font.\n * Next.js generates equivalent rules at build time.\n *\n * In Next.js, the .className class ONLY sets font-family — it does NOT\n * set CSS variables. CSS variables are handled separately by the .variable class.\n */\nfunction injectClassNameRule(className: string, fontFamily: string): void {\n if (injectedClassRules.has(className)) return;\n injectedClassRules.add(className);\n\n const css = `.${className} { font-family: ${fontFamily}; }\\n`;\n\n // On server, store the CSS for SSR injection\n if (typeof document === \"undefined\") {\n ssrFontStyles.push(css);\n return;\n }\n\n // On client, inject a <style> tag\n const style = document.createElement(\"style\");\n style.textContent = css;\n style.setAttribute(\"data-vinext-font-class\", className);\n document.head.appendChild(style);\n}\n\n/** Track which variable class CSS rules have been injected. */\nconst injectedVariableRules = new Set<string>();\n\n/** Track which :root CSS variable rules have been injected. */\nconst injectedRootVariables = new Set<string>();\n\n/**\n * Inject a CSS rule that sets a CSS variable on an element.\n * This is what makes `<html className={inter.variable}>` set the CSS variable\n * that can be referenced by other styles (e.g., Tailwind's font-sans).\n *\n * In Next.js, the .variable class ONLY sets the CSS variable — it does NOT\n * set font-family. This is critical because apps commonly apply multiple\n * .variable classes to <body> (e.g., geistSans.variable + geistMono.variable).\n * If we also set font-family here, the last class wins due to CSS cascade,\n * causing all text to use that font (e.g., everything becomes monospace).\n */\nfunction injectVariableClassRule(\n variableClassName: string,\n cssVarName: string,\n fontFamily: string,\n): void {\n if (injectedVariableRules.has(variableClassName)) return;\n injectedVariableRules.add(variableClassName);\n\n // Only set the CSS variable — do NOT set font-family.\n // This matches Next.js behavior where .variable classes only define CSS variables.\n let css = `.${variableClassName} { ${cssVarName}: ${fontFamily}; }\\n`;\n\n // Also inject at :root so CSS variable inheritance works throughout the page.\n // This ensures Tailwind utilities like `font-sans` that reference these\n // variables via var(--font-geist-sans) work correctly.\n if (!injectedRootVariables.has(cssVarName)) {\n injectedRootVariables.add(cssVarName);\n css += `:root { ${cssVarName}: ${fontFamily}; }\\n`;\n }\n\n // On server, store the CSS for SSR injection\n if (typeof document === \"undefined\") {\n ssrFontStyles.push(css);\n return;\n }\n\n // On client, inject a <style> tag\n const style = document.createElement(\"style\");\n style.textContent = css;\n style.setAttribute(\"data-vinext-font-variable\", variableClassName);\n document.head.appendChild(style);\n}\n\n// SSR: collect font class CSS for injection in <head>\nconst ssrFontStyles: string[] = [];\n\n/**\n * Get collected SSR font class styles (used by the renderer).\n * Note: We don't clear the arrays because fonts are loaded at module import\n * time and need to persist across all requests in the Workers environment.\n */\nexport function getSSRFontStyles(): string[] {\n return [...ssrFontStyles];\n}\n\n// SSR: collect font URLs to inject in <head>\nconst ssrFontUrls: string[] = [];\n\n/**\n * Get collected SSR font URLs (used by the renderer).\n * Note: We don't clear the arrays because fonts are loaded at module import\n * time and need to persist across all requests in the Workers environment.\n */\nexport function getSSRFontLinks(): string[] {\n return [...ssrFontUrls];\n}\n\n// SSR: collect font file URLs for <link rel=\"preload\"> injection (self-hosted Google fonts)\nconst ssrFontPreloads: Array<{ href: string; type: string }> = [];\nconst ssrFontPreloadHrefs = new Set<string>();\n\n/**\n * Get collected SSR font preload data (used by the renderer).\n * Returns an array of { href, type } objects for emitting\n * <link rel=\"preload\" as=\"font\" ...> tags.\n */\nexport function getSSRFontPreloads(): Array<{ href: string; type: string }> {\n return [...ssrFontPreloads];\n}\n\n/**\n * Determine the MIME type for a font file based on its extension.\n */\nfunction getFontMimeType(pathOrUrl: string): string {\n if (pathOrUrl.endsWith(\".woff2\")) return \"font/woff2\";\n if (pathOrUrl.endsWith(\".woff\")) return \"font/woff\";\n if (pathOrUrl.endsWith(\".ttf\")) return \"font/ttf\";\n if (pathOrUrl.endsWith(\".otf\")) return \"font/opentype\";\n return \"font/woff2\";\n}\n\n/**\n * Extract font file URLs from @font-face CSS rules.\n * Parses url('...') references from the CSS text.\n */\nfunction extractFontUrlsFromCSS(css: string): string[] {\n const urls: string[] = [];\n const urlRegex = /url\\(['\"]?([^'\")]+)['\"]?\\)/g;\n let match: RegExpExecArray | null;\n while ((match = urlRegex.exec(css)) !== null) {\n const url = match[1];\n // Only collect absolute paths (starting with /) — these are self-hosted font files\n if (url && url.startsWith(\"/\")) {\n urls.push(url);\n }\n }\n return urls;\n}\n\n/**\n * Collect font file URLs from self-hosted CSS for preload link generation.\n * Only collects on the server (SSR). Deduplicates by href using a Set for O(1) lookups.\n */\nfunction collectFontPreloadsFromCSS(css: string): void {\n if (typeof document !== \"undefined\") return; // client-side, skip\n\n const urls = extractFontUrlsFromCSS(css);\n for (const href of urls) {\n if (!ssrFontPreloadHrefs.has(href)) {\n ssrFontPreloadHrefs.add(href);\n ssrFontPreloads.push({ href, type: getFontMimeType(href) });\n }\n }\n}\n\n/** Track injected self-hosted @font-face blocks (deduplicate) */\nconst injectedSelfHosted = new Set<string>();\n\n/**\n * Inject self-hosted @font-face CSS (from the build plugin).\n * This replaces the CDN <link> tag with inline CSS.\n */\nfunction injectSelfHostedCSS(css: string): void {\n if (injectedSelfHosted.has(css)) return;\n injectedSelfHosted.add(css);\n\n // Extract font file URLs for preload hints (SSR only)\n collectFontPreloadsFromCSS(css);\n\n if (typeof document === \"undefined\") {\n // SSR: add to collected styles\n ssrFontStyles.push(css);\n return;\n }\n\n // Client: inject <style> tag\n const style = document.createElement(\"style\");\n style.textContent = css;\n style.setAttribute(\"data-vinext-font-selfhosted\", \"true\");\n document.head.appendChild(style);\n}\n\nexport type FontLoader = (options?: FontOptions & { _selfHostedCSS?: string }) => FontResult;\n\nexport function createFontLoader(family: string): FontLoader {\n return function fontLoader(options: FontOptions & { _selfHostedCSS?: string } = {}): FontResult {\n const id = classCounter++;\n const className = `__font_${family.toLowerCase().replace(/\\s+/g, \"_\")}_${id}`;\n const fallback = options.fallback ?? [\"sans-serif\"];\n // Sanitize each fallback name to prevent CSS injection via crafted values\n const fontFamily = `'${escapeCSSString(family)}', ${fallback.map(sanitizeFallback).join(\", \")}`;\n // Validate CSS variable name — reject anything that could inject CSS.\n // Fall back to auto-generated name if invalid.\n const defaultVarName = toVarName(family);\n const cssVarName = options.variable\n ? (sanitizeCSSVarName(options.variable) ?? defaultVarName)\n : defaultVarName;\n // In Next.js, `variable` returns a CLASS NAME that sets the CSS variable.\n // Users apply this class to set the CSS variable on that element.\n const variableClassName = `__variable_${family.toLowerCase().replace(/\\s+/g, \"_\")}_${id}`;\n\n if (options._selfHostedCSS) {\n // Self-hosted mode: inject local @font-face CSS instead of CDN link\n injectSelfHostedCSS(options._selfHostedCSS);\n } else {\n // CDN mode: inject <link> to Google Fonts\n const url = buildGoogleFontsUrl(family, options);\n injectFontStylesheet(url);\n\n // On SSR, collect the URL for head injection\n if (typeof document === \"undefined\") {\n if (!ssrFontUrls.includes(url)) {\n ssrFontUrls.push(url);\n }\n }\n }\n\n // Inject a CSS rule that maps className to font-family.\n // This is what makes `<div className={inter.className}>` work.\n injectClassNameRule(className, fontFamily);\n\n // Inject a CSS rule for the variable class name.\n // This is what makes `<html className={inter.variable}>` set the CSS variable.\n injectVariableClassRule(variableClassName, cssVarName, fontFamily);\n\n return {\n className,\n style: { fontFamily },\n variable: variableClassName,\n };\n };\n}\n\n// Export a Proxy that creates font loaders for any Google Font family.\n// Usage: import { Inter } from 'next/font/google'\n// The proxy intercepts property access and returns a loader for that font.\nconst googleFonts = new Proxy({} as Record<string, (options?: FontOptions) => FontResult>, {\n get(_target, prop: string) {\n if (prop === \"__esModule\") return true;\n if (prop === \"default\") return googleFonts;\n // Convert export-style names to proper font family names:\n // - Underscores to spaces: \"Roboto_Mono\" -> \"Roboto Mono\"\n // - PascalCase to spaces: \"RobotoMono\" -> \"Roboto Mono\"\n const family = prop.replace(/_/g, \" \").replace(/([a-z])([A-Z])/g, \"$1 $2\");\n return createFontLoader(family);\n },\n});\n\nexport default googleFonts;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"font-google-base.js","names":["buildUrlFromAxes"],"sources":["../../src/shims/font-google-base.ts"],"sourcesContent":["import { buildGoogleFontsUrl as buildUrlFromAxes } from \"../build/google-fonts/build-url.js\";\n\n/**\n * next/font/google shim\n *\n * Provides a compatible shim for Next.js Google Fonts.\n *\n * Two modes:\n * 1. **Dev / CDN mode** (default): Loads fonts from Google Fonts CDN via <link> tags.\n * 2. **Self-hosted mode** (production build): The vinext:google-fonts Vite plugin\n * fetches font CSS + .woff2 files at build time, caches them locally, and injects\n * @font-face CSS pointing at local assets. No requests to Google at runtime.\n *\n * Usage:\n * import { Inter } from 'next/font/google';\n * const inter = Inter({ subsets: ['latin'], weight: ['400', '700'] });\n * // inter.className -> unique CSS class\n * // inter.style -> { fontFamily: \"'Inter', sans-serif\" }\n * // inter.variable -> CSS variable name like '--font-inter'\n */\n\n/**\n * Escape a string for safe interpolation inside a CSS single-quoted string.\n *\n * Prevents CSS injection by escaping characters that could break out of\n * a `'...'` CSS string context: backslashes, single quotes, and newlines.\n */\nfunction escapeCSSString(value: string): string {\n return value\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/'/g, \"\\\\'\")\n .replace(/\\n/g, \"\\\\a \")\n .replace(/\\r/g, \"\\\\d \");\n}\n\n/**\n * Validate a CSS custom property name (e.g. `--font-inter`).\n *\n * Custom properties must start with `--` and only contain alphanumeric\n * characters, hyphens, and underscores. Anything else could be used to\n * break out of the CSS declaration and inject arbitrary rules.\n *\n * Returns the name if valid, undefined otherwise.\n */\nfunction sanitizeCSSVarName(name: string): string | undefined {\n if (/^--[a-zA-Z0-9_-]+$/.test(name)) return name;\n return undefined;\n}\n\n/**\n * Sanitize a CSS font-family fallback name.\n *\n * Generic family names (sans-serif, serif, monospace, etc.) are used as-is.\n * Named families are wrapped in escaped quotes. This prevents injection via\n * crafted fallback values like `); } body { color: red; } .x {`.\n */\nfunction sanitizeFallback(name: string): string {\n // CSS generic font families — safe to use unquoted\n const generics = new Set([\n \"serif\",\n \"sans-serif\",\n \"monospace\",\n \"cursive\",\n \"fantasy\",\n \"system-ui\",\n \"ui-serif\",\n \"ui-sans-serif\",\n \"ui-monospace\",\n \"ui-rounded\",\n \"emoji\",\n \"math\",\n \"fangsong\",\n ]);\n const trimmed = name.trim();\n if (generics.has(trimmed)) return trimmed;\n // Wrap in single quotes with escaping to prevent CSS injection\n return `'${escapeCSSString(trimmed)}'`;\n}\n\n// Counter for generating unique class names\nlet classCounter = 0;\n\n// Track which font stylesheets have been injected (SSR + client)\nconst injectedFonts = new Set<string>();\n\nexport type FontOptions = {\n weight?: string | string[];\n style?: string | string[];\n subsets?: string[];\n display?: string;\n preload?: boolean;\n fallback?: string[];\n adjustFontFallback?: boolean | string;\n variable?: string;\n axes?: string[];\n};\n\nexport type FontResult = {\n className: string;\n style: { fontFamily: string };\n variable?: string;\n};\n\n/**\n * Convert a font family name to a CSS variable name.\n * e.g., \"Inter\" -> \"--font-inter\", \"Roboto Mono\" -> \"--font-roboto-mono\"\n */\nfunction toVarName(family: string): string {\n return \"--font-\" + family.toLowerCase().replace(/\\s+/g, \"-\");\n}\n\n/**\n * Build a Google Fonts CSS URL.\n *\n * In production this code path is dead. The build plugin\n * (`vinext:google-fonts` in `src/plugins/fonts.ts`) statically resolves\n * each font call's axis values against the bundled metadata, fetches the\n * Google Fonts CSS, and injects the resulting CSS as `_selfHostedCSS` so\n * the runtime never queries Google. The shim only reaches this builder\n * when the plugin's static parser bails (dynamic options, eval-only\n * shapes), which is dev-only.\n *\n * The dev fallback intentionally has no metadata: shipping the 388 KB\n * `font-data.json` to the Worker bundle would dwarf the rest of the shim,\n * and the production path already has the metadata-aware variant. The\n * tradeoff is that the dev fallback cannot resolve a variable font's\n * actual `wght` axis range. It emits no axis segment when no `weight` is\n * given, which makes Google return the default static face (200) instead\n * of the broken `:wght@100..900` URL that issue #885 reports.\n */\nexport function buildGoogleFontsUrl(family: string, options: FontOptions): string {\n const weights = options.weight\n ? Array.isArray(options.weight)\n ? options.weight\n : [options.weight]\n : [];\n const styles = options.style\n ? Array.isArray(options.style)\n ? options.style\n : [options.style]\n : [];\n\n const hasItalic = styles.includes(\"italic\");\n const hasNormal = styles.includes(\"normal\");\n // Google treats omitted ital as ital=0, so italic-only requests emit\n // ['1']; mixed requests emit ['0','1']; normal-only stays undefined so\n // the URL has no ital axis at all.\n const ital = hasItalic ? [...(hasNormal ? [\"0\"] : []), \"1\"] : undefined;\n\n // The dev fallback has no metadata, so the variable sentinel cannot be\n // resolved to the font's real axis range here. Drop it like empty options\n // instead of emitting the invalid Google Fonts URL `:wght@variable`.\n const normalizedWeights = weights.length === 1 && weights[0] === \"variable\" ? [] : weights;\n\n // Italic-only with no explicit weight still needs a wght value or the\n // ital axis has nowhere to attach in Google's URL grammar. Fall back to\n // '400' because every Google Font has it and it is the visible default.\n // The plugin's metadata-aware path covers the variable-font case in\n // production.\n const wght = normalizedWeights.length > 0 ? normalizedWeights : ital ? [\"400\"] : undefined;\n\n return buildUrlFromAxes(family, { wght, ital }, options.display ?? \"swap\");\n}\n\n/**\n * Inject a <link> tag for the font (client-side only).\n * On the server, we track font URLs for SSR head injection.\n */\nfunction injectFontStylesheet(url: string): void {\n if (injectedFonts.has(url)) return;\n injectedFonts.add(url);\n\n if (typeof document !== \"undefined\") {\n const link = document.createElement(\"link\");\n link.rel = \"stylesheet\";\n link.href = url;\n document.head.appendChild(link);\n }\n}\n\n/** Track which className CSS rules have been injected. */\nconst injectedClassRules = new Set<string>();\n\n/**\n * Inject a CSS rule that maps a className to a font-family.\n *\n * This is what makes `<div className={inter.className}>` apply the font.\n * Next.js generates equivalent rules at build time.\n *\n * In Next.js, the .className class ONLY sets font-family — it does NOT\n * set CSS variables. CSS variables are handled separately by the .variable class.\n */\nfunction injectClassNameRule(className: string, fontFamily: string): void {\n if (injectedClassRules.has(className)) return;\n injectedClassRules.add(className);\n\n const css = `.${className} { font-family: ${fontFamily}; }\\n`;\n\n // On server, store the CSS for SSR injection\n if (typeof document === \"undefined\") {\n ssrFontStyles.push(css);\n return;\n }\n\n // On client, inject a <style> tag\n const style = document.createElement(\"style\");\n style.textContent = css;\n style.setAttribute(\"data-vinext-font-class\", className);\n document.head.appendChild(style);\n}\n\n/** Track which variable class CSS rules have been injected. */\nconst injectedVariableRules = new Set<string>();\n\n/** Track which :root CSS variable rules have been injected. */\nconst injectedRootVariables = new Set<string>();\n\n/**\n * Inject a CSS rule that sets a CSS variable on an element.\n * This is what makes `<html className={inter.variable}>` set the CSS variable\n * that can be referenced by other styles (e.g., Tailwind's font-sans).\n *\n * In Next.js, the .variable class ONLY sets the CSS variable — it does NOT\n * set font-family. This is critical because apps commonly apply multiple\n * .variable classes to <body> (e.g., geistSans.variable + geistMono.variable).\n * If we also set font-family here, the last class wins due to CSS cascade,\n * causing all text to use that font (e.g., everything becomes monospace).\n */\nfunction injectVariableClassRule(\n variableClassName: string,\n cssVarName: string,\n fontFamily: string,\n): void {\n if (injectedVariableRules.has(variableClassName)) return;\n injectedVariableRules.add(variableClassName);\n\n // Only set the CSS variable — do NOT set font-family.\n // This matches Next.js behavior where .variable classes only define CSS variables.\n let css = `.${variableClassName} { ${cssVarName}: ${fontFamily}; }\\n`;\n\n // Also inject at :root so CSS variable inheritance works throughout the page.\n // This ensures Tailwind utilities like `font-sans` that reference these\n // variables via var(--font-geist-sans) work correctly.\n if (!injectedRootVariables.has(cssVarName)) {\n injectedRootVariables.add(cssVarName);\n css += `:root { ${cssVarName}: ${fontFamily}; }\\n`;\n }\n\n // On server, store the CSS for SSR injection\n if (typeof document === \"undefined\") {\n ssrFontStyles.push(css);\n return;\n }\n\n // On client, inject a <style> tag\n const style = document.createElement(\"style\");\n style.textContent = css;\n style.setAttribute(\"data-vinext-font-variable\", variableClassName);\n document.head.appendChild(style);\n}\n\n// SSR: collect font class CSS for injection in <head>\nconst ssrFontStyles: string[] = [];\n\n/**\n * Get collected SSR font class styles (used by the renderer).\n * Note: We don't clear the arrays because fonts are loaded at module import\n * time and need to persist across all requests in the Workers environment.\n */\nexport function getSSRFontStyles(): string[] {\n return [...ssrFontStyles];\n}\n\n// SSR: collect font URLs to inject in <head>\nconst ssrFontUrls: string[] = [];\n\n/**\n * Get collected SSR font URLs (used by the renderer).\n * Note: We don't clear the arrays because fonts are loaded at module import\n * time and need to persist across all requests in the Workers environment.\n */\nexport function getSSRFontLinks(): string[] {\n return [...ssrFontUrls];\n}\n\n// SSR: collect font file URLs for <link rel=\"preload\"> injection (self-hosted Google fonts)\nconst ssrFontPreloads: Array<{ href: string; type: string }> = [];\nconst ssrFontPreloadHrefs = new Set<string>();\n\n/**\n * Get collected SSR font preload data (used by the renderer).\n * Returns an array of { href, type } objects for emitting\n * <link rel=\"preload\" as=\"font\" ...> tags.\n */\nexport function getSSRFontPreloads(): Array<{ href: string; type: string }> {\n return [...ssrFontPreloads];\n}\n\n/**\n * Determine the MIME type for a font file based on its extension.\n */\nfunction getFontMimeType(pathOrUrl: string): string {\n if (pathOrUrl.endsWith(\".woff2\")) return \"font/woff2\";\n if (pathOrUrl.endsWith(\".woff\")) return \"font/woff\";\n if (pathOrUrl.endsWith(\".ttf\")) return \"font/ttf\";\n if (pathOrUrl.endsWith(\".otf\")) return \"font/opentype\";\n return \"font/woff2\";\n}\n\n/**\n * Extract font file URLs from @font-face CSS rules.\n * Parses url('...') references from the CSS text.\n */\nfunction extractFontUrlsFromCSS(css: string): string[] {\n const urls: string[] = [];\n const urlRegex = /url\\(['\"]?([^'\")]+)['\"]?\\)/g;\n let match: RegExpExecArray | null;\n while ((match = urlRegex.exec(css)) !== null) {\n const url = match[1];\n // Only collect absolute paths (starting with /) — these are self-hosted font files\n if (url && url.startsWith(\"/\")) {\n urls.push(url);\n }\n }\n return urls;\n}\n\n/**\n * Collect font file URLs from self-hosted CSS for preload link generation.\n * Only collects on the server (SSR). Deduplicates by href using a Set for O(1) lookups.\n */\nfunction collectFontPreloadsFromCSS(css: string): void {\n if (typeof document !== \"undefined\") return; // client-side, skip\n\n const urls = extractFontUrlsFromCSS(css);\n for (const href of urls) {\n if (!ssrFontPreloadHrefs.has(href)) {\n ssrFontPreloadHrefs.add(href);\n ssrFontPreloads.push({ href, type: getFontMimeType(href) });\n }\n }\n}\n\n/** Track injected self-hosted @font-face blocks (deduplicate) */\nconst injectedSelfHosted = new Set<string>();\n\n/**\n * Inject self-hosted @font-face CSS (from the build plugin).\n * This replaces the CDN <link> tag with inline CSS.\n */\nfunction injectSelfHostedCSS(css: string): void {\n if (injectedSelfHosted.has(css)) return;\n injectedSelfHosted.add(css);\n\n // Extract font file URLs for preload hints (SSR only)\n collectFontPreloadsFromCSS(css);\n\n if (typeof document === \"undefined\") {\n // SSR: add to collected styles\n ssrFontStyles.push(css);\n return;\n }\n\n // Client: inject <style> tag\n const style = document.createElement(\"style\");\n style.textContent = css;\n style.setAttribute(\"data-vinext-font-selfhosted\", \"true\");\n document.head.appendChild(style);\n}\n\nexport type FontLoader = (options?: FontOptions & { _selfHostedCSS?: string }) => FontResult;\n\nexport function createFontLoader(family: string): FontLoader {\n return function fontLoader(options: FontOptions & { _selfHostedCSS?: string } = {}): FontResult {\n const id = classCounter++;\n const className = `__font_${family.toLowerCase().replace(/\\s+/g, \"_\")}_${id}`;\n const fallback = options.fallback ?? [\"sans-serif\"];\n // Sanitize each fallback name to prevent CSS injection via crafted values\n const fontFamily = `'${escapeCSSString(family)}', ${fallback.map(sanitizeFallback).join(\", \")}`;\n // Validate CSS variable name — reject anything that could inject CSS.\n // Fall back to auto-generated name if invalid.\n const defaultVarName = toVarName(family);\n const cssVarName = options.variable\n ? (sanitizeCSSVarName(options.variable) ?? defaultVarName)\n : defaultVarName;\n // In Next.js, `variable` returns a CLASS NAME that sets the CSS variable.\n // Users apply this class to set the CSS variable on that element.\n const variableClassName = `__variable_${family.toLowerCase().replace(/\\s+/g, \"_\")}_${id}`;\n\n if (options._selfHostedCSS) {\n // Self-hosted mode: inject local @font-face CSS instead of CDN link\n injectSelfHostedCSS(options._selfHostedCSS);\n } else {\n // CDN mode: inject <link> to Google Fonts\n const url = buildGoogleFontsUrl(family, options);\n injectFontStylesheet(url);\n\n // On SSR, collect the URL for head injection\n if (typeof document === \"undefined\") {\n if (!ssrFontUrls.includes(url)) {\n ssrFontUrls.push(url);\n }\n }\n }\n\n // Inject a CSS rule that maps className to font-family.\n // This is what makes `<div className={inter.className}>` work.\n injectClassNameRule(className, fontFamily);\n\n // Inject a CSS rule for the variable class name.\n // This is what makes `<html className={inter.variable}>` set the CSS variable.\n injectVariableClassRule(variableClassName, cssVarName, fontFamily);\n\n return {\n className,\n style: { fontFamily },\n variable: variableClassName,\n };\n };\n}\n\n// Export a Proxy that creates font loaders for any Google Font family.\n// Usage: import { Inter } from 'next/font/google'\n// The proxy intercepts property access and returns a loader for that font.\nconst googleFonts = new Proxy({} as Record<string, (options?: FontOptions) => FontResult>, {\n get(_target, prop: string) {\n if (prop === \"__esModule\") return true;\n if (prop === \"default\") return googleFonts;\n // Convert export-style names to proper font family names:\n // - Underscores to spaces: \"Roboto_Mono\" -> \"Roboto Mono\"\n // - PascalCase to spaces: \"RobotoMono\" -> \"Roboto Mono\"\n const family = prop.replace(/_/g, \" \").replace(/([a-z])([A-Z])/g, \"$1 $2\");\n return createFontLoader(family);\n },\n});\n\nexport default googleFonts;\n"],"mappings":"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"}
|
package/dist/shims/form.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { isDangerousScheme } from "./url-safety.js";
|
|
2
3
|
import { toSameOriginPath } from "./url-utils.js";
|
|
3
4
|
import { navigateClientSide } from "./navigation.js";
|
|
4
|
-
import { isDangerousScheme } from "./url-safety.js";
|
|
5
5
|
import { forwardRef, useActionState } from "react";
|
|
6
6
|
import { jsx } from "react/jsx-runtime";
|
|
7
7
|
//#region src/shims/form.tsx
|
package/dist/shims/link.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { isDangerousScheme } from "./url-safety.js";
|
|
2
3
|
import { resolveRelativeHref, toBrowserNavigationHref, toSameOriginAppPath, withBasePath } from "./url-utils.js";
|
|
3
4
|
import { addLocalePrefix, getDomainLocaleUrl } from "../utils/domain-locale.js";
|
|
4
5
|
import { appendSearchParamsToUrl, urlQueryToSearchParams } from "../utils/query.js";
|
|
5
6
|
import { createAppPayloadCacheKey } from "../server/app-elements.js";
|
|
6
7
|
import { getCurrentInterceptionContext, getMountedSlotsHeader, getPrefetchedUrls, navigateClientSide, prefetchRscResponse, toRscUrl } from "./navigation.js";
|
|
7
|
-
import { isDangerousScheme } from "./url-safety.js";
|
|
8
8
|
import { getI18nContext } from "./i18n-context.js";
|
|
9
9
|
import React, { createContext, forwardRef, useCallback, useContext, useEffect, useRef, useState } from "react";
|
|
10
10
|
import { jsx } from "react/jsx-runtime";
|
|
@@ -152,6 +152,9 @@ type ClientNavigationState = {
|
|
|
152
152
|
suppressUrlNotifyCount: number;
|
|
153
153
|
navigationSnapshotActiveCount: number;
|
|
154
154
|
};
|
|
155
|
+
type CommitClientNavigationStateOptions = {
|
|
156
|
+
releaseSnapshot?: boolean;
|
|
157
|
+
};
|
|
155
158
|
declare function setMountedSlotsHeader(header: string | null): void;
|
|
156
159
|
declare function getMountedSlotsHeader(): string | null;
|
|
157
160
|
declare function getClientNavigationState(): ClientNavigationState | null;
|
|
@@ -203,10 +206,11 @@ declare function useParams<T extends Record<string, string | string[]> = Record<
|
|
|
203
206
|
* Commit pending client navigation state to committed snapshots.
|
|
204
207
|
*
|
|
205
208
|
* navId is optional: callers that don't own pendingPathname (for example,
|
|
206
|
-
* superseded pre-paint cleanup) may pass undefined to flush
|
|
207
|
-
*
|
|
209
|
+
* superseded pre-paint cleanup) may pass undefined to flush URL/params state
|
|
210
|
+
* without clearing pendingPathname owned by the active navigation. Such callers
|
|
211
|
+
* must opt in explicitly if they also own an activated render snapshot.
|
|
208
212
|
*/
|
|
209
|
-
declare function commitClientNavigationState(navId?: number): void;
|
|
213
|
+
declare function commitClientNavigationState(navId?: number, options?: CommitClientNavigationStateOptions): void;
|
|
210
214
|
declare function pushHistoryStateWithoutNotify(data: unknown, unused: string, url?: string | URL | null): void;
|
|
211
215
|
declare function replaceHistoryStateWithoutNotify(data: unknown, unused: string, url?: string | URL | null): void;
|
|
212
216
|
/**
|
package/dist/shims/navigation.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { assertSafeNavigationUrl } from "./url-safety.js";
|
|
1
2
|
import { stripBasePath } from "../utils/base-path.js";
|
|
2
3
|
import { toBrowserNavigationHref, toSameOriginAppPath } from "./url-utils.js";
|
|
3
4
|
import { notifyAppRouterTransitionStart } from "../client/instrumentation-client-state.js";
|
|
@@ -578,14 +579,15 @@ function withSuppressedUrlNotifications(fn) {
|
|
|
578
579
|
* Commit pending client navigation state to committed snapshots.
|
|
579
580
|
*
|
|
580
581
|
* navId is optional: callers that don't own pendingPathname (for example,
|
|
581
|
-
* superseded pre-paint cleanup) may pass undefined to flush
|
|
582
|
-
*
|
|
582
|
+
* superseded pre-paint cleanup) may pass undefined to flush URL/params state
|
|
583
|
+
* without clearing pendingPathname owned by the active navigation. Such callers
|
|
584
|
+
* must opt in explicitly if they also own an activated render snapshot.
|
|
583
585
|
*/
|
|
584
|
-
function commitClientNavigationState(navId) {
|
|
586
|
+
function commitClientNavigationState(navId, options) {
|
|
585
587
|
if (isServer) return;
|
|
586
588
|
const state = getClientNavigationState();
|
|
587
589
|
if (!state) return;
|
|
588
|
-
if (state.navigationSnapshotActiveCount > 0) state.navigationSnapshotActiveCount -= 1;
|
|
590
|
+
if ((navId !== void 0 || options?.releaseSnapshot === true) && state.navigationSnapshotActiveCount > 0) state.navigationSnapshotActiveCount -= 1;
|
|
589
591
|
const urlChanged = syncCommittedUrlStateFromLocation();
|
|
590
592
|
if (state.pendingClientParams !== null && state.pendingClientParamsJson !== null) {
|
|
591
593
|
state.clientParams = state.pendingClientParams;
|
|
@@ -694,12 +696,14 @@ async function navigateClientSide(href, mode, scroll, programmaticTransition = f
|
|
|
694
696
|
}
|
|
695
697
|
const _appRouter = {
|
|
696
698
|
push(href, options) {
|
|
699
|
+
assertSafeNavigationUrl(href);
|
|
697
700
|
if (isServer) return;
|
|
698
701
|
React$1.startTransition(() => {
|
|
699
702
|
navigateClientSide(href, "push", options?.scroll !== false, true);
|
|
700
703
|
});
|
|
701
704
|
},
|
|
702
705
|
replace(href, options) {
|
|
706
|
+
assertSafeNavigationUrl(href);
|
|
703
707
|
if (isServer) return;
|
|
704
708
|
React$1.startTransition(() => {
|
|
705
709
|
navigateClientSide(href, "replace", options?.scroll !== false, true);
|
|
@@ -724,6 +728,7 @@ const _appRouter = {
|
|
|
724
728
|
}
|
|
725
729
|
},
|
|
726
730
|
prefetch(href) {
|
|
731
|
+
assertSafeNavigationUrl(href);
|
|
727
732
|
if (isServer) return;
|
|
728
733
|
const rscUrl = toRscUrl(toBrowserNavigationHref(href, window.location.href, __basePath));
|
|
729
734
|
const interceptionContext = getCurrentInterceptionContext();
|
|
@@ -764,7 +769,8 @@ function useRouter() {
|
|
|
764
769
|
*/
|
|
765
770
|
function useSelectedLayoutSegment(parallelRoutesKey) {
|
|
766
771
|
const segments = useSelectedLayoutSegments(parallelRoutesKey);
|
|
767
|
-
|
|
772
|
+
if (segments.length === 0) return null;
|
|
773
|
+
return parallelRoutesKey === void 0 || parallelRoutesKey === "children" ? segments[0] : segments[segments.length - 1];
|
|
768
774
|
}
|
|
769
775
|
/**
|
|
770
776
|
* Returns all active segments below the layout where it's called.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation.js","names":["React"],"sources":["../../src/shims/navigation.ts"],"sourcesContent":["/**\n * next/navigation shim\n *\n * App Router navigation hooks. These work on both server (RSC) and client.\n * Server-side: reads from a request context set by the RSC handler.\n * Client-side: reads from browser Location API and provides navigation.\n */\n\n// Use namespace import for RSC safety: the react-server condition doesn't export\n// createContext/useContext/useSyncExternalStore as named exports, and strict ESM\n// would throw at link time for missing bindings. With `import * as React`, the\n// bindings are just `undefined` on the namespace object and we can guard at runtime.\nimport * as React from \"react\";\nimport { notifyAppRouterTransitionStart } from \"../client/instrumentation-client-state.js\";\nimport { createAppPayloadCacheKey } from \"../server/app-elements.js\";\nimport { toBrowserNavigationHref, toSameOriginAppPath } from \"./url-utils.js\";\nimport { stripBasePath } from \"../utils/base-path.js\";\nimport { ReadonlyURLSearchParams } from \"./readonly-url-search-params.js\";\n\n// ─── Layout segment context ───────────────────────────────────────────────────\n// Stores the child segments below the current layout. Each layout wraps its\n// children with a provider whose value is the remaining route tree segments\n// (including route groups, with dynamic params resolved to actual values).\n// Created lazily because `React.createContext` is NOT available in the\n// react-server condition of React. In the RSC environment, this remains null.\n// The shared context lives behind a global singleton so provider/hook pairs\n// still line up if Vite loads this shim through multiple resolved module IDs.\nconst _LAYOUT_SEGMENT_CTX_KEY = Symbol.for(\"vinext.layoutSegmentContext\");\nconst _SERVER_INSERTED_HTML_CTX_KEY = Symbol.for(\"vinext.serverInsertedHTMLContext\");\n\n/**\n * Map of parallel route key → child segments below the current layout.\n * The \"children\" key is always present (the default parallel route).\n * Named parallel routes add their own keys (e.g., \"team\", \"analytics\").\n *\n * Arrays are mutable (`string[]`) to match Next.js's public API return type\n * without requiring `as` casts. The map itself is Readonly — no key addition.\n */\nexport type SegmentMap = Readonly<Record<string, string[]>> & { readonly children: string[] };\n\ntype _LayoutSegmentGlobal = typeof globalThis & {\n [_LAYOUT_SEGMENT_CTX_KEY]?: React.Context<SegmentMap> | null;\n [_SERVER_INSERTED_HTML_CTX_KEY]?: React.Context<\n ((callback: () => unknown) => void) | null\n > | null;\n};\n\n// ─── ServerInsertedHTML context ────────────────────────────────────────────────\n// Used by CSS-in-JS libraries (Apollo Client, styled-components, emotion) to\n// register HTML injection callbacks during SSR via useContext().\n// The SSR entry wraps the rendered tree with a Provider whose value is a\n// callback registration function (useServerInsertedHTML).\n//\n// In Next.js, ServerInsertedHTMLContext holds a function:\n// (callback: () => React.ReactNode) => void\n// Libraries call useContext(ServerInsertedHTMLContext) to get this function,\n// then call it to register callbacks that inject HTML during SSR.\n//\n// Created eagerly at module load time. In the RSC environment (react-server\n// condition), createContext isn't available so this will be null.\n\nfunction getServerInsertedHTMLContext(): React.Context<\n ((callback: () => unknown) => void) | null\n> | null {\n if (typeof React.createContext !== \"function\") return null;\n\n const globalState = globalThis as _LayoutSegmentGlobal;\n if (!globalState[_SERVER_INSERTED_HTML_CTX_KEY]) {\n globalState[_SERVER_INSERTED_HTML_CTX_KEY] = React.createContext<\n ((callback: () => unknown) => void) | null\n >(null);\n }\n\n return globalState[_SERVER_INSERTED_HTML_CTX_KEY] ?? null;\n}\n\nexport const ServerInsertedHTMLContext: React.Context<\n ((callback: () => unknown) => void) | null\n> | null = getServerInsertedHTMLContext();\n\n/**\n * Get or create the layout segment context.\n * Returns null in the RSC environment (createContext unavailable).\n */\nexport function getLayoutSegmentContext(): React.Context<SegmentMap> | null {\n if (typeof React.createContext !== \"function\") return null;\n\n const globalState = globalThis as _LayoutSegmentGlobal;\n if (!globalState[_LAYOUT_SEGMENT_CTX_KEY]) {\n globalState[_LAYOUT_SEGMENT_CTX_KEY] = React.createContext<SegmentMap>({ children: [] });\n }\n\n return globalState[_LAYOUT_SEGMENT_CTX_KEY] ?? null;\n}\n\n/**\n * Read the child segments for a parallel route below the current layout.\n * Returns [] if no context is available (RSC environment, outside React tree)\n * or if the requested key is not present in the segment map.\n */\n/* oxlint-disable eslint-plugin-react-hooks/rules-of-hooks */\nfunction useChildSegments(parallelRoutesKey: string = \"children\"): string[] {\n const ctx = getLayoutSegmentContext();\n if (!ctx) return [];\n // useContext is safe here because if createContext exists, useContext does too.\n // This branch is only taken in SSR/Browser, never in RSC.\n // Try/catch for unit tests that call this hook outside a React render tree.\n try {\n const segmentMap = React.useContext(ctx);\n return segmentMap[parallelRoutesKey] ?? [];\n } catch {\n return [];\n }\n}\n/* oxlint-enable eslint-plugin-react-hooks/rules-of-hooks */\n\n// ---------------------------------------------------------------------------\n// Server-side request context (set by the RSC entry before rendering)\n// ---------------------------------------------------------------------------\n\nexport type NavigationContext = {\n pathname: string;\n searchParams: URLSearchParams;\n params: Record<string, string | string[]>;\n};\n\nconst _READONLY_SEARCH_PARAMS = Symbol(\"vinext.navigation.readonlySearchParams\");\nconst _READONLY_SEARCH_PARAMS_SOURCE = Symbol(\"vinext.navigation.readonlySearchParamsSource\");\n\ntype NavigationContextWithReadonlyCache = NavigationContext & {\n [_READONLY_SEARCH_PARAMS]?: ReadonlyURLSearchParams;\n [_READONLY_SEARCH_PARAMS_SOURCE]?: URLSearchParams;\n};\n\n// ---------------------------------------------------------------------------\n// Server-side navigation state lives in a separate server-only module\n// (navigation-state.ts) that uses AsyncLocalStorage for request isolation.\n// This module is bundled for the browser, so it can't import node:async_hooks.\n//\n// On the server: state functions are set by navigation-state.ts at import time.\n// On the client: _serverContext falls back to null (hooks use window instead).\n//\n// Global accessor pattern (issue #688):\n// Vite's multi-environment dev mode can create separate module instances of\n// this file for the SSR entry vs \"use client\" components. When that happens,\n// _registerStateAccessors only updates the SSR entry's instance, leaving the\n// \"use client\" instance with the default (null) fallbacks.\n//\n// To fix this, navigation-state.ts also stores the accessors on globalThis\n// via Symbol.for, and the defaults here check for that global before falling\n// back to module-level state. This ensures all module instances can reach the\n// ALS-backed state regardless of which instance was registered.\n// ---------------------------------------------------------------------------\n\ntype _StateAccessors = {\n getServerContext: () => NavigationContext | null;\n setServerContext: (ctx: NavigationContext | null) => void;\n getInsertedHTMLCallbacks: () => Array<() => unknown>;\n clearInsertedHTMLCallbacks: () => void;\n};\n\nexport const GLOBAL_ACCESSORS_KEY = Symbol.for(\"vinext.navigation.globalAccessors\");\nconst _GLOBAL_ACCESSORS_KEY = GLOBAL_ACCESSORS_KEY;\ntype _GlobalWithAccessors = typeof globalThis & { [_GLOBAL_ACCESSORS_KEY]?: _StateAccessors };\n\n// Browser hydration has the same module-split shape as SSR in Vite dev:\n// the browser entry seeds the snapshot before hydrateRoot(), but client\n// components can import a different module instance of this shim.\nconst GLOBAL_HYDRATION_CONTEXT_KEY = Symbol.for(\"vinext.navigation.clientHydrationContext\");\nconst _GLOBAL_HYDRATION_CONTEXT_KEY = GLOBAL_HYDRATION_CONTEXT_KEY;\ntype _GlobalWithHydrationContext = typeof globalThis & {\n [_GLOBAL_HYDRATION_CONTEXT_KEY]?: NavigationContext | null;\n};\n\nfunction _getGlobalAccessors(): _StateAccessors | undefined {\n return (globalThis as _GlobalWithAccessors)[_GLOBAL_ACCESSORS_KEY];\n}\n\nfunction _getClientHydrationContext(): NavigationContext | null | undefined {\n const globalState = globalThis as _GlobalWithHydrationContext;\n if (Object.prototype.hasOwnProperty.call(globalState, _GLOBAL_HYDRATION_CONTEXT_KEY)) {\n return globalState[_GLOBAL_HYDRATION_CONTEXT_KEY] ?? null;\n }\n return undefined;\n}\n\nfunction _setClientHydrationContext(ctx: NavigationContext | null): void {\n (globalThis as _GlobalWithHydrationContext)[_GLOBAL_HYDRATION_CONTEXT_KEY] = ctx;\n}\n\nlet _serverContext: NavigationContext | null = null;\nlet _serverInsertedHTMLCallbacks: Array<() => unknown> = [];\n\n// These are overridden by navigation-state.ts on the server to use ALS.\n// The defaults check globalThis for cross-module-instance access (issue #688).\nlet _getServerContext = (): NavigationContext | null => {\n if (typeof window !== \"undefined\") {\n const hydrationContext = _getClientHydrationContext();\n return hydrationContext !== undefined ? hydrationContext : _serverContext;\n }\n const g = _getGlobalAccessors();\n return g ? g.getServerContext() : _serverContext;\n};\nlet _setServerContext = (ctx: NavigationContext | null): void => {\n if (typeof window !== \"undefined\") {\n _serverContext = ctx;\n _setClientHydrationContext(ctx);\n return;\n }\n const g = _getGlobalAccessors();\n if (g) {\n g.setServerContext(ctx);\n } else {\n _serverContext = ctx;\n }\n};\nlet _getInsertedHTMLCallbacks = (): Array<() => unknown> => {\n const g = _getGlobalAccessors();\n return g ? g.getInsertedHTMLCallbacks() : _serverInsertedHTMLCallbacks;\n};\nlet _clearInsertedHTMLCallbacks = (): void => {\n const g = _getGlobalAccessors();\n if (g) {\n g.clearInsertedHTMLCallbacks();\n } else {\n _serverInsertedHTMLCallbacks = [];\n }\n};\n\n/**\n * Register ALS-backed state accessors. Called by navigation-state.ts on import.\n * @internal\n */\nexport function _registerStateAccessors(accessors: _StateAccessors): void {\n _getServerContext = accessors.getServerContext;\n _setServerContext = accessors.setServerContext;\n _getInsertedHTMLCallbacks = accessors.getInsertedHTMLCallbacks;\n _clearInsertedHTMLCallbacks = accessors.clearInsertedHTMLCallbacks;\n}\n\n/**\n * Get the navigation context for the current SSR/RSC render.\n * Reads from AsyncLocalStorage when available (concurrent-safe),\n * otherwise falls back to module-level state.\n */\nexport function getNavigationContext(): NavigationContext | null {\n return _getServerContext();\n}\n\n/**\n * Set the navigation context for the current SSR/RSC render.\n * Called by the framework entry before rendering each request.\n */\nexport function setNavigationContext(ctx: NavigationContext | null): void {\n _setServerContext(ctx);\n}\n\n// ---------------------------------------------------------------------------\n// Client-side state\n// ---------------------------------------------------------------------------\n\nconst isServer = typeof window === \"undefined\";\n\n/** basePath from next.config.js, injected by the plugin at build time */\nexport const __basePath: string = process.env.__NEXT_ROUTER_BASEPATH ?? \"\";\n\n// ---------------------------------------------------------------------------\n// RSC prefetch cache utilities (shared between link.tsx and browser entry)\n// ---------------------------------------------------------------------------\n\n/** Maximum number of entries in the RSC prefetch cache. */\nexport const MAX_PREFETCH_CACHE_SIZE = 50;\n\n/** TTL for prefetch cache entries in ms (matches Next.js static prefetch TTL). */\nexport const PREFETCH_CACHE_TTL = 30_000;\n\n/** A buffered RSC response stored as an ArrayBuffer for replay. */\nexport type CachedRscResponse = {\n buffer: ArrayBuffer;\n contentType: string;\n mountedSlotsHeader?: string | null;\n paramsHeader: string | null;\n url: string;\n};\n\nexport type PrefetchCacheEntry = {\n snapshot?: CachedRscResponse;\n pending?: Promise<void>;\n timestamp: number;\n};\n\n/**\n * Convert a pathname (with optional query/hash) to its .rsc URL.\n * Strips trailing slashes before appending `.rsc` so that cache keys\n * are consistent regardless of the `trailingSlash` config setting.\n */\nexport function toRscUrl(href: string): string {\n const [beforeHash] = href.split(\"#\");\n const qIdx = beforeHash.indexOf(\"?\");\n const pathname = qIdx === -1 ? beforeHash : beforeHash.slice(0, qIdx);\n const query = qIdx === -1 ? \"\" : beforeHash.slice(qIdx);\n // Strip trailing slash (but preserve \"/\" root) for consistent cache keys\n const normalizedPath =\n pathname.length > 1 && pathname.endsWith(\"/\") ? pathname.slice(0, -1) : pathname;\n return normalizedPath + \".rsc\" + query;\n}\n\nexport function getCurrentInterceptionContext(): string | null {\n if (isServer) {\n return null;\n }\n\n return stripBasePath(window.location.pathname, __basePath);\n}\n\nexport function getCurrentNextUrl(): string {\n if (isServer) {\n return \"/\";\n }\n\n return window.location.pathname + window.location.search;\n}\n\n/** Get or create the shared in-memory RSC prefetch cache on window. */\nexport function getPrefetchCache(): Map<string, PrefetchCacheEntry> {\n if (isServer) return new Map();\n if (!window.__VINEXT_RSC_PREFETCH_CACHE__) {\n window.__VINEXT_RSC_PREFETCH_CACHE__ = new Map<string, PrefetchCacheEntry>();\n }\n return window.__VINEXT_RSC_PREFETCH_CACHE__;\n}\n\n/**\n * Get or create the shared set of already-prefetched RSC URLs on window.\n * Keyed by interception-aware cache key so distinct source routes do not alias.\n */\nexport function getPrefetchedUrls(): Set<string> {\n if (isServer) return new Set();\n if (!window.__VINEXT_RSC_PREFETCHED_URLS__) {\n window.__VINEXT_RSC_PREFETCHED_URLS__ = new Set<string>();\n }\n return window.__VINEXT_RSC_PREFETCHED_URLS__;\n}\n\n/**\n * Evict prefetch cache entries if at capacity.\n * First sweeps expired entries, then falls back to FIFO eviction.\n */\nfunction evictPrefetchCacheIfNeeded(): void {\n const cache = getPrefetchCache();\n if (cache.size < MAX_PREFETCH_CACHE_SIZE) return;\n\n const now = Date.now();\n const prefetched = getPrefetchedUrls();\n\n for (const [key, entry] of cache) {\n if (now - entry.timestamp >= PREFETCH_CACHE_TTL) {\n cache.delete(key);\n prefetched.delete(key);\n }\n }\n\n while (cache.size >= MAX_PREFETCH_CACHE_SIZE) {\n const oldest = cache.keys().next().value;\n if (oldest !== undefined) {\n cache.delete(oldest);\n prefetched.delete(oldest);\n } else {\n break;\n }\n }\n}\n\n/**\n * Store a prefetched RSC response in the cache by snapshotting it to an\n * ArrayBuffer. The snapshot completes asynchronously; during that window\n * the entry is marked `pending` so consumePrefetchResponse() will skip it\n * (the caller falls back to a fresh fetch, which is acceptable).\n *\n * Prefer prefetchRscResponse() for new call-sites — it handles the full\n * prefetch lifecycle including dedup and explicit slot context.\n * storePrefetchResponse() is kept for backward compatibility and test\n * helpers. It is slot-unaware: the snapshot's mountedSlotsHeader comes\n * from the response headers, not the caller, so consumePrefetchResponse\n * may reject the entry if the caller's slot context differs.\n *\n * NB: Caller is responsible for managing getPrefetchedUrls() — this\n * function only stores the response in the prefetch cache.\n */\nexport function storePrefetchResponse(\n rscUrl: string,\n response: Response,\n interceptionContext: string | null = null,\n): void {\n const cacheKey = createAppPayloadCacheKey(rscUrl, interceptionContext);\n evictPrefetchCacheIfNeeded();\n const entry: PrefetchCacheEntry = { timestamp: Date.now() };\n entry.pending = snapshotRscResponse(response)\n .then((snapshot) => {\n entry.snapshot = snapshot;\n })\n .catch(() => {\n getPrefetchCache().delete(cacheKey);\n })\n .finally(() => {\n entry.pending = undefined;\n });\n getPrefetchCache().set(cacheKey, entry);\n}\n\n/**\n * Snapshot an RSC response to an ArrayBuffer for caching and replay.\n * Consumes the response body and stores it with content-type and URL metadata.\n */\nexport async function snapshotRscResponse(response: Response): Promise<CachedRscResponse> {\n const buffer = await response.arrayBuffer();\n return {\n buffer,\n contentType: response.headers.get(\"content-type\") ?? \"text/x-component\",\n mountedSlotsHeader: response.headers.get(\"X-Vinext-Mounted-Slots\"),\n paramsHeader: response.headers.get(\"X-Vinext-Params\"),\n url: response.url,\n };\n}\n\n/**\n * Reconstruct a Response from a cached RSC snapshot.\n * Creates a new Response with the original ArrayBuffer so createFromFetch\n * can consume the stream from scratch.\n *\n * NOTE: The reconstructed Response always has `url === \"\"` — the Response\n * constructor does not accept a `url` option, and `response.url` is read-only\n * set by the fetch infrastructure. Callers that need the original URL should\n * read it from `cached.url` directly rather than from the restored Response.\n *\n * @param copy - When true (default), copies the ArrayBuffer so the cached\n * snapshot remains replayable (needed for the visited-response cache).\n * Pass false for single-consumption paths (e.g. prefetch cache entries\n * that are deleted after consumption) to avoid the extra allocation.\n */\nexport function restoreRscResponse(cached: CachedRscResponse, copy = true): Response {\n const headers = new Headers({ \"content-type\": cached.contentType });\n if (cached.mountedSlotsHeader != null) {\n headers.set(\"X-Vinext-Mounted-Slots\", cached.mountedSlotsHeader);\n }\n if (cached.paramsHeader != null) {\n headers.set(\"X-Vinext-Params\", cached.paramsHeader);\n }\n\n return new Response(copy ? cached.buffer.slice(0) : cached.buffer, {\n status: 200,\n headers,\n });\n}\n\n/**\n * Prefetch an RSC response and snapshot it for later consumption.\n * Stores the in-flight promise so immediate clicks can await it instead\n * of firing a duplicate fetch.\n * Enforces a maximum cache size to prevent unbounded memory growth on\n * link-heavy pages.\n */\nexport function prefetchRscResponse(\n rscUrl: string,\n fetchPromise: Promise<Response>,\n interceptionContext: string | null = null,\n mountedSlotsHeader: string | null = null,\n): void {\n const cacheKey = createAppPayloadCacheKey(rscUrl, interceptionContext);\n const cache = getPrefetchCache();\n const prefetched = getPrefetchedUrls();\n const now = Date.now();\n\n const entry: PrefetchCacheEntry = { timestamp: now };\n\n entry.pending = fetchPromise\n .then(async (response) => {\n if (response.ok) {\n entry.snapshot = {\n ...(await snapshotRscResponse(response)),\n // Prefetch compatibility is defined by the slot context at fetch\n // time, not by whatever header a reused response happens to carry.\n mountedSlotsHeader,\n };\n } else {\n prefetched.delete(cacheKey);\n cache.delete(cacheKey);\n }\n })\n .catch(() => {\n prefetched.delete(cacheKey);\n cache.delete(cacheKey);\n })\n .finally(() => {\n entry.pending = undefined;\n });\n\n // Insert the new entry before evicting. FIFO evicts from the front of the\n // Map (oldest insertion order), so the just-appended entry is safe — only\n // entries inserted before it are candidates for removal.\n cache.set(cacheKey, entry);\n evictPrefetchCacheIfNeeded();\n}\n\n/**\n * Consume a prefetched response for a given rscUrl.\n * Only returns settled (non-pending) snapshots synchronously.\n * Returns null if the entry is still in flight or doesn't exist.\n */\nexport function consumePrefetchResponse(\n rscUrl: string,\n interceptionContext: string | null = null,\n mountedSlotsHeader: string | null = null,\n): CachedRscResponse | null {\n const cacheKey = createAppPayloadCacheKey(rscUrl, interceptionContext);\n const cache = getPrefetchCache();\n const entry = cache.get(cacheKey);\n if (!entry) return null;\n\n // Don't consume pending entries — let the navigation fetch independently.\n if (entry.pending) return null;\n\n cache.delete(cacheKey);\n getPrefetchedUrls().delete(cacheKey);\n\n if (entry.snapshot) {\n if ((entry.snapshot.mountedSlotsHeader ?? null) !== mountedSlotsHeader) {\n // Entry was already removed above. Slot mismatch means the prefetch\n // used stale slot context and cannot be safely reused.\n return null;\n }\n if (Date.now() - entry.timestamp >= PREFETCH_CACHE_TTL) {\n return null;\n }\n return entry.snapshot;\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Client navigation state — stored on a Symbol.for global to survive\n// multiple Vite module instances loading this file through different IDs.\n// ---------------------------------------------------------------------------\n\ntype NavigationListener = () => void;\nconst _CLIENT_NAV_STATE_KEY = Symbol.for(\"vinext.clientNavigationState\");\nconst _MOUNTED_SLOTS_HEADER_KEY = Symbol.for(\"vinext.mountedSlotsHeader\");\n\ntype ClientNavigationState = {\n listeners: Set<NavigationListener>;\n cachedSearch: string;\n cachedReadonlySearchParams: ReadonlyURLSearchParams;\n cachedPathname: string;\n clientParams: Record<string, string | string[]>;\n clientParamsJson: string;\n pendingClientParams: Record<string, string | string[]> | null;\n pendingClientParamsJson: string | null;\n pendingPathname: string | null;\n pendingPathnameNavId: number | null;\n originalPushState: typeof window.history.pushState;\n originalReplaceState: typeof window.history.replaceState;\n patchInstalled: boolean;\n hasPendingNavigationUpdate: boolean;\n suppressUrlNotifyCount: number;\n navigationSnapshotActiveCount: number;\n};\n\ntype ClientNavigationGlobal = typeof globalThis & {\n [_CLIENT_NAV_STATE_KEY]?: ClientNavigationState;\n [_MOUNTED_SLOTS_HEADER_KEY]?: string | null;\n};\n\nexport function setMountedSlotsHeader(header: string | null): void {\n if (isServer) return;\n const globalState = window as ClientNavigationGlobal;\n globalState[_MOUNTED_SLOTS_HEADER_KEY] = header;\n}\n\nexport function getMountedSlotsHeader(): string | null {\n if (isServer) return null;\n const globalState = window as ClientNavigationGlobal;\n return globalState[_MOUNTED_SLOTS_HEADER_KEY] ?? null;\n}\n\nexport function getClientNavigationState(): ClientNavigationState | null {\n if (isServer) return null;\n\n const globalState = window as ClientNavigationGlobal;\n globalState[_CLIENT_NAV_STATE_KEY] ??= {\n listeners: new Set<NavigationListener>(),\n cachedSearch: window.location.search,\n cachedReadonlySearchParams: new ReadonlyURLSearchParams(window.location.search),\n cachedPathname: stripBasePath(window.location.pathname, __basePath),\n clientParams: {},\n clientParamsJson: \"{}\",\n pendingClientParams: null,\n pendingClientParamsJson: null,\n pendingPathname: null,\n pendingPathnameNavId: null,\n // NB: These capture the currently installed history methods, not guaranteed\n // native ones. If a third-party library (analytics, router) has already patched\n // history methods before this module loads, we intentionally preserve that\n // wrapper. With Symbol.for global state, the first module instance to load wins.\n originalPushState: window.history.pushState.bind(window.history),\n originalReplaceState: window.history.replaceState.bind(window.history),\n patchInstalled: false,\n hasPendingNavigationUpdate: false,\n suppressUrlNotifyCount: 0,\n navigationSnapshotActiveCount: 0,\n };\n\n return globalState[_CLIENT_NAV_STATE_KEY]!;\n}\n\nfunction notifyNavigationListeners(): void {\n const state = getClientNavigationState();\n if (!state) return;\n for (const fn of state.listeners) fn();\n}\n\n// Cached URLSearchParams, pathname, etc. for referential stability\n// useSyncExternalStore compares snapshots with Object.is — avoid creating\n// new instances on every render (infinite re-renders).\nlet _cachedEmptyServerSearchParams: ReadonlyURLSearchParams | null = null;\n\n/**\n * Get cached pathname snapshot for useSyncExternalStore.\n * Note: Returns cached value from ClientNavigationState, not live window.location.\n * The cache is updated by syncCommittedUrlStateFromLocation() after navigation commits.\n * This ensures referential stability and prevents infinite re-renders.\n * External pushState/replaceState while URL notifications are suppressed won't\n * be visible until the next commit.\n */\nfunction getPathnameSnapshot(): string {\n return getClientNavigationState()?.cachedPathname ?? \"/\";\n}\n\nlet _cachedEmptyClientSearchParams: ReadonlyURLSearchParams | null = null;\n\n/**\n * Get cached search params snapshot for useSyncExternalStore.\n * Note: Returns cached value from ClientNavigationState, not live window.location.search.\n * The cache is updated by syncCommittedUrlStateFromLocation() after navigation commits.\n * This ensures referential stability and prevents infinite re-renders.\n * External pushState/replaceState while URL notifications are suppressed won't\n * be visible until the next commit.\n */\nfunction getSearchParamsSnapshot(): ReadonlyURLSearchParams {\n const cached = getClientNavigationState()?.cachedReadonlySearchParams;\n if (cached) return cached;\n if (_cachedEmptyClientSearchParams === null) {\n _cachedEmptyClientSearchParams = new ReadonlyURLSearchParams();\n }\n return _cachedEmptyClientSearchParams;\n}\n\nfunction syncCommittedUrlStateFromLocation(): boolean {\n const state = getClientNavigationState();\n if (!state) return false;\n\n let changed = false;\n\n const pathname = stripBasePath(window.location.pathname, __basePath);\n if (pathname !== state.cachedPathname) {\n state.cachedPathname = pathname;\n changed = true;\n }\n\n const search = window.location.search;\n if (search !== state.cachedSearch) {\n state.cachedSearch = search;\n state.cachedReadonlySearchParams = new ReadonlyURLSearchParams(search);\n changed = true;\n }\n\n return changed;\n}\n\nfunction getServerSearchParamsSnapshot(): ReadonlyURLSearchParams {\n const ctx = _getServerContext() as NavigationContextWithReadonlyCache | null;\n\n if (!ctx) {\n // No server context available - return cached empty instance\n if (_cachedEmptyServerSearchParams === null) {\n _cachedEmptyServerSearchParams = new ReadonlyURLSearchParams();\n }\n return _cachedEmptyServerSearchParams;\n }\n\n const source = ctx.searchParams;\n const cached = ctx[_READONLY_SEARCH_PARAMS];\n const cachedSource = ctx[_READONLY_SEARCH_PARAMS_SOURCE];\n\n // Return cached wrapper if source hasn't changed\n if (cached && cachedSource === source) {\n return cached;\n }\n\n // Create and cache new wrapper\n const readonly = new ReadonlyURLSearchParams(source);\n ctx[_READONLY_SEARCH_PARAMS] = readonly;\n ctx[_READONLY_SEARCH_PARAMS_SOURCE] = source;\n\n return readonly;\n}\n\n// ---------------------------------------------------------------------------\n// Navigation snapshot activation flag\n//\n// The render snapshot context provides pending URL values during transitions.\n// After the transition commits, the snapshot becomes stale and must NOT shadow\n// subsequent external URL changes (user pushState/replaceState). This flag\n// tracks whether a navigation transition is in progress — hooks only prefer\n// the snapshot while it's active.\n// ---------------------------------------------------------------------------\n\n/**\n * Mark a navigation snapshot as active. Called before startTransition\n * in renderNavigationPayload. While active, hooks prefer the snapshot\n * context value over useSyncExternalStore. Uses a counter (not boolean)\n * to handle overlapping navigations — rapid clicks can interleave\n * activate/deactivate if multiple transitions are in flight.\n */\nexport function activateNavigationSnapshot(): void {\n const state = getClientNavigationState();\n if (state) state.navigationSnapshotActiveCount++;\n}\n\n// Track client-side params (set during RSC hydration/navigation)\n// We cache the params object for referential stability — only create a new\n// object when the params actually change (shallow key/value comparison).\nconst _EMPTY_PARAMS: Record<string, string | string[]> = {};\n\n// ---------------------------------------------------------------------------\n// Client navigation render snapshot — provides pending URL values to hooks\n// during a startTransition so they see the destination, not the stale URL.\n// ---------------------------------------------------------------------------\n\nexport type ClientNavigationRenderSnapshot = {\n pathname: string;\n searchParams: ReadonlyURLSearchParams;\n params: Record<string, string | string[]>;\n};\n\nconst _CLIENT_NAV_RENDER_CTX_KEY = Symbol.for(\"vinext.clientNavigationRenderContext\");\ntype _ClientNavRenderGlobal = typeof globalThis & {\n [_CLIENT_NAV_RENDER_CTX_KEY]?: React.Context<ClientNavigationRenderSnapshot | null> | null;\n};\n\nexport function getClientNavigationRenderContext(): React.Context<ClientNavigationRenderSnapshot | null> | null {\n if (typeof React.createContext !== \"function\") return null;\n\n const globalState = globalThis as _ClientNavRenderGlobal;\n if (!globalState[_CLIENT_NAV_RENDER_CTX_KEY]) {\n globalState[_CLIENT_NAV_RENDER_CTX_KEY] =\n React.createContext<ClientNavigationRenderSnapshot | null>(null);\n }\n\n return globalState[_CLIENT_NAV_RENDER_CTX_KEY] ?? null;\n}\n\n/* oxlint-disable eslint-plugin-react-hooks/rules-of-hooks */\nfunction useClientNavigationRenderSnapshot(): ClientNavigationRenderSnapshot | null {\n const ctx = getClientNavigationRenderContext();\n if (!ctx || typeof React.useContext !== \"function\") return null;\n try {\n return React.useContext(ctx);\n } catch {\n return null;\n }\n}\n/* oxlint-enable eslint-plugin-react-hooks/rules-of-hooks */\n\nexport function createClientNavigationRenderSnapshot(\n href: string,\n params: Record<string, string | string[]>,\n): ClientNavigationRenderSnapshot {\n const origin = typeof window !== \"undefined\" ? window.location.origin : \"http://localhost\";\n const url = new URL(href, origin);\n\n return {\n pathname: stripBasePath(url.pathname, __basePath),\n searchParams: new ReadonlyURLSearchParams(url.search),\n params,\n };\n}\n\n// Module-level fallback for environments without window (tests, SSR).\nlet _fallbackClientParams: Record<string, string | string[]> = _EMPTY_PARAMS;\nlet _fallbackClientParamsJson = \"{}\";\n\nexport function setClientParams(params: Record<string, string | string[]>): void {\n const state = getClientNavigationState();\n if (!state) {\n const json = JSON.stringify(params);\n if (json !== _fallbackClientParamsJson) {\n _fallbackClientParams = params;\n _fallbackClientParamsJson = json;\n }\n return;\n }\n\n const json = JSON.stringify(params);\n if (json !== state.clientParamsJson) {\n state.clientParams = params;\n state.clientParamsJson = json;\n state.pendingClientParams = null;\n state.pendingClientParamsJson = null;\n notifyNavigationListeners();\n }\n}\n\nexport function replaceClientParamsWithoutNotify(params: Record<string, string | string[]>): void {\n const state = getClientNavigationState();\n if (!state) return;\n\n const json = JSON.stringify(params);\n if (json !== state.clientParamsJson && json !== state.pendingClientParamsJson) {\n state.pendingClientParams = params;\n state.pendingClientParamsJson = json;\n state.hasPendingNavigationUpdate = true;\n }\n}\n\n/** Get the current client params (for testing referential stability). */\nexport function getClientParams(): Record<string, string | string[]> {\n return getClientNavigationState()?.clientParams ?? _fallbackClientParams;\n}\n\n/**\n * Set the pending pathname for client-side navigation.\n * Strips the base path before storing. Associates the pathname with the given navId\n * so only that navigation (or a newer one) can clear it.\n */\nexport function setPendingPathname(pathname: string, navId: number): void {\n const state = getClientNavigationState();\n if (!state) return;\n state.pendingPathname = stripBasePath(pathname, __basePath);\n state.pendingPathnameNavId = navId;\n}\n\n/**\n * Clear the pending pathname, but only if the given navId matches the one\n * that set it, or if pendingPathnameNavId is null (no active owner).\n * This prevents superseded navigations from clearing state belonging to newer navigations.\n */\nexport function clearPendingPathname(navId: number): void {\n const state = getClientNavigationState();\n if (!state) return;\n // Only clear if this navId is the one that set the pendingPathname,\n // or if pendingPathnameNavId is null (no owner)\n if (state.pendingPathnameNavId === null || state.pendingPathnameNavId === navId) {\n state.pendingPathname = null;\n state.pendingPathnameNavId = null;\n }\n}\n\nfunction getClientParamsSnapshot(): Record<string, string | string[]> {\n return getClientNavigationState()?.clientParams ?? _EMPTY_PARAMS;\n}\n\nfunction getServerParamsSnapshot(): Record<string, string | string[]> {\n return _getServerContext()?.params ?? _EMPTY_PARAMS;\n}\n\nfunction subscribeToNavigation(cb: () => void): () => void {\n const state = getClientNavigationState();\n if (!state) return () => {};\n\n state.listeners.add(cb);\n return () => {\n state.listeners.delete(cb);\n };\n}\n\n/* oxlint-disable eslint-plugin-react-hooks/rules-of-hooks */\n/**\n * Returns the current pathname.\n * Server: from request context. Client: from window.location.\n */\nexport function usePathname(): string {\n if (isServer) {\n // During SSR of \"use client\" components, the navigation context may not be set.\n // Return a safe fallback — the client will hydrate with the real value.\n return _getServerContext()?.pathname ?? \"/\";\n }\n const renderSnapshot = useClientNavigationRenderSnapshot();\n // Client-side: use the hook system for reactivity\n const pathname = React.useSyncExternalStore(\n subscribeToNavigation,\n getPathnameSnapshot,\n () => _getServerContext()?.pathname ?? \"/\",\n );\n // Prefer the render snapshot during an active navigation transition so\n // hooks return the pending URL, not the stale committed one. After commit,\n // fall through to useSyncExternalStore so user pushState/replaceState\n // calls are immediately reflected.\n if (renderSnapshot && (getClientNavigationState()?.navigationSnapshotActiveCount ?? 0) > 0) {\n return renderSnapshot.pathname;\n }\n return pathname;\n}\n/* oxlint-enable eslint-plugin-react-hooks/rules-of-hooks */\n\n/* oxlint-disable eslint-plugin-react-hooks/rules-of-hooks */\n/**\n * Returns the current search params as a read-only URLSearchParams.\n */\nexport function useSearchParams(): ReadonlyURLSearchParams {\n if (isServer) {\n // During SSR for \"use client\" components, the navigation context may not be set.\n // Return a safe fallback — the client will hydrate with the real value.\n return getServerSearchParamsSnapshot();\n }\n const renderSnapshot = useClientNavigationRenderSnapshot();\n const searchParams = React.useSyncExternalStore(\n subscribeToNavigation,\n getSearchParamsSnapshot,\n getServerSearchParamsSnapshot,\n );\n if (renderSnapshot && (getClientNavigationState()?.navigationSnapshotActiveCount ?? 0) > 0) {\n return renderSnapshot.searchParams;\n }\n return searchParams;\n}\n/* oxlint-enable eslint-plugin-react-hooks/rules-of-hooks */\n\n/* oxlint-disable eslint-plugin-react-hooks/rules-of-hooks */\n/**\n * Returns the dynamic params for the current route.\n */\nexport function useParams<\n T extends Record<string, string | string[]> = Record<string, string | string[]>,\n>(): T {\n if (isServer) {\n // During SSR for \"use client\" components, the navigation context may not be set.\n return (_getServerContext()?.params ?? _EMPTY_PARAMS) as T;\n }\n const renderSnapshot = useClientNavigationRenderSnapshot();\n const params = React.useSyncExternalStore(\n subscribeToNavigation,\n getClientParamsSnapshot as () => T,\n getServerParamsSnapshot as () => T,\n );\n if (renderSnapshot && (getClientNavigationState()?.navigationSnapshotActiveCount ?? 0) > 0) {\n return renderSnapshot.params as T;\n }\n return params;\n}\n/* oxlint-enable eslint-plugin-react-hooks/rules-of-hooks */\n\n/**\n * Check if a href is an external URL (any URL scheme per RFC 3986, or protocol-relative).\n */\nfunction isExternalUrl(href: string): boolean {\n return /^[a-z][a-z0-9+.-]*:/i.test(href) || href.startsWith(\"//\");\n}\n\n/**\n * Check if a href is only a hash change relative to the current URL.\n */\nfunction isHashOnlyChange(href: string): boolean {\n if (typeof window === \"undefined\") return false;\n if (href.startsWith(\"#\")) return true;\n try {\n const current = new URL(window.location.href);\n const next = new URL(href, window.location.href);\n // Strip basePath from both pathnames for consistent comparison\n // (matches how isSameRoute handles basePath in app-browser-entry.ts)\n const strippedCurrentPath = stripBasePath(current.pathname, __basePath);\n const strippedNextPath = stripBasePath(next.pathname, __basePath);\n return (\n strippedCurrentPath === strippedNextPath && current.search === next.search && next.hash !== \"\"\n );\n } catch {\n return false;\n }\n}\n\n/**\n * Scroll to a hash target element, or to the top if no hash.\n */\nfunction scrollToHash(hash: string): void {\n if (!hash || hash === \"#\") {\n window.scrollTo(0, 0);\n return;\n }\n const id = hash.slice(1);\n const element = document.getElementById(id);\n if (element) {\n element.scrollIntoView({ behavior: \"auto\" });\n }\n}\n\n// ---------------------------------------------------------------------------\n// History method wrappers — suppress notifications for internal updates\n// ---------------------------------------------------------------------------\n\nfunction withSuppressedUrlNotifications<T>(fn: () => T): T {\n const state = getClientNavigationState();\n if (!state) {\n return fn();\n }\n\n state.suppressUrlNotifyCount += 1;\n try {\n return fn();\n } finally {\n state.suppressUrlNotifyCount -= 1;\n }\n}\n\n/**\n * Commit pending client navigation state to committed snapshots.\n *\n * navId is optional: callers that don't own pendingPathname (for example,\n * superseded pre-paint cleanup) may pass undefined to flush snapshot/params\n * state without clearing pendingPathname owned by the active navigation.\n */\nexport function commitClientNavigationState(navId?: number): void {\n if (isServer) return;\n const state = getClientNavigationState();\n if (!state) return;\n\n // Only decrement the snapshot counter if a snapshot was previously activated.\n // Several code paths call commit without a prior activateNavigationSnapshot()\n // — hash-only changes (navigateClientSide), Pages Router popstate, and\n // patched history.pushState/replaceState — which legitimately have count == 0.\n if (state.navigationSnapshotActiveCount > 0) {\n state.navigationSnapshotActiveCount -= 1;\n }\n\n const urlChanged = syncCommittedUrlStateFromLocation();\n if (state.pendingClientParams !== null && state.pendingClientParamsJson !== null) {\n state.clientParams = state.pendingClientParams;\n state.clientParamsJson = state.pendingClientParamsJson;\n state.pendingClientParams = null;\n state.pendingClientParamsJson = null;\n }\n // Clear pending pathname when navigation commits, but only if:\n // - The navId matches the one that set pendingPathname\n // - No newer navigation has overwritten pendingPathname (pendingPathnameNavId === null or matches)\n // - navId is undefined only for non-owning callers, which must not clear\n // pendingPathname for an active navigation.\n const canClearPendingPathname =\n state.pendingPathnameNavId === null ||\n (navId !== undefined && state.pendingPathnameNavId === navId);\n if (canClearPendingPathname) {\n state.pendingPathname = null;\n state.pendingPathnameNavId = null;\n }\n const shouldNotify = urlChanged || state.hasPendingNavigationUpdate;\n state.hasPendingNavigationUpdate = false;\n\n if (shouldNotify) {\n notifyNavigationListeners();\n }\n}\n\nexport function pushHistoryStateWithoutNotify(\n data: unknown,\n unused: string,\n url?: string | URL | null,\n): void {\n withSuppressedUrlNotifications(() => {\n const state = getClientNavigationState();\n state?.originalPushState.call(window.history, data, unused, url);\n });\n}\n\nexport function replaceHistoryStateWithoutNotify(\n data: unknown,\n unused: string,\n url?: string | URL | null,\n): void {\n withSuppressedUrlNotifications(() => {\n const state = getClientNavigationState();\n state?.originalReplaceState.call(window.history, data, unused, url);\n });\n}\n\n/**\n * Save the current scroll position into the current history state.\n * Called before every navigation to enable scroll restoration on back/forward.\n *\n * Uses replaceHistoryStateWithoutNotify to avoid triggering the patched\n * history.replaceState interception (which would cause spurious re-renders).\n */\nfunction saveScrollPosition(): void {\n const state = window.history.state ?? {};\n replaceHistoryStateWithoutNotify(\n { ...state, __vinext_scrollX: window.scrollX, __vinext_scrollY: window.scrollY },\n \"\",\n );\n}\n\n/**\n * Restore scroll position from a history state object (used on popstate).\n *\n * When an RSC navigation is in flight (back/forward triggers both this\n * handler and the browser entry's popstate handler which calls\n * __VINEXT_RSC_NAVIGATE__), we must wait for the new content to render\n * before scrolling. Otherwise the user sees old content flash at the\n * restored scroll position.\n *\n * This handler fires before the browser entry's popstate handler (because\n * navigation.ts is loaded before hydration completes), so we defer via a\n * microtask to give the browser entry handler a chance to set\n * __VINEXT_RSC_PENDING__. Promise.resolve() schedules a microtask\n * that runs after all synchronous event listeners have completed.\n */\nfunction restoreScrollPosition(state: unknown): void {\n if (state && typeof state === \"object\" && \"__vinext_scrollY\" in state) {\n const { __vinext_scrollX: x, __vinext_scrollY: y } = state as {\n __vinext_scrollX: number;\n __vinext_scrollY: number;\n };\n\n // Defer to allow other popstate listeners (browser entry) to run first\n // and set __VINEXT_RSC_PENDING__. Promise.resolve() schedules a microtask\n // that runs after all synchronous event listeners have completed.\n void Promise.resolve().then(() => {\n const pending: Promise<void> | null = window.__VINEXT_RSC_PENDING__ ?? null;\n\n if (pending) {\n // Wait for the RSC navigation to finish rendering, then scroll.\n void pending.then(() => {\n requestAnimationFrame(() => {\n window.scrollTo(x, y);\n });\n });\n } else {\n // No RSC navigation in flight (Pages Router or already settled).\n requestAnimationFrame(() => {\n window.scrollTo(x, y);\n });\n }\n });\n }\n}\n\n/**\n * Navigate to a URL, handling external URLs, hash-only changes, and RSC navigation.\n */\nexport async function navigateClientSide(\n href: string,\n mode: \"push\" | \"replace\",\n scroll: boolean,\n programmaticTransition = false,\n): Promise<void> {\n // Normalize same-origin absolute URLs to local paths for SPA navigation\n let normalizedHref = href;\n if (isExternalUrl(href)) {\n const localPath = toSameOriginAppPath(href, __basePath);\n if (localPath == null) {\n // Truly external: use full page navigation\n if (mode === \"replace\") {\n window.location.replace(href);\n } else {\n window.location.assign(href);\n }\n return;\n }\n normalizedHref = localPath;\n }\n\n const fullHref = toBrowserNavigationHref(normalizedHref, window.location.href, __basePath);\n // Match Next.js: App Router reports navigation start before dispatching,\n // including hash-only navigations that short-circuit after URL update.\n notifyAppRouterTransitionStart(fullHref, mode);\n\n // Save scroll position before navigating (for back/forward restoration)\n if (mode === \"push\") {\n saveScrollPosition();\n }\n\n // Hash-only change: update URL and scroll to target, skip RSC fetch\n if (isHashOnlyChange(fullHref)) {\n const hash = fullHref.includes(\"#\") ? fullHref.slice(fullHref.indexOf(\"#\")) : \"\";\n if (mode === \"replace\") {\n replaceHistoryStateWithoutNotify(null, \"\", fullHref);\n } else {\n pushHistoryStateWithoutNotify(null, \"\", fullHref);\n }\n commitClientNavigationState();\n if (scroll) {\n scrollToHash(hash);\n }\n return;\n }\n\n // Extract hash for post-navigation scrolling\n const hashIdx = fullHref.indexOf(\"#\");\n const hash = hashIdx !== -1 ? fullHref.slice(hashIdx) : \"\";\n\n // Trigger RSC re-fetch if available, and wait for the new content to render\n // before scrolling. This prevents the old page from visibly jumping to the\n // top before the new content paints.\n //\n // History is NOT pushed here for RSC navigations — the commit effect inside\n // navigateRsc owns the push/replace exclusively. This avoids a fragile\n // double-push and ensures window.location still reflects the *current* URL\n // when navigateRsc computes isSameRoute (cross-route vs same-route).\n if (typeof window.__VINEXT_RSC_NAVIGATE__ === \"function\") {\n await window.__VINEXT_RSC_NAVIGATE__(\n fullHref,\n 0,\n \"navigate\",\n mode,\n undefined,\n programmaticTransition,\n );\n } else {\n if (mode === \"replace\") {\n replaceHistoryStateWithoutNotify(null, \"\", fullHref);\n } else {\n pushHistoryStateWithoutNotify(null, \"\", fullHref);\n }\n commitClientNavigationState();\n }\n\n if (scroll) {\n if (hash) {\n scrollToHash(hash);\n } else {\n window.scrollTo(0, 0);\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// App Router router singleton\n//\n// All methods close over module-level state (navigateClientSide, withBasePath, etc.)\n// and carry no per-render data, so the object can be created once and reused.\n// Next.js returns the same router reference on every call to useRouter(), which\n// matters for components that rely on referential equality (e.g. useMemo /\n// useEffect dependency arrays, React.memo bailouts).\n// ---------------------------------------------------------------------------\n\nconst _appRouter = {\n push(href: string, options?: { scroll?: boolean }): void {\n if (isServer) return;\n React.startTransition(() => {\n void navigateClientSide(href, \"push\", options?.scroll !== false, true);\n });\n },\n replace(href: string, options?: { scroll?: boolean }): void {\n if (isServer) return;\n React.startTransition(() => {\n void navigateClientSide(href, \"replace\", options?.scroll !== false, true);\n });\n },\n back(): void {\n if (isServer) return;\n window.history.back();\n },\n forward(): void {\n if (isServer) return;\n window.history.forward();\n },\n refresh(): void {\n if (isServer) return;\n // Re-fetch the current page's RSC stream\n const rscNavigate = window.__VINEXT_RSC_NAVIGATE__;\n if (typeof rscNavigate === \"function\") {\n const navigate = () => {\n void rscNavigate(window.location.href, 0, \"refresh\", undefined, undefined, true);\n };\n React.startTransition(navigate);\n }\n },\n prefetch(href: string): void {\n if (isServer) return;\n // Prefetch the RSC payload for the target route and store in cache.\n // We must add to prefetchedUrls manually for deduplication.\n // prefetchRscResponse only manages the cache Map, not the URL set.\n const fullHref = toBrowserNavigationHref(href, window.location.href, __basePath);\n const rscUrl = toRscUrl(fullHref);\n const interceptionContext = getCurrentInterceptionContext();\n const cacheKey = createAppPayloadCacheKey(rscUrl, interceptionContext);\n const prefetched = getPrefetchedUrls();\n if (prefetched.has(cacheKey)) return;\n prefetched.add(cacheKey);\n const mountedSlotsHeader = getMountedSlotsHeader();\n const headers = new Headers({ Accept: \"text/x-component\" });\n if (mountedSlotsHeader) {\n headers.set(\"X-Vinext-Mounted-Slots\", mountedSlotsHeader);\n }\n if (interceptionContext !== null) {\n headers.set(\"X-Vinext-Interception-Context\", interceptionContext);\n }\n prefetchRscResponse(\n rscUrl,\n fetch(rscUrl, {\n headers,\n credentials: \"include\",\n priority: \"low\" as RequestInit[\"priority\"],\n }),\n interceptionContext,\n mountedSlotsHeader,\n );\n },\n};\n\n/**\n * App Router's useRouter — returns push/replace/back/forward/refresh.\n * Different from Pages Router's useRouter (next/router).\n *\n * Returns a stable singleton: the same object reference on every call,\n * matching Next.js behavior so components using referential equality\n * (e.g. useMemo / useEffect deps, React.memo) don't re-render unnecessarily.\n */\nexport function useRouter() {\n return _appRouter;\n}\n\n/**\n * Returns the active child segment one level below the layout where it's called.\n *\n * Returns the first segment from the route tree below this layout, including\n * route groups (e.g., \"(marketing)\") and resolved dynamic params. Returns null\n * if at the leaf (no child segments).\n *\n * @param parallelRoutesKey - Which parallel route to read (default: \"children\")\n */\nexport function useSelectedLayoutSegment(parallelRoutesKey?: string): string | null {\n const segments = useSelectedLayoutSegments(parallelRoutesKey);\n return segments.length > 0 ? segments[0] : null;\n}\n\n/**\n * Returns all active segments below the layout where it's called.\n *\n * Each layout in the App Router tree wraps its children with a\n * LayoutSegmentProvider whose value is a map of parallel route key to\n * segment arrays. The \"children\" key is the default parallel route.\n *\n * @param parallelRoutesKey - Which parallel route to read (default: \"children\")\n */\nexport function useSelectedLayoutSegments(parallelRoutesKey?: string): string[] {\n return useChildSegments(parallelRoutesKey);\n}\n\nexport { ReadonlyURLSearchParams };\n\n/**\n * useServerInsertedHTML — inject HTML during SSR from client components.\n *\n * Used by CSS-in-JS libraries (styled-components, emotion, StyleX) to inject\n * <style> tags during SSR so styles appear in the initial HTML (no FOUC).\n *\n * The callback is called once after each SSR render pass. The returned JSX/HTML\n * is serialized and injected into the HTML stream.\n *\n * Usage (in a \"use client\" component wrapping children):\n * useServerInsertedHTML(() => {\n * const styles = sheet.getStyleElement();\n * sheet.instance.clearTag();\n * return <>{styles}</>;\n * });\n */\n\nexport function useServerInsertedHTML(callback: () => unknown): void {\n if (typeof document !== \"undefined\") {\n // Client-side: no-op (styles are already in the DOM)\n return;\n }\n _getInsertedHTMLCallbacks().push(callback);\n}\n\n/**\n * Flush all collected useServerInsertedHTML callbacks.\n * Returns an array of results (React elements or strings).\n * Clears the callback list so the next render starts fresh.\n *\n * Called by the SSR entry after renderToReadableStream completes.\n */\nexport function flushServerInsertedHTML(): unknown[] {\n const callbacks = _getInsertedHTMLCallbacks();\n const results: unknown[] = [];\n for (const cb of callbacks) {\n try {\n const result = cb();\n if (result != null) results.push(result);\n } catch {\n // Ignore errors from individual callbacks\n }\n }\n callbacks.length = 0;\n return results;\n}\n\n/**\n * Clear all collected useServerInsertedHTML callbacks without flushing.\n * Used for cleanup between requests.\n */\nexport function clearServerInsertedHTML(): void {\n _clearInsertedHTMLCallbacks();\n}\n\n// ---------------------------------------------------------------------------\n// Non-hook utilities (can be called from Server Components)\n// ---------------------------------------------------------------------------\n\n/**\n * HTTP Access Fallback error code — shared prefix for notFound/forbidden/unauthorized.\n * Matches Next.js 16's unified error handling approach.\n */\nexport const HTTP_ERROR_FALLBACK_ERROR_CODE = \"NEXT_HTTP_ERROR_FALLBACK\";\n\n/**\n * Check if an error is an HTTP Access Fallback error (notFound, forbidden, unauthorized).\n */\nexport function isHTTPAccessFallbackError(error: unknown): boolean {\n if (error && typeof error === \"object\" && \"digest\" in error) {\n const digest = String((error as { digest: unknown }).digest);\n return (\n digest === \"NEXT_NOT_FOUND\" || // legacy compat\n digest.startsWith(`${HTTP_ERROR_FALLBACK_ERROR_CODE};`)\n );\n }\n return false;\n}\n\n/**\n * Extract the HTTP status code from an HTTP Access Fallback error.\n * Returns 404 for legacy NEXT_NOT_FOUND errors.\n */\nexport function getAccessFallbackHTTPStatus(error: unknown): number {\n if (error && typeof error === \"object\" && \"digest\" in error) {\n const digest = String((error as { digest: unknown }).digest);\n if (digest === \"NEXT_NOT_FOUND\") return 404;\n if (digest.startsWith(`${HTTP_ERROR_FALLBACK_ERROR_CODE};`)) {\n return parseInt(digest.split(\";\")[1], 10);\n }\n }\n return 404;\n}\n\n/**\n * Enum matching Next.js RedirectType for type-safe redirect calls.\n */\nexport enum RedirectType {\n push = \"push\",\n replace = \"replace\",\n}\n\n/**\n * Internal error class used by redirect/notFound/forbidden/unauthorized.\n * The `digest` field is the serialised control-flow signal read by the\n * framework's error boundary and server-side request handlers.\n */\nclass VinextNavigationError extends Error {\n readonly digest: string;\n constructor(message: string, digest: string) {\n super(message);\n this.digest = digest;\n }\n}\n\n/**\n * Throw a redirect. Caught by the framework to send a redirect response.\n *\n * When `type` is omitted, the digest carries an empty sentinel so the\n * catch site can resolve the default based on context:\n * - Server Action context → \"push\" (Back button works after form submission)\n * - SSR render context → \"replace\"\n *\n * This matches Next.js behavior where `redirect()` checks\n * `actionAsyncStorage.getStore()?.isAction` at call time.\n *\n * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/redirect.ts\n */\nexport function redirect(url: string, type?: \"replace\" | \"push\" | RedirectType): never {\n throw new VinextNavigationError(\n `NEXT_REDIRECT:${url}`,\n `NEXT_REDIRECT;${type ?? \"\"};${encodeURIComponent(url)}`,\n );\n}\n\n/**\n * Trigger a permanent redirect (308).\n *\n * Accepts an optional `type` parameter matching Next.js's signature.\n * Defaults to \"replace\" (not context-dependent like `redirect()`).\n *\n * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/redirect.ts\n */\nexport function permanentRedirect(\n url: string,\n type: \"replace\" | \"push\" | RedirectType = \"replace\",\n): never {\n throw new VinextNavigationError(\n `NEXT_REDIRECT:${url}`,\n `NEXT_REDIRECT;${type};${encodeURIComponent(url)};308`,\n );\n}\n\n/**\n * Trigger a not-found response (404). Caught by the framework.\n */\nexport function notFound(): never {\n throw new VinextNavigationError(\"NEXT_NOT_FOUND\", `${HTTP_ERROR_FALLBACK_ERROR_CODE};404`);\n}\n\n/**\n * Trigger a forbidden response (403). Caught by the framework.\n * In Next.js, this is gated behind experimental.authInterrupts — we\n * support it unconditionally for maximum compatibility.\n */\nexport function forbidden(): never {\n throw new VinextNavigationError(\"NEXT_FORBIDDEN\", `${HTTP_ERROR_FALLBACK_ERROR_CODE};403`);\n}\n\n/**\n * Trigger an unauthorized response (401). Caught by the framework.\n * In Next.js, this is gated behind experimental.authInterrupts — we\n * support it unconditionally for maximum compatibility.\n */\nexport function unauthorized(): never {\n throw new VinextNavigationError(\"NEXT_UNAUTHORIZED\", `${HTTP_ERROR_FALLBACK_ERROR_CODE};401`);\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n// Listen for popstate on the client\nif (!isServer) {\n const state = getClientNavigationState();\n if (state && !state.patchInstalled) {\n state.patchInstalled = true;\n\n // Listen for popstate on the client.\n // Note: This handler runs for Pages Router only (when __VINEXT_RSC_NAVIGATE__\n // is not available). It restores scroll position with microtask-based deferral.\n // App Router scroll restoration is handled in server/app-browser-entry.ts:697\n // with RSC navigation coordination (waits for pending navigation to settle).\n window.addEventListener(\"popstate\", (event) => {\n if (typeof window.__VINEXT_RSC_NAVIGATE__ !== \"function\") {\n commitClientNavigationState();\n restoreScrollPosition(event.state);\n }\n });\n\n window.history.pushState = function patchedPushState(\n data: unknown,\n unused: string,\n url?: string | URL | null,\n ): void {\n state.originalPushState.call(window.history, data, unused, url);\n if (state.suppressUrlNotifyCount === 0) {\n commitClientNavigationState();\n }\n };\n\n window.history.replaceState = function patchedReplaceState(\n data: unknown,\n unused: string,\n url?: string | URL | null,\n ): void {\n state.originalReplaceState.call(window.history, data, unused, url);\n if (state.suppressUrlNotifyCount === 0) {\n commitClientNavigationState();\n }\n };\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"navigation.js","names":["React"],"sources":["../../src/shims/navigation.ts"],"sourcesContent":["/**\n * next/navigation shim\n *\n * App Router navigation hooks. These work on both server (RSC) and client.\n * Server-side: reads from a request context set by the RSC handler.\n * Client-side: reads from browser Location API and provides navigation.\n */\n\n// Use namespace import for RSC safety: the react-server condition doesn't export\n// createContext/useContext/useSyncExternalStore as named exports, and strict ESM\n// would throw at link time for missing bindings. With `import * as React`, the\n// bindings are just `undefined` on the namespace object and we can guard at runtime.\nimport * as React from \"react\";\nimport { notifyAppRouterTransitionStart } from \"../client/instrumentation-client-state.js\";\nimport { createAppPayloadCacheKey } from \"../server/app-elements.js\";\nimport { toBrowserNavigationHref, toSameOriginAppPath } from \"./url-utils.js\";\nimport { stripBasePath } from \"../utils/base-path.js\";\nimport { ReadonlyURLSearchParams } from \"./readonly-url-search-params.js\";\nimport { assertSafeNavigationUrl } from \"./url-safety.js\";\n\n// ─── Layout segment context ───────────────────────────────────────────────────\n// Stores the child segments below the current layout. Each layout wraps its\n// children with a provider whose value is the remaining route tree segments\n// (including route groups, with dynamic params resolved to actual values).\n// Created lazily because `React.createContext` is NOT available in the\n// react-server condition of React. In the RSC environment, this remains null.\n// The shared context lives behind a global singleton so provider/hook pairs\n// still line up if Vite loads this shim through multiple resolved module IDs.\nconst _LAYOUT_SEGMENT_CTX_KEY = Symbol.for(\"vinext.layoutSegmentContext\");\nconst _SERVER_INSERTED_HTML_CTX_KEY = Symbol.for(\"vinext.serverInsertedHTMLContext\");\n\n/**\n * Map of parallel route key → child segments below the current layout.\n * The \"children\" key is always present (the default parallel route).\n * Named parallel routes add their own keys (e.g., \"team\", \"analytics\").\n *\n * Arrays are mutable (`string[]`) to match Next.js's public API return type\n * without requiring `as` casts. The map itself is Readonly — no key addition.\n */\nexport type SegmentMap = Readonly<Record<string, string[]>> & { readonly children: string[] };\n\ntype _LayoutSegmentGlobal = typeof globalThis & {\n [_LAYOUT_SEGMENT_CTX_KEY]?: React.Context<SegmentMap> | null;\n [_SERVER_INSERTED_HTML_CTX_KEY]?: React.Context<\n ((callback: () => unknown) => void) | null\n > | null;\n};\n\n// ─── ServerInsertedHTML context ────────────────────────────────────────────────\n// Used by CSS-in-JS libraries (Apollo Client, styled-components, emotion) to\n// register HTML injection callbacks during SSR via useContext().\n// The SSR entry wraps the rendered tree with a Provider whose value is a\n// callback registration function (useServerInsertedHTML).\n//\n// In Next.js, ServerInsertedHTMLContext holds a function:\n// (callback: () => React.ReactNode) => void\n// Libraries call useContext(ServerInsertedHTMLContext) to get this function,\n// then call it to register callbacks that inject HTML during SSR.\n//\n// Created eagerly at module load time. In the RSC environment (react-server\n// condition), createContext isn't available so this will be null.\n\nfunction getServerInsertedHTMLContext(): React.Context<\n ((callback: () => unknown) => void) | null\n> | null {\n if (typeof React.createContext !== \"function\") return null;\n\n const globalState = globalThis as _LayoutSegmentGlobal;\n if (!globalState[_SERVER_INSERTED_HTML_CTX_KEY]) {\n globalState[_SERVER_INSERTED_HTML_CTX_KEY] = React.createContext<\n ((callback: () => unknown) => void) | null\n >(null);\n }\n\n return globalState[_SERVER_INSERTED_HTML_CTX_KEY] ?? null;\n}\n\nexport const ServerInsertedHTMLContext: React.Context<\n ((callback: () => unknown) => void) | null\n> | null = getServerInsertedHTMLContext();\n\n/**\n * Get or create the layout segment context.\n * Returns null in the RSC environment (createContext unavailable).\n */\nexport function getLayoutSegmentContext(): React.Context<SegmentMap> | null {\n if (typeof React.createContext !== \"function\") return null;\n\n const globalState = globalThis as _LayoutSegmentGlobal;\n if (!globalState[_LAYOUT_SEGMENT_CTX_KEY]) {\n globalState[_LAYOUT_SEGMENT_CTX_KEY] = React.createContext<SegmentMap>({ children: [] });\n }\n\n return globalState[_LAYOUT_SEGMENT_CTX_KEY] ?? null;\n}\n\n/**\n * Read the child segments for a parallel route below the current layout.\n * Returns [] if no context is available (RSC environment, outside React tree)\n * or if the requested key is not present in the segment map.\n */\n/* oxlint-disable eslint-plugin-react-hooks/rules-of-hooks */\nfunction useChildSegments(parallelRoutesKey: string = \"children\"): string[] {\n const ctx = getLayoutSegmentContext();\n if (!ctx) return [];\n // useContext is safe here because if createContext exists, useContext does too.\n // This branch is only taken in SSR/Browser, never in RSC.\n // Try/catch for unit tests that call this hook outside a React render tree.\n try {\n const segmentMap = React.useContext(ctx);\n return segmentMap[parallelRoutesKey] ?? [];\n } catch {\n return [];\n }\n}\n/* oxlint-enable eslint-plugin-react-hooks/rules-of-hooks */\n\n// ---------------------------------------------------------------------------\n// Server-side request context (set by the RSC entry before rendering)\n// ---------------------------------------------------------------------------\n\nexport type NavigationContext = {\n pathname: string;\n searchParams: URLSearchParams;\n params: Record<string, string | string[]>;\n};\n\nconst _READONLY_SEARCH_PARAMS = Symbol(\"vinext.navigation.readonlySearchParams\");\nconst _READONLY_SEARCH_PARAMS_SOURCE = Symbol(\"vinext.navigation.readonlySearchParamsSource\");\n\ntype NavigationContextWithReadonlyCache = NavigationContext & {\n [_READONLY_SEARCH_PARAMS]?: ReadonlyURLSearchParams;\n [_READONLY_SEARCH_PARAMS_SOURCE]?: URLSearchParams;\n};\n\n// ---------------------------------------------------------------------------\n// Server-side navigation state lives in a separate server-only module\n// (navigation-state.ts) that uses AsyncLocalStorage for request isolation.\n// This module is bundled for the browser, so it can't import node:async_hooks.\n//\n// On the server: state functions are set by navigation-state.ts at import time.\n// On the client: _serverContext falls back to null (hooks use window instead).\n//\n// Global accessor pattern (issue #688):\n// Vite's multi-environment dev mode can create separate module instances of\n// this file for the SSR entry vs \"use client\" components. When that happens,\n// _registerStateAccessors only updates the SSR entry's instance, leaving the\n// \"use client\" instance with the default (null) fallbacks.\n//\n// To fix this, navigation-state.ts also stores the accessors on globalThis\n// via Symbol.for, and the defaults here check for that global before falling\n// back to module-level state. This ensures all module instances can reach the\n// ALS-backed state regardless of which instance was registered.\n// ---------------------------------------------------------------------------\n\ntype _StateAccessors = {\n getServerContext: () => NavigationContext | null;\n setServerContext: (ctx: NavigationContext | null) => void;\n getInsertedHTMLCallbacks: () => Array<() => unknown>;\n clearInsertedHTMLCallbacks: () => void;\n};\n\nexport const GLOBAL_ACCESSORS_KEY = Symbol.for(\"vinext.navigation.globalAccessors\");\nconst _GLOBAL_ACCESSORS_KEY = GLOBAL_ACCESSORS_KEY;\ntype _GlobalWithAccessors = typeof globalThis & { [_GLOBAL_ACCESSORS_KEY]?: _StateAccessors };\n\n// Browser hydration has the same module-split shape as SSR in Vite dev:\n// the browser entry seeds the snapshot before hydrateRoot(), but client\n// components can import a different module instance of this shim.\nconst GLOBAL_HYDRATION_CONTEXT_KEY = Symbol.for(\"vinext.navigation.clientHydrationContext\");\nconst _GLOBAL_HYDRATION_CONTEXT_KEY = GLOBAL_HYDRATION_CONTEXT_KEY;\ntype _GlobalWithHydrationContext = typeof globalThis & {\n [_GLOBAL_HYDRATION_CONTEXT_KEY]?: NavigationContext | null;\n};\n\nfunction _getGlobalAccessors(): _StateAccessors | undefined {\n return (globalThis as _GlobalWithAccessors)[_GLOBAL_ACCESSORS_KEY];\n}\n\nfunction _getClientHydrationContext(): NavigationContext | null | undefined {\n const globalState = globalThis as _GlobalWithHydrationContext;\n if (Object.prototype.hasOwnProperty.call(globalState, _GLOBAL_HYDRATION_CONTEXT_KEY)) {\n return globalState[_GLOBAL_HYDRATION_CONTEXT_KEY] ?? null;\n }\n return undefined;\n}\n\nfunction _setClientHydrationContext(ctx: NavigationContext | null): void {\n (globalThis as _GlobalWithHydrationContext)[_GLOBAL_HYDRATION_CONTEXT_KEY] = ctx;\n}\n\nlet _serverContext: NavigationContext | null = null;\nlet _serverInsertedHTMLCallbacks: Array<() => unknown> = [];\n\n// These are overridden by navigation-state.ts on the server to use ALS.\n// The defaults check globalThis for cross-module-instance access (issue #688).\nlet _getServerContext = (): NavigationContext | null => {\n if (typeof window !== \"undefined\") {\n const hydrationContext = _getClientHydrationContext();\n return hydrationContext !== undefined ? hydrationContext : _serverContext;\n }\n const g = _getGlobalAccessors();\n return g ? g.getServerContext() : _serverContext;\n};\nlet _setServerContext = (ctx: NavigationContext | null): void => {\n if (typeof window !== \"undefined\") {\n _serverContext = ctx;\n _setClientHydrationContext(ctx);\n return;\n }\n const g = _getGlobalAccessors();\n if (g) {\n g.setServerContext(ctx);\n } else {\n _serverContext = ctx;\n }\n};\nlet _getInsertedHTMLCallbacks = (): Array<() => unknown> => {\n const g = _getGlobalAccessors();\n return g ? g.getInsertedHTMLCallbacks() : _serverInsertedHTMLCallbacks;\n};\nlet _clearInsertedHTMLCallbacks = (): void => {\n const g = _getGlobalAccessors();\n if (g) {\n g.clearInsertedHTMLCallbacks();\n } else {\n _serverInsertedHTMLCallbacks = [];\n }\n};\n\n/**\n * Register ALS-backed state accessors. Called by navigation-state.ts on import.\n * @internal\n */\nexport function _registerStateAccessors(accessors: _StateAccessors): void {\n _getServerContext = accessors.getServerContext;\n _setServerContext = accessors.setServerContext;\n _getInsertedHTMLCallbacks = accessors.getInsertedHTMLCallbacks;\n _clearInsertedHTMLCallbacks = accessors.clearInsertedHTMLCallbacks;\n}\n\n/**\n * Get the navigation context for the current SSR/RSC render.\n * Reads from AsyncLocalStorage when available (concurrent-safe),\n * otherwise falls back to module-level state.\n */\nexport function getNavigationContext(): NavigationContext | null {\n return _getServerContext();\n}\n\n/**\n * Set the navigation context for the current SSR/RSC render.\n * Called by the framework entry before rendering each request.\n */\nexport function setNavigationContext(ctx: NavigationContext | null): void {\n _setServerContext(ctx);\n}\n\n// ---------------------------------------------------------------------------\n// Client-side state\n// ---------------------------------------------------------------------------\n\nconst isServer = typeof window === \"undefined\";\n\n/** basePath from next.config.js, injected by the plugin at build time */\nexport const __basePath: string = process.env.__NEXT_ROUTER_BASEPATH ?? \"\";\n\n// ---------------------------------------------------------------------------\n// RSC prefetch cache utilities (shared between link.tsx and browser entry)\n// ---------------------------------------------------------------------------\n\n/** Maximum number of entries in the RSC prefetch cache. */\nexport const MAX_PREFETCH_CACHE_SIZE = 50;\n\n/** TTL for prefetch cache entries in ms (matches Next.js static prefetch TTL). */\nexport const PREFETCH_CACHE_TTL = 30_000;\n\n/** A buffered RSC response stored as an ArrayBuffer for replay. */\nexport type CachedRscResponse = {\n buffer: ArrayBuffer;\n contentType: string;\n mountedSlotsHeader?: string | null;\n paramsHeader: string | null;\n url: string;\n};\n\nexport type PrefetchCacheEntry = {\n snapshot?: CachedRscResponse;\n pending?: Promise<void>;\n timestamp: number;\n};\n\n/**\n * Convert a pathname (with optional query/hash) to its .rsc URL.\n * Strips trailing slashes before appending `.rsc` so that cache keys\n * are consistent regardless of the `trailingSlash` config setting.\n */\nexport function toRscUrl(href: string): string {\n const [beforeHash] = href.split(\"#\");\n const qIdx = beforeHash.indexOf(\"?\");\n const pathname = qIdx === -1 ? beforeHash : beforeHash.slice(0, qIdx);\n const query = qIdx === -1 ? \"\" : beforeHash.slice(qIdx);\n // Strip trailing slash (but preserve \"/\" root) for consistent cache keys\n const normalizedPath =\n pathname.length > 1 && pathname.endsWith(\"/\") ? pathname.slice(0, -1) : pathname;\n return normalizedPath + \".rsc\" + query;\n}\n\nexport function getCurrentInterceptionContext(): string | null {\n if (isServer) {\n return null;\n }\n\n return stripBasePath(window.location.pathname, __basePath);\n}\n\nexport function getCurrentNextUrl(): string {\n if (isServer) {\n return \"/\";\n }\n\n return window.location.pathname + window.location.search;\n}\n\n/** Get or create the shared in-memory RSC prefetch cache on window. */\nexport function getPrefetchCache(): Map<string, PrefetchCacheEntry> {\n if (isServer) return new Map();\n if (!window.__VINEXT_RSC_PREFETCH_CACHE__) {\n window.__VINEXT_RSC_PREFETCH_CACHE__ = new Map<string, PrefetchCacheEntry>();\n }\n return window.__VINEXT_RSC_PREFETCH_CACHE__;\n}\n\n/**\n * Get or create the shared set of already-prefetched RSC URLs on window.\n * Keyed by interception-aware cache key so distinct source routes do not alias.\n */\nexport function getPrefetchedUrls(): Set<string> {\n if (isServer) return new Set();\n if (!window.__VINEXT_RSC_PREFETCHED_URLS__) {\n window.__VINEXT_RSC_PREFETCHED_URLS__ = new Set<string>();\n }\n return window.__VINEXT_RSC_PREFETCHED_URLS__;\n}\n\n/**\n * Evict prefetch cache entries if at capacity.\n * First sweeps expired entries, then falls back to FIFO eviction.\n */\nfunction evictPrefetchCacheIfNeeded(): void {\n const cache = getPrefetchCache();\n if (cache.size < MAX_PREFETCH_CACHE_SIZE) return;\n\n const now = Date.now();\n const prefetched = getPrefetchedUrls();\n\n for (const [key, entry] of cache) {\n if (now - entry.timestamp >= PREFETCH_CACHE_TTL) {\n cache.delete(key);\n prefetched.delete(key);\n }\n }\n\n while (cache.size >= MAX_PREFETCH_CACHE_SIZE) {\n const oldest = cache.keys().next().value;\n if (oldest !== undefined) {\n cache.delete(oldest);\n prefetched.delete(oldest);\n } else {\n break;\n }\n }\n}\n\n/**\n * Store a prefetched RSC response in the cache by snapshotting it to an\n * ArrayBuffer. The snapshot completes asynchronously; during that window\n * the entry is marked `pending` so consumePrefetchResponse() will skip it\n * (the caller falls back to a fresh fetch, which is acceptable).\n *\n * Prefer prefetchRscResponse() for new call-sites — it handles the full\n * prefetch lifecycle including dedup and explicit slot context.\n * storePrefetchResponse() is kept for backward compatibility and test\n * helpers. It is slot-unaware: the snapshot's mountedSlotsHeader comes\n * from the response headers, not the caller, so consumePrefetchResponse\n * may reject the entry if the caller's slot context differs.\n *\n * NB: Caller is responsible for managing getPrefetchedUrls() — this\n * function only stores the response in the prefetch cache.\n */\nexport function storePrefetchResponse(\n rscUrl: string,\n response: Response,\n interceptionContext: string | null = null,\n): void {\n const cacheKey = createAppPayloadCacheKey(rscUrl, interceptionContext);\n evictPrefetchCacheIfNeeded();\n const entry: PrefetchCacheEntry = { timestamp: Date.now() };\n entry.pending = snapshotRscResponse(response)\n .then((snapshot) => {\n entry.snapshot = snapshot;\n })\n .catch(() => {\n getPrefetchCache().delete(cacheKey);\n })\n .finally(() => {\n entry.pending = undefined;\n });\n getPrefetchCache().set(cacheKey, entry);\n}\n\n/**\n * Snapshot an RSC response to an ArrayBuffer for caching and replay.\n * Consumes the response body and stores it with content-type and URL metadata.\n */\nexport async function snapshotRscResponse(response: Response): Promise<CachedRscResponse> {\n const buffer = await response.arrayBuffer();\n return {\n buffer,\n contentType: response.headers.get(\"content-type\") ?? \"text/x-component\",\n mountedSlotsHeader: response.headers.get(\"X-Vinext-Mounted-Slots\"),\n paramsHeader: response.headers.get(\"X-Vinext-Params\"),\n url: response.url,\n };\n}\n\n/**\n * Reconstruct a Response from a cached RSC snapshot.\n * Creates a new Response with the original ArrayBuffer so createFromFetch\n * can consume the stream from scratch.\n *\n * NOTE: The reconstructed Response always has `url === \"\"` — the Response\n * constructor does not accept a `url` option, and `response.url` is read-only\n * set by the fetch infrastructure. Callers that need the original URL should\n * read it from `cached.url` directly rather than from the restored Response.\n *\n * @param copy - When true (default), copies the ArrayBuffer so the cached\n * snapshot remains replayable (needed for the visited-response cache).\n * Pass false for single-consumption paths (e.g. prefetch cache entries\n * that are deleted after consumption) to avoid the extra allocation.\n */\nexport function restoreRscResponse(cached: CachedRscResponse, copy = true): Response {\n const headers = new Headers({ \"content-type\": cached.contentType });\n if (cached.mountedSlotsHeader != null) {\n headers.set(\"X-Vinext-Mounted-Slots\", cached.mountedSlotsHeader);\n }\n if (cached.paramsHeader != null) {\n headers.set(\"X-Vinext-Params\", cached.paramsHeader);\n }\n\n return new Response(copy ? cached.buffer.slice(0) : cached.buffer, {\n status: 200,\n headers,\n });\n}\n\n/**\n * Prefetch an RSC response and snapshot it for later consumption.\n * Stores the in-flight promise so immediate clicks can await it instead\n * of firing a duplicate fetch.\n * Enforces a maximum cache size to prevent unbounded memory growth on\n * link-heavy pages.\n */\nexport function prefetchRscResponse(\n rscUrl: string,\n fetchPromise: Promise<Response>,\n interceptionContext: string | null = null,\n mountedSlotsHeader: string | null = null,\n): void {\n const cacheKey = createAppPayloadCacheKey(rscUrl, interceptionContext);\n const cache = getPrefetchCache();\n const prefetched = getPrefetchedUrls();\n const now = Date.now();\n\n const entry: PrefetchCacheEntry = { timestamp: now };\n\n entry.pending = fetchPromise\n .then(async (response) => {\n if (response.ok) {\n entry.snapshot = {\n ...(await snapshotRscResponse(response)),\n // Prefetch compatibility is defined by the slot context at fetch\n // time, not by whatever header a reused response happens to carry.\n mountedSlotsHeader,\n };\n } else {\n prefetched.delete(cacheKey);\n cache.delete(cacheKey);\n }\n })\n .catch(() => {\n prefetched.delete(cacheKey);\n cache.delete(cacheKey);\n })\n .finally(() => {\n entry.pending = undefined;\n });\n\n // Insert the new entry before evicting. FIFO evicts from the front of the\n // Map (oldest insertion order), so the just-appended entry is safe — only\n // entries inserted before it are candidates for removal.\n cache.set(cacheKey, entry);\n evictPrefetchCacheIfNeeded();\n}\n\n/**\n * Consume a prefetched response for a given rscUrl.\n * Only returns settled (non-pending) snapshots synchronously.\n * Returns null if the entry is still in flight or doesn't exist.\n */\nexport function consumePrefetchResponse(\n rscUrl: string,\n interceptionContext: string | null = null,\n mountedSlotsHeader: string | null = null,\n): CachedRscResponse | null {\n const cacheKey = createAppPayloadCacheKey(rscUrl, interceptionContext);\n const cache = getPrefetchCache();\n const entry = cache.get(cacheKey);\n if (!entry) return null;\n\n // Don't consume pending entries — let the navigation fetch independently.\n if (entry.pending) return null;\n\n cache.delete(cacheKey);\n getPrefetchedUrls().delete(cacheKey);\n\n if (entry.snapshot) {\n if ((entry.snapshot.mountedSlotsHeader ?? null) !== mountedSlotsHeader) {\n // Entry was already removed above. Slot mismatch means the prefetch\n // used stale slot context and cannot be safely reused.\n return null;\n }\n if (Date.now() - entry.timestamp >= PREFETCH_CACHE_TTL) {\n return null;\n }\n return entry.snapshot;\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Client navigation state — stored on a Symbol.for global to survive\n// multiple Vite module instances loading this file through different IDs.\n// ---------------------------------------------------------------------------\n\ntype NavigationListener = () => void;\nconst _CLIENT_NAV_STATE_KEY = Symbol.for(\"vinext.clientNavigationState\");\nconst _MOUNTED_SLOTS_HEADER_KEY = Symbol.for(\"vinext.mountedSlotsHeader\");\n\ntype ClientNavigationState = {\n listeners: Set<NavigationListener>;\n cachedSearch: string;\n cachedReadonlySearchParams: ReadonlyURLSearchParams;\n cachedPathname: string;\n clientParams: Record<string, string | string[]>;\n clientParamsJson: string;\n pendingClientParams: Record<string, string | string[]> | null;\n pendingClientParamsJson: string | null;\n pendingPathname: string | null;\n pendingPathnameNavId: number | null;\n originalPushState: typeof window.history.pushState;\n originalReplaceState: typeof window.history.replaceState;\n patchInstalled: boolean;\n hasPendingNavigationUpdate: boolean;\n suppressUrlNotifyCount: number;\n navigationSnapshotActiveCount: number;\n};\n\ntype CommitClientNavigationStateOptions = {\n releaseSnapshot?: boolean;\n};\n\ntype ClientNavigationGlobal = typeof globalThis & {\n [_CLIENT_NAV_STATE_KEY]?: ClientNavigationState;\n [_MOUNTED_SLOTS_HEADER_KEY]?: string | null;\n};\n\nexport function setMountedSlotsHeader(header: string | null): void {\n if (isServer) return;\n const globalState = window as ClientNavigationGlobal;\n globalState[_MOUNTED_SLOTS_HEADER_KEY] = header;\n}\n\nexport function getMountedSlotsHeader(): string | null {\n if (isServer) return null;\n const globalState = window as ClientNavigationGlobal;\n return globalState[_MOUNTED_SLOTS_HEADER_KEY] ?? null;\n}\n\nexport function getClientNavigationState(): ClientNavigationState | null {\n if (isServer) return null;\n\n const globalState = window as ClientNavigationGlobal;\n globalState[_CLIENT_NAV_STATE_KEY] ??= {\n listeners: new Set<NavigationListener>(),\n cachedSearch: window.location.search,\n cachedReadonlySearchParams: new ReadonlyURLSearchParams(window.location.search),\n cachedPathname: stripBasePath(window.location.pathname, __basePath),\n clientParams: {},\n clientParamsJson: \"{}\",\n pendingClientParams: null,\n pendingClientParamsJson: null,\n pendingPathname: null,\n pendingPathnameNavId: null,\n // NB: These capture the currently installed history methods, not guaranteed\n // native ones. If a third-party library (analytics, router) has already patched\n // history methods before this module loads, we intentionally preserve that\n // wrapper. With Symbol.for global state, the first module instance to load wins.\n originalPushState: window.history.pushState.bind(window.history),\n originalReplaceState: window.history.replaceState.bind(window.history),\n patchInstalled: false,\n hasPendingNavigationUpdate: false,\n suppressUrlNotifyCount: 0,\n navigationSnapshotActiveCount: 0,\n };\n\n return globalState[_CLIENT_NAV_STATE_KEY]!;\n}\n\nfunction notifyNavigationListeners(): void {\n const state = getClientNavigationState();\n if (!state) return;\n for (const fn of state.listeners) fn();\n}\n\n// Cached URLSearchParams, pathname, etc. for referential stability\n// useSyncExternalStore compares snapshots with Object.is — avoid creating\n// new instances on every render (infinite re-renders).\nlet _cachedEmptyServerSearchParams: ReadonlyURLSearchParams | null = null;\n\n/**\n * Get cached pathname snapshot for useSyncExternalStore.\n * Note: Returns cached value from ClientNavigationState, not live window.location.\n * The cache is updated by syncCommittedUrlStateFromLocation() after navigation commits.\n * This ensures referential stability and prevents infinite re-renders.\n * External pushState/replaceState while URL notifications are suppressed won't\n * be visible until the next commit.\n */\nfunction getPathnameSnapshot(): string {\n return getClientNavigationState()?.cachedPathname ?? \"/\";\n}\n\nlet _cachedEmptyClientSearchParams: ReadonlyURLSearchParams | null = null;\n\n/**\n * Get cached search params snapshot for useSyncExternalStore.\n * Note: Returns cached value from ClientNavigationState, not live window.location.search.\n * The cache is updated by syncCommittedUrlStateFromLocation() after navigation commits.\n * This ensures referential stability and prevents infinite re-renders.\n * External pushState/replaceState while URL notifications are suppressed won't\n * be visible until the next commit.\n */\nfunction getSearchParamsSnapshot(): ReadonlyURLSearchParams {\n const cached = getClientNavigationState()?.cachedReadonlySearchParams;\n if (cached) return cached;\n if (_cachedEmptyClientSearchParams === null) {\n _cachedEmptyClientSearchParams = new ReadonlyURLSearchParams();\n }\n return _cachedEmptyClientSearchParams;\n}\n\nfunction syncCommittedUrlStateFromLocation(): boolean {\n const state = getClientNavigationState();\n if (!state) return false;\n\n let changed = false;\n\n const pathname = stripBasePath(window.location.pathname, __basePath);\n if (pathname !== state.cachedPathname) {\n state.cachedPathname = pathname;\n changed = true;\n }\n\n const search = window.location.search;\n if (search !== state.cachedSearch) {\n state.cachedSearch = search;\n state.cachedReadonlySearchParams = new ReadonlyURLSearchParams(search);\n changed = true;\n }\n\n return changed;\n}\n\nfunction getServerSearchParamsSnapshot(): ReadonlyURLSearchParams {\n const ctx = _getServerContext() as NavigationContextWithReadonlyCache | null;\n\n if (!ctx) {\n // No server context available - return cached empty instance\n if (_cachedEmptyServerSearchParams === null) {\n _cachedEmptyServerSearchParams = new ReadonlyURLSearchParams();\n }\n return _cachedEmptyServerSearchParams;\n }\n\n const source = ctx.searchParams;\n const cached = ctx[_READONLY_SEARCH_PARAMS];\n const cachedSource = ctx[_READONLY_SEARCH_PARAMS_SOURCE];\n\n // Return cached wrapper if source hasn't changed\n if (cached && cachedSource === source) {\n return cached;\n }\n\n // Create and cache new wrapper\n const readonly = new ReadonlyURLSearchParams(source);\n ctx[_READONLY_SEARCH_PARAMS] = readonly;\n ctx[_READONLY_SEARCH_PARAMS_SOURCE] = source;\n\n return readonly;\n}\n\n// ---------------------------------------------------------------------------\n// Navigation snapshot activation flag\n//\n// The render snapshot context provides pending URL values during transitions.\n// After the transition commits, the snapshot becomes stale and must NOT shadow\n// subsequent external URL changes (user pushState/replaceState). This flag\n// tracks whether a navigation transition is in progress — hooks only prefer\n// the snapshot while it's active.\n// ---------------------------------------------------------------------------\n\n/**\n * Mark a navigation snapshot as active. Called before startTransition\n * in renderNavigationPayload. While active, hooks prefer the snapshot\n * context value over useSyncExternalStore. Uses a counter (not boolean)\n * to handle overlapping navigations — rapid clicks can interleave\n * activate/deactivate if multiple transitions are in flight.\n */\nexport function activateNavigationSnapshot(): void {\n const state = getClientNavigationState();\n if (state) state.navigationSnapshotActiveCount++;\n}\n\n// Track client-side params (set during RSC hydration/navigation)\n// We cache the params object for referential stability — only create a new\n// object when the params actually change (shallow key/value comparison).\nconst _EMPTY_PARAMS: Record<string, string | string[]> = {};\n\n// ---------------------------------------------------------------------------\n// Client navigation render snapshot — provides pending URL values to hooks\n// during a startTransition so they see the destination, not the stale URL.\n// ---------------------------------------------------------------------------\n\nexport type ClientNavigationRenderSnapshot = {\n pathname: string;\n searchParams: ReadonlyURLSearchParams;\n params: Record<string, string | string[]>;\n};\n\nconst _CLIENT_NAV_RENDER_CTX_KEY = Symbol.for(\"vinext.clientNavigationRenderContext\");\ntype _ClientNavRenderGlobal = typeof globalThis & {\n [_CLIENT_NAV_RENDER_CTX_KEY]?: React.Context<ClientNavigationRenderSnapshot | null> | null;\n};\n\nexport function getClientNavigationRenderContext(): React.Context<ClientNavigationRenderSnapshot | null> | null {\n if (typeof React.createContext !== \"function\") return null;\n\n const globalState = globalThis as _ClientNavRenderGlobal;\n if (!globalState[_CLIENT_NAV_RENDER_CTX_KEY]) {\n globalState[_CLIENT_NAV_RENDER_CTX_KEY] =\n React.createContext<ClientNavigationRenderSnapshot | null>(null);\n }\n\n return globalState[_CLIENT_NAV_RENDER_CTX_KEY] ?? null;\n}\n\n/* oxlint-disable eslint-plugin-react-hooks/rules-of-hooks */\nfunction useClientNavigationRenderSnapshot(): ClientNavigationRenderSnapshot | null {\n const ctx = getClientNavigationRenderContext();\n if (!ctx || typeof React.useContext !== \"function\") return null;\n try {\n return React.useContext(ctx);\n } catch {\n return null;\n }\n}\n/* oxlint-enable eslint-plugin-react-hooks/rules-of-hooks */\n\nexport function createClientNavigationRenderSnapshot(\n href: string,\n params: Record<string, string | string[]>,\n): ClientNavigationRenderSnapshot {\n const origin = typeof window !== \"undefined\" ? window.location.origin : \"http://localhost\";\n const url = new URL(href, origin);\n\n return {\n pathname: stripBasePath(url.pathname, __basePath),\n searchParams: new ReadonlyURLSearchParams(url.search),\n params,\n };\n}\n\n// Module-level fallback for environments without window (tests, SSR).\nlet _fallbackClientParams: Record<string, string | string[]> = _EMPTY_PARAMS;\nlet _fallbackClientParamsJson = \"{}\";\n\nexport function setClientParams(params: Record<string, string | string[]>): void {\n const state = getClientNavigationState();\n if (!state) {\n const json = JSON.stringify(params);\n if (json !== _fallbackClientParamsJson) {\n _fallbackClientParams = params;\n _fallbackClientParamsJson = json;\n }\n return;\n }\n\n const json = JSON.stringify(params);\n if (json !== state.clientParamsJson) {\n state.clientParams = params;\n state.clientParamsJson = json;\n state.pendingClientParams = null;\n state.pendingClientParamsJson = null;\n notifyNavigationListeners();\n }\n}\n\nexport function replaceClientParamsWithoutNotify(params: Record<string, string | string[]>): void {\n const state = getClientNavigationState();\n if (!state) return;\n\n const json = JSON.stringify(params);\n if (json !== state.clientParamsJson && json !== state.pendingClientParamsJson) {\n state.pendingClientParams = params;\n state.pendingClientParamsJson = json;\n state.hasPendingNavigationUpdate = true;\n }\n}\n\n/** Get the current client params (for testing referential stability). */\nexport function getClientParams(): Record<string, string | string[]> {\n return getClientNavigationState()?.clientParams ?? _fallbackClientParams;\n}\n\n/**\n * Set the pending pathname for client-side navigation.\n * Strips the base path before storing. Associates the pathname with the given navId\n * so only that navigation (or a newer one) can clear it.\n */\nexport function setPendingPathname(pathname: string, navId: number): void {\n const state = getClientNavigationState();\n if (!state) return;\n state.pendingPathname = stripBasePath(pathname, __basePath);\n state.pendingPathnameNavId = navId;\n}\n\n/**\n * Clear the pending pathname, but only if the given navId matches the one\n * that set it, or if pendingPathnameNavId is null (no active owner).\n * This prevents superseded navigations from clearing state belonging to newer navigations.\n */\nexport function clearPendingPathname(navId: number): void {\n const state = getClientNavigationState();\n if (!state) return;\n // Only clear if this navId is the one that set the pendingPathname,\n // or if pendingPathnameNavId is null (no owner)\n if (state.pendingPathnameNavId === null || state.pendingPathnameNavId === navId) {\n state.pendingPathname = null;\n state.pendingPathnameNavId = null;\n }\n}\n\nfunction getClientParamsSnapshot(): Record<string, string | string[]> {\n return getClientNavigationState()?.clientParams ?? _EMPTY_PARAMS;\n}\n\nfunction getServerParamsSnapshot(): Record<string, string | string[]> {\n return _getServerContext()?.params ?? _EMPTY_PARAMS;\n}\n\nfunction subscribeToNavigation(cb: () => void): () => void {\n const state = getClientNavigationState();\n if (!state) return () => {};\n\n state.listeners.add(cb);\n return () => {\n state.listeners.delete(cb);\n };\n}\n\n/* oxlint-disable eslint-plugin-react-hooks/rules-of-hooks */\n/**\n * Returns the current pathname.\n * Server: from request context. Client: from window.location.\n */\nexport function usePathname(): string {\n if (isServer) {\n // During SSR of \"use client\" components, the navigation context may not be set.\n // Return a safe fallback — the client will hydrate with the real value.\n return _getServerContext()?.pathname ?? \"/\";\n }\n const renderSnapshot = useClientNavigationRenderSnapshot();\n // Client-side: use the hook system for reactivity\n const pathname = React.useSyncExternalStore(\n subscribeToNavigation,\n getPathnameSnapshot,\n () => _getServerContext()?.pathname ?? \"/\",\n );\n // Prefer the render snapshot during an active navigation transition so\n // hooks return the pending URL, not the stale committed one. After commit,\n // fall through to useSyncExternalStore so user pushState/replaceState\n // calls are immediately reflected.\n if (renderSnapshot && (getClientNavigationState()?.navigationSnapshotActiveCount ?? 0) > 0) {\n return renderSnapshot.pathname;\n }\n return pathname;\n}\n/* oxlint-enable eslint-plugin-react-hooks/rules-of-hooks */\n\n/* oxlint-disable eslint-plugin-react-hooks/rules-of-hooks */\n/**\n * Returns the current search params as a read-only URLSearchParams.\n */\nexport function useSearchParams(): ReadonlyURLSearchParams {\n if (isServer) {\n // During SSR for \"use client\" components, the navigation context may not be set.\n // Return a safe fallback — the client will hydrate with the real value.\n return getServerSearchParamsSnapshot();\n }\n const renderSnapshot = useClientNavigationRenderSnapshot();\n const searchParams = React.useSyncExternalStore(\n subscribeToNavigation,\n getSearchParamsSnapshot,\n getServerSearchParamsSnapshot,\n );\n if (renderSnapshot && (getClientNavigationState()?.navigationSnapshotActiveCount ?? 0) > 0) {\n return renderSnapshot.searchParams;\n }\n return searchParams;\n}\n/* oxlint-enable eslint-plugin-react-hooks/rules-of-hooks */\n\n/* oxlint-disable eslint-plugin-react-hooks/rules-of-hooks */\n/**\n * Returns the dynamic params for the current route.\n */\nexport function useParams<\n T extends Record<string, string | string[]> = Record<string, string | string[]>,\n>(): T {\n if (isServer) {\n // During SSR for \"use client\" components, the navigation context may not be set.\n return (_getServerContext()?.params ?? _EMPTY_PARAMS) as T;\n }\n const renderSnapshot = useClientNavigationRenderSnapshot();\n const params = React.useSyncExternalStore(\n subscribeToNavigation,\n getClientParamsSnapshot as () => T,\n getServerParamsSnapshot as () => T,\n );\n if (renderSnapshot && (getClientNavigationState()?.navigationSnapshotActiveCount ?? 0) > 0) {\n return renderSnapshot.params as T;\n }\n return params;\n}\n/* oxlint-enable eslint-plugin-react-hooks/rules-of-hooks */\n\n/**\n * Check if a href is an external URL (any URL scheme per RFC 3986, or protocol-relative).\n */\nfunction isExternalUrl(href: string): boolean {\n return /^[a-z][a-z0-9+.-]*:/i.test(href) || href.startsWith(\"//\");\n}\n\n/**\n * Check if a href is only a hash change relative to the current URL.\n */\nfunction isHashOnlyChange(href: string): boolean {\n if (typeof window === \"undefined\") return false;\n if (href.startsWith(\"#\")) return true;\n try {\n const current = new URL(window.location.href);\n const next = new URL(href, window.location.href);\n // Strip basePath from both pathnames for consistent comparison\n // (matches how isSameRoute handles basePath in app-browser-entry.ts)\n const strippedCurrentPath = stripBasePath(current.pathname, __basePath);\n const strippedNextPath = stripBasePath(next.pathname, __basePath);\n return (\n strippedCurrentPath === strippedNextPath && current.search === next.search && next.hash !== \"\"\n );\n } catch {\n return false;\n }\n}\n\n/**\n * Scroll to a hash target element, or to the top if no hash.\n */\nfunction scrollToHash(hash: string): void {\n if (!hash || hash === \"#\") {\n window.scrollTo(0, 0);\n return;\n }\n const id = hash.slice(1);\n const element = document.getElementById(id);\n if (element) {\n element.scrollIntoView({ behavior: \"auto\" });\n }\n}\n\n// ---------------------------------------------------------------------------\n// History method wrappers — suppress notifications for internal updates\n// ---------------------------------------------------------------------------\n\nfunction withSuppressedUrlNotifications<T>(fn: () => T): T {\n const state = getClientNavigationState();\n if (!state) {\n return fn();\n }\n\n state.suppressUrlNotifyCount += 1;\n try {\n return fn();\n } finally {\n state.suppressUrlNotifyCount -= 1;\n }\n}\n\n/**\n * Commit pending client navigation state to committed snapshots.\n *\n * navId is optional: callers that don't own pendingPathname (for example,\n * superseded pre-paint cleanup) may pass undefined to flush URL/params state\n * without clearing pendingPathname owned by the active navigation. Such callers\n * must opt in explicitly if they also own an activated render snapshot.\n */\nexport function commitClientNavigationState(\n navId?: number,\n options?: CommitClientNavigationStateOptions,\n): void {\n if (isServer) return;\n const state = getClientNavigationState();\n if (!state) return;\n\n // Only navigation-owned commits may release a render snapshot. Ownerless URL\n // syncs still update committed pathname/search state, but must not consume\n // the active snapshot for an in-flight App Router transition.\n const shouldReleaseSnapshot = navId !== undefined || options?.releaseSnapshot === true;\n if (shouldReleaseSnapshot && state.navigationSnapshotActiveCount > 0) {\n state.navigationSnapshotActiveCount -= 1;\n }\n\n const urlChanged = syncCommittedUrlStateFromLocation();\n if (state.pendingClientParams !== null && state.pendingClientParamsJson !== null) {\n state.clientParams = state.pendingClientParams;\n state.clientParamsJson = state.pendingClientParamsJson;\n state.pendingClientParams = null;\n state.pendingClientParamsJson = null;\n }\n // Clear pending pathname when navigation commits, but only if:\n // - The navId matches the one that set pendingPathname\n // - No newer navigation has overwritten pendingPathname (pendingPathnameNavId === null or matches)\n // - navId is undefined only for non-owning callers, which must not clear\n // pendingPathname for an active navigation.\n const canClearPendingPathname =\n state.pendingPathnameNavId === null ||\n (navId !== undefined && state.pendingPathnameNavId === navId);\n if (canClearPendingPathname) {\n state.pendingPathname = null;\n state.pendingPathnameNavId = null;\n }\n const shouldNotify = urlChanged || state.hasPendingNavigationUpdate;\n state.hasPendingNavigationUpdate = false;\n\n if (shouldNotify) {\n notifyNavigationListeners();\n }\n}\n\nexport function pushHistoryStateWithoutNotify(\n data: unknown,\n unused: string,\n url?: string | URL | null,\n): void {\n withSuppressedUrlNotifications(() => {\n const state = getClientNavigationState();\n state?.originalPushState.call(window.history, data, unused, url);\n });\n}\n\nexport function replaceHistoryStateWithoutNotify(\n data: unknown,\n unused: string,\n url?: string | URL | null,\n): void {\n withSuppressedUrlNotifications(() => {\n const state = getClientNavigationState();\n state?.originalReplaceState.call(window.history, data, unused, url);\n });\n}\n\n/**\n * Save the current scroll position into the current history state.\n * Called before every navigation to enable scroll restoration on back/forward.\n *\n * Uses replaceHistoryStateWithoutNotify to avoid triggering the patched\n * history.replaceState interception (which would cause spurious re-renders).\n */\nfunction saveScrollPosition(): void {\n const state = window.history.state ?? {};\n replaceHistoryStateWithoutNotify(\n { ...state, __vinext_scrollX: window.scrollX, __vinext_scrollY: window.scrollY },\n \"\",\n );\n}\n\n/**\n * Restore scroll position from a history state object (used on popstate).\n *\n * When an RSC navigation is in flight (back/forward triggers both this\n * handler and the browser entry's popstate handler which calls\n * __VINEXT_RSC_NAVIGATE__), we must wait for the new content to render\n * before scrolling. Otherwise the user sees old content flash at the\n * restored scroll position.\n *\n * This handler fires before the browser entry's popstate handler (because\n * navigation.ts is loaded before hydration completes), so we defer via a\n * microtask to give the browser entry handler a chance to set\n * __VINEXT_RSC_PENDING__. Promise.resolve() schedules a microtask\n * that runs after all synchronous event listeners have completed.\n */\nfunction restoreScrollPosition(state: unknown): void {\n if (state && typeof state === \"object\" && \"__vinext_scrollY\" in state) {\n const { __vinext_scrollX: x, __vinext_scrollY: y } = state as {\n __vinext_scrollX: number;\n __vinext_scrollY: number;\n };\n\n // Defer to allow other popstate listeners (browser entry) to run first\n // and set __VINEXT_RSC_PENDING__. Promise.resolve() schedules a microtask\n // that runs after all synchronous event listeners have completed.\n void Promise.resolve().then(() => {\n const pending: Promise<void> | null = window.__VINEXT_RSC_PENDING__ ?? null;\n\n if (pending) {\n // Wait for the RSC navigation to finish rendering, then scroll.\n void pending.then(() => {\n requestAnimationFrame(() => {\n window.scrollTo(x, y);\n });\n });\n } else {\n // No RSC navigation in flight (Pages Router or already settled).\n requestAnimationFrame(() => {\n window.scrollTo(x, y);\n });\n }\n });\n }\n}\n\n/**\n * Navigate to a URL, handling external URLs, hash-only changes, and RSC navigation.\n */\nexport async function navigateClientSide(\n href: string,\n mode: \"push\" | \"replace\",\n scroll: boolean,\n programmaticTransition = false,\n): Promise<void> {\n // Normalize same-origin absolute URLs to local paths for SPA navigation\n let normalizedHref = href;\n if (isExternalUrl(href)) {\n const localPath = toSameOriginAppPath(href, __basePath);\n if (localPath == null) {\n // Truly external: use full page navigation\n if (mode === \"replace\") {\n window.location.replace(href);\n } else {\n window.location.assign(href);\n }\n return;\n }\n normalizedHref = localPath;\n }\n\n const fullHref = toBrowserNavigationHref(normalizedHref, window.location.href, __basePath);\n // Match Next.js: App Router reports navigation start before dispatching,\n // including hash-only navigations that short-circuit after URL update.\n notifyAppRouterTransitionStart(fullHref, mode);\n\n // Save scroll position before navigating (for back/forward restoration)\n if (mode === \"push\") {\n saveScrollPosition();\n }\n\n // Hash-only change: update URL and scroll to target, skip RSC fetch\n if (isHashOnlyChange(fullHref)) {\n const hash = fullHref.includes(\"#\") ? fullHref.slice(fullHref.indexOf(\"#\")) : \"\";\n if (mode === \"replace\") {\n replaceHistoryStateWithoutNotify(null, \"\", fullHref);\n } else {\n pushHistoryStateWithoutNotify(null, \"\", fullHref);\n }\n commitClientNavigationState();\n if (scroll) {\n scrollToHash(hash);\n }\n return;\n }\n\n // Extract hash for post-navigation scrolling\n const hashIdx = fullHref.indexOf(\"#\");\n const hash = hashIdx !== -1 ? fullHref.slice(hashIdx) : \"\";\n\n // Trigger RSC re-fetch if available, and wait for the new content to render\n // before scrolling. This prevents the old page from visibly jumping to the\n // top before the new content paints.\n //\n // History is NOT pushed here for RSC navigations — the commit effect inside\n // navigateRsc owns the push/replace exclusively. This avoids a fragile\n // double-push and ensures window.location still reflects the *current* URL\n // when navigateRsc computes isSameRoute (cross-route vs same-route).\n if (typeof window.__VINEXT_RSC_NAVIGATE__ === \"function\") {\n await window.__VINEXT_RSC_NAVIGATE__(\n fullHref,\n 0,\n \"navigate\",\n mode,\n undefined,\n programmaticTransition,\n );\n } else {\n if (mode === \"replace\") {\n replaceHistoryStateWithoutNotify(null, \"\", fullHref);\n } else {\n pushHistoryStateWithoutNotify(null, \"\", fullHref);\n }\n commitClientNavigationState();\n }\n\n if (scroll) {\n if (hash) {\n scrollToHash(hash);\n } else {\n window.scrollTo(0, 0);\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// App Router router singleton\n//\n// All methods close over module-level state (navigateClientSide, withBasePath, etc.)\n// and carry no per-render data, so the object can be created once and reused.\n// Next.js returns the same router reference on every call to useRouter(), which\n// matters for components that rely on referential equality (e.g. useMemo /\n// useEffect dependency arrays, React.memo bailouts).\n// ---------------------------------------------------------------------------\n\nconst _appRouter = {\n push(href: string, options?: { scroll?: boolean }): void {\n assertSafeNavigationUrl(href);\n if (isServer) return;\n React.startTransition(() => {\n void navigateClientSide(href, \"push\", options?.scroll !== false, true);\n });\n },\n replace(href: string, options?: { scroll?: boolean }): void {\n assertSafeNavigationUrl(href);\n if (isServer) return;\n React.startTransition(() => {\n void navigateClientSide(href, \"replace\", options?.scroll !== false, true);\n });\n },\n back(): void {\n if (isServer) return;\n window.history.back();\n },\n forward(): void {\n if (isServer) return;\n window.history.forward();\n },\n refresh(): void {\n if (isServer) return;\n // Re-fetch the current page's RSC stream\n const rscNavigate = window.__VINEXT_RSC_NAVIGATE__;\n if (typeof rscNavigate === \"function\") {\n const navigate = () => {\n void rscNavigate(window.location.href, 0, \"refresh\", undefined, undefined, true);\n };\n React.startTransition(navigate);\n }\n },\n prefetch(href: string): void {\n assertSafeNavigationUrl(href);\n if (isServer) return;\n // Prefetch the RSC payload for the target route and store in cache.\n // We must add to prefetchedUrls manually for deduplication.\n // prefetchRscResponse only manages the cache Map, not the URL set.\n const fullHref = toBrowserNavigationHref(href, window.location.href, __basePath);\n const rscUrl = toRscUrl(fullHref);\n const interceptionContext = getCurrentInterceptionContext();\n const cacheKey = createAppPayloadCacheKey(rscUrl, interceptionContext);\n const prefetched = getPrefetchedUrls();\n if (prefetched.has(cacheKey)) return;\n prefetched.add(cacheKey);\n const mountedSlotsHeader = getMountedSlotsHeader();\n const headers = new Headers({ Accept: \"text/x-component\" });\n if (mountedSlotsHeader) {\n headers.set(\"X-Vinext-Mounted-Slots\", mountedSlotsHeader);\n }\n if (interceptionContext !== null) {\n headers.set(\"X-Vinext-Interception-Context\", interceptionContext);\n }\n prefetchRscResponse(\n rscUrl,\n fetch(rscUrl, {\n headers,\n credentials: \"include\",\n priority: \"low\" as RequestInit[\"priority\"],\n }),\n interceptionContext,\n mountedSlotsHeader,\n );\n },\n};\n\n/**\n * App Router's useRouter — returns push/replace/back/forward/refresh.\n * Different from Pages Router's useRouter (next/router).\n *\n * Returns a stable singleton: the same object reference on every call,\n * matching Next.js behavior so components using referential equality\n * (e.g. useMemo / useEffect deps, React.memo) don't re-render unnecessarily.\n */\nexport function useRouter() {\n return _appRouter;\n}\n\n/**\n * Returns the active child segment one level below the layout where it's called.\n *\n * Returns the first segment from the route tree below this layout, including\n * route groups (e.g., \"(marketing)\") and resolved dynamic params. Returns null\n * if at the leaf (no child segments).\n *\n * @param parallelRoutesKey - Which parallel route to read (default: \"children\")\n */\nexport function useSelectedLayoutSegment(parallelRoutesKey?: string): string | null {\n const segments = useSelectedLayoutSegments(parallelRoutesKey);\n if (segments.length === 0) return null;\n\n return parallelRoutesKey === undefined || parallelRoutesKey === \"children\"\n ? segments[0]\n : segments[segments.length - 1];\n}\n\n/**\n * Returns all active segments below the layout where it's called.\n *\n * Each layout in the App Router tree wraps its children with a\n * LayoutSegmentProvider whose value is a map of parallel route key to\n * segment arrays. The \"children\" key is the default parallel route.\n *\n * @param parallelRoutesKey - Which parallel route to read (default: \"children\")\n */\nexport function useSelectedLayoutSegments(parallelRoutesKey?: string): string[] {\n return useChildSegments(parallelRoutesKey);\n}\n\nexport { ReadonlyURLSearchParams };\n\n/**\n * useServerInsertedHTML — inject HTML during SSR from client components.\n *\n * Used by CSS-in-JS libraries (styled-components, emotion, StyleX) to inject\n * <style> tags during SSR so styles appear in the initial HTML (no FOUC).\n *\n * The callback is called once after each SSR render pass. The returned JSX/HTML\n * is serialized and injected into the HTML stream.\n *\n * Usage (in a \"use client\" component wrapping children):\n * useServerInsertedHTML(() => {\n * const styles = sheet.getStyleElement();\n * sheet.instance.clearTag();\n * return <>{styles}</>;\n * });\n */\n\nexport function useServerInsertedHTML(callback: () => unknown): void {\n if (typeof document !== \"undefined\") {\n // Client-side: no-op (styles are already in the DOM)\n return;\n }\n _getInsertedHTMLCallbacks().push(callback);\n}\n\n/**\n * Flush all collected useServerInsertedHTML callbacks.\n * Returns an array of results (React elements or strings).\n * Clears the callback list so the next render starts fresh.\n *\n * Called by the SSR entry after renderToReadableStream completes.\n */\nexport function flushServerInsertedHTML(): unknown[] {\n const callbacks = _getInsertedHTMLCallbacks();\n const results: unknown[] = [];\n for (const cb of callbacks) {\n try {\n const result = cb();\n if (result != null) results.push(result);\n } catch {\n // Ignore errors from individual callbacks\n }\n }\n callbacks.length = 0;\n return results;\n}\n\n/**\n * Clear all collected useServerInsertedHTML callbacks without flushing.\n * Used for cleanup between requests.\n */\nexport function clearServerInsertedHTML(): void {\n _clearInsertedHTMLCallbacks();\n}\n\n// ---------------------------------------------------------------------------\n// Non-hook utilities (can be called from Server Components)\n// ---------------------------------------------------------------------------\n\n/**\n * HTTP Access Fallback error code — shared prefix for notFound/forbidden/unauthorized.\n * Matches Next.js 16's unified error handling approach.\n */\nexport const HTTP_ERROR_FALLBACK_ERROR_CODE = \"NEXT_HTTP_ERROR_FALLBACK\";\n\n/**\n * Check if an error is an HTTP Access Fallback error (notFound, forbidden, unauthorized).\n */\nexport function isHTTPAccessFallbackError(error: unknown): boolean {\n if (error && typeof error === \"object\" && \"digest\" in error) {\n const digest = String((error as { digest: unknown }).digest);\n return (\n digest === \"NEXT_NOT_FOUND\" || // legacy compat\n digest.startsWith(`${HTTP_ERROR_FALLBACK_ERROR_CODE};`)\n );\n }\n return false;\n}\n\n/**\n * Extract the HTTP status code from an HTTP Access Fallback error.\n * Returns 404 for legacy NEXT_NOT_FOUND errors.\n */\nexport function getAccessFallbackHTTPStatus(error: unknown): number {\n if (error && typeof error === \"object\" && \"digest\" in error) {\n const digest = String((error as { digest: unknown }).digest);\n if (digest === \"NEXT_NOT_FOUND\") return 404;\n if (digest.startsWith(`${HTTP_ERROR_FALLBACK_ERROR_CODE};`)) {\n return parseInt(digest.split(\";\")[1], 10);\n }\n }\n return 404;\n}\n\n/**\n * Enum matching Next.js RedirectType for type-safe redirect calls.\n */\nexport enum RedirectType {\n push = \"push\",\n replace = \"replace\",\n}\n\n/**\n * Internal error class used by redirect/notFound/forbidden/unauthorized.\n * The `digest` field is the serialised control-flow signal read by the\n * framework's error boundary and server-side request handlers.\n */\nclass VinextNavigationError extends Error {\n readonly digest: string;\n constructor(message: string, digest: string) {\n super(message);\n this.digest = digest;\n }\n}\n\n/**\n * Throw a redirect. Caught by the framework to send a redirect response.\n *\n * When `type` is omitted, the digest carries an empty sentinel so the\n * catch site can resolve the default based on context:\n * - Server Action context → \"push\" (Back button works after form submission)\n * - SSR render context → \"replace\"\n *\n * This matches Next.js behavior where `redirect()` checks\n * `actionAsyncStorage.getStore()?.isAction` at call time.\n *\n * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/redirect.ts\n */\nexport function redirect(url: string, type?: \"replace\" | \"push\" | RedirectType): never {\n throw new VinextNavigationError(\n `NEXT_REDIRECT:${url}`,\n `NEXT_REDIRECT;${type ?? \"\"};${encodeURIComponent(url)}`,\n );\n}\n\n/**\n * Trigger a permanent redirect (308).\n *\n * Accepts an optional `type` parameter matching Next.js's signature.\n * Defaults to \"replace\" (not context-dependent like `redirect()`).\n *\n * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/redirect.ts\n */\nexport function permanentRedirect(\n url: string,\n type: \"replace\" | \"push\" | RedirectType = \"replace\",\n): never {\n throw new VinextNavigationError(\n `NEXT_REDIRECT:${url}`,\n `NEXT_REDIRECT;${type};${encodeURIComponent(url)};308`,\n );\n}\n\n/**\n * Trigger a not-found response (404). Caught by the framework.\n */\nexport function notFound(): never {\n throw new VinextNavigationError(\"NEXT_NOT_FOUND\", `${HTTP_ERROR_FALLBACK_ERROR_CODE};404`);\n}\n\n/**\n * Trigger a forbidden response (403). Caught by the framework.\n * In Next.js, this is gated behind experimental.authInterrupts — we\n * support it unconditionally for maximum compatibility.\n */\nexport function forbidden(): never {\n throw new VinextNavigationError(\"NEXT_FORBIDDEN\", `${HTTP_ERROR_FALLBACK_ERROR_CODE};403`);\n}\n\n/**\n * Trigger an unauthorized response (401). Caught by the framework.\n * In Next.js, this is gated behind experimental.authInterrupts — we\n * support it unconditionally for maximum compatibility.\n */\nexport function unauthorized(): never {\n throw new VinextNavigationError(\"NEXT_UNAUTHORIZED\", `${HTTP_ERROR_FALLBACK_ERROR_CODE};401`);\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n// Listen for popstate on the client\nif (!isServer) {\n const state = getClientNavigationState();\n if (state && !state.patchInstalled) {\n state.patchInstalled = true;\n\n // Listen for popstate on the client.\n // Note: This handler runs for Pages Router only (when __VINEXT_RSC_NAVIGATE__\n // is not available). It restores scroll position with microtask-based deferral.\n // App Router scroll restoration is handled in server/app-browser-entry.ts:697\n // with RSC navigation coordination (waits for pending navigation to settle).\n window.addEventListener(\"popstate\", (event) => {\n if (typeof window.__VINEXT_RSC_NAVIGATE__ !== \"function\") {\n commitClientNavigationState();\n restoreScrollPosition(event.state);\n }\n });\n\n window.history.pushState = function patchedPushState(\n data: unknown,\n unused: string,\n url?: string | URL | null,\n ): void {\n state.originalPushState.call(window.history, data, unused, url);\n if (state.suppressUrlNotifyCount === 0) {\n commitClientNavigationState();\n }\n };\n\n window.history.replaceState = function patchedReplaceState(\n data: unknown,\n unused: string,\n url?: string | URL | null,\n ): void {\n state.originalReplaceState.call(window.history, data, unused, url);\n if (state.suppressUrlNotifyCount === 0) {\n commitClientNavigationState();\n }\n };\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AA4BA,MAAM,0BAA0B,OAAO,IAAI,8BAA8B;AACzE,MAAM,gCAAgC,OAAO,IAAI,mCAAmC;AAiCpF,SAAS,+BAEA;AACP,KAAI,OAAOA,QAAM,kBAAkB,WAAY,QAAO;CAEtD,MAAM,cAAc;AACpB,KAAI,CAAC,YAAY,+BACf,aAAY,iCAAiCA,QAAM,cAEjD,KAAK;AAGT,QAAO,YAAY,kCAAkC;;AAGvD,MAAa,4BAEF,8BAA8B;;;;;AAMzC,SAAgB,0BAA4D;AAC1E,KAAI,OAAOA,QAAM,kBAAkB,WAAY,QAAO;CAEtD,MAAM,cAAc;AACpB,KAAI,CAAC,YAAY,yBACf,aAAY,2BAA2BA,QAAM,cAA0B,EAAE,UAAU,EAAE,EAAE,CAAC;AAG1F,QAAO,YAAY,4BAA4B;;;;;;;AASjD,SAAS,iBAAiB,oBAA4B,YAAsB;CAC1E,MAAM,MAAM,yBAAyB;AACrC,KAAI,CAAC,IAAK,QAAO,EAAE;AAInB,KAAI;AAEF,SADmBA,QAAM,WAAW,IAAI,CACtB,sBAAsB,EAAE;SACpC;AACN,SAAO,EAAE;;;AAeb,MAAM,0BAA0B,OAAO,yCAAyC;AAChF,MAAM,iCAAiC,OAAO,+CAA+C;AAkC7F,MAAa,uBAAuB,OAAO,IAAI,oCAAoC;AACnF,MAAM,wBAAwB;AAO9B,MAAM,gCAD+B,OAAO,IAAI,2CAA2C;AAM3F,SAAS,sBAAmD;AAC1D,QAAQ,WAAoC;;AAG9C,SAAS,6BAAmE;CAC1E,MAAM,cAAc;AACpB,KAAI,OAAO,UAAU,eAAe,KAAK,aAAa,8BAA8B,CAClF,QAAO,YAAY,kCAAkC;;AAKzD,SAAS,2BAA2B,KAAqC;AACtE,YAA2C,iCAAiC;;AAG/E,IAAI,iBAA2C;AAC/C,IAAI,+BAAqD,EAAE;AAI3D,IAAI,0BAAoD;AACtD,KAAI,OAAO,WAAW,aAAa;EACjC,MAAM,mBAAmB,4BAA4B;AACrD,SAAO,qBAAqB,KAAA,IAAY,mBAAmB;;CAE7D,MAAM,IAAI,qBAAqB;AAC/B,QAAO,IAAI,EAAE,kBAAkB,GAAG;;AAEpC,IAAI,qBAAqB,QAAwC;AAC/D,KAAI,OAAO,WAAW,aAAa;AACjC,mBAAiB;AACjB,6BAA2B,IAAI;AAC/B;;CAEF,MAAM,IAAI,qBAAqB;AAC/B,KAAI,EACF,GAAE,iBAAiB,IAAI;KAEvB,kBAAiB;;AAGrB,IAAI,kCAAwD;CAC1D,MAAM,IAAI,qBAAqB;AAC/B,QAAO,IAAI,EAAE,0BAA0B,GAAG;;AAE5C,IAAI,oCAA0C;CAC5C,MAAM,IAAI,qBAAqB;AAC/B,KAAI,EACF,GAAE,4BAA4B;KAE9B,gCAA+B,EAAE;;;;;;AAQrC,SAAgB,wBAAwB,WAAkC;AACxE,qBAAoB,UAAU;AAC9B,qBAAoB,UAAU;AAC9B,6BAA4B,UAAU;AACtC,+BAA8B,UAAU;;;;;;;AAQ1C,SAAgB,uBAAiD;AAC/D,QAAO,mBAAmB;;;;;;AAO5B,SAAgB,qBAAqB,KAAqC;AACxE,mBAAkB,IAAI;;AAOxB,MAAM,WAAW,OAAO,WAAW;;AAGnC,MAAa,aAAqB,QAAQ,IAAI,0BAA0B;;AAOxE,MAAa,0BAA0B;;AAGvC,MAAa,qBAAqB;;;;;;AAsBlC,SAAgB,SAAS,MAAsB;CAC7C,MAAM,CAAC,cAAc,KAAK,MAAM,IAAI;CACpC,MAAM,OAAO,WAAW,QAAQ,IAAI;CACpC,MAAM,WAAW,SAAS,KAAK,aAAa,WAAW,MAAM,GAAG,KAAK;CACrE,MAAM,QAAQ,SAAS,KAAK,KAAK,WAAW,MAAM,KAAK;AAIvD,SADE,SAAS,SAAS,KAAK,SAAS,SAAS,IAAI,GAAG,SAAS,MAAM,GAAG,GAAG,GAAG,YAClD,SAAS;;AAGnC,SAAgB,gCAA+C;AAC7D,KAAI,SACF,QAAO;AAGT,QAAO,cAAc,OAAO,SAAS,UAAU,WAAW;;AAG5D,SAAgB,oBAA4B;AAC1C,KAAI,SACF,QAAO;AAGT,QAAO,OAAO,SAAS,WAAW,OAAO,SAAS;;;AAIpD,SAAgB,mBAAoD;AAClE,KAAI,SAAU,wBAAO,IAAI,KAAK;AAC9B,KAAI,CAAC,OAAO,8BACV,QAAO,gDAAgC,IAAI,KAAiC;AAE9E,QAAO,OAAO;;;;;;AAOhB,SAAgB,oBAAiC;AAC/C,KAAI,SAAU,wBAAO,IAAI,KAAK;AAC9B,KAAI,CAAC,OAAO,+BACV,QAAO,iDAAiC,IAAI,KAAa;AAE3D,QAAO,OAAO;;;;;;AAOhB,SAAS,6BAAmC;CAC1C,MAAM,QAAQ,kBAAkB;AAChC,KAAI,MAAM,OAAA,GAAgC;CAE1C,MAAM,MAAM,KAAK,KAAK;CACtB,MAAM,aAAa,mBAAmB;AAEtC,MAAK,MAAM,CAAC,KAAK,UAAU,MACzB,KAAI,MAAM,MAAM,aAAA,KAAiC;AAC/C,QAAM,OAAO,IAAI;AACjB,aAAW,OAAO,IAAI;;AAI1B,QAAO,MAAM,QAAA,IAAiC;EAC5C,MAAM,SAAS,MAAM,MAAM,CAAC,MAAM,CAAC;AACnC,MAAI,WAAW,KAAA,GAAW;AACxB,SAAM,OAAO,OAAO;AACpB,cAAW,OAAO,OAAO;QAEzB;;;;;;;;;;;;;;;;;;;AAqBN,SAAgB,sBACd,QACA,UACA,sBAAqC,MAC/B;CACN,MAAM,WAAW,yBAAyB,QAAQ,oBAAoB;AACtE,6BAA4B;CAC5B,MAAM,QAA4B,EAAE,WAAW,KAAK,KAAK,EAAE;AAC3D,OAAM,UAAU,oBAAoB,SAAS,CAC1C,MAAM,aAAa;AAClB,QAAM,WAAW;GACjB,CACD,YAAY;AACX,oBAAkB,CAAC,OAAO,SAAS;GACnC,CACD,cAAc;AACb,QAAM,UAAU,KAAA;GAChB;AACJ,mBAAkB,CAAC,IAAI,UAAU,MAAM;;;;;;AAOzC,eAAsB,oBAAoB,UAAgD;AAExF,QAAO;EACL,QAFa,MAAM,SAAS,aAAa;EAGzC,aAAa,SAAS,QAAQ,IAAI,eAAe,IAAI;EACrD,oBAAoB,SAAS,QAAQ,IAAI,yBAAyB;EAClE,cAAc,SAAS,QAAQ,IAAI,kBAAkB;EACrD,KAAK,SAAS;EACf;;;;;;;;;;;;;;;;;AAkBH,SAAgB,mBAAmB,QAA2B,OAAO,MAAgB;CACnF,MAAM,UAAU,IAAI,QAAQ,EAAE,gBAAgB,OAAO,aAAa,CAAC;AACnE,KAAI,OAAO,sBAAsB,KAC/B,SAAQ,IAAI,0BAA0B,OAAO,mBAAmB;AAElE,KAAI,OAAO,gBAAgB,KACzB,SAAQ,IAAI,mBAAmB,OAAO,aAAa;AAGrD,QAAO,IAAI,SAAS,OAAO,OAAO,OAAO,MAAM,EAAE,GAAG,OAAO,QAAQ;EACjE,QAAQ;EACR;EACD,CAAC;;;;;;;;;AAUJ,SAAgB,oBACd,QACA,cACA,sBAAqC,MACrC,qBAAoC,MAC9B;CACN,MAAM,WAAW,yBAAyB,QAAQ,oBAAoB;CACtE,MAAM,QAAQ,kBAAkB;CAChC,MAAM,aAAa,mBAAmB;CAGtC,MAAM,QAA4B,EAAE,WAFxB,KAAK,KAAK,EAE8B;AAEpD,OAAM,UAAU,aACb,KAAK,OAAO,aAAa;AACxB,MAAI,SAAS,GACX,OAAM,WAAW;GACf,GAAI,MAAM,oBAAoB,SAAS;GAGvC;GACD;OACI;AACL,cAAW,OAAO,SAAS;AAC3B,SAAM,OAAO,SAAS;;GAExB,CACD,YAAY;AACX,aAAW,OAAO,SAAS;AAC3B,QAAM,OAAO,SAAS;GACtB,CACD,cAAc;AACb,QAAM,UAAU,KAAA;GAChB;AAKJ,OAAM,IAAI,UAAU,MAAM;AAC1B,6BAA4B;;;;;;;AAQ9B,SAAgB,wBACd,QACA,sBAAqC,MACrC,qBAAoC,MACV;CAC1B,MAAM,WAAW,yBAAyB,QAAQ,oBAAoB;CACtE,MAAM,QAAQ,kBAAkB;CAChC,MAAM,QAAQ,MAAM,IAAI,SAAS;AACjC,KAAI,CAAC,MAAO,QAAO;AAGnB,KAAI,MAAM,QAAS,QAAO;AAE1B,OAAM,OAAO,SAAS;AACtB,oBAAmB,CAAC,OAAO,SAAS;AAEpC,KAAI,MAAM,UAAU;AAClB,OAAK,MAAM,SAAS,sBAAsB,UAAU,mBAGlD,QAAO;AAET,MAAI,KAAK,KAAK,GAAG,MAAM,aAAA,IACrB,QAAO;AAET,SAAO,MAAM;;AAGf,QAAO;;AAST,MAAM,wBAAwB,OAAO,IAAI,+BAA+B;AACxE,MAAM,4BAA4B,OAAO,IAAI,4BAA4B;AA8BzE,SAAgB,sBAAsB,QAA6B;AACjE,KAAI,SAAU;CACd,MAAM,cAAc;AACpB,aAAY,6BAA6B;;AAG3C,SAAgB,wBAAuC;AACrD,KAAI,SAAU,QAAO;AAErB,QADoB,OACD,8BAA8B;;AAGnD,SAAgB,2BAAyD;AACvE,KAAI,SAAU,QAAO;CAErB,MAAM,cAAc;AACpB,aAAY,2BAA2B;EACrC,2BAAW,IAAI,KAAyB;EACxC,cAAc,OAAO,SAAS;EAC9B,4BAA4B,IAAI,wBAAwB,OAAO,SAAS,OAAO;EAC/E,gBAAgB,cAAc,OAAO,SAAS,UAAU,WAAW;EACnE,cAAc,EAAE;EAChB,kBAAkB;EAClB,qBAAqB;EACrB,yBAAyB;EACzB,iBAAiB;EACjB,sBAAsB;EAKtB,mBAAmB,OAAO,QAAQ,UAAU,KAAK,OAAO,QAAQ;EAChE,sBAAsB,OAAO,QAAQ,aAAa,KAAK,OAAO,QAAQ;EACtE,gBAAgB;EAChB,4BAA4B;EAC5B,wBAAwB;EACxB,+BAA+B;EAChC;AAED,QAAO,YAAY;;AAGrB,SAAS,4BAAkC;CACzC,MAAM,QAAQ,0BAA0B;AACxC,KAAI,CAAC,MAAO;AACZ,MAAK,MAAM,MAAM,MAAM,UAAW,KAAI;;AAMxC,IAAI,iCAAiE;;;;;;;;;AAUrE,SAAS,sBAA8B;AACrC,QAAO,0BAA0B,EAAE,kBAAkB;;AAGvD,IAAI,iCAAiE;;;;;;;;;AAUrE,SAAS,0BAAmD;CAC1D,MAAM,SAAS,0BAA0B,EAAE;AAC3C,KAAI,OAAQ,QAAO;AACnB,KAAI,mCAAmC,KACrC,kCAAiC,IAAI,yBAAyB;AAEhE,QAAO;;AAGT,SAAS,oCAA6C;CACpD,MAAM,QAAQ,0BAA0B;AACxC,KAAI,CAAC,MAAO,QAAO;CAEnB,IAAI,UAAU;CAEd,MAAM,WAAW,cAAc,OAAO,SAAS,UAAU,WAAW;AACpE,KAAI,aAAa,MAAM,gBAAgB;AACrC,QAAM,iBAAiB;AACvB,YAAU;;CAGZ,MAAM,SAAS,OAAO,SAAS;AAC/B,KAAI,WAAW,MAAM,cAAc;AACjC,QAAM,eAAe;AACrB,QAAM,6BAA6B,IAAI,wBAAwB,OAAO;AACtE,YAAU;;AAGZ,QAAO;;AAGT,SAAS,gCAAyD;CAChE,MAAM,MAAM,mBAAmB;AAE/B,KAAI,CAAC,KAAK;AAER,MAAI,mCAAmC,KACrC,kCAAiC,IAAI,yBAAyB;AAEhE,SAAO;;CAGT,MAAM,SAAS,IAAI;CACnB,MAAM,SAAS,IAAI;CACnB,MAAM,eAAe,IAAI;AAGzB,KAAI,UAAU,iBAAiB,OAC7B,QAAO;CAIT,MAAM,WAAW,IAAI,wBAAwB,OAAO;AACpD,KAAI,2BAA2B;AAC/B,KAAI,kCAAkC;AAEtC,QAAO;;;;;;;;;AAoBT,SAAgB,6BAAmC;CACjD,MAAM,QAAQ,0BAA0B;AACxC,KAAI,MAAO,OAAM;;AAMnB,MAAM,gBAAmD,EAAE;AAa3D,MAAM,6BAA6B,OAAO,IAAI,uCAAuC;AAKrF,SAAgB,mCAAgG;AAC9G,KAAI,OAAOA,QAAM,kBAAkB,WAAY,QAAO;CAEtD,MAAM,cAAc;AACpB,KAAI,CAAC,YAAY,4BACf,aAAY,8BACVA,QAAM,cAAqD,KAAK;AAGpE,QAAO,YAAY,+BAA+B;;AAIpD,SAAS,oCAA2E;CAClF,MAAM,MAAM,kCAAkC;AAC9C,KAAI,CAAC,OAAO,OAAOA,QAAM,eAAe,WAAY,QAAO;AAC3D,KAAI;AACF,SAAOA,QAAM,WAAW,IAAI;SACtB;AACN,SAAO;;;AAKX,SAAgB,qCACd,MACA,QACgC;CAChC,MAAM,SAAS,OAAO,WAAW,cAAc,OAAO,SAAS,SAAS;CACxE,MAAM,MAAM,IAAI,IAAI,MAAM,OAAO;AAEjC,QAAO;EACL,UAAU,cAAc,IAAI,UAAU,WAAW;EACjD,cAAc,IAAI,wBAAwB,IAAI,OAAO;EACrD;EACD;;AAIH,IAAI,wBAA2D;AAC/D,IAAI,4BAA4B;AAEhC,SAAgB,gBAAgB,QAAiD;CAC/E,MAAM,QAAQ,0BAA0B;AACxC,KAAI,CAAC,OAAO;EACV,MAAM,OAAO,KAAK,UAAU,OAAO;AACnC,MAAI,SAAS,2BAA2B;AACtC,2BAAwB;AACxB,+BAA4B;;AAE9B;;CAGF,MAAM,OAAO,KAAK,UAAU,OAAO;AACnC,KAAI,SAAS,MAAM,kBAAkB;AACnC,QAAM,eAAe;AACrB,QAAM,mBAAmB;AACzB,QAAM,sBAAsB;AAC5B,QAAM,0BAA0B;AAChC,6BAA2B;;;AAI/B,SAAgB,iCAAiC,QAAiD;CAChG,MAAM,QAAQ,0BAA0B;AACxC,KAAI,CAAC,MAAO;CAEZ,MAAM,OAAO,KAAK,UAAU,OAAO;AACnC,KAAI,SAAS,MAAM,oBAAoB,SAAS,MAAM,yBAAyB;AAC7E,QAAM,sBAAsB;AAC5B,QAAM,0BAA0B;AAChC,QAAM,6BAA6B;;;;AAKvC,SAAgB,kBAAqD;AACnE,QAAO,0BAA0B,EAAE,gBAAgB;;;;;;;AAQrD,SAAgB,mBAAmB,UAAkB,OAAqB;CACxE,MAAM,QAAQ,0BAA0B;AACxC,KAAI,CAAC,MAAO;AACZ,OAAM,kBAAkB,cAAc,UAAU,WAAW;AAC3D,OAAM,uBAAuB;;;;;;;AAQ/B,SAAgB,qBAAqB,OAAqB;CACxD,MAAM,QAAQ,0BAA0B;AACxC,KAAI,CAAC,MAAO;AAGZ,KAAI,MAAM,yBAAyB,QAAQ,MAAM,yBAAyB,OAAO;AAC/E,QAAM,kBAAkB;AACxB,QAAM,uBAAuB;;;AAIjC,SAAS,0BAA6D;AACpE,QAAO,0BAA0B,EAAE,gBAAgB;;AAGrD,SAAS,0BAA6D;AACpE,QAAO,mBAAmB,EAAE,UAAU;;AAGxC,SAAS,sBAAsB,IAA4B;CACzD,MAAM,QAAQ,0BAA0B;AACxC,KAAI,CAAC,MAAO,cAAa;AAEzB,OAAM,UAAU,IAAI,GAAG;AACvB,cAAa;AACX,QAAM,UAAU,OAAO,GAAG;;;;;;;AAS9B,SAAgB,cAAsB;AACpC,KAAI,SAGF,QAAO,mBAAmB,EAAE,YAAY;CAE1C,MAAM,iBAAiB,mCAAmC;CAE1D,MAAM,WAAWA,QAAM,qBACrB,uBACA,2BACM,mBAAmB,EAAE,YAAY,IACxC;AAKD,KAAI,mBAAmB,0BAA0B,EAAE,iCAAiC,KAAK,EACvF,QAAO,eAAe;AAExB,QAAO;;;;;AAQT,SAAgB,kBAA2C;AACzD,KAAI,SAGF,QAAO,+BAA+B;CAExC,MAAM,iBAAiB,mCAAmC;CAC1D,MAAM,eAAeA,QAAM,qBACzB,uBACA,yBACA,8BACD;AACD,KAAI,mBAAmB,0BAA0B,EAAE,iCAAiC,KAAK,EACvF,QAAO,eAAe;AAExB,QAAO;;;;;AAQT,SAAgB,YAET;AACL,KAAI,SAEF,QAAQ,mBAAmB,EAAE,UAAU;CAEzC,MAAM,iBAAiB,mCAAmC;CAC1D,MAAM,SAASA,QAAM,qBACnB,uBACA,yBACA,wBACD;AACD,KAAI,mBAAmB,0BAA0B,EAAE,iCAAiC,KAAK,EACvF,QAAO,eAAe;AAExB,QAAO;;;;;AAOT,SAAS,cAAc,MAAuB;AAC5C,QAAO,uBAAuB,KAAK,KAAK,IAAI,KAAK,WAAW,KAAK;;;;;AAMnE,SAAS,iBAAiB,MAAuB;AAC/C,KAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,KAAI,KAAK,WAAW,IAAI,CAAE,QAAO;AACjC,KAAI;EACF,MAAM,UAAU,IAAI,IAAI,OAAO,SAAS,KAAK;EAC7C,MAAM,OAAO,IAAI,IAAI,MAAM,OAAO,SAAS,KAAK;AAKhD,SAF4B,cAAc,QAAQ,UAAU,WAAW,KAC9C,cAAc,KAAK,UAAU,WAAW,IAEnB,QAAQ,WAAW,KAAK,UAAU,KAAK,SAAS;SAExF;AACN,SAAO;;;;;;AAOX,SAAS,aAAa,MAAoB;AACxC,KAAI,CAAC,QAAQ,SAAS,KAAK;AACzB,SAAO,SAAS,GAAG,EAAE;AACrB;;CAEF,MAAM,KAAK,KAAK,MAAM,EAAE;CACxB,MAAM,UAAU,SAAS,eAAe,GAAG;AAC3C,KAAI,QACF,SAAQ,eAAe,EAAE,UAAU,QAAQ,CAAC;;AAQhD,SAAS,+BAAkC,IAAgB;CACzD,MAAM,QAAQ,0BAA0B;AACxC,KAAI,CAAC,MACH,QAAO,IAAI;AAGb,OAAM,0BAA0B;AAChC,KAAI;AACF,SAAO,IAAI;WACH;AACR,QAAM,0BAA0B;;;;;;;;;;;AAYpC,SAAgB,4BACd,OACA,SACM;AACN,KAAI,SAAU;CACd,MAAM,QAAQ,0BAA0B;AACxC,KAAI,CAAC,MAAO;AAMZ,MAD8B,UAAU,KAAA,KAAa,SAAS,oBAAoB,SACrD,MAAM,gCAAgC,EACjE,OAAM,iCAAiC;CAGzC,MAAM,aAAa,mCAAmC;AACtD,KAAI,MAAM,wBAAwB,QAAQ,MAAM,4BAA4B,MAAM;AAChF,QAAM,eAAe,MAAM;AAC3B,QAAM,mBAAmB,MAAM;AAC/B,QAAM,sBAAsB;AAC5B,QAAM,0BAA0B;;AAUlC,KAFE,MAAM,yBAAyB,QAC9B,UAAU,KAAA,KAAa,MAAM,yBAAyB,OAC5B;AAC3B,QAAM,kBAAkB;AACxB,QAAM,uBAAuB;;CAE/B,MAAM,eAAe,cAAc,MAAM;AACzC,OAAM,6BAA6B;AAEnC,KAAI,aACF,4BAA2B;;AAI/B,SAAgB,8BACd,MACA,QACA,KACM;AACN,sCAAqC;AACrB,4BAA0B,EACjC,kBAAkB,KAAK,OAAO,SAAS,MAAM,QAAQ,IAAI;GAChE;;AAGJ,SAAgB,iCACd,MACA,QACA,KACM;AACN,sCAAqC;AACrB,4BAA0B,EACjC,qBAAqB,KAAK,OAAO,SAAS,MAAM,QAAQ,IAAI;GACnE;;;;;;;;;AAUJ,SAAS,qBAA2B;AAElC,kCACE;EAAE,GAFU,OAAO,QAAQ,SAAS,EAAE;EAE1B,kBAAkB,OAAO;EAAS,kBAAkB,OAAO;EAAS,EAChF,GACD;;;;;;;;;;;;;;;;;AAkBH,SAAS,sBAAsB,OAAsB;AACnD,KAAI,SAAS,OAAO,UAAU,YAAY,sBAAsB,OAAO;EACrE,MAAM,EAAE,kBAAkB,GAAG,kBAAkB,MAAM;AAQhD,UAAQ,SAAS,CAAC,WAAW;GAChC,MAAM,UAAgC,OAAO,0BAA0B;AAEvE,OAAI,QAEG,SAAQ,WAAW;AACtB,gCAA4B;AAC1B,YAAO,SAAS,GAAG,EAAE;MACrB;KACF;OAGF,6BAA4B;AAC1B,WAAO,SAAS,GAAG,EAAE;KACrB;IAEJ;;;;;;AAON,eAAsB,mBACpB,MACA,MACA,QACA,yBAAyB,OACV;CAEf,IAAI,iBAAiB;AACrB,KAAI,cAAc,KAAK,EAAE;EACvB,MAAM,YAAY,oBAAoB,MAAM,WAAW;AACvD,MAAI,aAAa,MAAM;AAErB,OAAI,SAAS,UACX,QAAO,SAAS,QAAQ,KAAK;OAE7B,QAAO,SAAS,OAAO,KAAK;AAE9B;;AAEF,mBAAiB;;CAGnB,MAAM,WAAW,wBAAwB,gBAAgB,OAAO,SAAS,MAAM,WAAW;AAG1F,gCAA+B,UAAU,KAAK;AAG9C,KAAI,SAAS,OACX,qBAAoB;AAItB,KAAI,iBAAiB,SAAS,EAAE;EAC9B,MAAM,OAAO,SAAS,SAAS,IAAI,GAAG,SAAS,MAAM,SAAS,QAAQ,IAAI,CAAC,GAAG;AAC9E,MAAI,SAAS,UACX,kCAAiC,MAAM,IAAI,SAAS;MAEpD,+BAA8B,MAAM,IAAI,SAAS;AAEnD,+BAA6B;AAC7B,MAAI,OACF,cAAa,KAAK;AAEpB;;CAIF,MAAM,UAAU,SAAS,QAAQ,IAAI;CACrC,MAAM,OAAO,YAAY,KAAK,SAAS,MAAM,QAAQ,GAAG;AAUxD,KAAI,OAAO,OAAO,4BAA4B,WAC5C,OAAM,OAAO,wBACX,UACA,GACA,YACA,MACA,KAAA,GACA,uBACD;MACI;AACL,MAAI,SAAS,UACX,kCAAiC,MAAM,IAAI,SAAS;MAEpD,+BAA8B,MAAM,IAAI,SAAS;AAEnD,+BAA6B;;AAG/B,KAAI,OACF,KAAI,KACF,cAAa,KAAK;KAElB,QAAO,SAAS,GAAG,EAAE;;AAe3B,MAAM,aAAa;CACjB,KAAK,MAAc,SAAsC;AACvD,0BAAwB,KAAK;AAC7B,MAAI,SAAU;AACd,UAAM,sBAAsB;AACrB,sBAAmB,MAAM,QAAQ,SAAS,WAAW,OAAO,KAAK;IACtE;;CAEJ,QAAQ,MAAc,SAAsC;AAC1D,0BAAwB,KAAK;AAC7B,MAAI,SAAU;AACd,UAAM,sBAAsB;AACrB,sBAAmB,MAAM,WAAW,SAAS,WAAW,OAAO,KAAK;IACzE;;CAEJ,OAAa;AACX,MAAI,SAAU;AACd,SAAO,QAAQ,MAAM;;CAEvB,UAAgB;AACd,MAAI,SAAU;AACd,SAAO,QAAQ,SAAS;;CAE1B,UAAgB;AACd,MAAI,SAAU;EAEd,MAAM,cAAc,OAAO;AAC3B,MAAI,OAAO,gBAAgB,YAAY;GACrC,MAAM,iBAAiB;AAChB,gBAAY,OAAO,SAAS,MAAM,GAAG,WAAW,KAAA,GAAW,KAAA,GAAW,KAAK;;AAElF,WAAM,gBAAgB,SAAS;;;CAGnC,SAAS,MAAoB;AAC3B,0BAAwB,KAAK;AAC7B,MAAI,SAAU;EAKd,MAAM,SAAS,SADE,wBAAwB,MAAM,OAAO,SAAS,MAAM,WAAW,CAC/C;EACjC,MAAM,sBAAsB,+BAA+B;EAC3D,MAAM,WAAW,yBAAyB,QAAQ,oBAAoB;EACtE,MAAM,aAAa,mBAAmB;AACtC,MAAI,WAAW,IAAI,SAAS,CAAE;AAC9B,aAAW,IAAI,SAAS;EACxB,MAAM,qBAAqB,uBAAuB;EAClD,MAAM,UAAU,IAAI,QAAQ,EAAE,QAAQ,oBAAoB,CAAC;AAC3D,MAAI,mBACF,SAAQ,IAAI,0BAA0B,mBAAmB;AAE3D,MAAI,wBAAwB,KAC1B,SAAQ,IAAI,iCAAiC,oBAAoB;AAEnE,sBACE,QACA,MAAM,QAAQ;GACZ;GACA,aAAa;GACb,UAAU;GACX,CAAC,EACF,qBACA,mBACD;;CAEJ;;;;;;;;;AAUD,SAAgB,YAAY;AAC1B,QAAO;;;;;;;;;;;AAYT,SAAgB,yBAAyB,mBAA2C;CAClF,MAAM,WAAW,0BAA0B,kBAAkB;AAC7D,KAAI,SAAS,WAAW,EAAG,QAAO;AAElC,QAAO,sBAAsB,KAAA,KAAa,sBAAsB,aAC5D,SAAS,KACT,SAAS,SAAS,SAAS;;;;;;;;;;;AAYjC,SAAgB,0BAA0B,mBAAsC;AAC9E,QAAO,iBAAiB,kBAAkB;;;;;;;;;;;;;;;;;;AAsB5C,SAAgB,sBAAsB,UAA+B;AACnE,KAAI,OAAO,aAAa,YAEtB;AAEF,4BAA2B,CAAC,KAAK,SAAS;;;;;;;;;AAU5C,SAAgB,0BAAqC;CACnD,MAAM,YAAY,2BAA2B;CAC7C,MAAM,UAAqB,EAAE;AAC7B,MAAK,MAAM,MAAM,UACf,KAAI;EACF,MAAM,SAAS,IAAI;AACnB,MAAI,UAAU,KAAM,SAAQ,KAAK,OAAO;SAClC;AAIV,WAAU,SAAS;AACnB,QAAO;;;;;;AAOT,SAAgB,0BAAgC;AAC9C,8BAA6B;;;;;;AAW/B,MAAa,iCAAiC;;;;AAK9C,SAAgB,0BAA0B,OAAyB;AACjE,KAAI,SAAS,OAAO,UAAU,YAAY,YAAY,OAAO;EAC3D,MAAM,SAAS,OAAQ,MAA8B,OAAO;AAC5D,SACE,WAAW,oBACX,OAAO,WAAW,4BAAqC;;AAG3D,QAAO;;;;;;AAOT,SAAgB,4BAA4B,OAAwB;AAClE,KAAI,SAAS,OAAO,UAAU,YAAY,YAAY,OAAO;EAC3D,MAAM,SAAS,OAAQ,MAA8B,OAAO;AAC5D,MAAI,WAAW,iBAAkB,QAAO;AACxC,MAAI,OAAO,WAAW,4BAAqC,CACzD,QAAO,SAAS,OAAO,MAAM,IAAI,CAAC,IAAI,GAAG;;AAG7C,QAAO;;;;;AAMT,IAAY,eAAL,yBAAA,cAAA;AACL,cAAA,UAAA;AACA,cAAA,aAAA;;KACD;;;;;;AAOD,IAAM,wBAAN,cAAoC,MAAM;CACxC;CACA,YAAY,SAAiB,QAAgB;AAC3C,QAAM,QAAQ;AACd,OAAK,SAAS;;;;;;;;;;;;;;;;AAiBlB,SAAgB,SAAS,KAAa,MAAiD;AACrF,OAAM,IAAI,sBACR,iBAAiB,OACjB,iBAAiB,QAAQ,GAAG,GAAG,mBAAmB,IAAI,GACvD;;;;;;;;;;AAWH,SAAgB,kBACd,KACA,OAA0C,WACnC;AACP,OAAM,IAAI,sBACR,iBAAiB,OACjB,iBAAiB,KAAK,GAAG,mBAAmB,IAAI,CAAC,MAClD;;;;;AAMH,SAAgB,WAAkB;AAChC,OAAM,IAAI,sBAAsB,kBAAkB,GAAG,+BAA+B,MAAM;;;;;;;AAQ5F,SAAgB,YAAmB;AACjC,OAAM,IAAI,sBAAsB,kBAAkB,GAAG,+BAA+B,MAAM;;;;;;;AAQ5F,SAAgB,eAAsB;AACpC,OAAM,IAAI,sBAAsB,qBAAqB,GAAG,+BAA+B,MAAM;;AAQ/F,IAAI,CAAC,UAAU;CACb,MAAM,QAAQ,0BAA0B;AACxC,KAAI,SAAS,CAAC,MAAM,gBAAgB;AAClC,QAAM,iBAAiB;AAOvB,SAAO,iBAAiB,aAAa,UAAU;AAC7C,OAAI,OAAO,OAAO,4BAA4B,YAAY;AACxD,iCAA6B;AAC7B,0BAAsB,MAAM,MAAM;;IAEpC;AAEF,SAAO,QAAQ,YAAY,SAAS,iBAClC,MACA,QACA,KACM;AACN,SAAM,kBAAkB,KAAK,OAAO,SAAS,MAAM,QAAQ,IAAI;AAC/D,OAAI,MAAM,2BAA2B,EACnC,8BAA6B;;AAIjC,SAAO,QAAQ,eAAe,SAAS,oBACrC,MACA,QACA,KACM;AACN,SAAM,qBAAqB,KAAK,OAAO,SAAS,MAAM,QAAQ,IAAI;AAClE,OAAI,MAAM,2BAA2B,EACnC,8BAA6B"}
|
package/dist/shims/server.d.ts
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
declare class NextRequest extends Request {
|
|
13
13
|
private _nextUrl;
|
|
14
|
+
private _url;
|
|
14
15
|
private _cookies;
|
|
15
16
|
constructor(input: URL | RequestInfo, init?: RequestInit & {
|
|
16
17
|
nextConfig?: {
|
|
@@ -22,6 +23,7 @@ declare class NextRequest extends Request {
|
|
|
22
23
|
};
|
|
23
24
|
});
|
|
24
25
|
get nextUrl(): NextURL;
|
|
26
|
+
get url(): string;
|
|
25
27
|
get cookies(): RequestCookies;
|
|
26
28
|
/**
|
|
27
29
|
* Client IP address. Prefers Cloudflare's trusted CF-Connecting-IP header
|