@onmax/nuxt-better-auth 0.0.2-alpha.9 → 0.0.3

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 (74) hide show
  1. package/README.md +57 -17
  2. package/dist/module.d.mts +28 -1
  3. package/dist/module.json +3 -3
  4. package/dist/module.mjs +1258 -351
  5. package/dist/runtime/app/components/BetterAuthState.d.vue.ts +4 -4
  6. package/dist/runtime/app/components/BetterAuthState.vue +1 -0
  7. package/dist/runtime/app/components/BetterAuthState.vue.d.ts +4 -4
  8. package/dist/runtime/app/composables/runWithSessionRefresh.d.ts +1 -0
  9. package/dist/runtime/app/composables/runWithSessionRefresh.js +12 -0
  10. package/dist/runtime/app/composables/useAction.d.ts +2 -0
  11. package/dist/runtime/app/composables/useAction.js +6 -0
  12. package/dist/runtime/app/composables/useAuthAsyncData.d.ts +6 -0
  13. package/dist/runtime/app/composables/useAuthAsyncData.js +16 -0
  14. package/dist/runtime/app/composables/useAuthClient.d.ts +9 -0
  15. package/dist/runtime/app/composables/useAuthClient.js +34 -0
  16. package/dist/runtime/app/composables/useAuthClientAction.d.ts +3 -0
  17. package/dist/runtime/app/composables/useAuthClientAction.js +15 -0
  18. package/dist/runtime/app/composables/useAuthRequestFetch.d.ts +11 -0
  19. package/dist/runtime/app/composables/useAuthRequestFetch.js +4 -0
  20. package/dist/runtime/app/composables/useSignIn.d.ts +16 -0
  21. package/dist/runtime/app/composables/useSignIn.js +8 -0
  22. package/dist/runtime/app/composables/useSignUp.d.ts +5 -0
  23. package/dist/runtime/app/composables/useSignUp.js +8 -0
  24. package/dist/runtime/app/composables/useUserSession.d.ts +6 -5
  25. package/dist/runtime/app/composables/useUserSession.js +189 -100
  26. package/dist/runtime/app/composables/useUserSessionState.d.ts +3 -0
  27. package/dist/runtime/app/composables/useUserSessionState.js +4 -0
  28. package/dist/runtime/app/internal/auth-action-error.d.ts +3 -0
  29. package/dist/runtime/app/internal/auth-action-error.js +33 -0
  30. package/dist/runtime/app/internal/auth-action-handles.d.ts +21 -0
  31. package/dist/runtime/app/internal/auth-action-handles.js +105 -0
  32. package/dist/runtime/app/internal/redirect-helpers.d.ts +4 -0
  33. package/dist/runtime/app/internal/redirect-helpers.js +37 -0
  34. package/dist/runtime/app/internal/session-fetch.d.ts +12 -0
  35. package/dist/runtime/app/internal/session-fetch.js +56 -0
  36. package/dist/runtime/app/internal/utils.d.ts +1 -0
  37. package/dist/runtime/app/internal/utils.js +3 -0
  38. package/dist/runtime/app/internal/vue-safe-auth-proxy.d.ts +3 -0
  39. package/dist/runtime/app/internal/vue-safe-auth-proxy.js +68 -0
  40. package/dist/runtime/app/internal/wrap-auth-method.d.ts +18 -0
  41. package/dist/runtime/app/internal/wrap-auth-method.js +69 -0
  42. package/dist/runtime/app/middleware/auth.global.js +80 -15
  43. package/dist/runtime/app/pages/__better-auth-devtools.vue +293 -339
  44. package/dist/runtime/composables.d.ts +12 -0
  45. package/dist/runtime/composables.js +10 -0
  46. package/dist/runtime/config.d.ts +69 -15
  47. package/dist/runtime/config.js +9 -2
  48. package/dist/runtime/internal/auth-route-rules.d.ts +1 -0
  49. package/dist/runtime/internal/auth-route-rules.js +24 -0
  50. package/dist/runtime/server/api/_better-auth/_schema.d.ts +1 -5
  51. package/dist/runtime/server/api/_better-auth/_schema.js +2 -1
  52. package/dist/runtime/server/api/_better-auth/accounts.get.d.ts +2 -2
  53. package/dist/runtime/server/api/_better-auth/accounts.get.js +3 -2
  54. package/dist/runtime/server/api/_better-auth/config.get.d.ts +9 -3
  55. package/dist/runtime/server/api/_better-auth/config.get.js +18 -6
  56. package/dist/runtime/server/api/_better-auth/sessions.delete.js +3 -2
  57. package/dist/runtime/server/api/_better-auth/sessions.get.d.ts +5 -3
  58. package/dist/runtime/server/api/_better-auth/sessions.get.js +3 -2
  59. package/dist/runtime/server/api/_better-auth/users.get.d.ts +2 -2
  60. package/dist/runtime/server/api/_better-auth/users.get.js +3 -2
  61. package/dist/runtime/server/api/auth/[...all].js +1 -1
  62. package/dist/runtime/server/middleware/route-access.js +4 -2
  63. package/dist/runtime/server/tsconfig.json +9 -1
  64. package/dist/runtime/server/utils/auth.d.ts +16 -8
  65. package/dist/runtime/server/utils/auth.js +229 -23
  66. package/dist/runtime/server/utils/custom-secondary-storage.d.ts +6 -0
  67. package/dist/runtime/server/utils/custom-secondary-storage.js +8 -0
  68. package/dist/runtime/server/utils/session.d.ts +7 -8
  69. package/dist/runtime/server/utils/session.js +256 -5
  70. package/dist/runtime/server/virtual-modules.d.ts +27 -0
  71. package/dist/runtime/types/augment.d.ts +18 -4
  72. package/dist/runtime/types.d.ts +12 -13
  73. package/dist/types.d.mts +1 -1
  74. package/package.json +53 -47
