vinext 0.0.38 → 0.0.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. package/README.md +33 -20
  2. package/dist/build/nitro-route-rules.d.ts +50 -0
  3. package/dist/build/nitro-route-rules.js +81 -0
  4. package/dist/build/nitro-route-rules.js.map +1 -0
  5. package/dist/build/precompress.d.ts +17 -0
  6. package/dist/build/precompress.js +102 -0
  7. package/dist/build/precompress.js.map +1 -0
  8. package/dist/build/prerender.d.ts +27 -22
  9. package/dist/build/prerender.js +17 -17
  10. package/dist/build/prerender.js.map +1 -1
  11. package/dist/build/report.d.ts +3 -4
  12. package/dist/build/report.js.map +1 -1
  13. package/dist/build/run-prerender.d.ts +3 -4
  14. package/dist/build/run-prerender.js.map +1 -1
  15. package/dist/build/standalone.d.ts +32 -0
  16. package/dist/build/standalone.js +199 -0
  17. package/dist/build/standalone.js.map +1 -0
  18. package/dist/build/static-export.d.ts +17 -29
  19. package/dist/build/static-export.js.map +1 -1
  20. package/dist/check.d.ts +4 -4
  21. package/dist/check.js +1 -1
  22. package/dist/check.js.map +1 -1
  23. package/dist/cli.js +31 -4
  24. package/dist/cli.js.map +1 -1
  25. package/dist/client/instrumentation-client.d.ts +2 -2
  26. package/dist/client/instrumentation-client.js.map +1 -1
  27. package/dist/client/vinext-next-data.d.ts +5 -8
  28. package/dist/cloudflare/index.js +1 -1
  29. package/dist/cloudflare/kv-cache-handler.d.ts +5 -3
  30. package/dist/cloudflare/kv-cache-handler.js +1 -1
  31. package/dist/cloudflare/kv-cache-handler.js.map +1 -1
  32. package/dist/cloudflare/tpr.d.ts +35 -27
  33. package/dist/cloudflare/tpr.js +36 -12
  34. package/dist/cloudflare/tpr.js.map +1 -1
  35. package/dist/config/config-matchers.d.ts +2 -2
  36. package/dist/config/config-matchers.js +1 -1
  37. package/dist/config/config-matchers.js.map +1 -1
  38. package/dist/config/dotenv.d.ts +4 -4
  39. package/dist/config/dotenv.js.map +1 -1
  40. package/dist/config/next-config.d.ts +40 -61
  41. package/dist/config/next-config.js +5 -4
  42. package/dist/config/next-config.js.map +1 -1
  43. package/dist/deploy.d.ts +25 -41
  44. package/dist/deploy.js +1 -1
  45. package/dist/deploy.js.map +1 -1
  46. package/dist/entries/app-rsc-entry.d.ts +6 -10
  47. package/dist/entries/app-rsc-entry.js +4 -6
  48. package/dist/entries/app-rsc-entry.js.map +1 -1
  49. package/dist/entries/pages-server-entry.js +1 -3
  50. package/dist/entries/pages-server-entry.js.map +1 -1
  51. package/dist/index.d.ts +23 -33
  52. package/dist/index.js +165 -84
  53. package/dist/index.js.map +1 -1
  54. package/dist/init.d.ts +14 -26
  55. package/dist/init.js +8 -2
  56. package/dist/init.js.map +1 -1
  57. package/dist/plugins/client-reference-dedup.js.map +1 -1
  58. package/dist/plugins/fix-use-server-closure-collision.js.map +1 -1
  59. package/dist/plugins/fonts.d.ts +18 -1
  60. package/dist/plugins/fonts.js +107 -8
  61. package/dist/plugins/fonts.js.map +1 -1
  62. package/dist/plugins/optimize-imports.d.ts +2 -2
  63. package/dist/plugins/optimize-imports.js +4 -4
  64. package/dist/plugins/optimize-imports.js.map +1 -1
  65. package/dist/plugins/server-externals-manifest.d.ts +27 -0
  66. package/dist/plugins/server-externals-manifest.js +76 -0
  67. package/dist/plugins/server-externals-manifest.js.map +1 -0
  68. package/dist/routing/app-router.d.ts +29 -55
  69. package/dist/routing/app-router.js.map +1 -1
  70. package/dist/routing/file-matcher.d.ts +2 -2
  71. package/dist/routing/file-matcher.js.map +1 -1
  72. package/dist/routing/pages-router.d.ts +6 -11
  73. package/dist/routing/pages-router.js.map +1 -1
  74. package/dist/routing/route-trie.d.ts +2 -2
  75. package/dist/routing/route-trie.js.map +1 -1
  76. package/dist/server/api-handler.js.map +1 -1
  77. package/dist/server/app-browser-entry.js +270 -39
  78. package/dist/server/app-browser-entry.js.map +1 -1
  79. package/dist/server/app-browser-stream.d.ts +6 -6
  80. package/dist/server/app-browser-stream.js.map +1 -1
  81. package/dist/server/app-page-boundary-render.d.ts +8 -8
  82. package/dist/server/app-page-boundary-render.js +2 -2
  83. package/dist/server/app-page-boundary-render.js.map +1 -1
  84. package/dist/server/app-page-boundary.d.ts +13 -11
  85. package/dist/server/app-page-boundary.js +1 -1
  86. package/dist/server/app-page-boundary.js.map +1 -1
  87. package/dist/server/app-page-cache.d.ts +10 -10
  88. package/dist/server/app-page-cache.js.map +1 -1
  89. package/dist/server/app-page-execution.d.ts +10 -10
  90. package/dist/server/app-page-execution.js.map +1 -1
  91. package/dist/server/app-page-probe.d.ts +2 -2
  92. package/dist/server/app-page-probe.js.map +1 -1
  93. package/dist/server/app-page-render.d.ts +4 -4
  94. package/dist/server/app-page-render.js.map +1 -1
  95. package/dist/server/app-page-request.d.ts +12 -12
  96. package/dist/server/app-page-request.js.map +1 -1
  97. package/dist/server/app-page-response.d.ts +18 -18
  98. package/dist/server/app-page-response.js.map +1 -1
  99. package/dist/server/app-page-stream.d.ts +18 -18
  100. package/dist/server/app-page-stream.js.map +1 -1
  101. package/dist/server/app-route-handler-cache.d.ts +2 -2
  102. package/dist/server/app-route-handler-cache.js.map +1 -1
  103. package/dist/server/app-route-handler-execution.d.ts +6 -6
  104. package/dist/server/app-route-handler-execution.js.map +1 -1
  105. package/dist/server/app-route-handler-policy.d.ts +8 -8
  106. package/dist/server/app-route-handler-policy.js.map +1 -1
  107. package/dist/server/app-route-handler-response.d.ts +6 -6
  108. package/dist/server/app-route-handler-response.js.map +1 -1
  109. package/dist/server/app-route-handler-runtime.d.ts +4 -4
  110. package/dist/server/app-route-handler-runtime.js.map +1 -1
  111. package/dist/server/app-ssr-entry.d.ts +4 -4
  112. package/dist/server/app-ssr-entry.js.map +1 -1
  113. package/dist/server/app-ssr-stream.d.ts +2 -2
  114. package/dist/server/app-ssr-stream.js +1 -3
  115. package/dist/server/app-ssr-stream.js.map +1 -1
  116. package/dist/server/dev-module-runner.d.ts +2 -2
  117. package/dist/server/dev-module-runner.js.map +1 -1
  118. package/dist/server/dev-server.js +5 -7
  119. package/dist/server/dev-server.js.map +1 -1
  120. package/dist/server/image-optimization.d.ts +7 -12
  121. package/dist/server/image-optimization.js.map +1 -1
  122. package/dist/server/instrumentation.d.ts +8 -12
  123. package/dist/server/instrumentation.js +1 -1
  124. package/dist/server/instrumentation.js.map +1 -1
  125. package/dist/server/isr-cache.d.ts +2 -2
  126. package/dist/server/isr-cache.js.map +1 -1
  127. package/dist/server/metadata-routes.d.ts +14 -19
  128. package/dist/server/metadata-routes.js.map +1 -1
  129. package/dist/server/middleware.d.ts +9 -17
  130. package/dist/server/middleware.js +1 -1
  131. package/dist/server/middleware.js.map +1 -1
  132. package/dist/server/pages-api-route.d.ts +6 -6
  133. package/dist/server/pages-api-route.js.map +1 -1
  134. package/dist/server/pages-i18n.d.ts +4 -4
  135. package/dist/server/pages-i18n.js.map +1 -1
  136. package/dist/server/pages-node-compat.d.ts +10 -10
  137. package/dist/server/pages-node-compat.js.map +1 -1
  138. package/dist/server/pages-page-data.d.ts +22 -22
  139. package/dist/server/pages-page-data.js.map +1 -1
  140. package/dist/server/pages-page-response.d.ts +8 -8
  141. package/dist/server/pages-page-response.js.map +1 -1
  142. package/dist/server/prod-server.d.ts +20 -15
  143. package/dist/server/prod-server.js +170 -53
  144. package/dist/server/prod-server.js.map +1 -1
  145. package/dist/server/seed-cache.js.map +1 -1
  146. package/dist/server/static-file-cache.d.ts +57 -0
  147. package/dist/server/static-file-cache.js +219 -0
  148. package/dist/server/static-file-cache.js.map +1 -0
  149. package/dist/shims/app.d.ts +2 -2
  150. package/dist/shims/cache-runtime.d.ts +6 -9
  151. package/dist/shims/cache-runtime.js.map +1 -1
  152. package/dist/shims/cache.d.ts +28 -31
  153. package/dist/shims/cache.js.map +1 -1
  154. package/dist/shims/config.d.ts +2 -2
  155. package/dist/shims/config.js.map +1 -1
  156. package/dist/shims/dynamic.d.ts +2 -2
  157. package/dist/shims/dynamic.js +5 -7
  158. package/dist/shims/dynamic.js.map +1 -1
  159. package/dist/shims/error-boundary.d.ts +7 -7
  160. package/dist/shims/error-boundary.js.map +1 -1
  161. package/dist/shims/error.d.ts +2 -2
  162. package/dist/shims/error.js.map +1 -1
  163. package/dist/shims/fetch-cache.d.ts +4 -4
  164. package/dist/shims/fetch-cache.js.map +1 -1
  165. package/dist/shims/font-google-base.d.ts +4 -4
  166. package/dist/shims/font-google-base.js.map +1 -1
  167. package/dist/shims/font-local.d.ts +6 -6
  168. package/dist/shims/font-local.js.map +1 -1
  169. package/dist/shims/form.d.ts +4 -8
  170. package/dist/shims/form.js +4 -6
  171. package/dist/shims/form.js.map +1 -1
  172. package/dist/shims/head-state.d.ts +2 -2
  173. package/dist/shims/head-state.js.map +1 -1
  174. package/dist/shims/head.d.ts +2 -2
  175. package/dist/shims/head.js +18 -20
  176. package/dist/shims/head.js.map +1 -1
  177. package/dist/shims/headers.d.ts +4 -4
  178. package/dist/shims/headers.js.map +1 -1
  179. package/dist/shims/i18n-context.d.ts +2 -2
  180. package/dist/shims/i18n-context.js.map +1 -1
  181. package/dist/shims/i18n-state.d.ts +2 -2
  182. package/dist/shims/i18n-state.js.map +1 -1
  183. package/dist/shims/image-config.d.ts +2 -2
  184. package/dist/shims/image-config.js.map +1 -1
  185. package/dist/shims/image.d.ts +5 -6
  186. package/dist/shims/image.js.map +1 -1
  187. package/dist/shims/internal/app-router-context.d.ts +6 -6
  188. package/dist/shims/internal/app-router-context.js.map +1 -1
  189. package/dist/shims/internal/utils.d.ts +2 -2
  190. package/dist/shims/internal/utils.js.map +1 -1
  191. package/dist/shims/layout-segment-context.d.ts +12 -5
  192. package/dist/shims/layout-segment-context.js +9 -4
  193. package/dist/shims/layout-segment-context.js.map +1 -1
  194. package/dist/shims/legacy-image.d.ts +5 -8
  195. package/dist/shims/legacy-image.js.map +1 -1
  196. package/dist/shims/link.d.ts +21 -31
  197. package/dist/shims/link.js +4 -58
  198. package/dist/shims/link.js.map +1 -1
  199. package/dist/shims/metadata.d.ts +23 -31
  200. package/dist/shims/metadata.js.map +1 -1
  201. package/dist/shims/navigation-state.d.ts +2 -2
  202. package/dist/shims/navigation-state.js.map +1 -1
  203. package/dist/shims/navigation.d.ts +102 -17
  204. package/dist/shims/navigation.js +359 -113
  205. package/dist/shims/navigation.js.map +1 -1
  206. package/dist/shims/request-context.d.ts +2 -2
  207. package/dist/shims/request-context.js.map +1 -1
  208. package/dist/shims/router-state.d.ts +4 -4
  209. package/dist/shims/router-state.js.map +1 -1
  210. package/dist/shims/router.d.ts +28 -47
  211. package/dist/shims/router.js.map +1 -1
  212. package/dist/shims/script.d.ts +16 -31
  213. package/dist/shims/script.js.map +1 -1
  214. package/dist/shims/server.d.ts +10 -10
  215. package/dist/shims/server.js.map +1 -1
  216. package/dist/shims/unified-request-context.d.ts +3 -5
  217. package/dist/shims/unified-request-context.js.map +1 -1
  218. package/dist/shims/web-vitals.d.ts +2 -2
  219. package/dist/shims/web-vitals.js.map +1 -1
  220. package/dist/utils/lazy-chunks.d.ts +34 -0
  221. package/dist/utils/lazy-chunks.js +50 -0
  222. package/dist/utils/lazy-chunks.js.map +1 -0
  223. package/dist/utils/vinext-root.d.ts +24 -0
  224. package/dist/utils/vinext-root.js +31 -0
  225. package/dist/utils/vinext-root.js.map +1 -0
  226. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"image.js","names":["UnpicImage"],"sources":["../../src/shims/image.tsx"],"sourcesContent":["/**\n * next/image shim\n *\n * Translates Next.js Image props to @unpic/react Image component.\n * @unpic/react auto-detects CDN from URL and uses native transforms.\n * For local images (relative paths), routes through `/_vinext/image`\n * for server-side optimization (resize, format negotiation, quality).\n *\n * Remote images are validated against `images.remotePatterns` and\n * `images.domains` from next.config.js. Unmatched URLs are blocked\n * in production and warn in development, matching Next.js behavior.\n */\nimport React, { forwardRef } from \"react\";\nimport { Image as UnpicImage } from \"@unpic/react\";\nimport { hasRemoteMatch, type RemotePattern } from \"./image-config.js\";\n\nexport interface StaticImageData {\n src: string;\n height: number;\n width: number;\n blurDataURL?: string;\n}\n\n/**\n * Image config injected at build time via Vite define.\n * Serialized as JSON — parsed once at module level.\n */\nconst __imageRemotePatterns: RemotePattern[] = (() => {\n try {\n return JSON.parse(process.env.__VINEXT_IMAGE_REMOTE_PATTERNS ?? \"[]\");\n } catch {\n return [];\n }\n})();\nconst __imageDomains: string[] = (() => {\n try {\n return JSON.parse(process.env.__VINEXT_IMAGE_DOMAINS ?? \"[]\");\n } catch {\n return [];\n }\n})();\nconst __hasImageConfig = __imageRemotePatterns.length > 0 || __imageDomains.length > 0;\nconst __isDev = process.env.NODE_ENV !== \"production\";\nconst __imageDeviceSizes: number[] = (() => {\n try {\n return JSON.parse(\n process.env.__VINEXT_IMAGE_DEVICE_SIZES ?? \"[640,750,828,1080,1200,1920,2048,3840]\",\n );\n } catch {\n return [640, 750, 828, 1080, 1200, 1920, 2048, 3840];\n }\n})();\n/**\n * Whether dangerouslyAllowSVG is enabled in next.config.js.\n * When false (default), .svg sources auto-skip the optimization endpoint\n * and are served directly, matching Next.js behavior.\n * When true, .svg sources are routed through the optimizer (served as-is\n * with security headers).\n */\nconst __dangerouslyAllowSVG = process.env.__VINEXT_IMAGE_DANGEROUSLY_ALLOW_SVG === \"true\";\n/**\n * Validate that a remote URL is allowed by the configured remote patterns.\n * Returns true if the URL is allowed, false otherwise.\n *\n * When no remotePatterns/domains are configured, all remote URLs are allowed\n * (backwards-compatible — user hasn't opted into restriction).\n *\n * When patterns ARE configured, only matching URLs are allowed.\n * In development, non-matching URLs produce a console warning.\n * In production, non-matching URLs are blocked (src replaced with empty string).\n */\nfunction validateRemoteUrl(src: string): { allowed: boolean; reason?: string } {\n if (!__hasImageConfig) {\n // No image config — allow everything (backwards-compatible)\n return { allowed: true };\n }\n\n let url: URL;\n try {\n url = new URL(src, \"http://n\");\n } catch {\n return { allowed: false, reason: `Invalid URL: ${src}` };\n }\n\n if (hasRemoteMatch(__imageDomains, __imageRemotePatterns, url)) {\n return { allowed: true };\n }\n\n return {\n allowed: false,\n reason: `Image URL \"${src}\" is not configured in images.remotePatterns or images.domains in next.config.js. See: https://nextjs.org/docs/messages/next-image-unconfigured-host`,\n };\n}\n\ninterface ImageProps {\n src: string | StaticImageData;\n alt: string;\n width?: number;\n height?: number;\n fill?: boolean;\n priority?: boolean;\n quality?: number;\n placeholder?: \"blur\" | \"empty\";\n blurDataURL?: string;\n loader?: (params: { src: string; width: number; quality?: number }) => string;\n sizes?: string;\n className?: string;\n style?: React.CSSProperties;\n onLoad?: React.ReactEventHandler<HTMLImageElement>;\n /** @deprecated Use onLoad instead. Still supported for migration compat. */\n onLoadingComplete?: (img: HTMLImageElement) => void;\n onError?: React.ReactEventHandler<HTMLImageElement>;\n onClick?: React.MouseEventHandler<HTMLImageElement>;\n id?: string;\n // Accept and ignore Next.js-specific props that don't apply\n unoptimized?: boolean;\n overrideSrc?: string;\n loading?: \"lazy\" | \"eager\";\n}\n\n/**\n * Sanitize a blurDataURL to prevent CSS injection.\n *\n * A crafted data URL containing `)` can break out of the `url()` CSS function,\n * allowing injection of arbitrary CSS properties or rules. Characters like `{`,\n * `}`, and `\\` can also assist in crafting injection payloads.\n *\n * This validates the URL starts with `data:image/` and rejects characters that\n * could escape the `url()` context. Semicolons are allowed since they're part\n * of valid data URLs (`data:image/png;base64,...`) and harmless inside `url()`.\n *\n * Returns undefined for invalid URLs, which causes the blur placeholder to be\n * skipped gracefully.\n */\nfunction sanitizeBlurDataURL(url: string): string | undefined {\n // Must be a data: image URL\n if (!url.startsWith(\"data:image/\")) return undefined;\n // Reject characters that can break out of CSS url():\n // ) - closes url()\n // ( - could open nested functions\n // { } - CSS rule boundaries\n // \\ - CSS escape sequences\n // newlines - break CSS parsing\n if (/[)(}{\\\\'\"\\n\\r]/.test(url)) return undefined;\n return url;\n}\n\n/**\n * Determine if a src is a remote URL (CDN-optimizable) or local.\n */\nfunction isRemoteUrl(src: string): boolean {\n return src.startsWith(\"http://\") || src.startsWith(\"https://\") || src.startsWith(\"//\");\n}\n\n/**\n * Resolve src, width, height, blurDataURL from Image props (string or StaticImageData).\n * Shared by the Image component and getImageProps to keep behavior in sync.\n */\nfunction resolveImageSource(v: {\n src: string | StaticImageData;\n width?: number;\n height?: number;\n blurDataURL?: string;\n}): { src: string; width?: number; height?: number; blurDataURL?: string } {\n const src = typeof v.src === \"string\" ? v.src : v.src.src;\n const imgWidth = v.width ?? (typeof v.src === \"object\" ? v.src.width : undefined);\n const imgHeight = v.height ?? (typeof v.src === \"object\" ? v.src.height : undefined);\n const imgBlurDataURL =\n v.blurDataURL ?? (typeof v.src === \"object\" ? v.src.blurDataURL : undefined);\n return { src, width: imgWidth, height: imgHeight, blurDataURL: imgBlurDataURL };\n}\n\n/**\n * Responsive image widths matching Next.js's device sizes config.\n * These are the breakpoints used for srcSet generation.\n * Configurable via `images.deviceSizes` in next.config.js.\n */\nconst RESPONSIVE_WIDTHS = __imageDeviceSizes;\n\n/**\n * Build a `/_vinext/image` optimization URL.\n *\n * In production (Cloudflare Workers), the worker intercepts this path and uses\n * the Images binding to resize/transcode on the fly. In dev, the Vite dev\n * server handles it as a passthrough (serves the original file).\n */\nexport function imageOptimizationUrl(src: string, width: number, quality: number = 75): string {\n return `/_vinext/image?url=${encodeURIComponent(src)}&w=${width}&q=${quality}`;\n}\n\n/**\n * Generate a srcSet string for responsive images.\n *\n * Each width points to the `/_vinext/image` optimization endpoint so the\n * server can resize and transcode the image. Only includes widths that are\n * <= 2x the original image width to avoid pointless upscaling.\n */\nfunction generateSrcSet(src: string, originalWidth: number, quality: number = 75): string {\n const widths = RESPONSIVE_WIDTHS.filter((w) => w <= originalWidth * 2);\n if (widths.length === 0)\n return `${imageOptimizationUrl(src, originalWidth, quality)} ${originalWidth}w`;\n return widths.map((w) => `${imageOptimizationUrl(src, w, quality)} ${w}w`).join(\", \");\n}\n\nconst Image = forwardRef<HTMLImageElement, ImageProps>(function Image(\n {\n src: srcProp,\n alt,\n width,\n height,\n fill,\n priority,\n quality,\n placeholder,\n blurDataURL,\n loader,\n sizes,\n className,\n style,\n onLoad,\n onLoadingComplete,\n unoptimized: _unoptimized,\n overrideSrc: _overrideSrc,\n loading,\n ...rest\n },\n ref,\n) {\n // Wire onLoadingComplete (deprecated) into onLoad — matches Next.js behavior.\n // onLoad fires first, then onLoadingComplete receives the HTMLImageElement.\n const handleLoad = onLoadingComplete\n ? (e: React.SyntheticEvent<HTMLImageElement>) => {\n onLoad?.(e);\n onLoadingComplete(e.currentTarget);\n }\n : onLoad;\n\n const {\n src,\n width: imgWidth,\n height: imgHeight,\n blurDataURL: imgBlurDataURL,\n } = resolveImageSource({ src: srcProp, width, height, blurDataURL });\n\n // If a custom loader is provided, use basic img with loader URL\n if (loader) {\n const resolvedSrc = loader({ src, width: imgWidth ?? 0, quality: quality ?? 75 });\n return (\n <img\n ref={ref}\n src={resolvedSrc}\n alt={alt}\n width={fill ? undefined : imgWidth}\n height={fill ? undefined : imgHeight}\n loading={priority ? \"eager\" : (loading ?? \"lazy\")}\n decoding=\"async\"\n sizes={sizes}\n className={className}\n onLoad={handleLoad}\n style={\n fill\n ? {\n position: \"absolute\",\n inset: 0,\n width: \"100%\",\n height: \"100%\",\n objectFit: \"cover\",\n ...style,\n }\n : style\n }\n {...rest}\n />\n );\n }\n\n // For remote URLs, validate against remotePatterns then use @unpic/react\n if (isRemoteUrl(src)) {\n const validation = validateRemoteUrl(src);\n if (!validation.allowed) {\n if (__isDev) {\n console.warn(`[next/image] ${validation.reason}`);\n // In dev, render the image but with a warning — matches Next.js dev behavior\n } else {\n // In production, block the image entirely\n console.error(`[next/image] ${validation.reason}`);\n return null;\n }\n }\n\n const sanitizedBlur = imgBlurDataURL ? sanitizeBlurDataURL(imgBlurDataURL) : undefined;\n const bg = placeholder === \"blur\" && sanitizedBlur ? `url(${sanitizedBlur})` : undefined;\n\n if (fill) {\n return (\n <UnpicImage\n src={src}\n alt={alt}\n layout=\"fullWidth\"\n // `priority` is a Next.js concept — translate it to HTML attributes so\n // it is never forwarded to the DOM as a non-boolean attribute, which\n // would trigger React's \"Received `true` for a non-boolean attribute\"\n // warning.\n loading={priority ? \"eager\" : (loading ?? \"lazy\")}\n fetchPriority={priority ? \"high\" : undefined}\n sizes={sizes}\n className={className}\n background={bg}\n onLoad={handleLoad}\n />\n );\n }\n // constrained layout requires width+height or aspectRatio\n if (imgWidth && imgHeight) {\n return (\n <UnpicImage\n src={src}\n alt={alt}\n width={imgWidth}\n height={imgHeight}\n layout=\"constrained\"\n // Same translation as above — never pass `priority` to the DOM.\n loading={priority ? \"eager\" : (loading ?? \"lazy\")}\n fetchPriority={priority ? \"high\" : undefined}\n sizes={sizes}\n className={className}\n background={bg}\n onLoad={handleLoad}\n />\n );\n }\n // Fall through to basic <img> if dimensions not provided\n // (unpic requires them for constrained layout)\n }\n\n // Route local images through the /_vinext/image optimization endpoint.\n // In production on Cloudflare Workers, this resizes and transcodes via\n // the Images binding. In dev, it serves the original file as a passthrough.\n // When `unoptimized` is true, bypass the endpoint entirely (Next.js compat).\n // SVG sources auto-skip unless dangerouslyAllowSVG is enabled, matching\n // Next.js behavior where .svg triggers unoptimized=true by default.\n const imgQuality = quality ?? 75;\n const isSvg = src.endsWith(\".svg\");\n const skipOptimization = _unoptimized === true || (isSvg && !__dangerouslyAllowSVG);\n\n // Build srcSet for responsive local images (common breakpoints).\n // Each entry points to /_vinext/image with the appropriate width.\n const srcSet =\n imgWidth && !fill && !skipOptimization\n ? generateSrcSet(src, imgWidth, imgQuality)\n : imgWidth && !fill\n ? RESPONSIVE_WIDTHS.filter((w) => w <= imgWidth * 2)\n .map((w) => `${src} ${w}w`)\n .join(\", \") || `${src} ${imgWidth}w`\n : undefined;\n\n // The main `src` also goes through the optimization endpoint. Use the\n // declared width (or the first responsive width as fallback).\n const optimizedSrc = skipOptimization\n ? src\n : imgWidth\n ? imageOptimizationUrl(src, imgWidth, imgQuality)\n : imageOptimizationUrl(src, RESPONSIVE_WIDTHS[0], imgQuality);\n\n // Blur placeholder: show a low-quality background while the image loads.\n // Sanitize blurDataURL to prevent CSS injection via crafted data URLs.\n const sanitizedLocalBlur = imgBlurDataURL ? sanitizeBlurDataURL(imgBlurDataURL) : undefined;\n const blurStyle =\n placeholder === \"blur\" && sanitizedLocalBlur\n ? {\n backgroundImage: `url(${sanitizedLocalBlur})`,\n backgroundSize: \"cover\",\n backgroundRepeat: \"no-repeat\",\n backgroundPosition: \"center\",\n }\n : undefined;\n\n // For local images, render a standard <img> tag with srcSet and blur support.\n // The src and srcSet point to the /_vinext/image optimization endpoint.\n return (\n <img\n ref={ref}\n src={optimizedSrc}\n alt={alt}\n width={fill ? undefined : imgWidth}\n height={fill ? undefined : imgHeight}\n loading={priority ? \"eager\" : (loading ?? \"lazy\")}\n fetchPriority={priority ? \"high\" : undefined}\n decoding=\"async\"\n srcSet={srcSet}\n sizes={sizes ?? (fill ? \"100vw\" : undefined)}\n className={className}\n data-nimg={fill ? \"fill\" : \"1\"}\n onLoad={handleLoad}\n style={\n fill\n ? {\n position: \"absolute\",\n inset: 0,\n width: \"100%\",\n height: \"100%\",\n objectFit: \"cover\",\n ...blurStyle,\n ...style,\n }\n : { ...blurStyle, ...style }\n }\n {...rest}\n />\n );\n});\n\n/**\n * getImageProps — for advanced use cases (picture elements, background images).\n * Returns the props that would be passed to the underlying <img> element.\n */\nexport function getImageProps(props: ImageProps): {\n props: React.ImgHTMLAttributes<HTMLImageElement>;\n} {\n const {\n src: srcProp,\n alt,\n width,\n height,\n fill,\n priority,\n quality: _quality,\n placeholder,\n blurDataURL: blurDataURLProp,\n loader,\n sizes,\n className,\n style,\n onLoad: _onLoad,\n onLoadingComplete: _onLoadingComplete,\n unoptimized: _unoptimized,\n overrideSrc: _overrideSrc,\n loading,\n ...rest\n } = props;\n\n const {\n src,\n width: imgWidth,\n height: imgHeight,\n blurDataURL: imgBlurDataURL,\n } = resolveImageSource({ src: srcProp, width, height, blurDataURL: blurDataURLProp });\n\n // Validate remote URLs against configured patterns\n let blockedInProd = false;\n if (isRemoteUrl(src)) {\n const validation = validateRemoteUrl(src);\n if (!validation.allowed) {\n if (__isDev) {\n console.warn(`[next/image] ${validation.reason}`);\n } else {\n console.error(`[next/image] ${validation.reason}`);\n blockedInProd = true;\n }\n }\n }\n\n // Resolve src through custom loader if provided\n const imgQuality = _quality ?? 75;\n const resolvedSrc = blockedInProd\n ? \"\"\n : loader\n ? loader({ src, width: imgWidth ?? 0, quality: imgQuality })\n : src;\n\n // For local images (no loader, not remote), route through optimization endpoint.\n // When `unoptimized` is true, bypass the endpoint entirely (Next.js compat).\n // SVG sources auto-skip unless dangerouslyAllowSVG is enabled.\n const isSvg = resolvedSrc.endsWith(\".svg\");\n const skipOpt =\n _unoptimized === true ||\n (isSvg && !__dangerouslyAllowSVG) ||\n blockedInProd ||\n !!loader ||\n isRemoteUrl(resolvedSrc);\n const optimizedSrc = skipOpt\n ? resolvedSrc\n : imgWidth\n ? imageOptimizationUrl(resolvedSrc, imgWidth, imgQuality)\n : imageOptimizationUrl(resolvedSrc, RESPONSIVE_WIDTHS[0], imgQuality);\n\n // Build srcSet for local images — each width points to /_vinext/image\n const srcSet =\n imgWidth && !fill && !isRemoteUrl(resolvedSrc) && !loader && !skipOpt\n ? generateSrcSet(resolvedSrc, imgWidth, imgQuality)\n : undefined;\n\n // Blur placeholder styles — sanitize to prevent CSS injection\n const sanitizedBlurURL = imgBlurDataURL ? sanitizeBlurDataURL(imgBlurDataURL) : undefined;\n const blurStyle =\n placeholder === \"blur\" && sanitizedBlurURL\n ? {\n backgroundImage: `url(${sanitizedBlurURL})`,\n backgroundSize: \"cover\",\n backgroundRepeat: \"no-repeat\" as const,\n backgroundPosition: \"center\" as const,\n }\n : undefined;\n\n return {\n props: {\n src: optimizedSrc,\n alt,\n width: fill ? undefined : imgWidth,\n height: fill ? undefined : imgHeight,\n loading: priority ? \"eager\" : (loading ?? \"lazy\"),\n fetchPriority: priority ? (\"high\" as const) : undefined,\n decoding: \"async\" as const,\n srcSet,\n sizes: sizes ?? (fill ? \"100vw\" : undefined),\n className,\n \"data-nimg\": fill ? \"fill\" : \"1\",\n style: fill\n ? {\n position: \"absolute\" as const,\n inset: 0,\n width: \"100%\",\n height: \"100%\",\n objectFit: \"cover\" as const,\n ...blurStyle,\n ...style,\n }\n : { ...blurStyle, ...style },\n ...rest,\n } as React.ImgHTMLAttributes<HTMLImageElement>,\n };\n}\n\nexport default Image;\n"],"mappings":"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"}
