@bagelink/auth 1.7.72 → 1.7.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +332 -244
- package/dist/index.cjs +307 -74
- package/dist/index.d.ts +3 -0
- package/dist/index.mjs +307 -74
- package/dist/redirect.d.ts +21 -0
- package/dist/router.d.ts +36 -0
- package/dist/types/redirect.d.ts +70 -0
- package/dist/useAuth.d.ts +57 -0
- package/package.json +1 -1
- package/src/index.ts +10 -2
- package/src/redirect.ts +95 -0
- package/src/router.ts +129 -0
- package/src/types/redirect.ts +96 -0
- package/src/useAuth.ts +128 -1
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -14,17 +14,25 @@ export { default as ForgotPasswordPage } from './pages/ForgotPasswordPage.vue'
|
|
|
14
14
|
export { default as LoginPage } from './pages/LoginPage.vue'
|
|
15
15
|
export { default as ResetPasswordPage } from './pages/ResetPasswordPage.vue'
|
|
16
16
|
export { default as SignupPage } from './pages/SignupPage.vue'
|
|
17
|
+
|
|
18
|
+
// Redirect utilities
|
|
19
|
+
export * from './redirect'
|
|
20
|
+
|
|
21
|
+
// Router integration
|
|
22
|
+
export * from './router'
|
|
23
|
+
|
|
17
24
|
// Routes
|
|
18
25
|
export * from './routes'
|
|
19
26
|
export * from './sso'
|
|
20
27
|
|
|
21
|
-
// Types (
|
|
28
|
+
// Types ( e-export fro types file and modu e)
|
|
22
29
|
export * from './types'
|
|
23
|
-
|
|
24
30
|
export type {
|
|
25
31
|
ForgotPasswordTexts,
|
|
26
32
|
LoginTexts,
|
|
27
33
|
ResetPasswordTexts,
|
|
28
34
|
SignupTexts,
|
|
29
35
|
} from './types/'
|
|
36
|
+
|
|
37
|
+
export * from './types/redirect'
|
|
30
38
|
export * from './useAuth'
|
package/src/redirect.ts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { Router } from 'vue-router'
|
|
2
|
+
import type { NormalizedRedirectConfig } from './types/redirect'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Redirect utilities for handling post-authentication navigation
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Get redirect URL from current route query params
|
|
10
|
+
*/
|
|
11
|
+
export function getRedirectUrl(
|
|
12
|
+
router: Router,
|
|
13
|
+
config: NormalizedRedirectConfig,
|
|
14
|
+
): string {
|
|
15
|
+
const redirect = router.currentRoute.value.query[config.queryKey] as string
|
|
16
|
+
return redirect || config.fallback
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Validate redirect URL is safe (prevents open redirect attacks)
|
|
21
|
+
*/
|
|
22
|
+
export function isValidRedirect(
|
|
23
|
+
redirectUrl: string,
|
|
24
|
+
allowedPaths?: RegExp[],
|
|
25
|
+
): boolean {
|
|
26
|
+
// Null or empty check
|
|
27
|
+
if (!redirectUrl) {
|
|
28
|
+
return false
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Prevent redirects to external URLs (absolute URLs with protocol)
|
|
32
|
+
if (redirectUrl.startsWith('http://') || redirectUrl.startsWith('https://')) {
|
|
33
|
+
return false
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Prevent protocol-relative URLs
|
|
37
|
+
if (redirectUrl.startsWith('//')) {
|
|
38
|
+
return false
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Prevent javascript: and data: URLs
|
|
42
|
+
if (redirectUrl.startsWith('javascript:') || redirectUrl.startsWith('data:')) {
|
|
43
|
+
return false
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Ensure it starts with /
|
|
47
|
+
if (!redirectUrl.startsWith('/')) {
|
|
48
|
+
return false
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// If allowed paths are specified, check against them
|
|
52
|
+
if (allowedPaths && allowedPaths.length > 0) {
|
|
53
|
+
return allowedPaths.some(pattern => pattern.test(redirectUrl))
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return true
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Perform redirect after login with security validation
|
|
61
|
+
*/
|
|
62
|
+
export async function performRedirect(
|
|
63
|
+
router: Router,
|
|
64
|
+
config: NormalizedRedirectConfig,
|
|
65
|
+
): Promise<void> {
|
|
66
|
+
const redirect = getRedirectUrl(router, config)
|
|
67
|
+
|
|
68
|
+
// Always validate redirect URL for security
|
|
69
|
+
if (redirect !== config.fallback && !isValidRedirect(redirect, config.allowedPaths)) {
|
|
70
|
+
console.warn('[Auth] Invalid redirect URL detected, using fallback:', redirect)
|
|
71
|
+
await router.push(config.fallback)
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
await router.push(redirect)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Build query params for redirect to login
|
|
80
|
+
*/
|
|
81
|
+
export function buildLoginQuery(
|
|
82
|
+
currentPath: string,
|
|
83
|
+
config: NormalizedRedirectConfig,
|
|
84
|
+
): Record<string, string> {
|
|
85
|
+
if (!config.preserveRedirect) {
|
|
86
|
+
return {}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Validate the current path before storing it
|
|
90
|
+
if (isValidRedirect(currentPath, config.allowedPaths)) {
|
|
91
|
+
return { [config.queryKey]: currentPath }
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return {}
|
|
95
|
+
}
|
package/src/router.ts
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type { NavigationGuard, NavigationGuardNext, RouteLocationNormalized } from 'vue-router'
|
|
2
|
+
import { buildLoginQuery } from './redirect'
|
|
3
|
+
import { useAuth, getRedirectConfig } from './useAuth'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Auth router integration for Vue Router
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Track if auth has been initialized (for performance)
|
|
10
|
+
let authInitialized = false
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Reset auth initialization state
|
|
14
|
+
* Useful for testing or app reload scenarios
|
|
15
|
+
*/
|
|
16
|
+
export function resetAuthState() {
|
|
17
|
+
authInitialized = false
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Auth guard for Vue Router
|
|
22
|
+
*
|
|
23
|
+
* Protects routes requiring authentication and handles redirect logic.
|
|
24
|
+
* Reads configuration from the auth instance created via createAuth().
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* const auth = createAuth({
|
|
29
|
+
* baseURL: 'https://api.example.com',
|
|
30
|
+
* redirect: { ... }
|
|
31
|
+
* })
|
|
32
|
+
* router.beforeEach(authGuard())
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export function authGuard() {
|
|
36
|
+
return async function guard(
|
|
37
|
+
|
|
38
|
+
to: RouteLocationNormalized,
|
|
39
|
+
_from: RouteLocationNormalized,
|
|
40
|
+
next: NavigationGuardNext,
|
|
41
|
+
): Promise<void> {
|
|
42
|
+
const auth = useAuth()
|
|
43
|
+
const config = getRedirectConfig()
|
|
44
|
+
|
|
45
|
+
// Check if route requires authentication
|
|
46
|
+
const requiresAuth = to.meta[config.authMetaKey]
|
|
47
|
+
|
|
48
|
+
// Check if route is an auth-only page (login, signup, etc)
|
|
49
|
+
const requiresNoAuth = config.noAuthRoutes.includes(to.name as string)
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
// Only check auth once on first navigation for performance
|
|
53
|
+
if (!authInitialized) {
|
|
54
|
+
await auth.checkAuth()
|
|
55
|
+
authInitialized = true
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Use cached auth state from reactive user ref
|
|
59
|
+
const isAuthenticated = !!auth.user.value
|
|
60
|
+
|
|
61
|
+
// Redirect authenticated users away from auth pages
|
|
62
|
+
if (isAuthenticated && requiresNoAuth) {
|
|
63
|
+
next(config.authenticatedRedirect)
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Redirect unauthenticated users to login for protected pages
|
|
68
|
+
if (!isAuthenticated && requiresAuth) {
|
|
69
|
+
const query = buildLoginQuery(to.fullPath, config)
|
|
70
|
+
|
|
71
|
+
next({
|
|
72
|
+
name: config.loginRoute,
|
|
73
|
+
query,
|
|
74
|
+
})
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Allow navigation
|
|
79
|
+
next()
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error('[Auth Guard] Error:', error)
|
|
82
|
+
// On error, allow navigation but log the issue
|
|
83
|
+
next()
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Compose multiple navigation guards into one
|
|
90
|
+
* Guards are executed in order, stopping at the first one that calls next with a value
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```ts
|
|
94
|
+
* router.beforeEach(composeGuards([
|
|
95
|
+
* authGuard(),
|
|
96
|
+
* orgAccessGuard(),
|
|
97
|
+
* featureFlagGuard(),
|
|
98
|
+
* ]))
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
export function composeGuards(guards: NavigationGuard[]): NavigationGuard {
|
|
102
|
+
return async (to, from, next) => {
|
|
103
|
+
let guardIndex = 0
|
|
104
|
+
|
|
105
|
+
const runNextGuard = async (): Promise<void> => {
|
|
106
|
+
if (guardIndex >= guards.length) {
|
|
107
|
+
// All guards passed, allow navigation
|
|
108
|
+
next()
|
|
109
|
+
return
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const guard = guards[guardIndex]
|
|
113
|
+
guardIndex++
|
|
114
|
+
|
|
115
|
+
// Run the current guard
|
|
116
|
+
await guard(to, from, (result?: any) => {
|
|
117
|
+
if (result !== undefined) {
|
|
118
|
+
// Guard blocked or redirected, stop here
|
|
119
|
+
next(result)
|
|
120
|
+
} else {
|
|
121
|
+
// Guard passed, run next guard
|
|
122
|
+
runNextGuard()
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
await runNextGuard()
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Redirect configuration types for auth library
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface RedirectConfig {
|
|
6
|
+
/**
|
|
7
|
+
* Query parameter key used to store the redirect URL
|
|
8
|
+
* After login, read this param to redirect users back to their intended destination
|
|
9
|
+
* @default 'redirect'
|
|
10
|
+
*/
|
|
11
|
+
queryKey?: string
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Default fallback URL when no redirect is specified
|
|
15
|
+
* @default '/'
|
|
16
|
+
*/
|
|
17
|
+
fallback?: string
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Routes that require NO authentication (login, signup, forgot password, etc)
|
|
21
|
+
* Authenticated users will be automatically redirected away from these pages
|
|
22
|
+
* @default ['Login', 'Signup', 'ForgotPassword', 'ResetPassword', 'Callback']
|
|
23
|
+
*/
|
|
24
|
+
noAuthRoutes?: string[]
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Route name to redirect to when authenticated users try to access auth-only pages
|
|
28
|
+
* @default '/'
|
|
29
|
+
*/
|
|
30
|
+
authenticatedRedirect?: string
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Route name to redirect to when unauthenticated users try to access protected pages
|
|
34
|
+
* @default 'Login'
|
|
35
|
+
*/
|
|
36
|
+
loginRoute?: string
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Meta key used to check if a route requires authentication
|
|
40
|
+
* @default 'auth'
|
|
41
|
+
* @example In your route: `meta: { auth: true }`
|
|
42
|
+
*/
|
|
43
|
+
authMetaKey?: string
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Enable automatic redirect handling after login
|
|
47
|
+
* When true, the library automatically redirects users after successful login
|
|
48
|
+
* @default true
|
|
49
|
+
*/
|
|
50
|
+
autoRedirect?: boolean
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Enable redirect preservation for protected routes
|
|
54
|
+
* When enabled, the original URL is preserved as a query param after redirecting to login
|
|
55
|
+
* @default true
|
|
56
|
+
*/
|
|
57
|
+
preserveRedirect?: boolean
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Optional allowed redirect path patterns for security validation
|
|
61
|
+
* If specified, only URLs matching these patterns will be allowed
|
|
62
|
+
* @default undefined (allows all internal paths)
|
|
63
|
+
*/
|
|
64
|
+
allowedPaths?: RegExp[]
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Normalized redirect configuration with all defaults applied
|
|
69
|
+
*/
|
|
70
|
+
export interface NormalizedRedirectConfig extends Required<Omit<RedirectConfig, 'allowedPaths'>> {
|
|
71
|
+
allowedPaths?: RegExp[]
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Default redirect configuration
|
|
76
|
+
*/
|
|
77
|
+
export const DEFAULT_REDIRECT_CONFIG: NormalizedRedirectConfig = {
|
|
78
|
+
queryKey: 'redirect',
|
|
79
|
+
fallback: '/',
|
|
80
|
+
noAuthRoutes: ['Login', 'Signup', 'ForgotPassword', 'ResetPassword', 'Callback'],
|
|
81
|
+
authenticatedRedirect: '/',
|
|
82
|
+
loginRoute: 'Login',
|
|
83
|
+
authMetaKey: 'auth',
|
|
84
|
+
autoRedirect: true,
|
|
85
|
+
preserveRedirect: true,
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Normalize redirect configuration by applying defaults
|
|
90
|
+
*/
|
|
91
|
+
export function normalizeRedirectConfig(config?: RedirectConfig): NormalizedRedirectConfig {
|
|
92
|
+
return {
|
|
93
|
+
...DEFAULT_REDIRECT_CONFIG,
|
|
94
|
+
...config,
|
|
95
|
+
}
|
|
96
|
+
}
|
package/src/useAuth.ts
CHANGED
|
@@ -11,19 +11,40 @@ import type {
|
|
|
11
11
|
SSOCallbackRequest,
|
|
12
12
|
SSOLinkRequest,
|
|
13
13
|
} from './types'
|
|
14
|
+
import type { RedirectConfig, NormalizedRedirectConfig } from './types/redirect'
|
|
14
15
|
import { ref, computed } from 'vue'
|
|
15
16
|
import { AuthApi } from './api'
|
|
16
17
|
import { setAuthContext, sso } from './sso'
|
|
17
18
|
import { AuthState, accountToUser } from './types'
|
|
19
|
+
import { normalizeRedirectConfig } from './types/redirect'
|
|
18
20
|
import { EventEmitter } from './utils'
|
|
19
21
|
|
|
20
22
|
// Global state
|
|
21
23
|
let authApi: AuthApi | null = null
|
|
22
24
|
let eventEmitter: EventEmitter | null = null
|
|
25
|
+
let redirectConfig: NormalizedRedirectConfig | null = null
|
|
26
|
+
let autoRedirectRouter: any = null // Router instance for auto-redirect
|
|
27
|
+
let cachedAuthGuard: any = null // Cached router guard
|
|
23
28
|
const accountInfo = ref<AccountInfo | null>(null)
|
|
24
29
|
|
|
25
30
|
interface InitParams {
|
|
26
31
|
baseURL: string
|
|
32
|
+
/**
|
|
33
|
+
* Redirect configuration for authentication flows
|
|
34
|
+
* @see RedirectConfig
|
|
35
|
+
*/
|
|
36
|
+
redirect?: RedirectConfig
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get the current redirect configuration
|
|
41
|
+
* Used internally by router guard
|
|
42
|
+
*/
|
|
43
|
+
export function getRedirectConfig(): NormalizedRedirectConfig {
|
|
44
|
+
if (!redirectConfig) {
|
|
45
|
+
throw new Error('Redirect config not initialized. Did you call createAuth with redirect config?')
|
|
46
|
+
}
|
|
47
|
+
return redirectConfig
|
|
27
48
|
}
|
|
28
49
|
|
|
29
50
|
// Initialize auth
|
|
@@ -36,7 +57,17 @@ export function createAuth(params: InitParams) {
|
|
|
36
57
|
eventEmitter = new EventEmitter()
|
|
37
58
|
}
|
|
38
59
|
|
|
39
|
-
|
|
60
|
+
// Store redirect configuration
|
|
61
|
+
if (params.redirect) {
|
|
62
|
+
redirectConfig = normalizeRedirectConfig(params.redirect)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Setup auto-redirect on login if enabled
|
|
66
|
+
if (redirectConfig?.autoRedirect) {
|
|
67
|
+
setupAutoRedirect()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const authInstance = {
|
|
40
71
|
// Event listener methods
|
|
41
72
|
on<K extends AuthState>(event: K, handler: AuthEventMap[K]): void {
|
|
42
73
|
if (eventEmitter) {
|
|
@@ -56,11 +87,107 @@ export function createAuth(params: InitParams) {
|
|
|
56
87
|
}
|
|
57
88
|
},
|
|
58
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Connect external dependencies like Vue Router
|
|
92
|
+
* Automatically sets up router guard when router is provided
|
|
93
|
+
* @param dependency - Vue Router instance or other plugins
|
|
94
|
+
* @param options - Configuration options
|
|
95
|
+
* @param options.guard - Whether to automatically set up auth guard (default: true)
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* // Auto setup (default)
|
|
99
|
+
* auth.use(router)
|
|
100
|
+
*
|
|
101
|
+
* // Manual guard control (for custom composition)
|
|
102
|
+
* auth.use(router, { guard: false })
|
|
103
|
+
* router.beforeEach(async (to, from, next) => {
|
|
104
|
+
* // Custom logic first
|
|
105
|
+
* if (!hasOrgAccess(to)) return next('/no-access')
|
|
106
|
+
* // Then run auth guard
|
|
107
|
+
* return auth.routerGuard()(to, from, next)
|
|
108
|
+
* })
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
use(dependency: any, options: { guard?: boolean } = {}) {
|
|
112
|
+
const { guard = true } = options
|
|
113
|
+
|
|
114
|
+
// Detect if it's a router by checking for common router properties
|
|
115
|
+
if (dependency && (dependency.beforeEach || dependency.push || dependency.currentRoute)) {
|
|
116
|
+
autoRedirectRouter = dependency
|
|
117
|
+
// Automatically set up the auth guard unless disabled
|
|
118
|
+
if (guard) {
|
|
119
|
+
dependency.beforeEach(authInstance.routerGuard())
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return authInstance
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Create a Vue Router navigation guard for authentication
|
|
127
|
+
* Protects routes requiring authentication and handles redirect logic
|
|
128
|
+
* Note: Automatically called by auth.use(router), only use directly for custom setups
|
|
129
|
+
* @example
|
|
130
|
+
* ```ts
|
|
131
|
+
* // Automatic (recommended)
|
|
132
|
+
* auth.use(router)
|
|
133
|
+
*
|
|
134
|
+
* // Manual (for custom setups)
|
|
135
|
+
* router.beforeEach(auth.routerGuard())
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
routerGuard() {
|
|
139
|
+
// Return factory that lazily loads authGuard to avoid circular dependency
|
|
140
|
+
if (cachedAuthGuard === null) {
|
|
141
|
+
cachedAuthGuard = async (to: any, from: any, next: any) => {
|
|
142
|
+
const { authGuard } = await import('./router')
|
|
143
|
+
const guard = authGuard()
|
|
144
|
+
// Cache the actual guard for next time
|
|
145
|
+
cachedAuthGuard = guard
|
|
146
|
+
return guard(to, from, next)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return cachedAuthGuard
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Vue plugin install method
|
|
154
|
+
* Makes auth available globally as $auth
|
|
155
|
+
* @example
|
|
156
|
+
* ```ts
|
|
157
|
+
* app.use(auth)
|
|
158
|
+
* ```
|
|
159
|
+
*/
|
|
59
160
|
install(app: App) {
|
|
60
161
|
// Make auth available globally
|
|
61
162
|
app.config.globalProperties.$auth = useAuth()
|
|
62
163
|
},
|
|
63
164
|
}
|
|
165
|
+
|
|
166
|
+
return authInstance
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Setup automatic redirect after successful login
|
|
171
|
+
*/
|
|
172
|
+
function setupAutoRedirect() {
|
|
173
|
+
if (!eventEmitter || !redirectConfig) return
|
|
174
|
+
|
|
175
|
+
eventEmitter.on(AuthState.LOGIN, async () => {
|
|
176
|
+
// Only auto-redirect if router is available
|
|
177
|
+
if (!autoRedirectRouter) {
|
|
178
|
+
console.warn('[Auth] Auto-redirect enabled but router not set. Call setAuthRouter(router) in your app setup.')
|
|
179
|
+
return
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Dynamic import to avoid circular dependency
|
|
183
|
+
const { performRedirect } = await import('./redirect')
|
|
184
|
+
|
|
185
|
+
try {
|
|
186
|
+
await performRedirect(autoRedirectRouter, redirectConfig!)
|
|
187
|
+
} catch (error) {
|
|
188
|
+
console.error('[Auth] Auto-redirect error:', error)
|
|
189
|
+
}
|
|
190
|
+
})
|
|
64
191
|
}
|
|
65
192
|
|
|
66
193
|
// Composable
|