@@ -0,0 +1,105 @@
1
+ import { ref } from "#imports";
2
+ import { normalizeAuthActionError } from "./auth-action-error.js";
3
+ import { isRecord } from "./utils.js";
4
+ export function isAuthActionErrorResult(value) {
5
+ if (!isRecord(value))
6
+ return false;
7
+ if (!("error" in value))
8
+ return false;
9
+ return Boolean(value.error);
10
+ }
11
+ function isRedirectResult(value) {
12
+ if (!isRecord(value))
13
+ return false;
14
+ return value.redirect === true && typeof value.url === "string" && value.url.length > 0;
15
+ }
16
+ function getRedirectResult(value) {
17
+ if (isRedirectResult(value))
18
+ return value;
19
+ if (!isRecord(value))
20
+ return null;
21
+ const nested = value.data;
22
+ if (isRedirectResult(nested))
23
+ return nested;
24
+ return null;
25
+ }
26
+ const REDIRECT_PENDING_FALLBACK_MS = 1e4;
27
+ export function createActionHandle(getMethod, options = {}) {
28
+ const status = ref("idle");
29
+ const data = ref(null);
30
+ const error = ref(null);
31
+ let latestCallId = 0;
32
+ const run = async (...args) => {
33
+ const callId = ++latestCallId;
34
+ status.value = "pending";
35
+ data.value = null;
36
+ error.value = null;
37
+ try {
38
+ const result = await getMethod()(...args);
39
+ if (isAuthActionErrorResult(result)) {
40
+ const normalizedError = normalizeAuthActionError(result.error);
41
+ if (callId === latestCallId) {
42
+ status.value = "error";
43
+ data.value = null;
44
+ error.value = normalizedError;
45
+ }
46
+ return;
47
+ }
48
+ if (callId === latestCallId) {
49
+ if (options.keepPendingOnRedirect !== false) {
50
+ const redirectResult = getRedirectResult(result);
51
+ if (redirectResult) {
52
+ status.value = "pending";
53
+ data.value = result;
54
+ error.value = null;
55
+ setTimeout(() => {
56
+ if (callId !== latestCallId || status.value !== "pending")
57
+ return;
58
+ status.value = "success";
59
+ }, REDIRECT_PENDING_FALLBACK_MS);
60
+ return;
61
+ }
62
+ }
63
+ status.value = "success";
64
+ data.value = result;
65
+ error.value = null;
66
+ }
67
+ } catch (thrown) {
68
+ const normalizedError = normalizeAuthActionError(thrown);
69
+ if (callId === latestCallId) {
70
+ status.value = "error";
71
+ data.value = null;
72
+ error.value = normalizedError;
73
+ }
74
+ }
75
+ };
76
+ const execute = (async (...args) => {
77
+ await run(...args);
78
+ });
79
+ return {
80
+ execute,
81
+ status,
82
+ data,
83
+ error
84
+ };
85
+ }
86
+ export function createActionHandles(getTarget, targetName) {
87
+ const handles = /* @__PURE__ */ new Map();
88
+ return new Proxy({}, {
89
+ get(_target, prop) {
90
+ if (prop === "then")
91
+ return void 0;
92
+ if (handles.has(prop))
93
+ return handles.get(prop);
94
+ const handle = createActionHandle(() => {
95
+ const target = getTarget();
96
+ const method = target[prop];
97
+ if (typeof method !== "function")
98
+ throw new TypeError(`${targetName}.${String(prop)}() is not a function`);
99
+ return method;
100
+ });
101
+ handles.set(prop, handle);
102
+ return handle;
103
+ }
104
+ });
105
+ }
@@ -0,0 +1,4 @@
1
+ export declare function isSafeLocalRedirect(redirect: unknown): string | undefined;
2
+ export declare function resolvePostAuthRedirect(requestURL: URL): string | undefined;
3
+ export declare function resolvePostAuthSuccessRedirect(requestURL: URL): (() => Promise<void>) | undefined;
4
+ export declare function withFallbackSocialCallbackURL(data: unknown, requestURL: URL): unknown;
@@ -0,0 +1,37 @@
1
+ import { navigateTo, useRuntimeConfig } from "#imports";
2
+ import { isRecord } from "./utils.js";
3
+ export function isSafeLocalRedirect(redirect) {
4
+ if (typeof redirect !== "string")
5
+ return;
6
+ if (!redirect.startsWith("/") || redirect.startsWith("//"))
7
+ return;
8
+ return redirect;
9
+ }
10
+ export function resolvePostAuthRedirect(requestURL) {
11
+ const runtimeConfig = useRuntimeConfig();
12
+ const authConfig = runtimeConfig.public.auth;
13
+ const redirectQueryKey = authConfig?.redirectQueryKey ?? "redirect";
14
+ const queryRedirect = requestURL.searchParams?.get(redirectQueryKey);
15
+ const safeQueryRedirect = isSafeLocalRedirect(queryRedirect);
16
+ if (safeQueryRedirect)
17
+ return safeQueryRedirect;
18
+ return isSafeLocalRedirect(authConfig?.redirects?.authenticated);
19
+ }
20
+ export function resolvePostAuthSuccessRedirect(requestURL) {
21
+ const target = resolvePostAuthRedirect(requestURL);
22
+ if (!target)
23
+ return;
24
+ return async () => {
25
+ await navigateTo(target);
26
+ };
27
+ }
28
+ export function withFallbackSocialCallbackURL(data, requestURL) {
29
+ const callbackURL = resolvePostAuthRedirect(requestURL);
30
+ if (!callbackURL)
31
+ return data;
32
+ if (!isRecord(data))
33
+ return { callbackURL };
34
+ if (typeof data.callbackURL === "string")
35
+ return data;
36
+ return { ...data, callbackURL };
37
+ }
@@ -0,0 +1,12 @@
1
+ import type { Ref } from 'vue';
2
+ import type { AppAuthClient, AuthSession, AuthUser } from '#nuxt-better-auth';
3
+ export declare function stripToken(session: AuthSession & {
4
+ token?: string;
5
+ }): AuthSession;
6
+ export declare function fetchSessionServer(session: Ref<AuthSession | null>, user: Ref<AuthUser | null>, authReady: Ref<boolean>, options?: {
7
+ headers?: HeadersInit;
8
+ }): Promise<void>;
9
+ export declare function fetchSessionClient(client: AppAuthClient, session: Ref<AuthSession | null>, user: Ref<AuthUser | null>, authReady: Ref<boolean>, options?: {
10
+ headers?: HeadersInit;
11
+ force?: boolean;
12
+ }): Promise<void>;
@@ -0,0 +1,56 @@
1
+ import { useRequestFetch, useRequestHeaders } from "#imports";
2
+ import { normalizeAuthActionError } from "./auth-action-error.js";
3
+ export function stripToken(session) {
4
+ const { token: _, ...safe } = session;
5
+ return safe;
6
+ }
7
+ function isExpectedSignedOutSessionError(error) {
8
+ const normalizedError = normalizeAuthActionError(error);
9
+ if (normalizedError.status === 401)
10
+ return true;
11
+ return normalizedError.code === "UNAUTHORIZED";
12
+ }
13
+ export async function fetchSessionServer(session, user, authReady, options = {}) {
14
+ try {
15
+ const headers = options.headers || useRequestHeaders(["cookie"]);
16
+ const requestFetch = useRequestFetch();
17
+ const data = await requestFetch("/api/auth/get-session", { headers });
18
+ if (data?.session && data?.user) {
19
+ session.value = stripToken(data.session);
20
+ user.value = data.user;
21
+ } else {
22
+ session.value = null;
23
+ user.value = null;
24
+ }
25
+ } catch {
26
+ session.value = null;
27
+ user.value = null;
28
+ } finally {
29
+ if (!authReady.value)
30
+ authReady.value = true;
31
+ }
32
+ }
33
+ export async function fetchSessionClient(client, session, user, authReady, options = {}) {
34
+ try {
35
+ const headers = options.headers || useRequestHeaders(["cookie"]);
36
+ const fetchOptions = headers ? { headers } : void 0;
37
+ const query = options.force ? { disableCookieCache: true } : void 0;
38
+ const result = await client.getSession({ query }, fetchOptions);
39
+ const data = result.data;
40
+ if (data?.session && data?.user) {
41
+ session.value = stripToken(data.session);
42
+ user.value = data.user;
43
+ } else {
44
+ session.value = null;
45
+ user.value = null;
46
+ }
47
+ } catch (error) {
48
+ session.value = null;
49
+ user.value = null;
50
+ if (!isExpectedSignedOutSessionError(error))
51
+ console.error("[nuxt-better-auth] Failed to fetch session:", error);
52
+ } finally {
53
+ if (!authReady.value)
54
+ authReady.value = true;
55
+ }
56
+ }
@@ -0,0 +1 @@
1
+ export declare function isRecord(value: unknown): value is Record<string, unknown>;
@@ -0,0 +1,3 @@
1
+ export function isRecord(value) {
2
+ return Boolean(value && typeof value === "object");
3
+ }
@@ -0,0 +1,3 @@
1
+ export declare function isAuthProxyProbeKey(prop: PropertyKey): boolean;
2
+ export declare function createVueSafeAuthFacade<T extends object>(resolve: (prop: PropertyKey, receiver: object) => unknown): T;
3
+ export declare function createVueSafeAuthProxy<T>(target: T): T;
@@ -0,0 +1,68 @@
1
+ const promiseProbeKeys = /* @__PURE__ */ new Set(["then", "catch", "finally"]);
2
+ export function isAuthProxyProbeKey(prop) {
3
+ return typeof prop !== "string" || promiseProbeKeys.has(prop) || prop.startsWith("__v");
4
+ }
5
+ function isObjectLike(value) {
6
+ return typeof value === "object" && value !== null || typeof value === "function";
7
+ }
8
+ export function createVueSafeAuthFacade(resolve) {
9
+ const propertyCache = /* @__PURE__ */ new Map();
10
+ const facadeTarget = {};
11
+ Object.defineProperty(facadeTarget, "__v_skip", {
12
+ value: true,
13
+ configurable: true
14
+ });
15
+ return new Proxy(facadeTarget, {
16
+ get(_target, prop, receiver) {
17
+ if (prop === "__v_skip")
18
+ return true;
19
+ if (isAuthProxyProbeKey(prop))
20
+ return void 0;
21
+ if (propertyCache.has(prop))
22
+ return propertyCache.get(prop);
23
+ const value = resolve(prop, receiver);
24
+ propertyCache.set(prop, value);
25
+ return value;
26
+ }
27
+ });
28
+ }
29
+ export function createVueSafeAuthProxy(target) {
30
+ if (!isObjectLike(target))
31
+ return target;
32
+ const cache = /* @__PURE__ */ new WeakMap();
33
+ const wrap = (value) => {
34
+ if (!isObjectLike(value))
35
+ return value;
36
+ const cached = cache.get(value);
37
+ if (cached)
38
+ return cached;
39
+ const propertyCache = /* @__PURE__ */ new Map();
40
+ const handler = {
41
+ get(target2, prop, receiver) {
42
+ if (prop === "__v_skip")
43
+ return true;
44
+ if (isAuthProxyProbeKey(prop))
45
+ return void 0;
46
+ if (propertyCache.has(prop))
47
+ return propertyCache.get(prop);
48
+ const wrapped = wrap(Reflect.get(target2, prop, receiver));
49
+ propertyCache.set(prop, wrapped);
50
+ return wrapped;
51
+ }
52
+ };
53
+ if (typeof value === "function") {
54
+ handler.apply = (target2, thisArg, args) => Reflect.apply(target2, thisArg, args);
55
+ }
56
+ const proxy = new Proxy(value, handler);
57
+ cache.set(value, proxy);
58
+ return proxy;
59
+ };
60
+ const createRootFacade = (value) => {
61
+ if (!isObjectLike(value))
62
+ return value;
63
+ const proxy = createVueSafeAuthFacade((prop, receiver) => wrap(Reflect.get(value, prop, receiver)));
64
+ cache.set(value, proxy);
65
+ return proxy;
66
+ };
67
+ return createRootFacade(target);
68
+ }
@@ -0,0 +1,18 @@
1
+ import type { ComputedRef } from 'vue';
2
+ export declare function refreshSessionAfterAuthAction(fetchSession: (options?: {
3
+ force?: boolean;
4
+ }) => Promise<void>, loggedIn: ComputedRef<boolean>, waitForSession: () => Promise<void>): Promise<void>;
5
+ export declare function wrapOnSuccess(fetchSession: (options?: {
6
+ force?: boolean;
7
+ }) => Promise<void>, loggedIn: ComputedRef<boolean>, waitForSession: () => Promise<void>, cb: (ctx: unknown) => void | Promise<void>): (ctx: unknown) => Promise<void>;
8
+ export declare function wrapAuthMethod<T extends (...args: unknown[]) => Promise<unknown>>(method: T, deps: {
9
+ fetchSession: (options?: {
10
+ force?: boolean;
11
+ }) => Promise<void>;
12
+ loggedIn: ComputedRef<boolean>;
13
+ waitForSession: () => Promise<void>;
14
+ resolvePostAuthSuccessRedirect: () => (() => Promise<void>) | undefined;
15
+ }, wrapOptions?: {
16
+ shouldSkipSessionSync?: (data: unknown, options: unknown) => boolean;
17
+ transformData?: (data: unknown, options: unknown) => unknown;
18
+ }): T;
@@ -0,0 +1,69 @@
1
+ import { nextTick } from "#imports";
2
+ import { isRecord } from "./utils.js";
3
+ export async function refreshSessionAfterAuthAction(fetchSession, loggedIn, waitForSession) {
4
+ await fetchSession({ force: true });
5
+ if (!loggedIn.value)
6
+ await waitForSession();
7
+ await nextTick();
8
+ }
9
+ export function wrapOnSuccess(fetchSession, loggedIn, waitForSession, cb) {
10
+ return async (ctx) => {
11
+ await refreshSessionAfterAuthAction(fetchSession, loggedIn, waitForSession);
12
+ await cb(ctx);
13
+ };
14
+ }
15
+ export function wrapAuthMethod(method, deps, wrapOptions = {}) {
16
+ return (async (...args) => {
17
+ const originalData = args[0];
18
+ const options = args[1];
19
+ const data = wrapOptions.transformData?.(originalData, options) ?? originalData;
20
+ const dataRecord = isRecord(data) ? data : void 0;
21
+ const optionsRecord = isRecord(options) ? options : void 0;
22
+ if (wrapOptions.shouldSkipSessionSync?.(data, options))
23
+ return method(data, options);
24
+ const fetchOptions = isRecord(dataRecord?.fetchOptions) ? dataRecord.fetchOptions : void 0;
25
+ const nestedOnSuccess = fetchOptions?.onSuccess;
26
+ const topLevelOnSuccess = optionsRecord?.onSuccess;
27
+ const fallbackOnSuccess = deps.resolvePostAuthSuccessRedirect();
28
+ const wrappedFallbackOnSuccess = fallbackOnSuccess && wrapOnSuccess(deps.fetchSession, deps.loggedIn, deps.waitForSession, async () => {
29
+ if (!deps.loggedIn.value)
30
+ return;
31
+ await fallbackOnSuccess();
32
+ });
33
+ if (typeof nestedOnSuccess === "function") {
34
+ const nextData = {
35
+ ...dataRecord,
36
+ fetchOptions: {
37
+ ...fetchOptions,
38
+ onSuccess: wrapOnSuccess(deps.fetchSession, deps.loggedIn, deps.waitForSession, nestedOnSuccess)
39
+ }
40
+ };
41
+ return method(nextData, options);
42
+ }
43
+ if (typeof topLevelOnSuccess === "function") {
44
+ const nextOptions = {
45
+ ...optionsRecord,
46
+ onSuccess: wrapOnSuccess(deps.fetchSession, deps.loggedIn, deps.waitForSession, topLevelOnSuccess)
47
+ };
48
+ return method(data, nextOptions);
49
+ }
50
+ if (wrappedFallbackOnSuccess) {
51
+ if (fetchOptions) {
52
+ const nextData = {
53
+ ...dataRecord,
54
+ fetchOptions: {
55
+ ...fetchOptions,
56
+ onSuccess: wrappedFallbackOnSuccess
57
+ }
58
+ };
59
+ return method(nextData, options);
60
+ }
61
+ const nextOptions = {
62
+ ...optionsRecord,
63
+ onSuccess: wrappedFallbackOnSuccess
64
+ };
65
+ return method(data, nextOptions);
66
+ }
67
+ return method(data, options);
68
+ });
69
+ }
@@ -1,37 +1,102 @@
1
- import { createError, defineNuxtRouteMiddleware, getRouteRules, navigateTo, useNuxtApp, useRequestHeaders, useRuntimeConfig, useUserSession } from "#imports";
1
+ import { defu } from "defu";
2
+ import { createRouter, toRouteMatcher } from "radix3";
3
+ import { createError, defineNuxtRouteMiddleware, getRouteRules, navigateTo, useNuxtApp, useRequestHeaders, useRuntimeConfig } from "#imports";
4
+ import { shouldSkipAuthRouteRules } from "../../internal/auth-route-rules.js";
2
5
  import { matchesUser } from "../../utils/match-user.js";
