vinext 0.0.51 → 0.0.52

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 (307) hide show
  1. package/dist/build/precompress.d.ts +7 -7
  2. package/dist/build/precompress.js +18 -17
  3. package/dist/build/precompress.js.map +1 -1
  4. package/dist/build/prerender.d.ts +3 -14
  5. package/dist/build/prerender.js +40 -40
  6. package/dist/build/prerender.js.map +1 -1
  7. package/dist/check.js +4 -0
  8. package/dist/check.js.map +1 -1
  9. package/dist/cli-args.d.ts +1 -0
  10. package/dist/cli-args.js +5 -0
  11. package/dist/cli-args.js.map +1 -1
  12. package/dist/cli.js +39 -0
  13. package/dist/cli.js.map +1 -1
  14. package/dist/client/navigation-runtime.d.ts +47 -0
  15. package/dist/client/navigation-runtime.js +156 -0
  16. package/dist/client/navigation-runtime.js.map +1 -0
  17. package/dist/client/pages-router-link-navigation.d.ts +26 -0
  18. package/dist/client/pages-router-link-navigation.js +14 -0
  19. package/dist/client/pages-router-link-navigation.js.map +1 -0
  20. package/dist/client/vinext-next-data.d.ts +12 -2
  21. package/dist/client/vinext-next-data.js +50 -1
  22. package/dist/client/vinext-next-data.js.map +1 -0
  23. package/dist/cloudflare/kv-cache-handler.js +2 -1
  24. package/dist/cloudflare/kv-cache-handler.js.map +1 -1
  25. package/dist/config/config-matchers.d.ts +63 -16
  26. package/dist/config/config-matchers.js +143 -8
  27. package/dist/config/config-matchers.js.map +1 -1
  28. package/dist/config/next-config.d.ts +20 -2
  29. package/dist/config/next-config.js +11 -1
  30. package/dist/config/next-config.js.map +1 -1
  31. package/dist/deploy.js +101 -39
  32. package/dist/deploy.js.map +1 -1
  33. package/dist/entries/app-browser-entry.js +9 -3
  34. package/dist/entries/app-browser-entry.js.map +1 -1
  35. package/dist/entries/app-rsc-entry.js +53 -13
  36. package/dist/entries/app-rsc-entry.js.map +1 -1
  37. package/dist/entries/app-rsc-manifest.d.ts +1 -0
  38. package/dist/entries/app-rsc-manifest.js +53 -6
  39. package/dist/entries/app-rsc-manifest.js.map +1 -1
  40. package/dist/entries/app-ssr-entry.d.ts +3 -3
  41. package/dist/entries/app-ssr-entry.js +4 -4
  42. package/dist/entries/app-ssr-entry.js.map +1 -1
  43. package/dist/entries/pages-client-entry.js +18 -2
  44. package/dist/entries/pages-client-entry.js.map +1 -1
  45. package/dist/entries/pages-server-entry.js +58 -8
  46. package/dist/entries/pages-server-entry.js.map +1 -1
  47. package/dist/entries/runtime-entry-module.d.ts +2 -1
  48. package/dist/entries/runtime-entry-module.js +9 -3
  49. package/dist/entries/runtime-entry-module.js.map +1 -1
  50. package/dist/index.js +132 -40
  51. package/dist/index.js.map +1 -1
  52. package/dist/plugins/css-data-url.d.ts +7 -0
  53. package/dist/plugins/css-data-url.js +81 -0
  54. package/dist/plugins/css-data-url.js.map +1 -0
  55. package/dist/plugins/fonts.js +5 -3
  56. package/dist/plugins/fonts.js.map +1 -1
  57. package/dist/plugins/middleware-server-only.d.ts +54 -0
  58. package/dist/plugins/middleware-server-only.js +91 -0
  59. package/dist/plugins/middleware-server-only.js.map +1 -0
  60. package/dist/plugins/optimize-imports.js +4 -4
  61. package/dist/plugins/optimize-imports.js.map +1 -1
  62. package/dist/plugins/strip-server-exports.js +5 -8
  63. package/dist/plugins/strip-server-exports.js.map +1 -1
  64. package/dist/routing/app-route-graph.d.ts +20 -1
  65. package/dist/routing/app-route-graph.js +58 -6
  66. package/dist/routing/app-route-graph.js.map +1 -1
  67. package/dist/routing/app-router.d.ts +2 -2
  68. package/dist/routing/app-router.js +2 -2
  69. package/dist/routing/app-router.js.map +1 -1
  70. package/dist/routing/utils.d.ts +2 -1
  71. package/dist/routing/utils.js +4 -1
  72. package/dist/routing/utils.js.map +1 -1
  73. package/dist/server/api-handler.js +139 -37
  74. package/dist/server/api-handler.js.map +1 -1
  75. package/dist/server/app-browser-entry.js +293 -149
  76. package/dist/server/app-browser-entry.js.map +1 -1
  77. package/dist/server/app-browser-interception-context.d.ts +24 -0
  78. package/dist/server/app-browser-interception-context.js +32 -0
  79. package/dist/server/app-browser-interception-context.js.map +1 -0
  80. package/dist/server/app-browser-navigation-controller.d.ts +3 -1
  81. package/dist/server/app-browser-navigation-controller.js +5 -1
  82. package/dist/server/app-browser-navigation-controller.js.map +1 -1
  83. package/dist/server/app-browser-rsc-redirect.d.ts +2 -1
  84. package/dist/server/app-browser-rsc-redirect.js +2 -2
  85. package/dist/server/app-browser-rsc-redirect.js.map +1 -1
  86. package/dist/server/app-browser-state.d.ts +18 -1
  87. package/dist/server/app-browser-state.js +19 -1
  88. package/dist/server/app-browser-state.js.map +1 -1
  89. package/dist/server/app-browser-stream.d.ts +5 -14
  90. package/dist/server/app-browser-stream.js +13 -7
  91. package/dist/server/app-browser-stream.js.map +1 -1
  92. package/dist/server/app-browser-visible-commit.d.ts +2 -1
  93. package/dist/server/app-browser-visible-commit.js +1 -0
  94. package/dist/server/app-browser-visible-commit.js.map +1 -1
  95. package/dist/server/app-elements-wire.d.ts +10 -5
  96. package/dist/server/app-elements-wire.js +84 -2
  97. package/dist/server/app-elements-wire.js.map +1 -1
  98. package/dist/server/app-elements.d.ts +3 -2
  99. package/dist/server/app-elements.js +3 -2
  100. package/dist/server/app-elements.js.map +1 -1
  101. package/dist/server/app-fallback-renderer.js +5 -3
  102. package/dist/server/app-fallback-renderer.js.map +1 -1
  103. package/dist/server/app-middleware.d.ts +13 -0
  104. package/dist/server/app-middleware.js +3 -1
  105. package/dist/server/app-middleware.js.map +1 -1
  106. package/dist/server/app-optimistic-routing.d.ts +54 -0
  107. package/dist/server/app-optimistic-routing.js +200 -0
  108. package/dist/server/app-optimistic-routing.js.map +1 -0
  109. package/dist/server/app-page-cache.d.ts +13 -1
  110. package/dist/server/app-page-cache.js +61 -6
  111. package/dist/server/app-page-cache.js.map +1 -1
  112. package/dist/server/app-page-dispatch.d.ts +2 -0
  113. package/dist/server/app-page-dispatch.js +28 -1
  114. package/dist/server/app-page-dispatch.js.map +1 -1
  115. package/dist/server/app-page-element-builder.js +2 -1
  116. package/dist/server/app-page-element-builder.js.map +1 -1
  117. package/dist/server/app-page-execution.d.ts +28 -1
  118. package/dist/server/app-page-execution.js +89 -4
  119. package/dist/server/app-page-execution.js.map +1 -1
  120. package/dist/server/app-page-head.js +21 -2
  121. package/dist/server/app-page-head.js.map +1 -1
  122. package/dist/server/app-page-probe.js +1 -1
  123. package/dist/server/app-page-render.d.ts +2 -0
  124. package/dist/server/app-page-render.js +2 -1
  125. package/dist/server/app-page-render.js.map +1 -1
  126. package/dist/server/app-page-response.js +4 -3
  127. package/dist/server/app-page-response.js.map +1 -1
  128. package/dist/server/app-page-route-wiring.js +17 -10
  129. package/dist/server/app-page-route-wiring.js.map +1 -1
  130. package/dist/server/app-page-stream.d.ts +3 -0
  131. package/dist/server/app-page-stream.js +1 -0
  132. package/dist/server/app-page-stream.js.map +1 -1
  133. package/dist/server/app-prerender-static-params.d.ts +2 -1
  134. package/dist/server/app-prerender-static-params.js +44 -8
  135. package/dist/server/app-prerender-static-params.js.map +1 -1
  136. package/dist/server/app-route-handler-cache.d.ts +2 -2
  137. package/dist/server/app-route-handler-cache.js +3 -2
  138. package/dist/server/app-route-handler-cache.js.map +1 -1
  139. package/dist/server/app-route-handler-dispatch.d.ts +6 -1
  140. package/dist/server/app-route-handler-dispatch.js +1 -1
  141. package/dist/server/app-route-handler-dispatch.js.map +1 -1
  142. package/dist/server/app-route-handler-execution.d.ts +17 -2
  143. package/dist/server/app-route-handler-execution.js.map +1 -1
  144. package/dist/server/app-route-handler-response.js +5 -4
  145. package/dist/server/app-route-handler-response.js.map +1 -1
  146. package/dist/server/app-router-entry.js +6 -2
  147. package/dist/server/app-router-entry.js.map +1 -1
  148. package/dist/server/app-rsc-handler.d.ts +9 -1
  149. package/dist/server/app-rsc-handler.js +32 -14
  150. package/dist/server/app-rsc-handler.js.map +1 -1
  151. package/dist/server/app-rsc-render-mode.d.ts +4 -3
  152. package/dist/server/app-rsc-render-mode.js +7 -1
  153. package/dist/server/app-rsc-render-mode.js.map +1 -1
  154. package/dist/server/app-rsc-request-normalization.d.ts +4 -1
  155. package/dist/server/app-rsc-request-normalization.js +4 -1
  156. package/dist/server/app-rsc-request-normalization.js.map +1 -1
  157. package/dist/server/app-rsc-response-finalizer.d.ts +8 -1
  158. package/dist/server/app-rsc-response-finalizer.js +10 -3
  159. package/dist/server/app-rsc-response-finalizer.js.map +1 -1
  160. package/dist/server/app-rsc-route-matching.js +2 -2
  161. package/dist/server/app-rsc-route-matching.js.map +1 -1
  162. package/dist/server/app-server-action-execution.js +1 -1
  163. package/dist/server/app-ssr-entry.d.ts +2 -0
  164. package/dist/server/app-ssr-entry.js +56 -55
  165. package/dist/server/app-ssr-entry.js.map +1 -1
  166. package/dist/server/app-ssr-stream.d.ts +6 -1
  167. package/dist/server/app-ssr-stream.js +17 -3
  168. package/dist/server/app-ssr-stream.js.map +1 -1
  169. package/dist/server/artifact-compatibility.d.ts +1 -1
  170. package/dist/server/artifact-compatibility.js.map +1 -1
  171. package/dist/server/cache-headers.d.ts +7 -0
  172. package/dist/server/cache-headers.js +19 -0
  173. package/dist/server/cache-headers.js.map +1 -0
  174. package/dist/server/cache-proof.d.ts +49 -3
  175. package/dist/server/cache-proof.js +78 -22
  176. package/dist/server/cache-proof.js.map +1 -1
  177. package/dist/server/client-reuse-manifest.d.ts +99 -0
  178. package/dist/server/client-reuse-manifest.js +212 -0
  179. package/dist/server/client-reuse-manifest.js.map +1 -0
  180. package/dist/server/default-global-error-module.d.ts +20 -0
  181. package/dist/server/default-global-error-module.js +20 -0
  182. package/dist/server/default-global-error-module.js.map +1 -0
  183. package/dist/server/dev-server.d.ts +9 -1
  184. package/dist/server/dev-server.js +76 -29
  185. package/dist/server/dev-server.js.map +1 -1
  186. package/dist/server/edge-api-runtime.d.ts +5 -0
  187. package/dist/server/edge-api-runtime.js +8 -0
  188. package/dist/server/edge-api-runtime.js.map +1 -0
  189. package/dist/server/headers.d.ts +18 -1
  190. package/dist/server/headers.js +18 -1
  191. package/dist/server/headers.js.map +1 -1
  192. package/dist/server/http-error-responses.d.ts +16 -1
  193. package/dist/server/http-error-responses.js +21 -1
  194. package/dist/server/http-error-responses.js.map +1 -1
  195. package/dist/server/isr-cache.d.ts +6 -2
  196. package/dist/server/isr-cache.js +20 -4
  197. package/dist/server/isr-cache.js.map +1 -1
  198. package/dist/server/middleware-runtime.d.ts +15 -0
  199. package/dist/server/middleware-runtime.js +59 -7
  200. package/dist/server/middleware-runtime.js.map +1 -1
  201. package/dist/server/middleware.d.ts +1 -1
  202. package/dist/server/middleware.js +4 -2
  203. package/dist/server/middleware.js.map +1 -1
  204. package/dist/server/navigation-planner.d.ts +9 -3
  205. package/dist/server/navigation-planner.js +98 -25
  206. package/dist/server/navigation-planner.js.map +1 -1
  207. package/dist/server/navigation-trace.d.ts +2 -1
  208. package/dist/server/navigation-trace.js +1 -0
  209. package/dist/server/navigation-trace.js.map +1 -1
  210. package/dist/server/pages-api-route.d.ts +27 -1
  211. package/dist/server/pages-api-route.js +24 -3
  212. package/dist/server/pages-api-route.js.map +1 -1
  213. package/dist/server/pages-data-route.d.ts +77 -0
  214. package/dist/server/pages-data-route.js +97 -0
  215. package/dist/server/pages-data-route.js.map +1 -0
  216. package/dist/server/pages-i18n.d.ts +51 -1
  217. package/dist/server/pages-i18n.js +61 -1
  218. package/dist/server/pages-i18n.js.map +1 -1
  219. package/dist/server/pages-page-data.d.ts +29 -2
  220. package/dist/server/pages-page-data.js +31 -17
  221. package/dist/server/pages-page-data.js.map +1 -1
  222. package/dist/server/pages-page-response.d.ts +11 -1
  223. package/dist/server/pages-page-response.js +5 -3
  224. package/dist/server/pages-page-response.js.map +1 -1
  225. package/dist/server/prod-server.d.ts +13 -15
  226. package/dist/server/prod-server.js +109 -56
  227. package/dist/server/prod-server.js.map +1 -1
  228. package/dist/server/request-pipeline.d.ts +11 -2
  229. package/dist/server/request-pipeline.js +28 -11
  230. package/dist/server/request-pipeline.js.map +1 -1
  231. package/dist/server/seed-cache.d.ts +12 -31
  232. package/dist/server/seed-cache.js +22 -35
  233. package/dist/server/seed-cache.js.map +1 -1
  234. package/dist/server/server-action-not-found.js +8 -3
  235. package/dist/server/server-action-not-found.js.map +1 -1
  236. package/dist/server/skip-cache-proof.d.ts +41 -0
  237. package/dist/server/skip-cache-proof.js +101 -0
  238. package/dist/server/skip-cache-proof.js.map +1 -0
  239. package/dist/server/static-file-cache.d.ts +1 -1
  240. package/dist/server/static-file-cache.js +7 -6
  241. package/dist/server/static-file-cache.js.map +1 -1
  242. package/dist/shims/client-locale.d.ts +15 -0
  243. package/dist/shims/client-locale.js +13 -0
  244. package/dist/shims/client-locale.js.map +1 -0
  245. package/dist/shims/default-global-error.d.ts +32 -0
  246. package/dist/shims/default-global-error.js +181 -0
  247. package/dist/shims/default-global-error.js.map +1 -0
  248. package/dist/shims/document.d.ts +59 -3
  249. package/dist/shims/document.js +36 -5
  250. package/dist/shims/document.js.map +1 -1
  251. package/dist/shims/error-boundary.d.ts +2 -2
  252. package/dist/shims/form.js +13 -6
  253. package/dist/shims/form.js.map +1 -1
  254. package/dist/shims/link.d.ts +21 -3
  255. package/dist/shims/link.js +131 -22
  256. package/dist/shims/link.js.map +1 -1
  257. package/dist/shims/metadata.js +4 -4
  258. package/dist/shims/metadata.js.map +1 -1
  259. package/dist/shims/navigation.d.ts +8 -2
  260. package/dist/shims/navigation.js +36 -15
  261. package/dist/shims/navigation.js.map +1 -1
  262. package/dist/shims/og.d.ts +18 -2
  263. package/dist/shims/og.js +49 -1
  264. package/dist/shims/og.js.map +1 -0
  265. package/dist/shims/request-state-types.d.ts +1 -1
  266. package/dist/shims/root-params.d.ts +3 -1
  267. package/dist/shims/root-params.js +11 -3
  268. package/dist/shims/root-params.js.map +1 -1
  269. package/dist/shims/router-state.d.ts +1 -0
  270. package/dist/shims/router-state.js.map +1 -1
  271. package/dist/shims/router.d.ts +12 -5
  272. package/dist/shims/router.js +172 -22
  273. package/dist/shims/router.js.map +1 -1
  274. package/dist/shims/server.d.ts +21 -4
  275. package/dist/shims/server.js +29 -9
  276. package/dist/shims/server.js.map +1 -1
  277. package/dist/shims/slot.js +5 -1
  278. package/dist/shims/slot.js.map +1 -1
  279. package/dist/shims/unified-request-context.d.ts +1 -1
  280. package/dist/shims/url-safety.d.ts +23 -1
  281. package/dist/shims/url-safety.js +29 -2
  282. package/dist/shims/url-safety.js.map +1 -1
  283. package/dist/typegen.d.ts +10 -0
  284. package/dist/typegen.js +242 -0
  285. package/dist/typegen.js.map +1 -0
  286. package/dist/utils/asset-prefix.d.ts +33 -5
  287. package/dist/utils/asset-prefix.js +39 -6
  288. package/dist/utils/asset-prefix.js.map +1 -1
  289. package/dist/utils/cache-control-metadata.d.ts +2 -1
  290. package/dist/utils/cache-control-metadata.js +1 -3
  291. package/dist/utils/cache-control-metadata.js.map +1 -1
  292. package/dist/utils/domain-locale.d.ts +2 -1
  293. package/dist/utils/domain-locale.js +9 -1
  294. package/dist/utils/domain-locale.js.map +1 -1
  295. package/dist/utils/lazy-chunks.d.ts +1 -1
  296. package/dist/utils/lazy-chunks.js +1 -1
  297. package/dist/utils/lazy-chunks.js.map +1 -1
  298. package/dist/utils/prerender-output-paths.d.ts +15 -0
  299. package/dist/utils/prerender-output-paths.js +24 -0
  300. package/dist/utils/prerender-output-paths.js.map +1 -0
  301. package/dist/utils/query.d.ts +17 -1
  302. package/dist/utils/query.js +36 -1
  303. package/dist/utils/query.js.map +1 -1
  304. package/dist/utils/record.d.ts +5 -0
  305. package/dist/utils/record.js +8 -0
  306. package/dist/utils/record.js.map +1 -0
  307. package/package.json +11 -3