1
+ {"version":3,"file":"image.js","names":["UnpicImage"],"sources":["../../src/shims/image.tsx"],"sourcesContent":["/**\n * next/image shim\n *\n * Translates Next.js Image props to @unpic/react Image component.\n * @unpic/react auto-detects CDN from URL and uses native transforms.\n * For local images (relative paths), routes through `/_vinext/image`\n * for server-side optimization (resize, format negotiation, quality).\n *\n * Remote images are validated against `images.remotePatterns` and\n * `images.domains` from next.config.js. Unmatched URLs are blocked\n * in production and warn in development, matching Next.js behavior.\n */\nimport React, { forwardRef } from \"react\";\nimport { Image as UnpicImage } from \"@unpic/react\";\nimport { hasRemoteMatch, type RemotePattern } from \"./image-config.js\";\n\nexport type StaticImageData = {\n src: string;\n height: number;\n width: number;\n blurDataURL?: string;\n};\n\n/**\n * Image config injected at build time via Vite define.\n * Serialized as JSON — parsed once at module level.\n */\nconst __imageRemotePatterns: RemotePattern[] = (() => {\n try {\n return JSON.parse(process.env.__VINEXT_IMAGE_REMOTE_PATTERNS ?? \"[]\");\n } catch {\n return [];\n }\n})();\nconst __imageDomains: string[] = (() => {\n try {\n return JSON.parse(process.env.__VINEXT_IMAGE_DOMAINS ?? \"[]\");\n } catch {\n return [];\n }\n})();\nconst __hasImageConfig = __imageRemotePatterns.length > 0 || __imageDomains.length > 0;\nconst __isDev = process.env.NODE_ENV !== \"production\";\nconst __imageDeviceSizes: number[] = (() => {\n try {\n return JSON.parse(\n process.env.__VINEXT_IMAGE_DEVICE_SIZES ?? \"[640,750,828,1080,1200,1920,2048,3840]\",\n );\n } catch {\n return [640, 750, 828, 1080, 1200, 1920, 2048, 3840];\n }\n})();\n/**\n * Whether dangerouslyAllowSVG is enabled in next.config.js.\n * When false (default), .svg sources auto-skip the optimization endpoint\n * and are served directly, matching Next.js behavior.\n * When true, .svg sources are routed through the optimizer (served as-is\n * with security headers).\n */\nconst __dangerouslyAllowSVG = process.env.__VINEXT_IMAGE_DANGEROUSLY_ALLOW_SVG === \"true\";\n/**\n * Validate that a remote URL is allowed by the configured remote patterns.\n * Returns true if the URL is allowed, false otherwise.\n *\n * When no remotePatterns/domains are configured, all remote URLs are allowed\n * (backwards-compatible — user hasn't opted into restriction).\n *\n * When patterns ARE configured, only matching URLs are allowed.\n * In development, non-matching URLs produce a console warning.\n * In production, non-matching URLs are blocked (src replaced with empty string).\n */\nfunction validateRemoteUrl(src: string): { allowed: boolean; reason?: string } {\n if (!__hasImageConfig) {\n // No image config — allow everything (backwards-compatible)\n return { allowed: true };\n }\n\n let url: URL;\n try {\n url = new URL(src, \"http://n\");\n } catch {\n return { allowed: false, reason: `Invalid URL: ${src}` };\n }\n\n if (hasRemoteMatch(__imageDomains, __imageRemotePatterns, url)) {\n return { allowed: true };\n }\n\n return {\n allowed: false,\n reason: `Image URL \"${src}\" is not configured in images.remotePatterns or images.domains in next.config.js. See: https://nextjs.org/docs/messages/next-image-unconfigured-host`,\n };\n}\n\ntype ImageProps = {\n src: string | StaticImageData;\n alt: string;\n width?: number;\n height?: number;\n fill?: boolean;\n priority?: boolean;\n quality?: number;\n placeholder?: \"blur\" | \"empty\";\n blurDataURL?: string;\n loader?: (params: { src: string; width: number; quality?: number }) => string;\n sizes?: string;\n className?: string;\n style?: React.CSSProperties;\n onLoad?: React.ReactEventHandler<HTMLImageElement>;\n /** @deprecated Use onLoad instead. Still supported for migration compat. */\n onLoadingComplete?: (img: HTMLImageElement) => void;\n onError?: React.ReactEventHandler<HTMLImageElement>;\n onClick?: React.MouseEventHandler<HTMLImageElement>;\n id?: string;\n // Accept and ignore Next.js-specific props that don't apply\n unoptimized?: boolean;\n overrideSrc?: string;\n loading?: \"lazy\" | \"eager\";\n};\n\n/**\n * Sanitize a blurDataURL to prevent CSS injection.\n *\n * A crafted data URL containing `)` can break out of the `url()` CSS function,\n * allowing injection of arbitrary CSS properties or rules. Characters like `{`,\n * `}`, and `\\` can also assist in crafting injection payloads.\n *\n * This validates the URL starts with `data:image/` and rejects characters that\n * could escape the `url()` context. Semicolons are allowed since they're part\n * of valid data URLs (`data:image/png;base64,...`) and harmless inside `url()`.\n *\n * Returns undefined for invalid URLs, which causes the blur placeholder to be\n * skipped gracefully.\n */\nfunction sanitizeBlurDataURL(url: string): string | undefined {\n // Must be a data: image URL\n if (!url.startsWith(\"data:image/\")) return undefined;\n // Reject characters that can break out of CSS url():\n // ) - closes url()\n // ( - could open nested functions\n // { } - CSS rule boundaries\n // \\ - CSS escape sequences\n // newlines - break CSS parsing\n if (/[)(}{\\\\'\"\\n\\r]/.test(url)) return undefined;\n return url;\n}\n\n/**\n * Determine if a src is a remote URL (CDN-optimizable) or local.\n */\nfunction isRemoteUrl(src: string): boolean {\n return src.startsWith(\"http://\") || src.startsWith(\"https://\") || src.startsWith(\"//\");\n}\n\n/**\n * Resolve src, width, height, blurDataURL from Image props (string or StaticImageData).\n * Shared by the Image component and getImageProps to keep behavior in sync.\n */\nfunction resolveImageSource(v: {\n src: string | StaticImageData;\n width?: number;\n height?: number;\n blurDataURL?: string;\n}): { src: string; width?: number; height?: number; blurDataURL?: string } {\n const src = typeof v.src === \"string\" ? v.src : v.src.src;\n const imgWidth = v.width ?? (typeof v.src === \"object\" ? v.src.width : undefined);\n const imgHeight = v.height ?? (typeof v.src === \"object\" ? v.src.height : undefined);\n const imgBlurDataURL =\n v.blurDataURL ?? (typeof v.src === \"object\" ? v.src.blurDataURL : undefined);\n return { src, width: imgWidth, height: imgHeight, blurDataURL: imgBlurDataURL };\n}\n\n/**\n * Responsive image widths matching Next.js's device sizes config.\n * These are the breakpoints used for srcSet generation.\n * Configurable via `images.deviceSizes` in next.config.js.\n */\nconst RESPONSIVE_WIDTHS = __imageDeviceSizes;\n\n/**\n * Build a `/_vinext/image` optimization URL.\n *\n * In production (Cloudflare Workers), the worker intercepts this path and uses\n * the Images binding to resize/transcode on the fly. In dev, the Vite dev\n * server handles it as a passthrough (serves the original file).\n */\nexport function imageOptimizationUrl(src: string, width: number, quality: number = 75): string {\n return `/_vinext/image?url=${encodeURIComponent(src)}&w=${width}&q=${quality}`;\n}\n\n/**\n * Generate a srcSet string for responsive images.\n *\n * Each width points to the `/_vinext/image` optimization endpoint so the\n * server can resize and transcode the image. Only includes widths that are\n * <= 2x the original image width to avoid pointless upscaling.\n */\nfunction generateSrcSet(src: string, originalWidth: number, quality: number = 75): string {\n const widths = RESPONSIVE_WIDTHS.filter((w) => w <= originalWidth * 2);\n if (widths.length === 0)\n return `${imageOptimizationUrl(src, originalWidth, quality)} ${originalWidth}w`;\n return widths.map((w) => `${imageOptimizationUrl(src, w, quality)} ${w}w`).join(\", \");\n}\n\nconst Image = forwardRef<HTMLImageElement, ImageProps>(function Image(\n {\n src: srcProp,\n alt,\n width,\n height,\n fill,\n priority,\n quality,\n placeholder,\n blurDataURL,\n loader,\n sizes,\n className,\n style,\n onLoad,\n onLoadingComplete,\n unoptimized: _unoptimized,\n overrideSrc: _overrideSrc,\n loading,\n ...rest\n },\n ref,\n) {\n // Wire onLoadingComplete (deprecated) into onLoad — matches Next.js behavior.\n // onLoad fires first, then onLoadingComplete receives the HTMLImageElement.\n const handleLoad = onLoadingComplete\n ? (e: React.SyntheticEvent<HTMLImageElement>) => {\n onLoad?.(e);\n onLoadingComplete(e.currentTarget);\n }\n : onLoad;\n\n const {\n src,\n width: imgWidth,\n height: imgHeight,\n blurDataURL: imgBlurDataURL,\n } = resolveImageSource({ src: srcProp, width, height, blurDataURL });\n\n // If a custom loader is provided, use basic img with loader URL\n if (loader) {\n const resolvedSrc = loader({ src, width: imgWidth ?? 0, quality: quality ?? 75 });\n return (\n <img\n ref={ref}\n src={resolvedSrc}\n alt={alt}\n width={fill ? undefined : imgWidth}\n height={fill ? undefined : imgHeight}\n loading={priority ? \"eager\" : (loading ?? \"lazy\")}\n decoding=\"async\"\n sizes={sizes}\n className={className}\n onLoad={handleLoad}\n style={\n fill\n ? {\n position: \"absolute\",\n inset: 0,\n width: \"100%\",\n height: \"100%\",\n objectFit: \"cover\",\n ...style,\n }\n : style\n }\n {...rest}\n />\n );\n }\n\n // For remote URLs, validate against remotePatterns then use @unpic/react\n if (isRemoteUrl(src)) {\n const validation = validateRemoteUrl(src);\n if (!validation.allowed) {\n if (__isDev) {\n console.warn(`[next/image] ${validation.reason}`);\n // In dev, render the image but with a warning — matches Next.js dev behavior\n } else {\n // In production, block the image entirely\n console.error(`[next/image] ${validation.reason}`);\n return null;\n }\n }\n\n const sanitizedBlur = imgBlurDataURL ? sanitizeBlurDataURL(imgBlurDataURL) : undefined;\n const bg = placeholder === \"blur\" && sanitizedBlur ? `url(${sanitizedBlur})` : undefined;\n\n if (fill) {\n return (\n <UnpicImage\n src={src}\n alt={alt}\n layout=\"fullWidth\"\n // `priority` is a Next.js concept — translate it to HTML attributes so\n // it is never forwarded to the DOM as a non-boolean attribute, which\n // would trigger React's \"Received `true` for a non-boolean attribute\"\n // warning.\n loading={priority ? \"eager\" : (loading ?? \"lazy\")}\n fetchPriority={priority ? \"high\" : undefined}\n sizes={sizes}\n className={className}\n background={bg}\n onLoad={handleLoad}\n />\n );\n }\n // constrained layout requires width+height or aspectRatio\n if (imgWidth && imgHeight) {\n return (\n <UnpicImage\n src={src}\n alt={alt}\n width={imgWidth}\n height={imgHeight}\n layout=\"constrained\"\n // Same translation as above — never pass `priority` to the DOM.\n loading={priority ? \"eager\" : (loading ?? \"lazy\")}\n fetchPriority={priority ? \"high\" : undefined}\n sizes={sizes}\n className={className}\n background={bg}\n onLoad={handleLoad}\n />\n );\n }\n // Fall through to basic <img> if dimensions not provided\n // (unpic requires them for constrained layout)\n }\n\n // Route local images through the /_vinext/image optimization endpoint.\n // In production on Cloudflare Workers, this resizes and transcodes via\n // the Images binding. In dev, it serves the original file as a passthrough.\n // When `unoptimized` is true, bypass the endpoint entirely (Next.js compat).\n // SVG sources auto-skip unless dangerouslyAllowSVG is enabled, matching\n // Next.js behavior where .svg triggers unoptimized=true by default.\n const imgQuality = quality ?? 75;\n const isSvg = src.endsWith(\".svg\");\n const skipOptimization = _unoptimized === true || (isSvg && !__dangerouslyAllowSVG);\n\n // Build srcSet for responsive local images (common breakpoints).\n // Each entry points to /_vinext/image with the appropriate width.\n const srcSet =\n imgWidth && !fill && !skipOptimization\n ? generateSrcSet(src, imgWidth, imgQuality)\n : imgWidth && !fill\n ? RESPONSIVE_WIDTHS.filter((w) => w <= imgWidth * 2)\n .map((w) => `${src} ${w}w`)\n .join(\", \") || `${src} ${imgWidth}w`\n : undefined;\n\n // The main `src` also goes through the optimization endpoint. Use the\n // declared width (or the first responsive width as fallback).\n const optimizedSrc = skipOptimization\n ? src\n : imgWidth\n ? imageOptimizationUrl(src, imgWidth, imgQuality)\n : imageOptimizationUrl(src, RESPONSIVE_WIDTHS[0], imgQuality);\n\n // Blur placeholder: show a low-quality background while the image loads.\n // Sanitize blurDataURL to prevent CSS injection via crafted data URLs.\n const sanitizedLocalBlur = imgBlurDataURL ? sanitizeBlurDataURL(imgBlurDataURL) : undefined;\n const blurStyle =\n placeholder === \"blur\" && sanitizedLocalBlur\n ? {\n backgroundImage: `url(${sanitizedLocalBlur})`,\n backgroundSize: \"cover\",\n backgroundRepeat: \"no-repeat\",\n backgroundPosition: \"center\",\n }\n : undefined;\n\n // For local images, render a standard <img> tag with srcSet and blur support.\n // The src and srcSet point to the /_vinext/image optimization endpoint.\n return (\n <img\n ref={ref}\n src={optimizedSrc}\n alt={alt}\n width={fill ? undefined : imgWidth}\n height={fill ? undefined : imgHeight}\n loading={priority ? \"eager\" : (loading ?? \"lazy\")}\n fetchPriority={priority ? \"high\" : undefined}\n decoding=\"async\"\n srcSet={srcSet}\n sizes={sizes ?? (fill ? \"100vw\" : undefined)}\n className={className}\n data-nimg={fill ? \"fill\" : \"1\"}\n onLoad={handleLoad}\n style={\n fill\n ? {\n position: \"absolute\",\n inset: 0,\n width: \"100%\",\n height: \"100%\",\n objectFit: \"cover\",\n ...blurStyle,\n ...style,\n }\n : { ...blurStyle, ...style }\n }\n {...rest}\n />\n );\n});\n\n/**\n * getImageProps — for advanced use cases (picture elements, background images).\n * Returns the props that would be passed to the underlying <img> element.\n */\nexport function getImageProps(props: ImageProps): {\n props: React.ImgHTMLAttributes<HTMLImageElement>;\n} {\n const {\n src: srcProp,\n alt,\n width,\n height,\n fill,\n priority,\n quality: _quality,\n placeholder,\n blurDataURL: blurDataURLProp,\n loader,\n sizes,\n className,\n style,\n onLoad: _onLoad,\n onLoadingComplete: _onLoadingComplete,\n unoptimized: _unoptimized,\n overrideSrc: _overrideSrc,\n loading,\n ...rest\n } = props;\n\n const {\n src,\n width: imgWidth,\n height: imgHeight,\n blurDataURL: imgBlurDataURL,\n } = resolveImageSource({ src: srcProp, width, height, blurDataURL: blurDataURLProp });\n\n // Validate remote URLs against configured patterns\n let blockedInProd = false;\n if (isRemoteUrl(src)) {\n const validation = validateRemoteUrl(src);\n if (!validation.allowed) {\n if (__isDev) {\n console.warn(`[next/image] ${validation.reason}`);\n } else {\n console.error(`[next/image] ${validation.reason}`);\n blockedInProd = true;\n }\n }\n }\n\n // Resolve src through custom loader if provided\n const imgQuality = _quality ?? 75;\n const resolvedSrc = blockedInProd\n ? \"\"\n : loader\n ? loader({ src, width: imgWidth ?? 0, quality: imgQuality })\n : src;\n\n // For local images (no loader, not remote), route through optimization endpoint.\n // When `unoptimized` is true, bypass the endpoint entirely (Next.js compat).\n // SVG sources auto-skip unless dangerouslyAllowSVG is enabled.\n const isSvg = resolvedSrc.endsWith(\".svg\");\n const skipOpt =\n _unoptimized === true ||\n (isSvg && !__dangerouslyAllowSVG) ||\n blockedInProd ||\n !!loader ||\n isRemoteUrl(resolvedSrc);\n const optimizedSrc = skipOpt\n ? resolvedSrc\n : imgWidth\n ? imageOptimizationUrl(resolvedSrc, imgWidth, imgQuality)\n : imageOptimizationUrl(resolvedSrc, RESPONSIVE_WIDTHS[0], imgQuality);\n\n // Build srcSet for local images — each width points to /_vinext/image\n const srcSet =\n imgWidth && !fill && !isRemoteUrl(resolvedSrc) && !loader && !skipOpt\n ? generateSrcSet(resolvedSrc, imgWidth, imgQuality)\n : undefined;\n\n // Blur placeholder styles — sanitize to prevent CSS injection\n const sanitizedBlurURL = imgBlurDataURL ? sanitizeBlurDataURL(imgBlurDataURL) : undefined;\n const blurStyle =\n placeholder === \"blur\" && sanitizedBlurURL\n ? {\n backgroundImage: `url(${sanitizedBlurURL})`,\n backgroundSize: \"cover\",\n backgroundRepeat: \"no-repeat\" as const,\n backgroundPosition: \"center\" as const,\n }\n : undefined;\n\n return {\n props: {\n src: optimizedSrc,\n alt,\n width: fill ? undefined : imgWidth,\n height: fill ? undefined : imgHeight,\n loading: priority ? \"eager\" : (loading ?? \"lazy\"),\n fetchPriority: priority ? (\"high\" as const) : undefined,\n decoding: \"async\" as const,\n srcSet,\n sizes: sizes ?? (fill ? \"100vw\" : undefined),\n className,\n \"data-nimg\": fill ? \"fill\" : \"1\",\n style: fill\n ? {\n position: \"absolute\" as const,\n inset: 0,\n width: \"100%\",\n height: \"100%\",\n objectFit: \"cover\" as const,\n ...blurStyle,\n ...style,\n }\n : { ...blurStyle, ...style },\n ...rest,\n } as React.ImgHTMLAttributes<HTMLImageElement>,\n };\n}\n\nexport default Image;\n"],"mappings":"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"}
@@ -1,21 +1,21 @@
1
1
  import * as react from "react";