6
+ import { useUserSession } from "../composables/useUserSession.js";
7
+ let authRouteRulesPromise = null;
8
+ let routeRulesMatcherPromise = null;
3
9
  export default defineNuxtRouteMiddleware(async (to) => {
10
+ if (shouldSkipAuthRouteRules(to.path))
11
+ return;
4
12
  const nuxtApp = useNuxtApp();
5
- if (import.meta.client) {
6
- const isPrerendered = nuxtApp.payload.prerenderedAt || nuxtApp.payload.isCached;
7
- if (isPrerendered && nuxtApp.isHydrating)
8
- return;
9
- }
10
13
  if (to.meta.auth === void 0) {
11
- const rules = await getRouteRules({ path: to.path });
12
- if (rules.auth !== void 0)
13
- to.meta.auth = rules.auth;
14
+ const routeRulesMatcher = await getRouteRulesMatcher();
15
+ const matches = routeRulesMatcher?.matchAll(to.path);
16
+ if (matches?.length) {
17
+ const merged = defu({}, ...matches.reverse());
18
+ if (merged.auth !== void 0)
19
+ to.meta.auth = merged.auth;
20
+ }
21
+ if (to.meta.auth === void 0) {
22
+ const rules = await getRouteRules({ path: to.path });
23
+ if (rules.auth !== void 0)
24
+ to.meta.auth = rules.auth;
25
+ }
14
26
  }
15
27
  const auth = to.meta.auth;
16
28
  if (auth === void 0 || auth === false)
17
29
  return;
18
30
  const config = useRuntimeConfig().public.auth;
19
31
  const { fetchSession, user, loggedIn } = useUserSession();
20
- if (!loggedIn.value) {
21
- const headers = import.meta.server ? useRequestHeaders(["cookie"]) : void 0;
22
- await fetchSession({ headers });
23
- }
24
32
  const mode = typeof auth === "string" ? auth : auth?.only ?? "user";
25
33
  const redirectTo = typeof auth === "object" ? auth.redirectTo : void 0;
34
+ if (!loggedIn.value || mode === "guest") {
35
+ const headers = import.meta.server ? useRequestHeaders(["cookie"]) : void 0;
36
+ const isHydratedPrerenderPayload = (import.meta.client || !import.meta.server) && nuxtApp.isHydrating && Boolean(nuxtApp.payload.prerenderedAt || nuxtApp.payload.isCached);
37
+ await fetchSession({ headers, ...isHydratedPrerenderPayload ? { force: true } : {} });
38
+ }
26
39
  if (mode === "guest") {
27
40
  if (loggedIn.value)
28
41
  return navigateTo(redirectTo ?? config?.redirects?.guest ?? "/");
29
42
  return;
30
43
  }
31
- if (!loggedIn.value)
32
- return navigateTo(redirectTo ?? config?.redirects?.login ?? "/login");
44
+ if (!loggedIn.value) {
45
+ const resolved = resolveLoginRedirect({
46
+ route: to,
47
+ loginTarget: redirectTo ?? config?.redirects?.login ?? "/login",
48
+ config
49
+ });
50
+ return resolved.external ? navigateTo(resolved.to, { external: true }) : navigateTo(resolved.to);
51
+ }
33
52
  if (typeof auth === "object" && auth.user) {
34
53
  if (!user.value || !matchesUser(user.value, auth.user))
35
54
  throw createError({ statusCode: 403, statusMessage: "Access denied" });
36
55
  }
37
56
  });