@@ -1,6 +1,13 @@
1
- import "react";
1
+ import React from "react";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  //#region src/shims/document.tsx
4
+ /**
5
+ * next/document shim
6
+ *
7
+ * Provides Html, Head, Main, NextScript components for custom _document.tsx.
8
+ * During SSR these render placeholder markers that the dev server replaces
9
+ * with actual content.
10
+ */
4
11
  function Html({ children, lang, ...props }) {
5
12
  return /* @__PURE__ */ jsx("html", {
6
13
  lang,
@@ -40,11 +47,35 @@ function NextScript() {
40
47
  return /* @__PURE__ */ jsx("span", { dangerouslySetInnerHTML: { __html: "<!-- __NEXT_SCRIPTS__ -->" } });
41
48
  }
42
49
  /**
43
- * Default Document component - used when no custom _document.tsx exists.
50
+ * Default Document component also the base class user `_document.tsx` files
51
+ * `extend`. Must be a class (not a function) to match Next.js's `next/document`
52
+ * default export so `class MyDocument extends Document` produces a constructible
53
+ * class that React can instantiate during SSR. Returning a function here breaks
54
+ * any user `_document.tsx` that uses the class-based form because `extends`
55
+ * against a non-constructor produces a class that can only be called without
56
+ * `new`, which React refuses to do.
57
+ *
58
+ * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/pages/_document.tsx
59
+ * Ported behavior: Next.js's default `Document` is a `class Document extends
60
+ * React.Component`. Custom documents extend it and override `getInitialProps`
61
+ * and `render`. Generic default matches Next.js (`P = {}`).
44
62
  */
45
- function Document() {
46
- return /* @__PURE__ */ jsxs(Html, { children: [/* @__PURE__ */ jsx(Head, {}), /* @__PURE__ */ jsxs("body", { children: [/* @__PURE__ */ jsx(Main, {}), /* @__PURE__ */ jsx(NextScript, {})] })] });
47
- }
63
+ var Document = class extends React.Component {
64
+ /**
65
+ * `getInitialProps` is invoked by the SSR pipeline. The default implementation
66
+ * is a stub: vinext does not yet plumb the Pages Router `renderPage` /
67
+ * `defaultGetInitialProps` chain into the SSR entry, so subclasses that
68
+ * delegate via `await Document.getInitialProps(ctx)` receive an empty shell
69
+ * (`html: ""`). This matches the runtime contract user code expects without
70
+ * pretending the chain is wired up.
71
+ */
72
+ static async getInitialProps(_ctx) {
73
+ return { html: "" };
74
+ }
75
+ render() {
76
+ return /* @__PURE__ */ jsxs(Html, { children: [/* @__PURE__ */ jsx(Head, {}), /* @__PURE__ */ jsxs("body", { children: [/* @__PURE__ */ jsx(Main, {}), /* @__PURE__ */ jsx(NextScript, {})] })] });
77
+ }
78
+ };
48
79
  //#endregion
49
80
  export { Head, Html, Main, NextScript, Document as default };
50
81
 
@@ -1 +1 @@
1
- {"version":3,"file":"document.js","names":[],"sources":["../../src/shims/document.tsx"],"sourcesContent":["/**\n * next/document shim\n *\n * Provides Html, Head, Main, NextScript components for custom _document.tsx.\n * During SSR these render placeholder markers that the dev server replaces\n * with actual content.\n */\nimport React from \"react\";\n\nexport function Html({\n children,\n lang,\n ...props\n}: React.HTMLAttributes<HTMLHtmlElement> & { children?: React.ReactNode }) {\n return (\n <html lang={lang} {...props}>\n {children}\n </html>\n );\n}\n\n/**\n * Document Head - renders <head> with children.\n * The dev server injects meta tags, styles, etc.\n */\nexport function Head({ children }: { children?: React.ReactNode }) {\n return (\n <head>\n <meta charSet=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n {children}\n </head>\n );\n}\n\n/**\n * Main - renders the page content container.\n */\nexport function Main() {\n return <div id=\"__next\" dangerouslySetInnerHTML={{ __html: \"__NEXT_MAIN__\" }} />;\n}\n\n/**\n * NextScript - renders a placeholder that the dev-server replaces with\n * actual hydration scripts (__NEXT_DATA__ + entry module).\n * Uses dangerouslySetInnerHTML so the HTML comment survives renderToString.\n */\nexport function NextScript() {\n return <span dangerouslySetInnerHTML={{ __html: \"<!-- __NEXT_SCRIPTS__ -->\" }} />;\n}\n\n/**\n * Default Document component - used when no custom _document.tsx exists.\n */\nexport default function Document() {\n return (\n <Html>\n <Head />\n <body>\n <Main />\n <NextScript />\n </body>\n </Html>\n );\n}\n"],"mappings":";;;AASA,SAAgB,KAAK,EACnB,UACA,MACA,GAAG,SACsE;CACzE,OACE,oBAAC,QAAD;EAAY;EAAM,GAAI;EACnB;EACI,CAAA;;;;;;AAQX,SAAgB,KAAK,EAAE,YAA4C;CACjE,OACE,qBAAC,QAAD,EAAA,UAAA;EACE,oBAAC,QAAD,EAAM,SAAQ,SAAU,CAAA;EACxB,oBAAC,QAAD;GAAM,MAAK;GAAW,SAAQ;GAAwC,CAAA;EACrE;EACI,EAAA,CAAA;;;;;AAOX,SAAgB,OAAO;CACrB,OAAO,oBAAC,OAAD;EAAK,IAAG;EAAS,yBAAyB,EAAE,QAAQ,iBAAiB;EAAI,CAAA;;;;;;;AAQlF,SAAgB,aAAa;CAC3B,OAAO,oBAAC,QAAD,EAAM,yBAAyB,EAAE,QAAQ,6BAA6B,EAAI,CAAA;;;;;AAMnF,SAAwB,WAAW;CACjC,OACE,qBAAC,MAAD,EAAA,UAAA,CACE,oBAAC,MAAD,EAAQ,CAAA,EACR,qBAAC,QAAD,EAAA,UAAA,CACE,oBAAC,MAAD,EAAQ,CAAA,EACR,oBAAC,YAAD,EAAc,CAAA,CACT,EAAA,CAAA,CACF,EAAA,CAAA"}
1
+ {"version":3,"file":"document.js","names":[],"sources":["../../src/shims/document.tsx"],"sourcesContent":["/**\n * next/document shim\n *\n * Provides Html, Head, Main, NextScript components for custom _document.tsx.\n * During SSR these render placeholder markers that the dev server replaces\n * with actual content.\n */\nimport React from \"react\";\n\nexport function Html({\n children,\n lang,\n ...props\n}: React.HTMLAttributes<HTMLHtmlElement> & { children?: React.ReactNode }) {\n return (\n <html lang={lang} {...props}>\n {children}\n </html>\n );\n}\n\n/**\n * Document Head - renders <head> with children.\n * The dev server injects meta tags, styles, etc.\n */\nexport function Head({ children }: { children?: React.ReactNode }) {\n return (\n <head>\n <meta charSet=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n {children}\n </head>\n );\n}\n\n/**\n * Main - renders the page content container.\n */\nexport function Main() {\n return <div id=\"__next\" dangerouslySetInnerHTML={{ __html: \"__NEXT_MAIN__\" }} />;\n}\n\n/**\n * NextScript - renders a placeholder that the dev-server replaces with\n * actual hydration scripts (__NEXT_DATA__ + entry module).\n * Uses dangerouslySetInnerHTML so the HTML comment survives renderToString.\n */\nexport function NextScript() {\n return <span dangerouslySetInnerHTML={{ __html: \"<!-- __NEXT_SCRIPTS__ -->\" }} />;\n}\n\n/**\n * Loose stand-ins for Next.js's `DocumentContext` / `DocumentInitialProps`.\n * The shim doesn't currently invoke `getInitialProps` on user `_document.tsx`\n * files (separate gap), but the signatures here match Next.js's so subclasses\n * that delegate via `await Document.getInitialProps(ctx)` typecheck against\n * the same shape they'd see under real Next.js.\n *\n * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/utils.ts\n */\nexport type DocumentContext = {\n // The full `DocumentContext` includes `renderPage`, `defaultGetInitialProps`,\n // and the inherited `NextPageContext` (`pathname`, `query`, `req`, `res`,\n // `err`, `asPath`, ...). They're declared as optional here because vinext\n // does not yet plumb them through; widening to optional avoids forcing user\n // code to assert their presence.\n renderPage?: (options?: {\n enhanceApp?: (App: React.ComponentType<{ children?: React.ReactNode }>) => unknown;\n enhanceComponent?: (Comp: React.ComponentType<unknown>) => unknown;\n }) => { html: string; head?: ReadonlyArray<React.ReactElement> };\n defaultGetInitialProps?: (\n ctx: DocumentContext,\n options?: { nonce?: string },\n ) => Promise<DocumentInitialProps>;\n pathname?: string;\n query?: Record<string, string | string[] | undefined>;\n asPath?: string;\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n err?: any;\n};\n\nexport type DocumentInitialProps = {\n html: string;\n head?: ReadonlyArray<React.ReactElement>;\n styles?: React.ReactElement[] | Iterable<React.ReactNode> | React.ReactElement;\n};\n\n/**\n * Default Document component — also the base class user `_document.tsx` files\n * `extend`. Must be a class (not a function) to match Next.js's `next/document`\n * default export so `class MyDocument extends Document` produces a constructible\n * class that React can instantiate during SSR. Returning a function here breaks\n * any user `_document.tsx` that uses the class-based form because `extends`\n * against a non-constructor produces a class that can only be called without\n * `new`, which React refuses to do.\n *\n * @see https://github.com/vercel/next.js/blob/canary/packages/next/src/pages/_document.tsx\n * Ported behavior: Next.js's default `Document` is a `class Document extends\n * React.Component`. Custom documents extend it and override `getInitialProps`\n * and `render`. Generic default matches Next.js (`P = {}`).\n */\n// oxlint-disable-next-line @typescript-eslint/no-empty-object-type\nexport default class Document<P = {}> extends React.Component<P & { children?: React.ReactNode }> {\n /**\n * `getInitialProps` is invoked by the SSR pipeline. The default implementation\n * is a stub: vinext does not yet plumb the Pages Router `renderPage` /\n * `defaultGetInitialProps` chain into the SSR entry, so subclasses that\n * delegate via `await Document.getInitialProps(ctx)` receive an empty shell\n * (`html: \"\"`). This matches the runtime contract user code expects without\n * pretending the chain is wired up.\n */\n static async getInitialProps(_ctx: DocumentContext): Promise<DocumentInitialProps> {\n return { html: \"\" };\n }\n\n render(): React.ReactNode {\n return (\n <Html>\n <Head />\n <body>\n <Main />\n <NextScript />\n </body>\n </Html>\n );\n }\n}\n"],"mappings":";;;;;;;;;;AASA,SAAgB,KAAK,EACnB,UACA,MACA,GAAG,SACsE;CACzE,OACE,oBAAC,QAAD;EAAY;EAAM,GAAI;EACnB;EACI,CAAA;;;;;;AAQX,SAAgB,KAAK,EAAE,YAA4C;CACjE,OACE,qBAAC,QAAD,EAAA,UAAA;EACE,oBAAC,QAAD,EAAM,SAAQ,SAAU,CAAA;EACxB,oBAAC,QAAD;GAAM,MAAK;GAAW,SAAQ;GAAwC,CAAA;EACrE;EACI,EAAA,CAAA;;;;;AAOX,SAAgB,OAAO;CACrB,OAAO,oBAAC,OAAD;EAAK,IAAG;EAAS,yBAAyB,EAAE,QAAQ,iBAAiB;EAAI,CAAA;;;;;;;AAQlF,SAAgB,aAAa;CAC3B,OAAO,oBAAC,QAAD,EAAM,yBAAyB,EAAE,QAAQ,6BAA6B,EAAI,CAAA;;;;;;;;;;;;;;;;AAsDnF,IAAqB,WAArB,cAA8C,MAAM,UAA8C;;;;;;;;;CAShG,aAAa,gBAAgB,MAAsD;EACjF,OAAO,EAAE,MAAM,IAAI;;CAGrB,SAA0B;EACxB,OACE,qBAAC,MAAD,EAAA,UAAA,CACE,oBAAC,MAAD,EAAQ,CAAA,EACR,qBAAC,QAAD,EAAA,UAAA,CACE,oBAAC,MAAD,EAAQ,CAAA,EACR,oBAAC,YAAD,EAAc,CAAA,CACT,EAAA,CAAA,CACF,EAAA,CAAA"}
@@ -32,7 +32,7 @@ declare class RedirectErrorBoundary extends React.Component<{
32
32
  children?: React.ReactNode;
33
33
  });
34
34
  static getDerivedStateFromError(error: unknown): RedirectBoundaryState;
35
- render(): string | number | bigint | boolean | _$react_jsx_runtime0.JSX.Element | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | null | undefined;
35
+ render(): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | _$react_jsx_runtime0.JSX.Element | null | undefined;
36
36
  }
37
37
  declare function RedirectBoundary({
38
38
  children
@@ -49,7 +49,7 @@ declare class ErrorBoundaryInner extends React.Component<ErrorBoundaryInnerProps
49
49
  static getDerivedStateFromProps(props: ErrorBoundaryInnerProps, state: ErrorBoundaryState): ErrorBoundaryState | null;
50
50
  static getDerivedStateFromError(error: unknown): Partial<ErrorBoundaryState>;
51
51
  reset: () => void;
52
- render(): string | number | bigint | boolean | _$react_jsx_runtime0.JSX.Element | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | null | undefined;
52
+ render(): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | _$react_jsx_runtime0.JSX.Element | null | undefined;
53
53
  }
54
54
  declare function ErrorBoundary({
55
55
  fallback,
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { isDangerousScheme } from "./url-safety.js";
3
- import { toSameOriginPath } from "./url-utils.js";
3
+ import { toSameOriginPath, withBasePath } from "./url-utils.js";
4
+ import { hasAppNavigationRuntime } from "../client/navigation-runtime.js";
4
5
  import { navigateClientSide } from "./navigation.js";
5
6
  import { forwardRef, useActionState } from "react";
6
7
  import { jsx } from "react/jsx-runtime";
@@ -22,6 +23,7 @@ import { jsx } from "react/jsx-runtime";
22
23
  * <button type="submit">Search</button>
23
24
  * </Form>
24
25
  */
26
+ const __basePath = process.env.__NEXT_ROUTER_BASEPATH ?? "";
25
27
  const SUPPORTED_FORM_ENCTYPE = "application/x-www-form-urlencoded";
26
28
  const SUPPORTED_FORM_METHOD = "GET";
27
29
  const SUPPORTED_FORM_TARGET = "_self";
@@ -112,6 +114,7 @@ const Form = forwardRef(function Form(props, ref) {
112
114
  ...rest
113
115
  });
114
116
  }
117
+ const actionHref = withBasePath(action, __basePath);
115
118
  async function handleSubmit(e) {
116
119
  if (onSubmit) {
117
120
  onSubmit(e);
@@ -120,7 +123,7 @@ const Form = forwardRef(function Form(props, ref) {
120
123
  const submitter = getSubmitter(e.nativeEvent);
121
124
  if (submitter && hasUnsupportedSubmitterAttributes(submitter)) return;
122
125
  if (getEffectiveMethod(submitter, rest.method) !== "GET") return;
123
- const effectiveAction = getEffectiveAction(submitter, action);
126
+ const effectiveAction = getEffectiveAction(submitter, actionHref);
124
127
  if (process.env.NODE_ENV !== "production" && submitter?.getAttribute("formaction") !== null) checkFormActionUrl(effectiveAction, "formAction");
125
128
  if (!isSafeAction(effectiveAction)) {
126
129
  if (process.env.NODE_ENV !== "production") console.warn(`<Form> blocked unsafe action: ${effectiveAction}`);
@@ -129,17 +132,21 @@ const Form = forwardRef(function Form(props, ref) {
129
132
  }
130
133
  e.preventDefault();
131
134
  const url = createFormSubmitDestinationUrl(effectiveAction, e.currentTarget, submitter);
132
- if (typeof window.__VINEXT_RSC_NAVIGATE__ === "function") await navigateClientSide(url, replace ? "replace" : "push", scroll);
133
- else {
135
+ if (hasAppNavigationRuntime()) await navigateClientSide(url, replace ? "replace" : "push", scroll);
136
+ else try {
137
+ const Router = (await import("./router.js")).default;
138
+ if (replace) await Router.replace(url, void 0, { scroll });
139
+ else await Router.push(url, void 0, { scroll });
140
+ } catch {
134
141
  if (replace) window.history.replaceState({}, "", url);
135
142
  else window.history.pushState({}, "", url);
136
143
  window.dispatchEvent(new PopStateEvent("popstate"));
144
+ if (scroll) window.scrollTo(0, 0);
137
145
  }
138
- if (typeof window.__VINEXT_RSC_NAVIGATE__ !== "function" && scroll) window.scrollTo(0, 0);
139
146
  }
140
147
  return /* @__PURE__ */ jsx("form", {
141
148
  ref,
142
- action,
149
+ action: actionHref,
143
150
  onSubmit: (event) => {
144
151
  handleSubmit(event);
145
152
  },
@@ -1 +1 @@
1
- {"version":3,"file":"form.js","names":[],"sources":["../../src/shims/form.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * next/form shim\n *\n * Progressive enhancement form component. In Next.js, this replaces\n * the standard <form> element with one that intercepts submissions\n * and performs client-side navigation for GET forms (search forms).\n *\n * For POST forms with server actions, it delegates to React's built-in\n * form action handling.\n *\n * Usage:\n * import Form from 'next/form';\n * <Form action=\"/search\">\n * <input name=\"q\" />\n * <button type=\"submit\">Search</button>\n * </Form>\n */\n\nimport { forwardRef, useActionState, type FormHTMLAttributes, type ForwardedRef } from \"react\";\nimport { navigateClientSide } from \"./navigation.js\";\nimport { isDangerousScheme } from \"./url-safety.js\";\nimport { toSameOriginPath } from \"./url-utils.js\";\n\n// Re-export useActionState from React 19 to match Next.js's next/form module\nexport { useActionState };\n\ntype FormSubmitter = HTMLButtonElement | HTMLInputElement;\nconst SUPPORTED_FORM_ENCTYPE = \"application/x-www-form-urlencoded\";\nconst SUPPORTED_FORM_METHOD = \"GET\";\nconst SUPPORTED_FORM_TARGET = \"_self\";\n\nfunction isSafeAction(action: string): boolean {\n // Block dangerous URI schemes\n if (isDangerousScheme(action)) return false;\n // Block protocol-relative URLs (//evil.com/...)\n if (action.startsWith(\"//\")) return false;\n // Block absolute URLs to external origins (client-side: compare origins)\n if (/^https?:\\/\\//i.test(action)) {\n if (typeof window !== \"undefined\") {\n try {\n const actionUrl = new URL(action);\n return actionUrl.origin === window.location.origin;\n } catch {\n return false;\n }\n }\n // Server-side: block all absolute URLs (can't compare origins)\n return false;\n }\n return true;\n}\n\nfunction getSubmitter(nativeEvent: unknown): FormSubmitter | null {\n const submitter =\n nativeEvent &&\n typeof nativeEvent === \"object\" &&\n \"submitter\" in nativeEvent &&\n nativeEvent.submitter instanceof Element\n ? nativeEvent.submitter\n : null;\n\n if (submitter instanceof HTMLButtonElement || submitter instanceof HTMLInputElement) {\n return submitter;\n }\n return null;\n}\n\nfunction getEffectiveMethod(\n submitter: FormSubmitter | null,\n formMethod: FormHTMLAttributes<HTMLFormElement>[\"method\"],\n): string {\n const override = submitter?.getAttribute(\"formmethod\");\n return (override ?? formMethod ?? \"GET\").toUpperCase();\n}\n\nfunction getEffectiveAction(submitter: FormSubmitter | null, formAction: string): string {\n return submitter?.getAttribute(\"formaction\") ?? formAction;\n}\n\nfunction checkFormActionUrl(action: string, source: \"action\" | \"formAction\"): void {\n const aPropName = source === \"action\" ? \"an `action`\" : \"a `formAction`\";\n\n let testUrl: URL;\n try {\n testUrl = new URL(action, \"http://n\");\n } catch {\n console.error(`<Form> received ${aPropName} that cannot be parsed as a URL: \"${action}\".`);\n return;\n }\n\n if (testUrl.searchParams.size) {\n console.warn(\n `<Form> received ${aPropName} that contains search params: \"${action}\". This is not supported, and they will be ignored. ` +\n `If you need to pass in additional search params, use an \\`<input type=\"hidden\" />\\` instead.`,\n );\n }\n}\n\nfunction hasUnsupportedSubmitterAttributes(submitter: FormSubmitter): boolean {\n const formEncType = submitter.getAttribute(\"formenctype\");\n if (formEncType !== null && formEncType !== SUPPORTED_FORM_ENCTYPE) {\n console.error(\n `<Form>'s \\`encType\\` was set to an unsupported value via \\`formEncType=\"${formEncType}\"\\`. ` +\n `This will disable <Form>'s navigation functionality. If you need this, use a native <form> element instead.`,\n );\n return true;\n }\n\n const formMethod = submitter.getAttribute(\"formmethod\");\n if (formMethod !== null && formMethod.toUpperCase() !== SUPPORTED_FORM_METHOD) {\n console.error(\n `<Form>'s \\`method\\` was set to an unsupported value via \\`formMethod=\"${formMethod}\"\\`. ` +\n `This will disable <Form>'s navigation functionality. If you need this, use a native <form> element instead.`,\n );\n return true;\n }\n\n const formTarget = submitter.getAttribute(\"formtarget\");\n if (formTarget !== null && formTarget !== SUPPORTED_FORM_TARGET) {\n console.error(\n `<Form>'s \\`target\\` was set to an unsupported value via \\`formTarget=\"${formTarget}\"\\`. ` +\n `This will disable <Form>'s navigation functionality. If you need this, use a native <form> element instead.`,\n );\n return true;\n }\n\n return false;\n}\n\nfunction createFormSubmitDestinationUrl(\n action: string,\n form: HTMLFormElement,\n submitter: FormSubmitter | null,\n): string {\n const targetUrl = new URL(action, window.location.href);\n if (targetUrl.searchParams.size) {\n targetUrl.search = \"\";\n }\n\n const formData = buildFormData(form, submitter);\n for (const [name, value] of formData) {\n targetUrl.searchParams.append(name, typeof value === \"string\" ? value : value.name);\n }\n\n return toSameOriginPath(targetUrl.href) ?? targetUrl.href;\n}\n\nfunction buildFormData(form: HTMLFormElement, submitter: FormSubmitter | null): FormData {\n if (!submitter) return new FormData(form);\n\n try {\n return new FormData(form, submitter);\n } catch {\n const formData = new FormData(form);\n if (!submitter.disabled && submitter.name) {\n formData.append(submitter.name, submitter.value);\n }\n return formData;\n }\n}\n\ntype FormProps = {\n /** Target URL for GET forms, or server action for POST forms */\n action: string | ((formData: FormData) => void | Promise<void>);\n /** Replace instead of push in history (default: false) */\n replace?: boolean;\n /** Scroll to top after navigation (default: true) */\n scroll?: boolean;\n} & FormHTMLAttributes<HTMLFormElement>;\n\nconst Form = forwardRef(function Form(props: FormProps, ref: ForwardedRef<HTMLFormElement>) {\n const { action, replace = false, scroll = true, onSubmit, ...rest } = props;\n\n // If action is a function (server action), pass it directly to React\n if (typeof action === \"function\") {\n return <form ref={ref} action={action} onSubmit={onSubmit} {...rest} />;\n }\n\n // Block dangerous action URLs. Render <form> without action attribute\n // so it submits to the current page (safe default).\n if (process.env.NODE_ENV !== \"production\") {\n checkFormActionUrl(action, \"action\");\n }\n\n if (!isSafeAction(action)) {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(`<Form> blocked unsafe action: ${action}`);\n }\n return <form ref={ref} onSubmit={onSubmit} {...rest} />;\n }\n\n async function handleSubmit(e: React.SubmitEvent<HTMLFormElement>) {\n // Call user's onSubmit first\n if (onSubmit) {\n onSubmit(e);\n if (e.defaultPrevented) return;\n }\n\n const submitter = getSubmitter(e.nativeEvent);\n if (submitter && hasUnsupportedSubmitterAttributes(submitter)) {\n return;\n }\n\n // Only intercept GET forms for client-side navigation\n const method = getEffectiveMethod(submitter, rest.method);\n if (method !== \"GET\") return;\n\n const effectiveAction = getEffectiveAction(submitter, action as string);\n if (process.env.NODE_ENV !== \"production\" && submitter?.getAttribute(\"formaction\") !== null) {\n checkFormActionUrl(effectiveAction, \"formAction\");\n }\n if (!isSafeAction(effectiveAction)) {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(`<Form> blocked unsafe action: ${effectiveAction}`);\n }\n e.preventDefault();\n return;\n }\n\n e.preventDefault();\n const url = createFormSubmitDestinationUrl(effectiveAction, e.currentTarget, submitter);\n\n // Navigate client-side\n if (typeof window.__VINEXT_RSC_NAVIGATE__ === \"function\") {\n // App Router: use the shared navigator so URL/history publish stays\n // aligned with the committed RSC tree.\n await navigateClientSide(url, replace ? \"replace\" : \"push\", scroll);\n } else {\n // Pages Router: use router or fallback\n if (replace) {\n window.history.replaceState({}, \"\", url);\n } else {\n window.history.pushState({}, \"\", url);\n }\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n }\n\n // App Router: scroll is handled inside navigateClientSide (called above).\n // Pages Router: scroll manually since pushState/popstate doesn't auto-scroll.\n if (typeof window.__VINEXT_RSC_NAVIGATE__ !== \"function\" && scroll) {\n window.scrollTo(0, 0);\n }\n }\n\n return (\n <form\n ref={ref}\n action={action}\n onSubmit={(event) => {\n void handleSubmit(event);\n }}\n {...rest}\n />\n );\n});\n\nexport default Form;\n"],"mappings":"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"}
1
+ {"version":3,"file":"form.js","names":[],"sources":["../../src/shims/form.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * next/form shim\n *\n * Progressive enhancement form component. In Next.js, this replaces\n * the standard <form> element with one that intercepts submissions\n * and performs client-side navigation for GET forms (search forms).\n *\n * For POST forms with server actions, it delegates to React's built-in\n * form action handling.\n *\n * Usage:\n * import Form from 'next/form';\n * <Form action=\"/search\">\n * <input name=\"q\" />\n * <button type=\"submit\">Search</button>\n * </Form>\n */\n\nimport { forwardRef, useActionState, type FormHTMLAttributes, type ForwardedRef } from \"react\";\nimport { hasAppNavigationRuntime } from \"../client/navigation-runtime.js\";\nimport { navigateClientSide } from \"./navigation.js\";\nimport { isDangerousScheme } from \"./url-safety.js\";\nimport { toSameOriginPath, withBasePath } from \"./url-utils.js\";\n\n// Mirrors `__NEXT_ROUTER_BASEPATH` exposure in `next/link` / `next/router`.\n// `addBasePath` is only applied to the form-level `action` prop. A submitter's\n// `formAction` is intentionally untouched, matching Next.js (the comment in\n// upstream `form.tsx` notes \"this should not have basePath added, because we\n// can't add it before hydration\").\nconst __basePath: string = process.env.__NEXT_ROUTER_BASEPATH ?? \"\";\n\n// Re-export useActionState from React 19 to match Next.js's next/form module\nexport { useActionState };\n\ntype FormSubmitter = HTMLButtonElement | HTMLInputElement;\nconst SUPPORTED_FORM_ENCTYPE = \"application/x-www-form-urlencoded\";\nconst SUPPORTED_FORM_METHOD = \"GET\";\nconst SUPPORTED_FORM_TARGET = \"_self\";\n\nfunction isSafeAction(action: string): boolean {\n // Block dangerous URI schemes\n if (isDangerousScheme(action)) return false;\n // Block protocol-relative URLs (//evil.com/...)\n if (action.startsWith(\"//\")) return false;\n // Block absolute URLs to external origins (client-side: compare origins)\n if (/^https?:\\/\\//i.test(action)) {\n if (typeof window !== \"undefined\") {\n try {\n const actionUrl = new URL(action);\n return actionUrl.origin === window.location.origin;\n } catch {\n return false;\n }\n }\n // Server-side: block all absolute URLs (can't compare origins)\n return false;\n }\n return true;\n}\n\nfunction getSubmitter(nativeEvent: unknown): FormSubmitter | null {\n const submitter =\n nativeEvent &&\n typeof nativeEvent === \"object\" &&\n \"submitter\" in nativeEvent &&\n nativeEvent.submitter instanceof Element\n ? nativeEvent.submitter\n : null;\n\n if (submitter instanceof HTMLButtonElement || submitter instanceof HTMLInputElement) {\n return submitter;\n }\n return null;\n}\n\nfunction getEffectiveMethod(\n submitter: FormSubmitter | null,\n formMethod: FormHTMLAttributes<HTMLFormElement>[\"method\"],\n): string {\n const override = submitter?.getAttribute(\"formmethod\");\n return (override ?? formMethod ?? \"GET\").toUpperCase();\n}\n\nfunction getEffectiveAction(submitter: FormSubmitter | null, formAction: string): string {\n return submitter?.getAttribute(\"formaction\") ?? formAction;\n}\n\nfunction checkFormActionUrl(action: string, source: \"action\" | \"formAction\"): void {\n const aPropName = source === \"action\" ? \"an `action`\" : \"a `formAction`\";\n\n let testUrl: URL;\n try {\n testUrl = new URL(action, \"http://n\");\n } catch {\n console.error(`<Form> received ${aPropName} that cannot be parsed as a URL: \"${action}\".`);\n return;\n }\n\n if (testUrl.searchParams.size) {\n console.warn(\n `<Form> received ${aPropName} that contains search params: \"${action}\". This is not supported, and they will be ignored. ` +\n `If you need to pass in additional search params, use an \\`<input type=\"hidden\" />\\` instead.`,\n );\n }\n}\n\nfunction hasUnsupportedSubmitterAttributes(submitter: FormSubmitter): boolean {\n const formEncType = submitter.getAttribute(\"formenctype\");\n if (formEncType !== null && formEncType !== SUPPORTED_FORM_ENCTYPE) {\n console.error(\n `<Form>'s \\`encType\\` was set to an unsupported value via \\`formEncType=\"${formEncType}\"\\`. ` +\n `This will disable <Form>'s navigation functionality. If you need this, use a native <form> element instead.`,\n );\n return true;\n }\n\n const formMethod = submitter.getAttribute(\"formmethod\");\n if (formMethod !== null && formMethod.toUpperCase() !== SUPPORTED_FORM_METHOD) {\n console.error(\n `<Form>'s \\`method\\` was set to an unsupported value via \\`formMethod=\"${formMethod}\"\\`. ` +\n `This will disable <Form>'s navigation functionality. If you need this, use a native <form> element instead.`,\n );\n return true;\n }\n\n const formTarget = submitter.getAttribute(\"formtarget\");\n if (formTarget !== null && formTarget !== SUPPORTED_FORM_TARGET) {\n console.error(\n `<Form>'s \\`target\\` was set to an unsupported value via \\`formTarget=\"${formTarget}\"\\`. ` +\n `This will disable <Form>'s navigation functionality. If you need this, use a native <form> element instead.`,\n );\n return true;\n }\n\n return false;\n}\n\nfunction createFormSubmitDestinationUrl(\n action: string,\n form: HTMLFormElement,\n submitter: FormSubmitter | null,\n): string {\n const targetUrl = new URL(action, window.location.href);\n if (targetUrl.searchParams.size) {\n targetUrl.search = \"\";\n }\n\n const formData = buildFormData(form, submitter);\n for (const [name, value] of formData) {\n targetUrl.searchParams.append(name, typeof value === \"string\" ? value : value.name);\n }\n\n return toSameOriginPath(targetUrl.href) ?? targetUrl.href;\n}\n\nfunction buildFormData(form: HTMLFormElement, submitter: FormSubmitter | null): FormData {\n if (!submitter) return new FormData(form);\n\n try {\n return new FormData(form, submitter);\n } catch {\n const formData = new FormData(form);\n if (!submitter.disabled && submitter.name) {\n formData.append(submitter.name, submitter.value);\n }\n return formData;\n }\n}\n\ntype FormProps = {\n /** Target URL for GET forms, or server action for POST forms */\n action: string | ((formData: FormData) => void | Promise<void>);\n /** Replace instead of push in history (default: false) */\n replace?: boolean;\n /** Scroll to top after navigation (default: true) */\n scroll?: boolean;\n} & FormHTMLAttributes<HTMLFormElement>;\n\nconst Form = forwardRef(function Form(props: FormProps, ref: ForwardedRef<HTMLFormElement>) {\n const { action, replace = false, scroll = true, onSubmit, ...rest } = props;\n\n // If action is a function (server action), pass it directly to React\n if (typeof action === \"function\") {\n return <form ref={ref} action={action} onSubmit={onSubmit} {...rest} />;\n }\n\n // Block dangerous action URLs. Render <form> without action attribute\n // so it submits to the current page (safe default).\n if (process.env.NODE_ENV !== \"production\") {\n checkFormActionUrl(action, \"action\");\n }\n\n if (!isSafeAction(action)) {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(`<Form> blocked unsafe action: ${action}`);\n }\n return <form ref={ref} onSubmit={onSubmit} {...rest} />;\n }\n\n // Prefix basePath to the navigating `action` prop (matches Next.js's\n // `addBasePath(actionProp)` in `client/form.tsx` and `client/app-dir/form.tsx`).\n // This becomes both the rendered `action=` attribute (so JS-disabled\n // submissions still hit the right URL) and the soft-navigation target.\n const actionHref = withBasePath(action, __basePath);\n\n async function handleSubmit(e: React.SubmitEvent<HTMLFormElement>) {\n // Call user's onSubmit first\n if (onSubmit) {\n onSubmit(e);\n if (e.defaultPrevented) return;\n }\n\n const submitter = getSubmitter(e.nativeEvent);\n if (submitter && hasUnsupportedSubmitterAttributes(submitter)) {\n return;\n }\n\n // Only intercept GET forms for client-side navigation\n const method = getEffectiveMethod(submitter, rest.method);\n if (method !== \"GET\") return;\n\n // NOTE: a submitter's `formAction` is intentionally NOT base-path-prefixed\n // here, matching Next.js. Upstream `form.tsx` notes: \"this should not have\n // `basePath` added, because we can't add it before hydration\".\n const effectiveAction = getEffectiveAction(submitter, actionHref);\n if (process.env.NODE_ENV !== \"production\" && submitter?.getAttribute(\"formaction\") !== null) {\n checkFormActionUrl(effectiveAction, \"formAction\");\n }\n if (!isSafeAction(effectiveAction)) {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(`<Form> blocked unsafe action: ${effectiveAction}`);\n }\n e.preventDefault();\n return;\n }\n\n e.preventDefault();\n const url = createFormSubmitDestinationUrl(effectiveAction, e.currentTarget, submitter);\n\n // Navigate client-side\n if (hasAppNavigationRuntime()) {\n // App Router: use the shared navigator so URL/history publish stays\n // aligned with the committed RSC tree.\n await navigateClientSide(url, replace ? \"replace\" : \"push\", scroll);\n } else {\n // Pages Router: delegate to the Router singleton so navigation flows\n // through `performNavigation` (route events, HTML fetch, scroll\n // handling). Mirrors what `<Link>` does at link.tsx:619-623.\n try {\n const routerModule = await import(\"./router.js\");\n const Router = routerModule.default;\n if (replace) {\n await Router.replace(url, undefined, { scroll });\n } else {\n await Router.push(url, undefined, { scroll });\n }\n } catch {\n // Fallback: pushState + popstate keeps the URL in sync even if the\n // Router singleton import fails (e.g. in test/SSR-only contexts).\n if (replace) {\n window.history.replaceState({}, \"\", url);\n } else {\n window.history.pushState({}, \"\", url);\n }\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n if (scroll) {\n window.scrollTo(0, 0);\n }\n }\n }\n }\n\n return (\n <form\n ref={ref}\n action={actionHref}\n onSubmit={(event) => {\n void handleSubmit(event);\n }}\n {...rest}\n />\n );\n});\n\nexport default Form;\n"],"mappings":"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"}
@@ -22,7 +22,14 @@ type LinkProps = {
22
22
  */
23
23
  unstable_dynamicOnHover?: boolean; /** Whether to pass the href to the child element */
24
24
  passHref?: boolean; /** Scroll to top on navigation (default: true) */
25
- scroll?: boolean; /** Locale for i18n (used for locale-prefixed URLs) */
25
+ scroll?: boolean;
26
+ /**
27
+ * Pages Router: update the URL without re-running data fetching methods
28
+ * (getServerSideProps / getStaticProps / getInitialProps). The shallow change
29
+ * still triggers the route change events and updates `router.query`. Only
30
+ * applies to navigations within the same page. No-op on the App Router.
31
+ */
32
+ shallow?: boolean; /** Locale for i18n (used for locale-prefixed URLs) */
26
33
  locale?: string | false; /** Called before navigation happens (Next.js 16). Return value is ignored. */
27
34
  onNavigate?: (event: NavigateEvent) => void;
28
35
  children?: React.ReactNode;
@@ -44,6 +51,10 @@ type LinkStatusContextValue = {
44
51
  declare function useLinkStatus(): LinkStatusContextValue;
45
52
  declare function resolveLinkPrefetchMode(prefetchProp: LinkProps["prefetch"], isDangerous: boolean): LinkPrefetchMode;
46
53
  declare function canAutoPrefetchFullAppRoute(href: string): boolean;
54
+ declare function resolveAutoAppRoutePrefetch(href: string): {
55
+ cacheForNavigation: boolean;
56
+ shouldPrefetch: boolean;
57
+ };
47
58
  declare const Link: React.ForwardRefExoticComponent<{
48
59
  href: string | {
49
60
  pathname?: string;
@@ -58,11 +69,18 @@ declare const Link: React.ForwardRefExoticComponent<{
58
69
  */
59
70
  unstable_dynamicOnHover?: boolean; /** Whether to pass the href to the child element */
60
71
  passHref?: boolean; /** Scroll to top on navigation (default: true) */
61
- scroll?: boolean; /** Locale for i18n (used for locale-prefixed URLs) */
72
+ scroll?: boolean;
73
+ /**
74
+ * Pages Router: update the URL without re-running data fetching methods
75
+ * (getServerSideProps / getStaticProps / getInitialProps). The shallow change
76
+ * still triggers the route change events and updates `router.query`. Only
77
+ * applies to navigations within the same page. No-op on the App Router.
78
+ */
79
+ shallow?: boolean; /** Locale for i18n (used for locale-prefixed URLs) */
62
80
  locale?: string | false; /** Called before navigation happens (Next.js 16). Return value is ignored. */
63
81
  onNavigate?: (event: NavigateEvent) => void;
64
82
  children?: React.ReactNode;
65
83
  } & Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, "href"> & React.RefAttributes<HTMLAnchorElement>>;
66
84
  //#endregion
67
- export { canAutoPrefetchFullAppRoute, Link as default, resolveLinkPrefetchMode, useLinkStatus };
85
+ export { canAutoPrefetchFullAppRoute, Link as default, resolveAutoAppRoutePrefetch, resolveLinkPrefetchMode, useLinkStatus };
68
86
  //# sourceMappingURL=link.d.ts.map
@@ -2,14 +2,18 @@
2
2
  import { stripBasePath } from "../utils/base-path.js";
3
3
  import { createRouteTrieCache, matchRouteWithTrie } from "../routing/route-matching.js";
4
4
  import { VINEXT_MOUNTED_SLOTS_HEADER } from "../server/headers.js";
5
- import { isDangerousScheme } from "./url-safety.js";
5
+ import { isDangerousScheme, reportBlockedDangerousNavigation } from "./url-safety.js";
6
+ import { appendSearchParamsToUrl, urlQueryToSearchParams } from "../utils/query.js";
7
+ import { APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL } from "../server/app-rsc-render-mode.js";
6
8
  import { isAbsoluteOrProtocolRelativeUrl, normalizePathTrailingSlash, resolveRelativeHref, toBrowserNavigationHref, toSameOriginAppPath, withBasePath } from "./url-utils.js";
7
9
  import { addLocalePrefix, getDomainLocaleUrl } from "../utils/domain-locale.js";
8
- import { appendSearchParamsToUrl, urlQueryToSearchParams } from "../utils/query.js";
10
+ import { getCurrentBrowserLocale } from "./client-locale.js";
11
+ import { getNavigationRuntime, hasAppNavigationRuntime, registerNavigationRuntimeFunctions } from "../client/navigation-runtime.js";
9
12
  import { AppElementsWire } from "../server/app-elements-wire.js";
10
13
  import "../server/app-elements.js";
11
- import { createRscRequestHeaders, createRscRequestUrl } from "../server/app-rsc-cache-busting.js";
12
- import { getCurrentInterceptionContext, getMountedSlotsHeader, getPrefetchedUrls, navigateClientSide, prefetchRscResponse } from "./navigation.js";
14
+ import { createRscRequestHeaders, createRscRequestUrl, stripRscCacheBustingSearchParam, stripRscSuffix } from "../server/app-rsc-cache-busting.js";
15
+ import { getMountedSlotsHeader, getPrefetchCache, getPrefetchInterceptionContext, getPrefetchedUrls, navigateClientSide, prefetchRscResponse } from "./navigation.js";
16
+ import { navigatePagesRouterLink } from "../client/pages-router-link-navigation.js";
13
17
  import { getI18nContext } from "./i18n-context.js";
14
18
  import { canLinkIntentPrefetch, canLinkPrefetch, getLinkPrefetchHref } from "./link-prefetch.js";
15
19
  import React, { createContext, forwardRef, useCallback, useContext, useEffect, useRef, useState } from "react";
@@ -62,7 +66,7 @@ function toSameOriginRouteHref(href) {
62
66
  return `${stripBasePath(url.pathname, __basePath)}${url.search}`;
63
67
  }
64
68
  function getLinkPrefetchRouterMode() {
65
- return typeof window !== "undefined" && typeof window.__VINEXT_RSC_NAVIGATE__ === "function" ? "app" : "pages";
69
+ return hasAppNavigationRuntime() ? "app" : "pages";
66
70
  }
67
71
  function canAutoPrefetchFullAppRoute(href) {
68
72
  if (typeof window === "undefined") return false;
@@ -74,6 +78,31 @@ function canAutoPrefetchFullAppRoute(href) {
74
78
  if (!match) return false;
75
79
  return !match.route.isDynamic;
76
80
  }
81
+ function resolveAutoAppRoutePrefetch(href) {
82
+ if (typeof window === "undefined") return {
83
+ cacheForNavigation: false,
84
+ shouldPrefetch: false
85
+ };
86
+ const routes = window.__VINEXT_LINK_PREFETCH_ROUTES__;
87
+ if (!routes) return {
88
+ cacheForNavigation: false,
89
+ shouldPrefetch: false
90
+ };
91
+ const routeHref = toSameOriginRouteHref(href);
92
+ if (routeHref === null) return {
93
+ cacheForNavigation: false,
94
+ shouldPrefetch: false
95
+ };
96
+ const match = matchRouteWithTrie(routeHref, routes, linkPrefetchRouteTrieCache);
97
+ if (!match) return {
98
+ cacheForNavigation: false,
99
+ shouldPrefetch: false
100
+ };
101
+ return {
102
+ cacheForNavigation: !match.route.isDynamic,
103
+ shouldPrefetch: !match.route.isDynamic || match.route.canPrefetchLoadingShell
104
+ };
105
+ }
77
106
  /**
78
107
  * Prefetch a URL for faster navigation.
79
108
  *
@@ -95,23 +124,41 @@ function prefetchUrl(href, mode, priority = "low") {
95
124
  const fullHref = toBrowserNavigationHref(prefetchHref, window.location.href, __basePath);
96
125
  (window.requestIdleCallback ?? ((fn) => setTimeout(fn, 100)))(() => {
97
126
  (async () => {
98
- if (typeof window.__VINEXT_RSC_NAVIGATE__ === "function") {
99
- if (mode === "auto" && !canAutoPrefetchFullAppRoute(prefetchHref)) return;
100
- const interceptionContext = getCurrentInterceptionContext();
127
+ if (hasAppNavigationRuntime()) {
128
+ const autoPrefetch = mode === "auto" ? resolveAutoAppRoutePrefetch(prefetchHref) : {
129
+ cacheForNavigation: true,
130
+ shouldPrefetch: true
131
+ };
132
+ if (!autoPrefetch.shouldPrefetch) return;
133
+ const interceptionContext = getPrefetchInterceptionContext(fullHref);
101
134
  const mountedSlotsHeader = getMountedSlotsHeader();
102
- const headers = createRscRequestHeaders({ interceptionContext });
135
+ const isOptimisticRouteShellPrefetch = !autoPrefetch.cacheForNavigation;
136
+ if (isOptimisticRouteShellPrefetch && interceptionContext !== null) return;
137
+ const headers = createRscRequestHeaders({
138
+ interceptionContext,
139
+ renderMode: isOptimisticRouteShellPrefetch ? APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL : void 0
140
+ });
103
141
  if (mountedSlotsHeader) headers.set(VINEXT_MOUNTED_SLOTS_HEADER, mountedSlotsHeader);
104
142
  const rscUrl = await createRscRequestUrl(fullHref, headers);
105
143
  const cacheKey = AppElementsWire.encodeCacheKey(rscUrl, interceptionContext);
106
144
  const prefetched = getPrefetchedUrls();
107
- if (prefetched.has(cacheKey)) return;
145
+ if (prefetched.has(cacheKey)) {
146
+ if (autoPrefetch.cacheForNavigation) {
147
+ const existing = getPrefetchCache().get(cacheKey);
148
+ if (existing?.cacheForNavigation === false) existing.cacheForNavigation = true;
149
+ }
150
+ return;
151
+ }
108
152
  prefetched.add(cacheKey);
109
153
  prefetchRscResponse(rscUrl, fetch(rscUrl, {
110
154
  headers,
111
155
  credentials: "include",
112
156
  priority,
113
157
  purpose: "prefetch"
114
- }), interceptionContext, mountedSlotsHeader);
158
+ }), interceptionContext, mountedSlotsHeader, void 0, {
159
+ cacheForNavigation: autoPrefetch.cacheForNavigation,
160
+ optimisticRouteShell: isOptimisticRouteShellPrefetch
161
+ });
115
162
  } else if (window.__NEXT_DATA__?.__vinext?.pageModuleUrl) {
116
163
  const link = document.createElement("link");
117
164
  link.rel = "prefetch";
@@ -124,6 +171,27 @@ function prefetchUrl(href, mode, priority = "low") {
124
171
  });
125
172
  });
126
173
  }
174
+ function promotePrefetchEntriesForNavigation(href) {
175
+ if (typeof window === "undefined") return;
176
+ let target;
177
+ try {
178
+ target = new URL(toBrowserNavigationHref(href, window.location.href, __basePath), window.location.href);
179
+ } catch {
180
+ return;
181
+ }
182
+ for (const [cacheKey, entry] of getPrefetchCache()) {
183
+ if (entry.optimisticRouteShell === true) continue;
184
+ const [rscUrl] = cacheKey.split("\0", 1);
185
+ let cached;
186
+ try {
187
+ cached = new URL(rscUrl, window.location.href);
188
+ } catch {
189
+ continue;
190
+ }
191
+ stripRscCacheBustingSearchParam(cached);
192
+ if (stripRscSuffix(cached.pathname) === target.pathname && cached.search === target.search) entry.cacheForNavigation = true;
193
+ }
194
+ }
127
195
  /**
128
196
  * Shared IntersectionObserver for viewport-based prefetching.
129
197
  * All Link elements use the same observer to minimize resource usage.
@@ -142,7 +210,7 @@ function setVisibleLinkPrefetch(instance, isVisible) {
142
210
  }
143
211
  function registerVisibleLinkPing() {
144
212
  if (typeof window === "undefined") return;
145
- window.__VINEXT_PING_VISIBLE_LINKS__ = pingVisibleLinkPrefetches;
213
+ registerNavigationRuntimeFunctions({ pingVisibleLinks: pingVisibleLinkPrefetches });
146
214
  }
147
215
  function pingVisibleLinkPrefetches() {
148
216
  for (const instance of visibleLinkPrefetches) if (instance.isVisible && instance.routerMode === "app") prefetchUrl(instance.href, instance.mode, "low");
@@ -163,6 +231,14 @@ function getDefaultLocale() {
163
231
  if (typeof window !== "undefined") return window.__VINEXT_DEFAULT_LOCALE__;
164
232
  return getI18nContext()?.defaultLocale;
165
233
  }
234
+ function getCurrentLocale() {
235
+ if (typeof window !== "undefined") return getCurrentBrowserLocale({
236
+ basePath: __basePath,
237
+ domainLocales: getDomainLocales(),
238
+ hostname: getCurrentHostname()
239
+ });
240
+ return getI18nContext()?.locale;
241
+ }
166
242
  function getDomainLocales() {
167
243
  if (typeof window !== "undefined") return window.__NEXT_DATA__?.domainLocales;
168
244
  return getI18nContext()?.domainLocales;
@@ -178,6 +254,17 @@ function getDomainLocaleHref(href, locale) {
178
254
  domainItems: getDomainLocales()
179
255
  });
180
256
  }
257
+ function addLocalePrefixForRoot(href, locale) {
258
+ if (href !== "/" && !href.startsWith("/?") && !href.startsWith("/#")) return;
259
+ let parsed;
260
+ try {
261
+ parsed = new URL(href, "http://vinext.local");
262
+ } catch {
263
+ return;
264
+ }
265
+ if (parsed.origin !== "http://vinext.local" || parsed.pathname !== "/") return;
266
+ return `/${locale}${parsed.search}${parsed.hash}`;
267
+ }
181
268
  /**
182
269
  * Apply locale prefix to a URL path based on the locale prop.
183
270
  * - locale="fr" → prepend /fr (unless it already has a locale prefix)
@@ -186,13 +273,19 @@ function getDomainLocaleHref(href, locale) {
186
273
  */
187
274
  function applyLocaleToHref(href, locale) {
188
275
  if (locale === false) return href;
189
- if (locale === void 0) return href;
276
+ const resolvedLocale = locale ?? getCurrentLocale();
277
+ if (resolvedLocale === void 0) return href;
190
278
  if (isAbsoluteOrProtocolRelativeUrl(href)) return href;
191
- const domainLocaleHref = getDomainLocaleHref(href, locale);
279
+ const domainLocaleHref = getDomainLocaleHref(href, resolvedLocale);
192
280
  if (domainLocaleHref) return domainLocaleHref;
193
- return addLocalePrefix(href, locale, getDefaultLocale() ?? "");
281
+ const defaultLocale = getDefaultLocale() ?? "";
282
+ if (resolvedLocale.toLowerCase() === defaultLocale.toLowerCase()) {
283
+ const localeRootHref = addLocalePrefixForRoot(href, resolvedLocale);
284
+ if (localeRootHref) return localeRootHref;
285
+ }
286
+ return addLocalePrefix(href, resolvedLocale, defaultLocale);
194
287
  }
195
- const Link = forwardRef(function Link({ href, as, replace = false, prefetch: prefetchProp, scroll = true, children, onClick, onMouseEnter, onTouchStart, onNavigate, unstable_dynamicOnHover = false, ...rest }, forwardedRef) {
288
+ const Link = forwardRef(function Link({ href, as, replace = false, prefetch: prefetchProp, scroll = true, shallow = false, children, onClick, onMouseEnter, onTouchStart, onNavigate, unstable_dynamicOnHover = false, ...rest }, forwardedRef) {
196
289
  const { locale, ...restWithoutLocale } = rest;
197
290
  const resolvedHref = as ?? resolveHref(href);
198
291
  const isDangerous = typeof resolvedHref === "string" && isDangerousScheme(resolvedHref);
@@ -261,6 +354,7 @@ const Link = forwardRef(function Link({ href, as, replace = false, prefetch: pre
261
354
  if (unstable_dynamicOnHover && internalRef.current) {
262
355
  const instance = observedLinkPrefetches.get(internalRef.current);
263
356
  if (instance) instance.mode = "full";
357
+ promotePrefetchEntriesForNavigation(normalizedHref);
264
358
  }
265
359
  prefetchUrl(normalizedHref, intentMode, "high");
266
360
  }, [
@@ -287,7 +381,13 @@ const Link = forwardRef(function Link({ href, as, replace = false, prefetch: pre
287
381
  let navigateHref = normalizedHref;
288
382
  if (isAbsoluteOrProtocolRelativeUrl(resolvedHref)) {
289
383
  const localPath = toSameOriginAppPath(resolvedHref, __basePath);
290
- if (localPath == null) return;
384
+ if (localPath == null) {
385
+ if (replace) {
386
+ e.preventDefault();
387
+ window.location.replace(resolvedHref);
388
+ }
389
+ return;
390
+ }
291
391
  navigateHref = localPath;
292
392
  }
293
393
  e.preventDefault();
@@ -308,7 +408,7 @@ const Link = forwardRef(function Link({ href, as, replace = false, prefetch: pre
308
408
  onNavigate(navEvent);
309
409
  if (navEvent.defaultPrevented) return;
310
410
  } catch {}
311
- if (typeof window.__VINEXT_RSC_NAVIGATE__ === "function") {
411
+ if (getNavigationRuntime()?.functions.navigate) {
312
412
  setPending(true);
313
413
  React.startTransition(() => {
314
414
  navigateClientSide(navigateHref, replace ? "replace" : "push", scroll, true).finally(() => {
@@ -318,8 +418,13 @@ const Link = forwardRef(function Link({ href, as, replace = false, prefetch: pre
318
418
  return;
319
419
  } else try {
320
420
  const Router = (await import("next/router.js")).default;
321
- if (replace) await Router.replace(absoluteHref, void 0, { scroll });
322
- else await Router.push(absoluteHref, void 0, { scroll });
421
+ await navigatePagesRouterLink(Router, {
422
+ href: absoluteHref,
423
+ replace,
424
+ scroll,
425
+ shallow,
426
+ locale
427
+ });
323
428
  } catch {
324
429
  if (replace) window.history.replaceState({}, "", absoluteFullHref);
325
430
  else window.history.pushState({}, "", absoluteFullHref);
@@ -330,11 +435,15 @@ const Link = forwardRef(function Link({ href, as, replace = false, prefetch: pre
330
435
  const linkStatusValue = React.useMemo(() => ({ pending }), [pending]);
331
436
  if (isDangerous) {
332
437
  if (process.env.NODE_ENV !== "production") console.warn(`<Link> blocked dangerous href: ${resolvedHref}`);
438
+ const handleDangerousClick = (event) => {
439
+ if (onClick) onClick(event);
440
+ reportBlockedDangerousNavigation();
441
+ };
333
442
  return /* @__PURE__ */ jsx(LinkStatusContext.Provider, {
334
443
  value: linkStatusValue,
335
444
  children: /* @__PURE__ */ jsx("a", {
336
445
  ref: setRefs,
337
- onClick,
446
+ onClick: handleDangerousClick,
338
447
  onMouseEnter: handleMouseEnter,
339
448
  onTouchStart: handleTouchStart,
340
449
  ...anchorProps,
@@ -358,6 +467,6 @@ const Link = forwardRef(function Link({ href, as, replace = false, prefetch: pre
358
467
  });
359
468
  });
360
469
  //#endregion
361
- export { canAutoPrefetchFullAppRoute, Link as default, resolveLinkPrefetchMode, useLinkStatus };
470
+ export { canAutoPrefetchFullAppRoute, Link as default, resolveAutoAppRoutePrefetch, resolveLinkPrefetchMode, useLinkStatus };
362
471
 
363
472
  //# sourceMappingURL=link.js.map