2
2
 
3
3
  //#region src/shims/internal/app-router-context.d.ts
4
- interface NavigateOptions {
4
+ type NavigateOptions = {
5
5
  scroll?: boolean;
6
- }
7
- interface PrefetchOptions {
6
+ };
7
+ type PrefetchOptions = {
8
8
  kind?: unknown;
9
9
  onInvalidate?: () => void;
10
- }
11
- interface AppRouterInstance {
10
+ };
11
+ type AppRouterInstance = {
12
12
  back(): void;
13
13
  forward(): void;
14
14
  refresh(): void;
15
15
  push(href: string, options?: NavigateOptions): void;
16
16
  replace(href: string, options?: NavigateOptions): void;
17
17
  prefetch(href: string, options?: PrefetchOptions): void;
18
- }
18
+ };
19
19
  declare const AppRouterContext: react.Context<AppRouterInstance | null>;
20
20
  declare const GlobalLayoutRouterContext: react.Context<unknown>;
21
21
  declare const LayoutRouterContext: react.Context<unknown>;
@@ -1 +1 @@
1
- {"version":3,"file":"app-router-context.js","names":[],"sources":["../../../src/shims/internal/app-router-context.ts"],"sourcesContent":["/**\n * Shim for next/dist/shared/lib/app-router-context.shared-runtime\n *\n * Used by: @clerk/nextjs, next-intl, next-nprogress-bar, nextjs-toploader,\n * next-view-transitions. Mostly type-only imports in published .d.ts files.\n *\n * We export the types and minimal context objects so these libraries resolve.\n */\nimport { createContext } from \"react\";\n\nexport interface NavigateOptions {\n scroll?: boolean;\n}\n\nexport interface PrefetchOptions {\n kind?: unknown;\n onInvalidate?: () => void;\n}\n\nexport interface AppRouterInstance {\n back(): void;\n forward(): void;\n refresh(): void;\n push(href: string, options?: NavigateOptions): void;\n replace(href: string, options?: NavigateOptions): void;\n prefetch(href: string, options?: PrefetchOptions): void;\n}\n\nexport const AppRouterContext = createContext<AppRouterInstance | null>(null);\nexport const GlobalLayoutRouterContext = createContext<unknown>(null);\nexport const LayoutRouterContext = createContext<unknown>(null);\nexport const MissingSlotContext = createContext<Set<string>>(new Set());\nexport const TemplateContext = createContext<unknown>(null);\n"],"mappings":";;;;;;;;;;AA4BA,MAAa,mBAAmB,cAAwC,KAAK;AAC7E,MAAa,4BAA4B,cAAuB,KAAK;AACrE,MAAa,sBAAsB,cAAuB,KAAK;AAC/D,MAAa,qBAAqB,8BAA2B,IAAI,KAAK,CAAC;AACvE,MAAa,kBAAkB,cAAuB,KAAK"}
1
+ {"version":3,"file":"app-router-context.js","names":[],"sources":["../../../src/shims/internal/app-router-context.ts"],"sourcesContent":["/**\n * Shim for next/dist/shared/lib/app-router-context.shared-runtime\n *\n * Used by: @clerk/nextjs, next-intl, next-nprogress-bar, nextjs-toploader,\n * next-view-transitions. Mostly type-only imports in published .d.ts files.\n *\n * We export the types and minimal context objects so these libraries resolve.\n */\nimport { createContext } from \"react\";\n\nexport type NavigateOptions = {\n scroll?: boolean;\n};\n\nexport type PrefetchOptions = {\n kind?: unknown;\n onInvalidate?: () => void;\n};\n\nexport type AppRouterInstance = {\n back(): void;\n forward(): void;\n refresh(): void;\n push(href: string, options?: NavigateOptions): void;\n replace(href: string, options?: NavigateOptions): void;\n prefetch(href: string, options?: PrefetchOptions): void;\n};\n\nexport const AppRouterContext = createContext<AppRouterInstance | null>(null);\nexport const GlobalLayoutRouterContext = createContext<unknown>(null);\nexport const LayoutRouterContext = createContext<unknown>(null);\nexport const MissingSlotContext = createContext<Set<string>>(new Set());\nexport const TemplateContext = createContext<unknown>(null);\n"],"mappings":";;;;;;;;;;AA4BA,MAAa,mBAAmB,cAAwC,KAAK;AAC7E,MAAa,4BAA4B,cAAuB,KAAK;AACrE,MAAa,sBAAsB,cAAuB,KAAK;AAC/D,MAAa,qBAAqB,8BAA2B,IAAI,KAAK,CAAC;AACvE,MAAa,kBAAkB,cAAuB,KAAK"}
@@ -5,7 +5,7 @@
5
5
  * Used by: @sentry/nextjs (type-only import of NEXT_DATA).
