Skip to content

Commit 7f97dce

Browse files
committed
fix(#970): make redirect implementation match Nuxt's
1 parent 52d4b9a commit 7f97dce

File tree

1 file changed

+35
-8
lines changed

1 file changed

+35
-8
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import { sanitizeStatusCode } from 'h3'
2-
import { type NuxtApp, abortNavigation, callWithNuxt, useNuxtApp } from '#app'
2+
import { hasProtocol, isScriptProtocol, joinURL } from 'ufo'
3+
import { type NuxtApp, abortNavigation, callWithNuxt, useNuxtApp, useRouter, useRuntimeConfig } from '#app'
34

45
export function navigateToAuthPageWN(nuxt: NuxtApp, href: string) {
56
return callWithNuxt(nuxt, navigateToAuthPage, [href])
67
}
78

9+
const URL_QUOTE_RE = /"/g
10+
811
/**
912
* Function to correctly navigate to auth-routes, necessary as the auth-routes are not part of the nuxt-app itself, so unknown to nuxt / vue-router.
1013
*
@@ -13,21 +16,33 @@ export function navigateToAuthPageWN(nuxt: NuxtApp, href: string) {
1316
* manually set `window.location.href` on the client **and then fake return a Promise that does not immediately resolve to block navigation (although it will not actually be fully awaited, but just be awaited long enough for the naviation to complete)**.
1417
* 2. Additionally on the server-side, we cannot use `navigateTo(signInUrl)` as this uses `vue-router` internally which does not know the "external" sign-in page of next-auth and thus will log a warning which we want to avoid.
1518
*
16-
* Adapted from: https://github.com/nuxt/nuxt/blob/d188542a35bb541c7ed2e4502c687c2132979882/packages/nuxt/src/app/composables/router.ts#L161-L188
19+
* Adapted from https://github.com/nuxt/nuxt/blob/16d213bbdcc69c0cc72afb355755ff877654a374/packages/nuxt/src/app/composables/router.ts#L119-L217
1720
*
1821
* @param href HREF / URL to navigate to
1922
*/
2023
export function navigateToAuthPage(href: string) {
24+
const router = useRouter()
2125
const nuxtApp = useNuxtApp()
2226

2327
if (import.meta.server) {
2428
if (nuxtApp.ssrContext) {
29+
const isExternalHost = hasProtocol(href, { acceptRelative: true })
30+
if (isExternalHost) {
31+
const { protocol } = new URL(href, 'http://localhost')
32+
if (protocol && isScriptProtocol(protocol)) {
33+
throw new Error(`Cannot navigate to a URL with '${protocol}' protocol.`)
34+
}
35+
}
36+
37+
const fullPath = isExternalHost ? href : router.resolve(href).fullPath || '/'
38+
const location = isExternalHost ? href : joinURL(useRuntimeConfig().app.baseURL, fullPath)
39+
2540
// TODO: consider deprecating in favour of `app:rendered` and removing
2641
return nuxtApp.callHook('app:redirected').then(() => {
27-
const encodedLoc = href.replace(/"/g, '%22')
28-
const encodedHeader = new URL(href).toString()
42+
const encodedLoc = location.replace(URL_QUOTE_RE, '%22')
43+
const encodedHeader = encodeURL(location, isExternalHost)
2944
nuxtApp.ssrContext!._renderResponse = {
30-
statusCode: sanitizeStatusCode(302, 302),
45+
statusCode: 302,
3146
body: `<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=${encodedLoc}"></head></html>`,
3247
headers: { location: encodedHeader },
3348
}
@@ -42,12 +57,24 @@ export function navigateToAuthPage(href: string) {
4257
window.location.reload()
4358
}
4459

45-
// TODO: Sadly, we cannot directly import types from `vue-router` as it leads to build failures. Typing the router about should help us to avoid manually typing `route` below
46-
const router = nuxtApp.$router as { push: (href: string) => void }
47-
4860
// Wait for the `window.location.href` navigation from above to complete to avoid showing content. If that doesn't work fast enough, delegate navigation back to the `vue-router` (risking a vue-router 404 warning in the console, but still avoiding content-flashes of the protected target page)
4961
const waitForNavigationWithFallbackToRouter = new Promise(resolve => setTimeout(resolve, 60 * 1000))
5062
.then(() => router.push(href))
5163

5264
return waitForNavigationWithFallbackToRouter as Promise<void | undefined>
5365
}
66+
67+
/**
68+
* Adapted from https://github.com/nuxt/nuxt/blob/16d213bbdcc69c0cc72afb355755ff877654a374/packages/nuxt/src/app/composables/router.ts#L270C1-L282C2
69+
* @internal
70+
*/
71+
export function encodeURL(location: string, isExternalHost = false) {
72+
const url = new URL(location, 'http://localhost')
73+
if (!isExternalHost) {
74+
return url.pathname + url.search + url.hash
75+
}
76+
if (location.startsWith('//')) {
77+
return url.toString().replace(url.protocol, '')
78+
}
79+
return url.toString()
80+
}

0 commit comments

Comments
 (0)