57
+ function resolveLoginRedirect(input) {
58
+ const { route, loginTarget, config } = input;
59
+ const preserveRedirect = config?.preserveRedirect ?? true;
60
+ const redirectQueryKey = config?.redirectQueryKey ?? "redirect";
61
+ if (!preserveRedirect)
62
+ return { to: loginTarget, external: false };
63
+ if (!loginTarget.startsWith("/") || loginTarget.startsWith("//"))
64
+ return { to: loginTarget, external: false };
65
+ const [beforeHash, hash = ""] = loginTarget.split("#", 2);
66
+ const [path, query = ""] = beforeHash.split("?", 2);
67
+ try {
68
+ const params2 = new URLSearchParams(query);
69
+ if (params2.has(redirectQueryKey))
70
+ return { to: loginTarget, external: false };
71
+ } catch {
72
+ return { to: loginTarget, external: false };
73
+ }
74
+ if (import.meta.server) {
75
+ const separator = query ? "&" : "";
76
+ const encodedRedirect = encodeURIComponent(route.fullPath);
77
+ const url = `${path}?${query}${separator}${redirectQueryKey}=${encodedRedirect}${hash ? `#${hash}` : ""}`;
78
+ return { to: url, external: true };
79
+ }
80
+ const params = new URLSearchParams(query);
81
+ const queryObj = {};
82
+ for (const [k, v] of params.entries())
83
+ queryObj[k] = v;
84
+ queryObj[redirectQueryKey] = route.fullPath;
85
+ return { to: { path, query: queryObj, ...hash ? { hash: `#${hash}` } : {} }, external: false };
86
+ }
87
+ async function getAuthRouteRules() {
88
+ if (!authRouteRulesPromise) {
89
+ authRouteRulesPromise = import("#auth/route-rules").then((mod) => mod.authRouteRules || {}).catch(() => ({}));
90
+ }
91
+ return await authRouteRulesPromise;
92
+ }
93
+ async function getRouteRulesMatcher() {
94
+ if (!routeRulesMatcherPromise) {
95
+ routeRulesMatcherPromise = getAuthRouteRules().then((authRouteRules) => {
96
+ if (!Object.keys(authRouteRules).length)
97
+ return null;
98
+ return toRouteMatcher(createRouter({ routes: authRouteRules }));
99
+ });
100
+ }
101
+ return await routeRulesMatcherPromise;
102
+ }