6
6
  * Provides the NEXT_DATA type that matches window.__NEXT_DATA__.
7
7
  */
8
- interface NEXT_DATA {
8
+ type NEXT_DATA = {
9
9
  props: Record<string, unknown>;
10
10
  page: string;
11
11
  query: Record<string, string | string[]>;
@@ -38,7 +38,7 @@ interface NEXT_DATA {
38
38
  scriptLoader?: unknown[];
39
39
  isPreview?: boolean;
40
40
  notFoundSrcPage?: string;
41
- }
41
+ };
42
42
  /**
43
43
  * Standard Next.js error shape.
44
44
  */
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","names":[],"sources":["../../../src/shims/internal/utils.ts"],"sourcesContent":["/**\n * Shim for next/dist/shared/lib/utils\n *\n * Used by: @sentry/nextjs (type-only import of NEXT_DATA).\n * Provides the NEXT_DATA type that matches window.__NEXT_DATA__.\n */\n\nexport interface NEXT_DATA {\n props: Record<string, unknown>;\n page: string;\n query: Record<string, string | string[]>;\n buildId?: string;\n assetPrefix?: string;\n runtimeConfig?: Record<string, unknown>;\n nextExport?: boolean;\n autoExport?: boolean;\n isFallback?: boolean;\n dynamicIds?: (string | number)[];\n err?: { message: string; statusCode: number; name?: string };\n gsp?: boolean;\n gssp?: boolean;\n customServer?: boolean;\n gip?: boolean;\n appGip?: boolean;\n locale?: string;\n locales?: string[];\n defaultLocale?: string;\n domainLocales?: Array<{\n domain: string;\n defaultLocale: string;\n locales?: string[];\n http?: boolean;\n }>;\n scriptLoader?: unknown[];\n isPreview?: boolean;\n notFoundSrcPage?: string;\n}\n\n/**\n * Standard Next.js error shape.\n */\nexport function execOnce<T extends (...args: unknown[]) => unknown>(fn: T): T {\n let used = false;\n let result: unknown;\n return ((...args: unknown[]) => {\n if (!used) {\n used = true;\n result = fn(...args);\n }\n return result;\n }) as T;\n}\n\nexport function getLocationOrigin(): string {\n if (typeof window !== \"undefined\") {\n return window.location.origin;\n }\n return \"http://localhost\";\n}\n\nexport function getURL(): string {\n if (typeof window !== \"undefined\") {\n return window.location.href;\n }\n return \"http://localhost/\";\n}\n\nexport const SP = typeof performance !== \"undefined\";\nexport const ST = SP && typeof performance.mark === \"function\";\n"],"mappings":";;;;AAyCA,SAAgB,SAAoD,IAAU;CAC5E,IAAI,OAAO;CACX,IAAI;AACJ,UAAS,GAAG,SAAoB;AAC9B,MAAI,CAAC,MAAM;AACT,UAAO;AACP,YAAS,GAAG,GAAG,KAAK;;AAEtB,SAAO;;;AAIX,SAAgB,oBAA4B;AAC1C,KAAI,OAAO,WAAW,YACpB,QAAO,OAAO,SAAS;AAEzB,QAAO;;AAGT,SAAgB,SAAiB;AAC/B,KAAI,OAAO,WAAW,YACpB,QAAO,OAAO,SAAS;AAEzB,QAAO;;AAGT,MAAa,KAAK,OAAO,gBAAgB;AACzC,MAAa,KAAK,MAAM,OAAO,YAAY,SAAS"}
1
+ {"version":3,"file":"utils.js","names":[],"sources":["../../../src/shims/internal/utils.ts"],"sourcesContent":["/**\n * Shim for next/dist/shared/lib/utils\n *\n * Used by: @sentry/nextjs (type-only import of NEXT_DATA).\n * Provides the NEXT_DATA type that matches window.__NEXT_DATA__.\n */\n\nexport type NEXT_DATA = {\n props: Record<string, unknown>;\n page: string;\n query: Record<string, string | string[]>;\n buildId?: string;\n assetPrefix?: string;\n runtimeConfig?: Record<string, unknown>;\n nextExport?: boolean;\n autoExport?: boolean;\n isFallback?: boolean;\n dynamicIds?: (string | number)[];\n err?: { message: string; statusCode: number; name?: string };\n gsp?: boolean;\n gssp?: boolean;\n customServer?: boolean;\n gip?: boolean;\n appGip?: boolean;\n locale?: string;\n locales?: string[];\n defaultLocale?: string;\n domainLocales?: Array<{\n domain: string;\n defaultLocale: string;\n locales?: string[];\n http?: boolean;\n }>;\n scriptLoader?: unknown[];\n isPreview?: boolean;\n notFoundSrcPage?: string;\n};\n\n/**\n * Standard Next.js error shape.\n */\nexport function execOnce<T extends (...args: unknown[]) => unknown>(fn: T): T {\n let used = false;\n let result: unknown;\n return ((...args: unknown[]) => {\n if (!used) {\n used = true;\n result = fn(...args);\n }\n return result;\n }) as T;\n}\n\nexport function getLocationOrigin(): string {\n if (typeof window !== \"undefined\") {\n return window.location.origin;\n }\n return \"http://localhost\";\n}\n\nexport function getURL(): string {\n if (typeof window !== \"undefined\") {\n return window.location.href;\n }\n return \"http://localhost/\";\n}\n\nexport const SP = typeof performance !== \"undefined\";\nexport const ST = SP && typeof performance.mark === \"function\";\n"],"mappings":";;;;AAyCA,SAAgB,SAAoD,IAAU;CAC5E,IAAI,OAAO;CACX,IAAI;AACJ,UAAS,GAAG,SAAoB;AAC9B,MAAI,CAAC,MAAM;AACT,UAAO;AACP,YAAS,GAAG,GAAG,KAAK;;AAEtB,SAAO;;;AAIX,SAAgB,oBAA4B;AAC1C,KAAI,OAAO,WAAW,YACpB,QAAO,OAAO,SAAS;AAEzB,QAAO;;AAGT,SAAgB,SAAiB;AAC/B,KAAI,OAAO,WAAW,YACpB,QAAO,OAAO,SAAS;AAEzB,QAAO;;AAGT,MAAa,KAAK,OAAO,gBAAgB;AACzC,MAAa,KAAK,MAAM,OAAO,YAAY,SAAS"}
@@ -1,19 +1,26 @@
1
+ import { SegmentMap } from "./navigation.js";
2
+ import * as react from "react";
1
3
  import { ReactNode } from "react";
2
4
 
3
5
  //#region src/shims/layout-segment-context.d.ts
4
6
  /**
5
7
  * Wraps children with the layout segment context.
8
+ *
6
9
  * Each layout in the App Router tree wraps its children with this provider,
7
- * passing the remaining route tree segments below that layout level.
8
- * Segments include route groups and resolved dynamic param values.
10
+ * passing a map of parallel route key to segment path. The "children" key is
11
+ * always present (the default parallel route). Named parallel slots at this
12
+ * layout level add their own keys.
13
+ *
14
+ * Components inside the provider call useSelectedLayoutSegments(parallelRoutesKey)
15
+ * to read the segments for a specific parallel route.
9
16
  */
10
17
  declare function LayoutSegmentProvider({
11
- childSegments,
18
+ segmentMap,
12
19
  children
13
20
  }: {
14
- childSegments: string[];
21
+ segmentMap: SegmentMap;
15
22
  children: ReactNode;
16
- }): any;
23
+ }): string | number | bigint | boolean | react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | react.FunctionComponentElement<react.ProviderProps<SegmentMap>> | null | undefined;
17
24
  //#endregion
18
25
  export { LayoutSegmentProvider };
19
26
  //# sourceMappingURL=layout-segment-context.d.ts.map
@@ -20,14 +20,19 @@ import { createElement } from "react";
20
20
  */
21
21
  /**
22
22
  * Wraps children with the layout segment context.
23
+ *
23
24
  * Each layout in the App Router tree wraps its children with this provider,
24
- * passing the remaining route tree segments below that layout level.
25
- * Segments include route groups and resolved dynamic param values.
25
+ * passing a map of parallel route key to segment path. The "children" key is
26
+ * always present (the default parallel route). Named parallel slots at this
27
+ * layout level add their own keys.
28
+ *
29
+ * Components inside the provider call useSelectedLayoutSegments(parallelRoutesKey)
30
+ * to read the segments for a specific parallel route.
26
31
  */
27
- function LayoutSegmentProvider({ childSegments, children }) {
32
+ function LayoutSegmentProvider({ segmentMap, children }) {
28
33
  const ctx = getLayoutSegmentContext();
29
34
  if (!ctx) return children;
30
- return createElement(ctx.Provider, { value: childSegments }, children);
35
+ return createElement(ctx.Provider, { value: segmentMap }, children);
31
36
  }
32
37
  //#endregion
33
38
  export { LayoutSegmentProvider };
@@ -1 +1 @@
1
- {"version":3,"file":"layout-segment-context.js","names":[],"sources":["../../src/shims/layout-segment-context.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * Layout segment context provider.\n *\n * Must be \"use client\" so that Vite's RSC bundler renders this component in\n * the SSR/browser environment where React.createContext is available. The RSC\n * entry imports and renders LayoutSegmentProvider directly, but because of the\n * \"use client\" boundary the actual execution happens on the SSR/client side\n * where the context can be created and consumed by useSelectedLayoutSegment(s).\n *\n * Without \"use client\", this runs in the RSC environment where\n * React.createContext is undefined, getLayoutSegmentContext() returns null,\n * the provider becomes a no-op, and useSelectedLayoutSegments always returns [].\n *\n * The context is shared with navigation.ts via getLayoutSegmentContext()\n * to avoid creating separate contexts in different modules.\n */\nimport { createElement, type ReactNode } from \"react\";\nimport { getLayoutSegmentContext } from \"./navigation.js\";\n\n/**\n * Wraps children with the layout segment context.\n * Each layout in the App Router tree wraps its children with this provider,\n * passing the remaining route tree segments below that layout level.\n * Segments include route groups and resolved dynamic param values.\n */\nexport function LayoutSegmentProvider({\n childSegments,\n children,\n}: {\n childSegments: string[];\n children: ReactNode;\n}) {\n const ctx = getLayoutSegmentContext();\n if (!ctx) {\n // Fallback: no context available (shouldn't happen in SSR/Browser)\n return children as any;\n }\n return createElement(ctx.Provider, { value: childSegments }, children);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,SAAgB,sBAAsB,EACpC,eACA,YAIC;CACD,MAAM,MAAM,yBAAyB;AACrC,KAAI,CAAC,IAEH,QAAO;AAET,QAAO,cAAc,IAAI,UAAU,EAAE,OAAO,eAAe,EAAE,SAAS"}
1
+ {"version":3,"file":"layout-segment-context.js","names":[],"sources":["../../src/shims/layout-segment-context.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * Layout segment context provider.\n *\n * Must be \"use client\" so that Vite's RSC bundler renders this component in\n * the SSR/browser environment where React.createContext is available. The RSC\n * entry imports and renders LayoutSegmentProvider directly, but because of the\n * \"use client\" boundary the actual execution happens on the SSR/client side\n * where the context can be created and consumed by useSelectedLayoutSegment(s).\n *\n * Without \"use client\", this runs in the RSC environment where\n * React.createContext is undefined, getLayoutSegmentContext() returns null,\n * the provider becomes a no-op, and useSelectedLayoutSegments always returns [].\n *\n * The context is shared with navigation.ts via getLayoutSegmentContext()\n * to avoid creating separate contexts in different modules.\n */\nimport { createElement, type ReactNode } from \"react\";\nimport { getLayoutSegmentContext, type SegmentMap } from \"./navigation.js\";\n\n/**\n * Wraps children with the layout segment context.\n *\n * Each layout in the App Router tree wraps its children with this provider,\n * passing a map of parallel route key to segment path. The \"children\" key is\n * always present (the default parallel route). Named parallel slots at this\n * layout level add their own keys.\n *\n * Components inside the provider call useSelectedLayoutSegments(parallelRoutesKey)\n * to read the segments for a specific parallel route.\n */\nexport function LayoutSegmentProvider({\n segmentMap,\n children,\n}: {\n segmentMap: SegmentMap;\n children: ReactNode;\n}) {\n const ctx = getLayoutSegmentContext();\n if (!ctx) {\n // No context available expected only in RSC environment, not SSR/browser.\n return children;\n }\n return createElement(ctx.Provider, { value: segmentMap }, children);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,SAAgB,sBAAsB,EACpC,YACA,YAIC;CACD,MAAM,MAAM,yBAAyB;AACrC,KAAI,CAAC,IAEH,QAAO;AAET,QAAO,cAAc,IAAI,UAAU,EAAE,OAAO,YAAY,EAAE,SAAS"}
@@ -1,7 +1,7 @@
1
1
  import React from "react";
2
2
 
3
3
  //#region src/shims/legacy-image.d.ts
4
- interface LegacyImageProps {
4
+ type LegacyImageProps = {
5
5
  src: string | {
6
6
  src: string;
7
7
  width: number;
@@ -10,12 +10,9 @@ interface LegacyImageProps {
10
10
  };
11
11
  alt: string;
12
12
  width?: number | string;
13
- height?: number | string;
14
- /** Legacy layout mode */
15
- layout?: "fixed" | "intrinsic" | "responsive" | "fill";
16
- /** CSS object-fit (used with layout="fill") */
17
- objectFit?: React.CSSProperties["objectFit"];
18
- /** CSS object-position (used with layout="fill") */
13
+ height?: number | string; /** Legacy layout mode */
14
+ layout?: "fixed" | "intrinsic" | "responsive" | "fill"; /** CSS object-fit (used with layout="fill") */
15
+ objectFit?: React.CSSProperties["objectFit"]; /** CSS object-position (used with layout="fill") */
19
16
  objectPosition?: string;
20
17
  priority?: boolean;
21
18
  quality?: number;
@@ -38,7 +35,7 @@ interface LegacyImageProps {
38
35
  loading?: "lazy" | "eager";
39
36
  unoptimized?: boolean;
40
37
  id?: string;
41
- }
38
+ };
42
39
  declare const LegacyImage: React.ForwardRefExoticComponent<LegacyImageProps & React.RefAttributes<HTMLImageElement>>;
43
40
  //#endregion
44
41
  export { LegacyImage as default };
@@ -1 +1 @@
1
- {"version":3,"file":"legacy-image.js","names":[],"sources":["../../src/shims/legacy-image.tsx"],"sourcesContent":["/**\n * next/legacy/image shim\n *\n * Provides the pre-Next.js 13 Image component API with layout prop.\n * Translates legacy props (layout, objectFit, objectPosition) to the\n * modern Image component's fill/style props.\n *\n * This module is used by apps that ran the `next-image-to-legacy-image`\n * codemod when upgrading from Next.js 12.\n */\nimport React, { forwardRef } from \"react\";\nimport Image from \"./image.js\";\n\ninterface LegacyImageProps {\n src: string | { src: string; width: number; height: number; blurDataURL?: string };\n alt: string;\n width?: number | string;\n height?: number | string;\n /** Legacy layout mode */\n layout?: \"fixed\" | \"intrinsic\" | \"responsive\" | \"fill\";\n /** CSS object-fit (used with layout=\"fill\") */\n objectFit?: React.CSSProperties[\"objectFit\"];\n /** CSS object-position (used with layout=\"fill\") */\n objectPosition?: string;\n priority?: boolean;\n quality?: number;\n placeholder?: \"blur\" | \"empty\";\n blurDataURL?: string;\n loader?: (params: { src: string; width: number; quality?: number }) => string;\n sizes?: string;\n className?: string;\n style?: React.CSSProperties;\n onLoad?: React.ReactEventHandler<HTMLImageElement>;\n onLoadingComplete?: (result: { naturalWidth: number; naturalHeight: number }) => void;\n onError?: React.ReactEventHandler<HTMLImageElement>;\n loading?: \"lazy\" | \"eager\";\n unoptimized?: boolean;\n id?: string;\n}\n\nconst LegacyImage = forwardRef<HTMLImageElement, LegacyImageProps>(\n function LegacyImage(props, ref) {\n const {\n layout = \"intrinsic\",\n objectFit,\n objectPosition,\n onLoadingComplete,\n onLoad,\n width,\n height,\n style,\n ...rest\n } = props;\n\n // Translate legacy props to modern Image props\n const modernStyle: React.CSSProperties = { ...style };\n\n if (objectFit) modernStyle.objectFit = objectFit;\n if (objectPosition) modernStyle.objectPosition = objectPosition;\n\n const handleLoad = onLoadingComplete\n ? (e: React.SyntheticEvent<HTMLImageElement>) => {\n const img = e.currentTarget;\n onLoadingComplete({\n naturalWidth: img.naturalWidth,\n naturalHeight: img.naturalHeight,\n });\n onLoad?.(e);\n }\n : onLoad;\n\n if (layout === \"fill\") {\n return <Image ref={ref} fill style={modernStyle} onLoad={handleLoad} {...rest} />;\n }\n\n if (layout === \"responsive\") {\n // Responsive: takes full width, maintains aspect ratio\n modernStyle.width = \"100%\";\n modernStyle.height = \"auto\";\n }\n\n // For \"fixed\" and \"intrinsic\", pass width/height directly\n const w = typeof width === \"string\" ? parseInt(width, 10) : width;\n const h = typeof height === \"string\" ? parseInt(height, 10) : height;\n\n return (\n <Image ref={ref} width={w} height={h} style={modernStyle} onLoad={handleLoad} {...rest} />\n );\n },\n);\n\nexport default LegacyImage;\n"],"mappings":";;;;;;;;;;;;;;AAwCA,MAAM,cAAc,WAClB,SAAS,YAAY,OAAO,KAAK;CAC/B,MAAM,EACJ,SAAS,aACT,WACA,gBACA,mBACA,QACA,OACA,QACA,OACA,GAAG,SACD;CAGJ,MAAM,cAAmC,EAAE,GAAG,OAAO;AAErD,KAAI,UAAW,aAAY,YAAY;AACvC,KAAI,eAAgB,aAAY,iBAAiB;CAEjD,MAAM,aAAa,qBACd,MAA8C;EAC7C,MAAM,MAAM,EAAE;AACd,oBAAkB;GAChB,cAAc,IAAI;GAClB,eAAe,IAAI;GACpB,CAAC;AACF,WAAS,EAAE;KAEb;AAEJ,KAAI,WAAW,OACb,QAAO,oBAAC,OAAD;EAAY;EAAK,MAAA;EAAK,OAAO;EAAa,QAAQ;EAAY,GAAI;EAAQ,CAAA;AAGnF,KAAI,WAAW,cAAc;AAE3B,cAAY,QAAQ;AACpB,cAAY,SAAS;;AAOvB,QACE,oBAAC,OAAD;EAAY;EAAK,OAJT,OAAO,UAAU,WAAW,SAAS,OAAO,GAAG,GAAG;EAI/B,QAHnB,OAAO,WAAW,WAAW,SAAS,QAAQ,GAAG,GAAG;EAGtB,OAAO;EAAa,QAAQ;EAAY,GAAI;EAAQ,CAAA;EAG/F"}
1
+ {"version":3,"file":"legacy-image.js","names":[],"sources":["../../src/shims/legacy-image.tsx"],"sourcesContent":["/**\n * next/legacy/image shim\n *\n * Provides the pre-Next.js 13 Image component API with layout prop.\n * Translates legacy props (layout, objectFit, objectPosition) to the\n * modern Image component's fill/style props.\n *\n * This module is used by apps that ran the `next-image-to-legacy-image`\n * codemod when upgrading from Next.js 12.\n */\nimport React, { forwardRef } from \"react\";\nimport Image from \"./image.js\";\n\ntype LegacyImageProps = {\n src: string | { src: string; width: number; height: number; blurDataURL?: string };\n alt: string;\n width?: number | string;\n height?: number | string;\n /** Legacy layout mode */\n layout?: \"fixed\" | \"intrinsic\" | \"responsive\" | \"fill\";\n /** CSS object-fit (used with layout=\"fill\") */\n objectFit?: React.CSSProperties[\"objectFit\"];\n /** CSS object-position (used with layout=\"fill\") */\n objectPosition?: string;\n priority?: boolean;\n quality?: number;\n placeholder?: \"blur\" | \"empty\";\n blurDataURL?: string;\n loader?: (params: { src: string; width: number; quality?: number }) => string;\n sizes?: string;\n className?: string;\n style?: React.CSSProperties;\n onLoad?: React.ReactEventHandler<HTMLImageElement>;\n onLoadingComplete?: (result: { naturalWidth: number; naturalHeight: number }) => void;\n onError?: React.ReactEventHandler<HTMLImageElement>;\n loading?: \"lazy\" | \"eager\";\n unoptimized?: boolean;\n id?: string;\n};\n\nconst LegacyImage = forwardRef<HTMLImageElement, LegacyImageProps>(\n function LegacyImage(props, ref) {\n const {\n layout = \"intrinsic\",\n objectFit,\n objectPosition,\n onLoadingComplete,\n onLoad,\n width,\n height,\n style,\n ...rest\n } = props;\n\n // Translate legacy props to modern Image props\n const modernStyle: React.CSSProperties = { ...style };\n\n if (objectFit) modernStyle.objectFit = objectFit;\n if (objectPosition) modernStyle.objectPosition = objectPosition;\n\n const handleLoad = onLoadingComplete\n ? (e: React.SyntheticEvent<HTMLImageElement>) => {\n const img = e.currentTarget;\n onLoadingComplete({\n naturalWidth: img.naturalWidth,\n naturalHeight: img.naturalHeight,\n });\n onLoad?.(e);\n }\n : onLoad;\n\n if (layout === \"fill\") {\n return <Image ref={ref} fill style={modernStyle} onLoad={handleLoad} {...rest} />;\n }\n\n if (layout === \"responsive\") {\n // Responsive: takes full width, maintains aspect ratio\n modernStyle.width = \"100%\";\n modernStyle.height = \"auto\";\n }\n\n // For \"fixed\" and \"intrinsic\", pass width/height directly\n const w = typeof width === \"string\" ? parseInt(width, 10) : width;\n const h = typeof height === \"string\" ? parseInt(height, 10) : height;\n\n return (\n <Image ref={ref} width={w} height={h} style={modernStyle} onLoad={handleLoad} {...rest} />\n );\n },\n);\n\nexport default LegacyImage;\n"],"mappings":";;;;;;;;;;;;;;AAwCA,MAAM,cAAc,WAClB,SAAS,YAAY,OAAO,KAAK;CAC/B,MAAM,EACJ,SAAS,aACT,WACA,gBACA,mBACA,QACA,OACA,QACA,OACA,GAAG,SACD;CAGJ,MAAM,cAAmC,EAAE,GAAG,OAAO;AAErD,KAAI,UAAW,aAAY,YAAY;AACvC,KAAI,eAAgB,aAAY,iBAAiB;CAEjD,MAAM,aAAa,qBACd,MAA8C;EAC7C,MAAM,MAAM,EAAE;AACd,oBAAkB;GAChB,cAAc,IAAI;GAClB,eAAe,IAAI;GACpB,CAAC;AACF,WAAS,EAAE;KAEb;AAEJ,KAAI,WAAW,OACb,QAAO,oBAAC,OAAD;EAAY;EAAK,MAAA;EAAK,OAAO;EAAa,QAAQ;EAAY,GAAI;EAAQ,CAAA;AAGnF,KAAI,WAAW,cAAc;AAE3B,cAAY,QAAQ;AACpB,cAAY,SAAS;;AAOvB,QACE,oBAAC,OAAD;EAAY;EAAK,OAJT,OAAO,UAAU,WAAW,SAAS,OAAO,GAAG,GAAG;EAI/B,QAHnB,OAAO,WAAW,WAAW,SAAS,QAAQ,GAAG,GAAG;EAGtB,OAAO;EAAa,QAAQ;EAAY,GAAI;EAAQ,CAAA;EAG/F"}
@@ -1,45 +1,35 @@
1
1
  import { UrlQuery } from "../utils/query.js";
2
- import React, { AnchorHTMLAttributes } from "react";
2
+ import React from "react";
3
3
 
4
4
  //#region src/shims/link.d.ts
5
- interface NavigateEvent {
6
- url: URL;
7
- /** Call to prevent the Link's default navigation (e.g. for View Transitions). */
8
- preventDefault(): void;
9
- /** Whether preventDefault() has been called. */
5
+ type NavigateEvent = {
6
+ url: URL; /** Call to prevent the Link's default navigation (e.g. for View Transitions). */
7
+ preventDefault(): void; /** Whether preventDefault() has been called. */
10
8
  defaultPrevented: boolean;
11
- }
12
- interface LinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, "href"> {
13
- href: string | {
14
- pathname?: string;
15
- query?: UrlQuery;
16
- };
17
- /** URL displayed in the browser (when href is a route pattern like /user/[id]) */
18
- as?: string;
19
- /** Replace the current history entry instead of pushing */
20
- replace?: boolean;
21
- /** Prefetch the page in the background (default: true, uses IntersectionObserver) */
22
- prefetch?: boolean;
23
- /** Whether to pass the href to the child element */
24
- passHref?: boolean;
25
- /** Scroll to top on navigation (default: true) */
26
- scroll?: boolean;
27
- /** Locale for i18n (used for locale-prefixed URLs) */
28
- locale?: string | false;
29
- /** Called before navigation happens (Next.js 16). Return value is ignored. */
30
- onNavigate?: (event: NavigateEvent) => void;
31
- children?: React.ReactNode;
32
- }
33
- interface LinkStatusContextValue {
9
+ };
10
+ type LinkStatusContextValue = {
34
11
  pending: boolean;
35
- }
12
+ };
36
13
  /**
37
14
  * useLinkStatus returns the pending state of the enclosing <Link>.
38
15
  * In Next.js, this is used to show loading indicators while a
39
16
  * prefetch-triggered navigation is in progress.
40
17
  */
41
18
  declare function useLinkStatus(): LinkStatusContextValue;
42
- declare const Link: React.ForwardRefExoticComponent<LinkProps & React.RefAttributes<HTMLAnchorElement>>;
19
+ declare const Link: React.ForwardRefExoticComponent<{
20
+ href: string | {
21
+ pathname?: string;
22
+ query?: UrlQuery;
23
+ }; /** URL displayed in the browser (when href is a route pattern like /user/[id]) */
24
+ as?: string; /** Replace the current history entry instead of pushing */
25
+ replace?: boolean; /** Prefetch the page in the background (default: true, uses IntersectionObserver) */
26
+ prefetch?: boolean; /** Whether to pass the href to the child element */
27
+ passHref?: boolean; /** Scroll to top on navigation (default: true) */
28
+ scroll?: boolean; /** Locale for i18n (used for locale-prefixed URLs) */
29
+ locale?: string | false; /** Called before navigation happens (Next.js 16). Return value is ignored. */
30
+ onNavigate?: (event: NavigateEvent) => void;
31
+ children?: React.ReactNode;
32
+ } & Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, "href"> & React.RefAttributes<HTMLAnchorElement>>;
43
33
  //#endregion
44
34
  export { Link as default, useLinkStatus };
45
35
  //# sourceMappingURL=link.d.ts.map
@@ -2,8 +2,7 @@
2
2
  import { resolveRelativeHref, toBrowserNavigationHref, toSameOriginAppPath, withBasePath } from "./url-utils.js";
3
3
  import { addLocalePrefix, getDomainLocaleUrl } from "../utils/domain-locale.js";
4
4
  import { appendSearchParamsToUrl, urlQueryToSearchParams } from "../utils/query.js";
5
- import { notifyAppRouterTransitionStart } from "../client/instrumentation-client-state.js";
6
- import { getPrefetchedUrls, storePrefetchResponse, toRscUrl } from "./navigation.js";
5
+ import { getPrefetchedUrls, navigateClientSide, prefetchRscResponse, toRscUrl } from "./navigation.js";
7
6
  import { isDangerousScheme } from "./url-safety.js";
8
7
  import { getI18nContext } from "./i18n-context.js";
9
8
  import React, { createContext, forwardRef, useCallback, useContext, useEffect, useRef, useState } from "react";
@@ -37,32 +36,6 @@ function resolveHref(href) {
37
36
  return url;
38
37
  }
39
38
  /**
40
- * Check if a href is only a hash change (same pathname, different/added hash).
41
- * Handles relative hashes like "#foo" and "?query#foo".
42
- */
43
- function isHashOnlyChange(href) {
44
- if (href.startsWith("#")) return true;
45
- try {
46
- const current = new URL(window.location.href);
47
- const next = new URL(href, window.location.href);
48
- return current.pathname === next.pathname && current.search === next.search && next.hash !== "";
49
- } catch {
50
- return false;
51
- }
52
- }
53
- /**
54
- * Scroll to a hash target element, or to the top if no hash.
55
- */
56
- function scrollToHash(hash) {
57
- if (!hash || hash === "#") {
58
- window.scrollTo(0, 0);
59
- return;
60
- }
61
- const id = hash.slice(1);
62
- const element = document.getElementById(id);
63
- if (element) element.scrollIntoView({ behavior: "auto" });
64
- }
65
- /**
66
39
  * Prefetch a URL for faster navigation.
67
40
  *
68
41
  * For App Router (RSC): fetches the .rsc payload in the background and
@@ -86,17 +59,12 @@ function prefetchUrl(href) {
86
59
  if (prefetched.has(rscUrl)) return;
87
60
  prefetched.add(rscUrl);
88
61
  (window.requestIdleCallback ?? ((fn) => setTimeout(fn, 100)))(() => {
89
- if (typeof window.__VINEXT_RSC_NAVIGATE__ === "function") fetch(rscUrl, {
62
+ if (typeof window.__VINEXT_RSC_NAVIGATE__ === "function") prefetchRscResponse(rscUrl, fetch(rscUrl, {
90
63
  headers: { Accept: "text/x-component" },
91
64
  credentials: "include",
92
65
  priority: "low",
93
66
  purpose: "prefetch"
94
- }).then((response) => {
95
- if (response.ok) storePrefetchResponse(rscUrl, response);
96
- else prefetched.delete(rscUrl);
97
- }).catch(() => {
98
- prefetched.delete(rscUrl);
99
- });
67
+ }));
100
68
  else if (window.__NEXT_DATA__?.__vinext?.pageModuleUrl) {
101
69
  const link = document.createElement("link");
102
70
  link.rel = "prefetch";
@@ -229,30 +197,10 @@ const Link = forwardRef(function Link({ href, as, replace = false, prefetch: pre
229
197
  onNavigate(navEvent);
230
198
  if (navEvent.defaultPrevented) return;
231
199
  } catch {}
232
- if (!replace) {
233
- const state = window.history.state ?? {};
234
- window.history.replaceState({
235
- ...state,
236
- __vinext_scrollX: window.scrollX,
237
- __vinext_scrollY: window.scrollY
238
- }, "");
239
- }
240
- if (typeof window !== "undefined" && isHashOnlyChange(absoluteFullHref)) {
241
- const hash = absoluteFullHref.includes("#") ? absoluteFullHref.slice(absoluteFullHref.indexOf("#")) : "";
242
- if (replace) window.history.replaceState(null, "", absoluteFullHref);
243
- else window.history.pushState(null, "", absoluteFullHref);
244
- if (scroll) scrollToHash(hash);
245
- return;
246
- }
247
- const hashIdx = absoluteFullHref.indexOf("#");
248
- const hash = hashIdx !== -1 ? absoluteFullHref.slice(hashIdx) : "";
249
200
  if (typeof window.__VINEXT_RSC_NAVIGATE__ === "function") {
250
- notifyAppRouterTransitionStart(absoluteFullHref, replace ? "replace" : "push");
251
- if (replace) window.history.replaceState(null, "", absoluteFullHref);
252
- else window.history.pushState(null, "", absoluteFullHref);
253
201
  setPending(true);
254
202
  try {
255
- await window.__VINEXT_RSC_NAVIGATE__(absoluteFullHref);
203
+ await navigateClientSide(navigateHref, replace ? "replace" : "push", scroll);
256
204
  } finally {
257
205
  if (mountedRef.current) setPending(false);
258
206
  }
@@ -265,8 +213,6 @@ const Link = forwardRef(function Link({ href, as, replace = false, prefetch: pre
265
213
  else window.history.pushState({}, "", absoluteFullHref);
266
214
  window.dispatchEvent(new PopStateEvent("popstate"));
267
215
  }
268
- if (scroll) if (hash) scrollToHash(hash);
269
- else window.scrollTo(0, 0);
270
216
  };
271
217
  const { passHref: _p, ...anchorProps } = restWithoutLocale;
272
218
  const linkStatusValue = React.useMemo(() => ({ pending }), [pending]);
@@ -1 +1 @@
1
- {"version":3,"file":"link.js","names":[],"sources":["../../src/shims/link.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * next/link shim\n *\n * Renders an <a> tag with client-side navigation support.\n * On click, prevents full page reload and triggers client-side\n * page swap via the router's navigation system.\n */\nimport React, {\n forwardRef,\n useRef,\n useEffect,\n useCallback,\n useContext,\n createContext,\n useState,\n type AnchorHTMLAttributes,\n type MouseEvent,\n} from \"react\";\n// Import shared RSC prefetch utilities from navigation shim (relative path\n// so this resolves both via the Vite plugin and in direct vitest imports)\nimport { toRscUrl, getPrefetchedUrls, storePrefetchResponse } from \"./navigation.js\";\nimport { notifyAppRouterTransitionStart } from \"../client/instrumentation-client-state.js\";\nimport { isDangerousScheme } from \"./url-safety.js\";\nimport {\n resolveRelativeHref,\n toBrowserNavigationHref,\n toSameOriginAppPath,\n withBasePath,\n} from \"./url-utils.js\";\nimport { appendSearchParamsToUrl, type UrlQuery, urlQueryToSearchParams } from \"../utils/query.js\";\nimport { addLocalePrefix, getDomainLocaleUrl, type DomainLocale } from \"../utils/domain-locale.js\";\nimport { getI18nContext } from \"./i18n-context.js\";\nimport type { VinextNextData } from \"../client/vinext-next-data.js\";\n\ninterface NavigateEvent {\n url: URL;\n /** Call to prevent the Link's default navigation (e.g. for View Transitions). */\n preventDefault(): void;\n /** Whether preventDefault() has been called. */\n defaultPrevented: boolean;\n}\n\ninterface LinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, \"href\"> {\n href: string | { pathname?: string; query?: UrlQuery };\n /** URL displayed in the browser (when href is a route pattern like /user/[id]) */\n as?: string;\n /** Replace the current history entry instead of pushing */\n replace?: boolean;\n /** Prefetch the page in the background (default: true, uses IntersectionObserver) */\n prefetch?: boolean;\n /** Whether to pass the href to the child element */\n passHref?: boolean;\n /** Scroll to top on navigation (default: true) */\n scroll?: boolean;\n /** Locale for i18n (used for locale-prefixed URLs) */\n locale?: string | false;\n /** Called before navigation happens (Next.js 16). Return value is ignored. */\n onNavigate?: (event: NavigateEvent) => void;\n children?: React.ReactNode;\n}\n\n// ---------------------------------------------------------------------------\n// useLinkStatus — reports the pending state of a parent <Link> navigation\n// ---------------------------------------------------------------------------\n\ninterface LinkStatusContextValue {\n pending: boolean;\n}\n\nconst LinkStatusContext = createContext<LinkStatusContextValue>({ pending: false });\n\n/**\n * useLinkStatus returns the pending state of the enclosing <Link>.\n * In Next.js, this is used to show loading indicators while a\n * prefetch-triggered navigation is in progress.\n */\nexport function useLinkStatus(): LinkStatusContextValue {\n return useContext(LinkStatusContext);\n}\n\n/** basePath from next.config.js, injected by the plugin at build time */\nconst __basePath: string = process.env.__NEXT_ROUTER_BASEPATH ?? \"\";\n\nfunction resolveHref(href: LinkProps[\"href\"]): string {\n if (typeof href === \"string\") return href;\n let url = href.pathname ?? \"/\";\n if (href.query) {\n const params = urlQueryToSearchParams(href.query);\n url = appendSearchParamsToUrl(url, params);\n }\n return url;\n}\n\n/**\n * Check if a href is only a hash change (same pathname, different/added hash).\n * Handles relative hashes like \"#foo\" and \"?query#foo\".\n */\nfunction isHashOnlyChange(href: string): boolean {\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 return current.pathname === next.pathname && current.search === next.search && next.hash !== \"\";\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); // Remove leading #\n const element = document.getElementById(id);\n if (element) {\n element.scrollIntoView({ behavior: \"auto\" });\n }\n}\n\n// ---------------------------------------------------------------------------\n// Prefetching infrastructure\n// ---------------------------------------------------------------------------\n\n/**\n * Prefetch a URL for faster navigation.\n *\n * For App Router (RSC): fetches the .rsc payload in the background and\n * stores it in an in-memory cache for instant use during navigation.\n * For Pages Router: injects a <link rel=\"prefetch\"> for the page module.\n *\n * Uses `requestIdleCallback` (or `setTimeout` fallback) to avoid blocking\n * the main thread during initial page load.\n */\nfunction prefetchUrl(href: string): void {\n if (typeof window === \"undefined\") return;\n\n // Normalize same-origin absolute URLs to local paths before prefetching\n let prefetchHref = href;\n if (href.startsWith(\"http://\") || href.startsWith(\"https://\") || href.startsWith(\"//\")) {\n const localPath = toSameOriginAppPath(href, __basePath);\n if (localPath == null) return; // truly external — don't prefetch\n prefetchHref = localPath;\n }\n\n const fullHref = toBrowserNavigationHref(prefetchHref, window.location.href, __basePath);\n\n // Don't prefetch the same URL twice (keyed by rscUrl so the browser\n // entry can clear the key when a cache entry is consumed)\n const rscUrl = toRscUrl(fullHref);\n const prefetched = getPrefetchedUrls();\n if (prefetched.has(rscUrl)) return;\n prefetched.add(rscUrl);\n\n const schedule = (window as any).requestIdleCallback ?? ((fn: () => void) => setTimeout(fn, 100));\n\n schedule(() => {\n if (typeof window.__VINEXT_RSC_NAVIGATE__ === \"function\") {\n // App Router: prefetch the RSC payload and store in cache\n fetch(rscUrl, {\n headers: { Accept: \"text/x-component\" },\n credentials: \"include\",\n priority: \"low\" as any,\n // @ts-expect-error — purpose is a valid fetch option in some browsers\n purpose: \"prefetch\",\n })\n .then((response) => {\n if (response.ok) {\n storePrefetchResponse(rscUrl, response);\n } else {\n // Non-ok response: allow retry on next viewport intersection\n prefetched.delete(rscUrl);\n }\n })\n .catch(() => {\n // Network error: allow retry on next viewport intersection\n prefetched.delete(rscUrl);\n });\n } else if ((window.__NEXT_DATA__ as VinextNextData | undefined)?.__vinext?.pageModuleUrl) {\n // Pages Router: inject a prefetch link for the target page module\n // We can't easily resolve the target page's module URL from the Link,\n // so we create a <link rel=\"prefetch\"> for the HTML page which helps\n // the browser's preload scanner.\n const link = document.createElement(\"link\");\n link.rel = \"prefetch\";\n link.href = fullHref;\n link.as = \"document\";\n document.head.appendChild(link);\n }\n });\n}\n\n/**\n * Shared IntersectionObserver for viewport-based prefetching.\n * All Link elements use the same observer to minimize resource usage.\n */\nlet sharedObserver: IntersectionObserver | null = null;\nconst observerCallbacks = new WeakMap<Element, () => void>();\n\nfunction getSharedObserver(): IntersectionObserver | null {\n if (typeof window === \"undefined\" || typeof IntersectionObserver === \"undefined\") return null;\n if (sharedObserver) return sharedObserver;\n\n sharedObserver = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (entry.isIntersecting) {\n const callback = observerCallbacks.get(entry.target);\n if (callback) {\n callback();\n // Unobserve after prefetching — only prefetch once\n sharedObserver?.unobserve(entry.target);\n observerCallbacks.delete(entry.target);\n }\n }\n }\n },\n {\n // Start prefetching when the link is within 250px of the viewport.\n // This gives the browser a head start before the user scrolls to it.\n rootMargin: \"250px\",\n },\n );\n\n return sharedObserver;\n}\n\nfunction getDefaultLocale(): string | undefined {\n if (typeof window !== \"undefined\") {\n return window.__VINEXT_DEFAULT_LOCALE__;\n }\n return getI18nContext()?.defaultLocale;\n}\n\nfunction getDomainLocales(): readonly DomainLocale[] | undefined {\n if (typeof window !== \"undefined\") {\n return (window.__NEXT_DATA__ as VinextNextData | undefined)?.domainLocales;\n }\n return getI18nContext()?.domainLocales;\n}\n\nfunction getCurrentHostname(): string | undefined {\n if (typeof window !== \"undefined\") return window.location.hostname;\n return getI18nContext()?.hostname;\n}\n\nfunction getDomainLocaleHref(href: string, locale: string): string | undefined {\n // Only cross-domain locale switches need a special absolute URL here.\n // Same-domain cases fall back to the standard locale-prefix logic below.\n return getDomainLocaleUrl(href, locale, {\n basePath: __basePath,\n currentHostname: getCurrentHostname(),\n domainItems: getDomainLocales(),\n });\n}\n\n/**\n * Apply locale prefix to a URL path based on the locale prop.\n * - locale=\"fr\" → prepend /fr (unless it already has a locale prefix)\n * - locale={false} → use the href as-is (no locale prefix, link to default)\n * - locale=undefined → use current locale (href as-is in most cases)\n */\nfunction applyLocaleToHref(href: string, locale: string | false | undefined): string {\n if (locale === false) {\n // Explicit false: no locale prefix\n return href;\n }\n\n if (locale === undefined) {\n // No locale prop: keep current behavior (href as-is)\n return href;\n }\n\n // Absolute and protocol-relative URLs must not be prefixed — locale\n // only applies to local paths.\n if (href.startsWith(\"http://\") || href.startsWith(\"https://\") || href.startsWith(\"//\")) {\n return href;\n }\n\n const domainLocaleHref = getDomainLocaleHref(href, locale);\n if (domainLocaleHref) {\n return domainLocaleHref;\n }\n\n return addLocalePrefix(href, locale, getDefaultLocale() ?? \"\");\n}\n\nconst Link = forwardRef<HTMLAnchorElement, LinkProps>(function Link(\n {\n href,\n as,\n replace = false,\n prefetch: prefetchProp,\n scroll = true,\n children,\n onClick,\n onNavigate,\n ...rest\n },\n forwardedRef,\n) {\n // Extract locale from rest props\n const { locale, ...restWithoutLocale } = rest as any;\n\n // If `as` is provided, use it as the actual URL (legacy Next.js pattern\n // where href is a route pattern like \"/user/[id]\" and as is \"/user/1\")\n const resolvedHref = as ?? resolveHref(href);\n\n const isDangerous = typeof resolvedHref === \"string\" && isDangerousScheme(resolvedHref);\n\n // Apply locale prefix if specified (safe even for dangerous hrefs since we\n // won't use the result when isDangerous is true)\n const localizedHref = applyLocaleToHref(isDangerous ? \"/\" : resolvedHref, locale);\n // Full href with basePath for browser URLs and fetches\n const fullHref = withBasePath(localizedHref, __basePath);\n\n // Track pending state for useLinkStatus()\n const [pending, setPending] = useState(false);\n const mountedRef = useRef(true);\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n\n // Prefetching: observe the element when it enters the viewport.\n // prefetch={false} disables, prefetch={true} or undefined/null (default) enables.\n const internalRef = useRef<HTMLAnchorElement | null>(null);\n const shouldPrefetch = prefetchProp !== false && !isDangerous;\n\n const setRefs = useCallback(\n (node: HTMLAnchorElement | null) => {\n internalRef.current = node;\n if (typeof forwardedRef === \"function\") forwardedRef(node);\n else if (forwardedRef)\n (forwardedRef as React.MutableRefObject<HTMLAnchorElement | null>).current = node;\n },\n [forwardedRef],\n );\n\n useEffect(() => {\n if (!shouldPrefetch || typeof window === \"undefined\") return;\n const node = internalRef.current;\n if (!node) return;\n\n // Normalize same-origin absolute URLs; skip truly external ones\n let hrefToPrefetch = localizedHref;\n if (\n localizedHref.startsWith(\"http://\") ||\n localizedHref.startsWith(\"https://\") ||\n localizedHref.startsWith(\"//\")\n ) {\n const localPath = toSameOriginAppPath(localizedHref, __basePath);\n if (localPath == null) return; // truly external\n hrefToPrefetch = localPath;\n }\n\n const observer = getSharedObserver();\n if (!observer) return;\n\n observerCallbacks.set(node, () => prefetchUrl(hrefToPrefetch));\n observer.observe(node);\n\n return () => {\n observer.unobserve(node);\n observerCallbacks.delete(node);\n };\n }, [shouldPrefetch, localizedHref]);\n\n const handleClick = async (e: MouseEvent<HTMLAnchorElement>) => {\n if (onClick) onClick(e);\n if (e.defaultPrevented) return;\n\n // Only intercept left clicks without modifiers (standard link behavior)\n if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {\n return;\n }\n\n // Don't intercept links with target (e.g. target=\"_blank\")\n if (e.currentTarget.target && e.currentTarget.target !== \"_self\") {\n return;\n }\n\n // External links: let the browser handle it.\n // Same-origin absolute URLs (e.g. http://localhost:3000/about) are\n // normalized to local paths so they get client-side navigation.\n let navigateHref = localizedHref;\n if (\n resolvedHref.startsWith(\"http://\") ||\n resolvedHref.startsWith(\"https://\") ||\n resolvedHref.startsWith(\"//\")\n ) {\n const localPath = toSameOriginAppPath(resolvedHref, __basePath);\n if (localPath == null) return; // truly external\n navigateHref = localPath;\n }\n\n e.preventDefault();\n\n // Resolve relative hrefs (#hash, ?query) against the current URL once so\n // onNavigate and the actual navigation target stay in sync.\n const absoluteHref = resolveRelativeHref(navigateHref, window.location.href, __basePath);\n const absoluteFullHref = toBrowserNavigationHref(\n navigateHref,\n window.location.href,\n __basePath,\n );\n\n // Call onNavigate callback if provided (Next.js 16 View Transitions support)\n if (onNavigate) {\n try {\n const navUrl = new URL(absoluteFullHref, window.location.origin);\n let prevented = false;\n const navEvent: NavigateEvent = {\n url: navUrl,\n preventDefault() {\n prevented = true;\n },\n get defaultPrevented() {\n return prevented;\n },\n };\n onNavigate(navEvent);\n // If the callback called preventDefault(), skip Link's default navigation.\n // The callback is responsible for its own navigation (e.g. via View Transitions API).\n if (navEvent.defaultPrevented) {\n return;\n }\n } catch {\n // Ignore URL parsing errors for relative/hash hrefs\n }\n }\n\n // Save scroll position for back/forward restoration\n if (!replace) {\n const state = window.history.state ?? {};\n window.history.replaceState(\n { ...state, __vinext_scrollX: window.scrollX, __vinext_scrollY: window.scrollY },\n \"\",\n );\n }\n\n // Hash-only change: update URL and scroll to target, skip RSC fetch\n if (typeof window !== \"undefined\" && isHashOnlyChange(absoluteFullHref)) {\n const hash = absoluteFullHref.includes(\"#\")\n ? absoluteFullHref.slice(absoluteFullHref.indexOf(\"#\"))\n : \"\";\n if (replace) {\n window.history.replaceState(null, \"\", absoluteFullHref);\n } else {\n window.history.pushState(null, \"\", absoluteFullHref);\n }\n if (scroll) {\n scrollToHash(hash);\n }\n return;\n }\n\n // Extract hash for scroll-after-navigation\n const hashIdx = absoluteFullHref.indexOf(\"#\");\n const hash = hashIdx !== -1 ? absoluteFullHref.slice(hashIdx) : \"\";\n\n // Try RSC navigation first (App Router), then Pages Router\n if (typeof window.__VINEXT_RSC_NAVIGATE__ === \"function\") {\n // App Router: push/replace history state, then fetch RSC stream.\n // Await the RSC navigate so scroll-to-top happens after the new\n // content is committed to the DOM (prevents flash of old page at top).\n notifyAppRouterTransitionStart(absoluteFullHref, replace ? \"replace\" : \"push\");\n if (replace) {\n window.history.replaceState(null, \"\", absoluteFullHref);\n } else {\n window.history.pushState(null, \"\", absoluteFullHref);\n }\n setPending(true);\n try {\n await window.__VINEXT_RSC_NAVIGATE__(absoluteFullHref);\n } finally {\n if (mountedRef.current) setPending(false);\n }\n } else {\n // Next.js only consumes onRouterTransitionStart in the App Router.\n // Pages Router still executes instrumentation-client side effects\n // during startup, but it does not invoke the named export on navigation.\n // Pages Router: use the Router singleton\n try {\n const routerModule = await import(\"next/router\");\n // eslint-disable-next-line -- vinext's Router shim accepts (url, as, options)\n const Router = routerModule.default as any;\n if (replace) {\n await Router.replace(absoluteHref, undefined, { scroll });\n } else {\n await Router.push(absoluteHref, undefined, { scroll });\n }\n } catch {\n // Fallback to hard navigation if router fails\n if (replace) {\n window.history.replaceState({}, \"\", absoluteFullHref);\n } else {\n window.history.pushState({}, \"\", absoluteFullHref);\n }\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n }\n }\n\n if (scroll) {\n if (hash) {\n scrollToHash(hash);\n } else {\n window.scrollTo(0, 0);\n }\n }\n };\n\n // Remove props that shouldn't be on <a>\n const { passHref: _p, ...anchorProps } = restWithoutLocale;\n\n const linkStatusValue = React.useMemo(() => ({ pending }), [pending]);\n\n // Block dangerous URI schemes (javascript:, data:, vbscript:).\n // Render an inert <a> without href to prevent XSS while preserving\n // styling and attributes like className, id, aria-*.\n // This check is placed after all hooks to satisfy the Rules of Hooks.\n if (isDangerous) {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(`<Link> blocked dangerous href: ${resolvedHref}`);\n }\n return <a {...anchorProps}>{children}</a>;\n }\n\n return (\n <LinkStatusContext.Provider value={linkStatusValue}>\n <a ref={setRefs} href={fullHref} onClick={handleClick} {...anchorProps}>\n {children}\n </a>\n </LinkStatusContext.Provider>\n );\n});\n\nexport default Link;\n"],"mappings":"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"}
1
+ {"version":3,"file":"link.js","names":[],"sources":["../../src/shims/link.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * next/link shim\n *\n * Renders an <a> tag with client-side navigation support.\n * On click, prevents full page reload and triggers client-side\n * page swap via the router's navigation system.\n */\nimport React, {\n forwardRef,\n useRef,\n useEffect,\n useCallback,\n useContext,\n createContext,\n useState,\n type AnchorHTMLAttributes,\n type MouseEvent,\n} from \"react\";\n// Import shared RSC prefetch utilities from navigation shim (relative path\n// so this resolves both via the Vite plugin and in direct vitest imports)\nimport {\n toRscUrl,\n getPrefetchedUrls,\n navigateClientSide,\n prefetchRscResponse,\n} from \"./navigation.js\";\nimport { isDangerousScheme } from \"./url-safety.js\";\nimport {\n resolveRelativeHref,\n toBrowserNavigationHref,\n toSameOriginAppPath,\n withBasePath,\n} from \"./url-utils.js\";\nimport { appendSearchParamsToUrl, type UrlQuery, urlQueryToSearchParams } from \"../utils/query.js\";\nimport { addLocalePrefix, getDomainLocaleUrl, type DomainLocale } from \"../utils/domain-locale.js\";\nimport { getI18nContext } from \"./i18n-context.js\";\nimport type { VinextNextData } from \"../client/vinext-next-data.js\";\n\ntype NavigateEvent = {\n url: URL;\n /** Call to prevent the Link's default navigation (e.g. for View Transitions). */\n preventDefault(): void;\n /** Whether preventDefault() has been called. */\n defaultPrevented: boolean;\n};\n\ntype LinkProps = {\n href: string | { pathname?: string; query?: UrlQuery };\n /** URL displayed in the browser (when href is a route pattern like /user/[id]) */\n as?: string;\n /** Replace the current history entry instead of pushing */\n replace?: boolean;\n /** Prefetch the page in the background (default: true, uses IntersectionObserver) */\n prefetch?: boolean;\n /** Whether to pass the href to the child element */\n passHref?: boolean;\n /** Scroll to top on navigation (default: true) */\n scroll?: boolean;\n /** Locale for i18n (used for locale-prefixed URLs) */\n locale?: string | false;\n /** Called before navigation happens (Next.js 16). Return value is ignored. */\n onNavigate?: (event: NavigateEvent) => void;\n children?: React.ReactNode;\n} & Omit<AnchorHTMLAttributes<HTMLAnchorElement>, \"href\">;\n\n// ---------------------------------------------------------------------------\n// useLinkStatus — reports the pending state of a parent <Link> navigation\n// ---------------------------------------------------------------------------\n\ntype LinkStatusContextValue = {\n pending: boolean;\n};\n\nconst LinkStatusContext = createContext<LinkStatusContextValue>({ pending: false });\n\n/**\n * useLinkStatus returns the pending state of the enclosing <Link>.\n * In Next.js, this is used to show loading indicators while a\n * prefetch-triggered navigation is in progress.\n */\nexport function useLinkStatus(): LinkStatusContextValue {\n return useContext(LinkStatusContext);\n}\n\n/** basePath from next.config.js, injected by the plugin at build time */\nconst __basePath: string = process.env.__NEXT_ROUTER_BASEPATH ?? \"\";\n\nfunction resolveHref(href: LinkProps[\"href\"]): string {\n if (typeof href === \"string\") return href;\n let url = href.pathname ?? \"/\";\n if (href.query) {\n const params = urlQueryToSearchParams(href.query);\n url = appendSearchParamsToUrl(url, params);\n }\n return url;\n}\n\n// ---------------------------------------------------------------------------\n// Prefetching infrastructure\n// ---------------------------------------------------------------------------\n\n/**\n * Prefetch a URL for faster navigation.\n *\n * For App Router (RSC): fetches the .rsc payload in the background and\n * stores it in an in-memory cache for instant use during navigation.\n * For Pages Router: injects a <link rel=\"prefetch\"> for the page module.\n *\n * Uses `requestIdleCallback` (or `setTimeout` fallback) to avoid blocking\n * the main thread during initial page load.\n */\nfunction prefetchUrl(href: string): void {\n if (typeof window === \"undefined\") return;\n\n // Normalize same-origin absolute URLs to local paths before prefetching\n let prefetchHref = href;\n if (href.startsWith(\"http://\") || href.startsWith(\"https://\") || href.startsWith(\"//\")) {\n const localPath = toSameOriginAppPath(href, __basePath);\n if (localPath == null) return; // truly external — don't prefetch\n prefetchHref = localPath;\n }\n\n const fullHref = toBrowserNavigationHref(prefetchHref, window.location.href, __basePath);\n\n // Don't prefetch the same URL twice (keyed by rscUrl so the browser\n // entry can clear the key when a cache entry is consumed)\n const rscUrl = toRscUrl(fullHref);\n const prefetched = getPrefetchedUrls();\n if (prefetched.has(rscUrl)) return;\n prefetched.add(rscUrl);\n\n const schedule = window.requestIdleCallback ?? ((fn: () => void) => setTimeout(fn, 100));\n\n schedule(() => {\n if (typeof window.__VINEXT_RSC_NAVIGATE__ === \"function\") {\n prefetchRscResponse(\n rscUrl,\n fetch(rscUrl, {\n headers: { Accept: \"text/x-component\" },\n credentials: \"include\",\n priority: \"low\" as const,\n // @ts-expect-error — purpose is a valid fetch option in some browsers\n purpose: \"prefetch\",\n }),\n );\n } else if ((window.__NEXT_DATA__ as VinextNextData | undefined)?.__vinext?.pageModuleUrl) {\n // Pages Router: inject a prefetch link for the target page module\n // We can't easily resolve the target page's module URL from the Link,\n // so we create a <link rel=\"prefetch\"> for the HTML page which helps\n // the browser's preload scanner.\n const link = document.createElement(\"link\");\n link.rel = \"prefetch\";\n link.href = fullHref;\n link.as = \"document\";\n document.head.appendChild(link);\n }\n });\n}\n\n/**\n * Shared IntersectionObserver for viewport-based prefetching.\n * All Link elements use the same observer to minimize resource usage.\n */\nlet sharedObserver: IntersectionObserver | null = null;\nconst observerCallbacks = new WeakMap<Element, () => void>();\n\nfunction getSharedObserver(): IntersectionObserver | null {\n if (typeof window === \"undefined\" || typeof IntersectionObserver === \"undefined\") return null;\n if (sharedObserver) return sharedObserver;\n\n sharedObserver = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (entry.isIntersecting) {\n const callback = observerCallbacks.get(entry.target);\n if (callback) {\n callback();\n // Unobserve after prefetching — only prefetch once\n sharedObserver?.unobserve(entry.target);\n observerCallbacks.delete(entry.target);\n }\n }\n }\n },\n {\n // Start prefetching when the link is within 250px of the viewport.\n // This gives the browser a head start before the user scrolls to it.\n rootMargin: \"250px\",\n },\n );\n\n return sharedObserver;\n}\n\nfunction getDefaultLocale(): string | undefined {\n if (typeof window !== \"undefined\") {\n return window.__VINEXT_DEFAULT_LOCALE__;\n }\n return getI18nContext()?.defaultLocale;\n}\n\nfunction getDomainLocales(): readonly DomainLocale[] | undefined {\n if (typeof window !== \"undefined\") {\n return (window.__NEXT_DATA__ as VinextNextData | undefined)?.domainLocales;\n }\n return getI18nContext()?.domainLocales;\n}\n\nfunction getCurrentHostname(): string | undefined {\n if (typeof window !== \"undefined\") return window.location.hostname;\n return getI18nContext()?.hostname;\n}\n\nfunction getDomainLocaleHref(href: string, locale: string): string | undefined {\n // Only cross-domain locale switches need a special absolute URL here.\n // Same-domain cases fall back to the standard locale-prefix logic below.\n return getDomainLocaleUrl(href, locale, {\n basePath: __basePath,\n currentHostname: getCurrentHostname(),\n domainItems: getDomainLocales(),\n });\n}\n\n/**\n * Apply locale prefix to a URL path based on the locale prop.\n * - locale=\"fr\" → prepend /fr (unless it already has a locale prefix)\n * - locale={false} → use the href as-is (no locale prefix, link to default)\n * - locale=undefined → use current locale (href as-is in most cases)\n */\nfunction applyLocaleToHref(href: string, locale: string | false | undefined): string {\n if (locale === false) {\n // Explicit false: no locale prefix\n return href;\n }\n\n if (locale === undefined) {\n // No locale prop: keep current behavior (href as-is)\n return href;\n }\n\n // Absolute and protocol-relative URLs must not be prefixed — locale\n // only applies to local paths.\n if (href.startsWith(\"http://\") || href.startsWith(\"https://\") || href.startsWith(\"//\")) {\n return href;\n }\n\n const domainLocaleHref = getDomainLocaleHref(href, locale);\n if (domainLocaleHref) {\n return domainLocaleHref;\n }\n\n return addLocalePrefix(href, locale, getDefaultLocale() ?? \"\");\n}\n\nconst Link = forwardRef<HTMLAnchorElement, LinkProps>(function Link(\n {\n href,\n as,\n replace = false,\n prefetch: prefetchProp,\n scroll = true,\n children,\n onClick,\n onNavigate,\n ...rest\n },\n forwardedRef,\n) {\n // Extract locale from rest props\n const { locale, ...restWithoutLocale } = rest;\n\n // If `as` is provided, use it as the actual URL (legacy Next.js pattern\n // where href is a route pattern like \"/user/[id]\" and as is \"/user/1\")\n const resolvedHref = as ?? resolveHref(href);\n\n const isDangerous = typeof resolvedHref === \"string\" && isDangerousScheme(resolvedHref);\n\n // Apply locale prefix if specified (safe even for dangerous hrefs since we\n // won't use the result when isDangerous is true)\n const localizedHref = applyLocaleToHref(isDangerous ? \"/\" : resolvedHref, locale);\n // Full href with basePath for browser URLs and fetches\n const fullHref = withBasePath(localizedHref, __basePath);\n\n // Track pending state for useLinkStatus()\n const [pending, setPending] = useState(false);\n const mountedRef = useRef(true);\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n\n // Prefetching: observe the element when it enters the viewport.\n // prefetch={false} disables, prefetch={true} or undefined/null (default) enables.\n const internalRef = useRef<HTMLAnchorElement | null>(null);\n const shouldPrefetch = prefetchProp !== false && !isDangerous;\n\n const setRefs = useCallback(\n (node: HTMLAnchorElement | null) => {\n internalRef.current = node;\n if (typeof forwardedRef === \"function\") forwardedRef(node);\n else if (forwardedRef)\n (forwardedRef as React.MutableRefObject<HTMLAnchorElement | null>).current = node;\n },\n [forwardedRef],\n );\n\n useEffect(() => {\n if (!shouldPrefetch || typeof window === \"undefined\") return;\n const node = internalRef.current;\n if (!node) return;\n\n // Normalize same-origin absolute URLs; skip truly external ones\n let hrefToPrefetch = localizedHref;\n if (\n localizedHref.startsWith(\"http://\") ||\n localizedHref.startsWith(\"https://\") ||\n localizedHref.startsWith(\"//\")\n ) {\n const localPath = toSameOriginAppPath(localizedHref, __basePath);\n if (localPath == null) return; // truly external\n hrefToPrefetch = localPath;\n }\n\n const observer = getSharedObserver();\n if (!observer) return;\n\n observerCallbacks.set(node, () => prefetchUrl(hrefToPrefetch));\n observer.observe(node);\n\n return () => {\n observer.unobserve(node);\n observerCallbacks.delete(node);\n };\n }, [shouldPrefetch, localizedHref]);\n\n const handleClick = async (e: MouseEvent<HTMLAnchorElement>) => {\n if (onClick) onClick(e);\n if (e.defaultPrevented) return;\n\n // Only intercept left clicks without modifiers (standard link behavior)\n if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {\n return;\n }\n\n // Don't intercept links with target (e.g. target=\"_blank\")\n if (e.currentTarget.target && e.currentTarget.target !== \"_self\") {\n return;\n }\n\n // External links: let the browser handle it.\n // Same-origin absolute URLs (e.g. http://localhost:3000/about) are\n // normalized to local paths so they get client-side navigation.\n let navigateHref = localizedHref;\n if (\n resolvedHref.startsWith(\"http://\") ||\n resolvedHref.startsWith(\"https://\") ||\n resolvedHref.startsWith(\"//\")\n ) {\n const localPath = toSameOriginAppPath(resolvedHref, __basePath);\n if (localPath == null) return; // truly external\n navigateHref = localPath;\n }\n\n e.preventDefault();\n\n // Resolve relative hrefs (#hash, ?query) against the current URL once so\n // onNavigate and the actual navigation target stay in sync.\n const absoluteHref = resolveRelativeHref(navigateHref, window.location.href, __basePath);\n const absoluteFullHref = toBrowserNavigationHref(\n navigateHref,\n window.location.href,\n __basePath,\n );\n\n // Call onNavigate callback if provided (Next.js 16 View Transitions support)\n if (onNavigate) {\n try {\n const navUrl = new URL(absoluteFullHref, window.location.origin);\n let prevented = false;\n const navEvent: NavigateEvent = {\n url: navUrl,\n preventDefault() {\n prevented = true;\n },\n get defaultPrevented() {\n return prevented;\n },\n };\n onNavigate(navEvent);\n // If the callback called preventDefault(), skip Link's default navigation.\n // The callback is responsible for its own navigation (e.g. via View Transitions API).\n if (navEvent.defaultPrevented) {\n return;\n }\n } catch {\n // Ignore URL parsing errors for relative/hash hrefs\n }\n }\n\n // App Router: delegate to navigateClientSide which handles scroll save,\n // hash-only changes, RSC fetch, and two-phase URL commit.\n if (typeof window.__VINEXT_RSC_NAVIGATE__ === \"function\") {\n setPending(true);\n try {\n await navigateClientSide(navigateHref, replace ? \"replace\" : \"push\", scroll);\n } finally {\n if (mountedRef.current) setPending(false);\n }\n } else {\n // Next.js only consumes onRouterTransitionStart in the App Router.\n // Pages Router still executes instrumentation-client side effects\n // during startup, but it does not invoke the named export on navigation.\n // Pages Router: use the Router singleton\n try {\n const routerModule = await import(\"next/router\");\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any -- vinext's Router shim accepts (url, as, options)\n const Router = routerModule.default as any;\n if (replace) {\n await Router.replace(absoluteHref, undefined, { scroll });\n } else {\n await Router.push(absoluteHref, undefined, { scroll });\n }\n } catch {\n // Fallback to hard navigation if router fails\n if (replace) {\n window.history.replaceState({}, \"\", absoluteFullHref);\n } else {\n window.history.pushState({}, \"\", absoluteFullHref);\n }\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n }\n }\n };\n\n // Remove props that shouldn't be on <a>\n const { passHref: _p, ...anchorProps } = restWithoutLocale;\n\n const linkStatusValue = React.useMemo(() => ({ pending }), [pending]);\n\n // Block dangerous URI schemes (javascript:, data:, vbscript:).\n // Render an inert <a> without href to prevent XSS while preserving\n // styling and attributes like className, id, aria-*.\n // This check is placed after all hooks to satisfy the Rules of Hooks.\n if (isDangerous) {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(`<Link> blocked dangerous href: ${resolvedHref}`);\n }\n return <a {...anchorProps}>{children}</a>;\n }\n\n return (\n <LinkStatusContext.Provider value={linkStatusValue}>\n <a ref={setRefs} href={fullHref} onClick={handleClick} {...anchorProps}>\n {children}\n </a>\n </LinkStatusContext.Provider>\n );\n});\n\nexport default Link;\n"],"mappings":"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"}