@payez/next-mvp 3.9.1 → 4.0.0
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/dist/api/auth-handler.d.ts +1 -2
- package/dist/api/auth-handler.js +9 -9
- package/dist/api-handlers/account/change-password.js +110 -112
- package/dist/api-handlers/admin/analytics.d.ts +19 -20
- package/dist/api-handlers/admin/analytics.js +378 -379
- package/dist/api-handlers/admin/audit.d.ts +19 -20
- package/dist/api-handlers/admin/audit.js +213 -214
- package/dist/api-handlers/admin/index.d.ts +21 -22
- package/dist/api-handlers/admin/index.js +42 -43
- package/dist/api-handlers/admin/redis-sessions.d.ts +35 -36
- package/dist/api-handlers/admin/redis-sessions.js +203 -204
- package/dist/api-handlers/admin/sessions.d.ts +20 -21
- package/dist/api-handlers/admin/sessions.js +283 -284
- package/dist/api-handlers/admin/site-logs.d.ts +45 -46
- package/dist/api-handlers/admin/site-logs.js +317 -318
- package/dist/api-handlers/admin/stats.d.ts +20 -21
- package/dist/api-handlers/admin/stats.js +239 -240
- package/dist/api-handlers/admin/users.d.ts +19 -20
- package/dist/api-handlers/admin/users.js +221 -222
- package/dist/api-handlers/admin/vibe-data.d.ts +79 -80
- package/dist/api-handlers/admin/vibe-data.js +267 -268
- package/dist/api-handlers/auth/refresh.js +633 -635
- package/dist/api-handlers/auth/signout.js +186 -187
- package/dist/api-handlers/auth/status.js +4 -7
- package/dist/api-handlers/auth/update-session.d.ts +1 -1
- package/dist/api-handlers/auth/update-session.js +12 -14
- package/dist/api-handlers/auth/verify-code.d.ts +43 -43
- package/dist/api-handlers/auth/verify-code.js +90 -94
- package/dist/api-handlers/session/viability.js +114 -146
- package/dist/api-handlers/test/force-expire.js +59 -65
- package/dist/auth/auth-decision.js +182 -182
- package/dist/auth/better-auth.d.ts +3 -6
- package/dist/auth/better-auth.js +3 -6
- package/dist/auth/route-config.js +2 -2
- package/dist/auth/utils/token-utils.d.ts +83 -84
- package/dist/auth/utils/token-utils.js +218 -219
- package/dist/client/AuthContext.js +115 -112
- package/dist/client/better-auth-client.d.ts +1020 -1020
- package/dist/client/fetch-with-auth.js +2 -2
- package/dist/components/SessionSync.js +121 -119
- package/dist/components/account/MobileNavDrawer.js +64 -64
- package/dist/components/account/UserAvatarMenu.js +91 -88
- package/dist/components/admin/VibeAdminLayout.js +71 -69
- package/dist/hooks/useAuth.js +9 -7
- package/dist/hooks/useAuthSettings.js +93 -93
- package/dist/hooks/useAvailableProviders.d.ts +43 -45
- package/dist/hooks/useAvailableProviders.js +112 -108
- package/dist/hooks/useSessionExpiration.d.ts +2 -3
- package/dist/hooks/useSessionExpiration.js +2 -2
- package/dist/hooks/useViabilitySession.js +3 -2
- package/dist/index.js +4 -6
- package/dist/lib/app-slug.d.ts +95 -95
- package/dist/lib/app-slug.js +172 -172
- package/dist/lib/standardized-client-api.js +10 -5
- package/dist/lib/startup-init.js +21 -25
- package/dist/lib/test-aware-get-token.js +86 -81
- package/dist/lib/token-lifecycle.d.ts +78 -52
- package/dist/lib/token-lifecycle.js +360 -398
- package/dist/pages/admin-login/page.js +73 -83
- package/dist/pages/client-admin/ClientSiteAdminPage.js +179 -177
- package/dist/pages/login/page.js +202 -211
- package/dist/pages/showcase/ShowcasePage.js +142 -140
- package/dist/pages/test-env/EmergencyLogoutPage.js +99 -98
- package/dist/pages/test-env/JwtInspectPage.js +116 -114
- package/dist/pages/test-env/RefreshTokenPage.js +4 -2
- package/dist/pages/test-env/TestEnvPage.js +51 -49
- package/dist/pages/verify-code/page.js +412 -408
- package/dist/routes/auth/logout.d.ts +31 -31
- package/dist/routes/auth/logout.js +98 -113
- package/dist/routes/auth/nextauth.d.ts +14 -11
- package/dist/routes/auth/nextauth.js +25 -57
- package/dist/routes/auth/session.js +157 -179
- package/dist/routes/auth/viability.js +190 -201
- package/dist/server/auth.d.ts +50 -0
- package/dist/server/auth.js +62 -0
- package/dist/stores/authStore.js +19 -23
- package/dist/utils/logout.js +5 -5
- package/package.json +1 -3
- package/src/api/auth-handler.ts +550 -549
- package/src/api-handlers/account/change-password.ts +5 -8
- package/src/api-handlers/admin/analytics.ts +4 -6
- package/src/api-handlers/admin/audit.ts +5 -7
- package/src/api-handlers/admin/index.ts +1 -2
- package/src/api-handlers/admin/redis-sessions.ts +6 -8
- package/src/api-handlers/admin/sessions.ts +5 -7
- package/src/api-handlers/admin/site-logs.ts +8 -10
- package/src/api-handlers/admin/stats.ts +4 -6
- package/src/api-handlers/admin/users.ts +5 -7
- package/src/api-handlers/admin/vibe-data.ts +10 -12
- package/src/api-handlers/auth/refresh.ts +5 -7
- package/src/api-handlers/auth/signout.ts +5 -6
- package/src/api-handlers/auth/status.ts +4 -7
- package/src/api-handlers/auth/update-session.ts +123 -125
- package/src/api-handlers/auth/verify-code.ts +9 -13
- package/src/api-handlers/session/viability.ts +10 -47
- package/src/api-handlers/test/force-expire.ts +4 -11
- package/src/auth/auth-decision.ts +1 -1
- package/src/auth/better-auth.ts +138 -141
- package/src/auth/route-config.ts +219 -219
- package/src/auth/utils/token-utils.ts +0 -1
- package/src/client/AuthContext.tsx +6 -2
- package/src/client/fetch-with-auth.ts +47 -47
- package/src/components/SessionSync.tsx +6 -5
- package/src/components/account/MobileNavDrawer.tsx +3 -3
- package/src/components/account/UserAvatarMenu.tsx +6 -3
- package/src/components/admin/VibeAdminLayout.tsx +4 -2
- package/src/config/logger.ts +1 -1
- package/src/hooks/useAuth.ts +117 -115
- package/src/hooks/useAuthSettings.ts +2 -2
- package/src/hooks/useAvailableProviders.ts +9 -5
- package/src/hooks/useSessionExpiration.ts +101 -102
- package/src/hooks/useViabilitySession.ts +336 -335
- package/src/index.ts +60 -63
- package/src/lib/api-handler.ts +0 -1
- package/src/lib/app-slug.ts +6 -6
- package/src/lib/standardized-client-api.ts +901 -895
- package/src/lib/startup-init.ts +243 -247
- package/src/lib/test-aware-get-token.ts +22 -12
- package/src/lib/token-lifecycle.ts +12 -53
- package/src/pages/admin-login/page.tsx +9 -17
- package/src/pages/client-admin/ClientSiteAdminPage.tsx +4 -2
- package/src/pages/login/page.tsx +21 -28
- package/src/pages/showcase/ShowcasePage.tsx +4 -2
- package/src/pages/test-env/EmergencyLogoutPage.tsx +7 -6
- package/src/pages/test-env/JwtInspectPage.tsx +5 -3
- package/src/pages/test-env/RefreshTokenPage.tsx +157 -155
- package/src/pages/test-env/TestEnvPage.tsx +4 -2
- package/src/pages/verify-code/page.tsx +10 -6
- package/src/routes/auth/logout.ts +7 -25
- package/src/routes/auth/nextauth.ts +45 -71
- package/src/routes/auth/session.ts +25 -50
- package/src/routes/auth/viability.ts +7 -19
- package/src/server/auth.ts +60 -0
- package/src/stores/authStore.ts +1899 -1904
- package/src/utils/logout.ts +30 -30
- package/src/auth/auth-options.ts +0 -237
- package/src/auth/callbacks/index.ts +0 -7
- package/src/auth/callbacks/jwt.ts +0 -382
- package/src/auth/callbacks/session.ts +0 -243
- package/src/auth/callbacks/signin.ts +0 -56
- package/src/auth/events/index.ts +0 -5
- package/src/auth/events/signout.ts +0 -33
- package/src/auth/providers/credentials.ts +0 -256
- package/src/auth/providers/index.ts +0 -6
- package/src/auth/providers/oauth.ts +0 -114
- package/src/lib/nextauth-secret.ts +0 -121
- package/src/types/next-auth.d.ts +0 -15
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import React, { ReactNode } from 'react';
|
|
4
|
-
import {
|
|
4
|
+
import { authClient } from '../../client/better-auth-client';
|
|
5
5
|
import { useRouter } from 'next/navigation';
|
|
6
6
|
import { useEffect } from 'react';
|
|
7
7
|
import Link from 'next/link';
|
|
@@ -50,7 +50,9 @@ export function VibeAdminLayout({
|
|
|
50
50
|
isDarkMode: isDarkModeProp,
|
|
51
51
|
adminRole = 'vibe_app_admin',
|
|
52
52
|
}: VibeAdminLayoutProps) {
|
|
53
|
-
const { data:
|
|
53
|
+
const { data: sessionData, isPending } = authClient.useSession();
|
|
54
|
+
const session = sessionData;
|
|
55
|
+
const status = isPending ? 'loading' : session ? 'authenticated' : 'unauthenticated';
|
|
54
56
|
const router = useRouter();
|
|
55
57
|
const adminConfig = useVibeAdmin();
|
|
56
58
|
|
package/src/config/logger.ts
CHANGED
|
@@ -45,7 +45,7 @@ const createLogger = (): any => {
|
|
|
45
45
|
};
|
|
46
46
|
|
|
47
47
|
let logger: any;
|
|
48
|
-
if (!globalThis.process?.browser) {
|
|
48
|
+
if (!(globalThis.process as any)?.browser) {
|
|
49
49
|
logger = createLogger();
|
|
50
50
|
addConfigWatcher((updatedConfig) => { loggingConfig = updatedConfig; if (logger && logger.level !== undefined) { logger.level = loggingConfig.logLevel; } });
|
|
51
51
|
} else { logger = console; }
|
package/src/hooks/useAuth.ts
CHANGED
|
@@ -1,115 +1,117 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* ⚠️ WARNING: This hook cannot be used directly from the @payez/next-mvp package!
|
|
5
|
-
*
|
|
6
|
-
* @deprecated Import this hook from your local app instead
|
|
7
|
-
*
|
|
8
|
-
* **Why?** React Context (SessionProvider) cannot cross package boundaries in file:// linked packages.
|
|
9
|
-
*
|
|
10
|
-
* **Solution:** Create a local version in your app (e.g., src/hooks/useAuth.ts) that imports standardizedApi:
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```typescript
|
|
14
|
-
* // src/hooks/useAuth.ts (YOUR APP)
|
|
15
|
-
* 'use client';
|
|
16
|
-
* import {
|
|
17
|
-
* import { standardizedApi } from '@payez/next-mvp/lib/standardized-client-api';
|
|
18
|
-
*
|
|
19
|
-
* export function useAuth() {
|
|
20
|
-
* const { data: session } = useSession(); // Works in your app context
|
|
21
|
-
* // ... implementation
|
|
22
|
-
* }
|
|
23
|
-
* ```
|
|
24
|
-
*
|
|
25
|
-
* @see {@link https://github.com/payez/next-mvp/blob/main/docs/centralized-auth-api-pattern.md#why-local-hooks-for-auth Complete documentation}
|
|
26
|
-
*/
|
|
27
|
-
|
|
28
|
-
import {
|
|
29
|
-
import { useCallback } from 'react';
|
|
30
|
-
import { useRouter } from 'next/navigation';
|
|
31
|
-
import { standardizedApi, ApiResult } from '../lib/standardized-client-api';
|
|
32
|
-
|
|
33
|
-
// Custom session type matching NextAuth structure
|
|
34
|
-
export interface CustomSession {
|
|
35
|
-
user: {
|
|
36
|
-
id: string;
|
|
37
|
-
email: string;
|
|
38
|
-
roles?: string[];
|
|
39
|
-
twoFactorMethod?: string;
|
|
40
|
-
twoFactorSessionVerified?: boolean;
|
|
41
|
-
requiresTwoFactor?: boolean;
|
|
42
|
-
};
|
|
43
|
-
accessToken?: string;
|
|
44
|
-
refreshToken?: string;
|
|
45
|
-
expires: string;
|
|
46
|
-
error?: string;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export interface UseAuthResult {
|
|
50
|
-
session: CustomSession | null;
|
|
51
|
-
status: 'loading' | 'authenticated' | 'unauthenticated';
|
|
52
|
-
isLoading: boolean;
|
|
53
|
-
isAuthenticated: boolean;
|
|
54
|
-
// API helper that automatically includes the auth token
|
|
55
|
-
apiCall: <T>(url: string, method?: 'GET' | 'POST' | 'PUT' | 'DELETE', data?: any) => Promise<ApiResult<T>>;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export function useAuth(): UseAuthResult {
|
|
59
|
-
const { data:
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
case '
|
|
85
|
-
return await standardizedApi.
|
|
86
|
-
case '
|
|
87
|
-
return await standardizedApi.
|
|
88
|
-
case '
|
|
89
|
-
return await standardizedApi.
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ⚠️ WARNING: This hook cannot be used directly from the @payez/next-mvp package!
|
|
5
|
+
*
|
|
6
|
+
* @deprecated Import this hook from your local app instead
|
|
7
|
+
*
|
|
8
|
+
* **Why?** React Context (SessionProvider) cannot cross package boundaries in file:// linked packages.
|
|
9
|
+
*
|
|
10
|
+
* **Solution:** Create a local version in your app (e.g., src/hooks/useAuth.ts) that imports standardizedApi:
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* // src/hooks/useAuth.ts (YOUR APP)
|
|
15
|
+
* 'use client';
|
|
16
|
+
* import { authClient } from '@payez/next-mvp/client/better-auth-client';
|
|
17
|
+
* import { standardizedApi } from '@payez/next-mvp/lib/standardized-client-api';
|
|
18
|
+
*
|
|
19
|
+
* export function useAuth() {
|
|
20
|
+
* const { data: session } = useSession(); // Works in your app context
|
|
21
|
+
* // ... implementation
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @see {@link https://github.com/payez/next-mvp/blob/main/docs/centralized-auth-api-pattern.md#why-local-hooks-for-auth Complete documentation}
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { authClient } from '../client/better-auth-client';
|
|
29
|
+
import { useCallback } from 'react';
|
|
30
|
+
import { useRouter } from 'next/navigation';
|
|
31
|
+
import { standardizedApi, ApiResult } from '../lib/standardized-client-api';
|
|
32
|
+
|
|
33
|
+
// Custom session type matching NextAuth structure
|
|
34
|
+
export interface CustomSession {
|
|
35
|
+
user: {
|
|
36
|
+
id: string;
|
|
37
|
+
email: string;
|
|
38
|
+
roles?: string[];
|
|
39
|
+
twoFactorMethod?: string;
|
|
40
|
+
twoFactorSessionVerified?: boolean;
|
|
41
|
+
requiresTwoFactor?: boolean;
|
|
42
|
+
};
|
|
43
|
+
accessToken?: string;
|
|
44
|
+
refreshToken?: string;
|
|
45
|
+
expires: string;
|
|
46
|
+
error?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface UseAuthResult {
|
|
50
|
+
session: CustomSession | null;
|
|
51
|
+
status: 'loading' | 'authenticated' | 'unauthenticated';
|
|
52
|
+
isLoading: boolean;
|
|
53
|
+
isAuthenticated: boolean;
|
|
54
|
+
// API helper that automatically includes the auth token
|
|
55
|
+
apiCall: <T>(url: string, method?: 'GET' | 'POST' | 'PUT' | 'DELETE', data?: any) => Promise<ApiResult<T>>;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function useAuth(): UseAuthResult {
|
|
59
|
+
const { data: sessionData, isPending } = authClient.useSession();
|
|
60
|
+
const session = sessionData;
|
|
61
|
+
const status = isPending ? 'loading' : session ? 'authenticated' : 'unauthenticated';
|
|
62
|
+
const router = useRouter();
|
|
63
|
+
|
|
64
|
+
const isLoading = status === 'loading';
|
|
65
|
+
const isAuthenticated = status === 'authenticated' && !!(session as any)?.accessToken;
|
|
66
|
+
|
|
67
|
+
// Handle sign out with redirect
|
|
68
|
+
const handleSignOut = useCallback(async () => {
|
|
69
|
+
await authClient.signOut();
|
|
70
|
+
router.push('/account-auth/login?error=SessionExpired');
|
|
71
|
+
}, [router]);
|
|
72
|
+
|
|
73
|
+
// API helper that automatically includes the auth token and uses standardized API
|
|
74
|
+
const apiCall = useCallback(
|
|
75
|
+
async <T>(url: string, method: 'GET' | 'POST' | 'PUT' | 'DELETE' = 'GET', data?: any): Promise<ApiResult<T>> => {
|
|
76
|
+
if (!(session as any)?.accessToken) {
|
|
77
|
+
console.error('[useAuth] No access token available');
|
|
78
|
+
throw new Error('Not authenticated');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
// Use standardized API which handles token refresh and validates response format
|
|
83
|
+
switch (method) {
|
|
84
|
+
case 'GET':
|
|
85
|
+
return await standardizedApi.get<T>(url, (session as any).accessToken!);
|
|
86
|
+
case 'POST':
|
|
87
|
+
return await standardizedApi.post<T>(url, data, (session as any).accessToken!);
|
|
88
|
+
case 'PUT':
|
|
89
|
+
return await standardizedApi.put<T>(url, data);
|
|
90
|
+
case 'DELETE':
|
|
91
|
+
return await standardizedApi.delete<T>(url);
|
|
92
|
+
default:
|
|
93
|
+
throw new Error(`Unsupported method: ${method}`);
|
|
94
|
+
}
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error('[useAuth] API call failed:', error);
|
|
97
|
+
|
|
98
|
+
// standardizedApi handles token refresh internally, but if we still get auth errors, sign out
|
|
99
|
+
if (error instanceof Error && error.message.includes('Authentication failed')) {
|
|
100
|
+
console.warn('[useAuth] Authentication failed, signing out...');
|
|
101
|
+
await handleSignOut();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
[(session as any)?.accessToken, handleSignOut]
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
session: session as CustomSession | null,
|
|
112
|
+
status,
|
|
113
|
+
isLoading,
|
|
114
|
+
isAuthenticated,
|
|
115
|
+
apiCall
|
|
116
|
+
};
|
|
117
|
+
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
'use client';
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { authClient } from '../client/better-auth-client';
|
|
11
11
|
import type { AuthSettings } from '../lib/idp-client-config';
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -39,7 +39,7 @@ interface SessionWithAuthSettings {
|
|
|
39
39
|
* ```
|
|
40
40
|
*/
|
|
41
41
|
export function useAuthSettings(): AuthSettings | null {
|
|
42
|
-
const { data: session } = useSession();
|
|
42
|
+
const { data: session } = authClient.useSession();
|
|
43
43
|
|
|
44
44
|
if (!session) {
|
|
45
45
|
return null;
|
|
@@ -8,8 +8,7 @@
|
|
|
8
8
|
'use client';
|
|
9
9
|
|
|
10
10
|
import { useState, useEffect } from 'react';
|
|
11
|
-
import {
|
|
12
|
-
import { BuiltInProviderType } from 'next-auth/providers/index';
|
|
11
|
+
import { authClient } from '../client/better-auth-client';
|
|
13
12
|
import type { FederatedProvider } from '../types/auth';
|
|
14
13
|
|
|
15
14
|
// Map NextAuth provider IDs to our FederatedProvider type
|
|
@@ -29,7 +28,7 @@ export interface UseAvailableProvidersResult {
|
|
|
29
28
|
providers: FederatedProvider[];
|
|
30
29
|
isLoading: boolean;
|
|
31
30
|
error: Error | null;
|
|
32
|
-
rawProviders: Record<
|
|
31
|
+
rawProviders: Record<string, any> | null;
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
/**
|
|
@@ -56,7 +55,7 @@ export interface UseAvailableProvidersResult {
|
|
|
56
55
|
*/
|
|
57
56
|
export function useAvailableProviders(): UseAvailableProvidersResult {
|
|
58
57
|
const [providers, setProviders] = useState<FederatedProvider[]>([]);
|
|
59
|
-
const [rawProviders, setRawProviders] = useState<Record<
|
|
58
|
+
const [rawProviders, setRawProviders] = useState<Record<string, any> | null>(null);
|
|
60
59
|
const [isLoading, setIsLoading] = useState(true);
|
|
61
60
|
const [error, setError] = useState<Error | null>(null);
|
|
62
61
|
|
|
@@ -65,7 +64,12 @@ export function useAvailableProviders(): UseAvailableProvidersResult {
|
|
|
65
64
|
|
|
66
65
|
async function fetchProviders() {
|
|
67
66
|
try {
|
|
68
|
-
|
|
67
|
+
// Fetch available providers from Better Auth
|
|
68
|
+
// Better Auth doesn't have a getProviders equivalent, so we use a static list
|
|
69
|
+
// based on configured social providers
|
|
70
|
+
const result: Record<string, { id: string; name: string }> = {
|
|
71
|
+
google: { id: 'google', name: 'Google' },
|
|
72
|
+
};
|
|
69
73
|
|
|
70
74
|
if (!mounted) return;
|
|
71
75
|
|
|
@@ -1,102 +1,101 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hook to detect and handle stale/expired sessions during 2FA flow
|
|
3
|
-
*
|
|
4
|
-
* Use this in verify-code pages to automatically redirect to login
|
|
5
|
-
* when the provisional bearer token has expired.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```tsx
|
|
9
|
-
* import { useSessionExpiration } from '@payez/next-mvp/hooks/useSessionExpiration';
|
|
10
|
-
*
|
|
11
|
-
* function VerifyCodePage() {
|
|
12
|
-
* const { data: session } = useSession();
|
|
13
|
-
* const router = useRouter();
|
|
14
|
-
* const searchParams = useSearchParams();
|
|
15
|
-
* const [error, setError] = useState<string | null>(null);
|
|
16
|
-
*
|
|
17
|
-
* const callbackUrl = searchParams?.get('callbackUrl') || '/dashboard';
|
|
18
|
-
*
|
|
19
|
-
* // Automatically handles session expiration
|
|
20
|
-
* const sessionValid = useSessionExpiration({
|
|
21
|
-
* session,
|
|
22
|
-
* router,
|
|
23
|
-
* callbackUrl,
|
|
24
|
-
* onExpired: (message) => setError(message)
|
|
25
|
-
* });
|
|
26
|
-
*
|
|
27
|
-
* if (!sessionValid) return null; // Will redirect
|
|
28
|
-
* // ... rest of component
|
|
29
|
-
* }
|
|
30
|
-
* ```
|
|
31
|
-
*/
|
|
32
|
-
|
|
33
|
-
import { useEffect } from 'react';
|
|
34
|
-
import {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* - `
|
|
59
|
-
* - `
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Hook to detect and handle stale/expired sessions during 2FA flow
|
|
3
|
+
*
|
|
4
|
+
* Use this in verify-code pages to automatically redirect to login
|
|
5
|
+
* when the provisional bearer token has expired.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* import { useSessionExpiration } from '@payez/next-mvp/hooks/useSessionExpiration';
|
|
10
|
+
*
|
|
11
|
+
* function VerifyCodePage() {
|
|
12
|
+
* const { data: session } = useSession();
|
|
13
|
+
* const router = useRouter();
|
|
14
|
+
* const searchParams = useSearchParams();
|
|
15
|
+
* const [error, setError] = useState<string | null>(null);
|
|
16
|
+
*
|
|
17
|
+
* const callbackUrl = searchParams?.get('callbackUrl') || '/dashboard';
|
|
18
|
+
*
|
|
19
|
+
* // Automatically handles session expiration
|
|
20
|
+
* const sessionValid = useSessionExpiration({
|
|
21
|
+
* session,
|
|
22
|
+
* router,
|
|
23
|
+
* callbackUrl,
|
|
24
|
+
* onExpired: (message) => setError(message)
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* if (!sessionValid) return null; // Will redirect
|
|
28
|
+
* // ... rest of component
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import { useEffect } from 'react';
|
|
34
|
+
import { authClient } from '../client/better-auth-client';
|
|
35
|
+
|
|
36
|
+
export interface UseSessionExpirationOptions {
|
|
37
|
+
/** Session object */
|
|
38
|
+
session: any | null | undefined;
|
|
39
|
+
/** Next.js router for navigation */
|
|
40
|
+
router: {
|
|
41
|
+
push: (url: string) => void;
|
|
42
|
+
};
|
|
43
|
+
/** URL to redirect to after login */
|
|
44
|
+
callbackUrl?: string;
|
|
45
|
+
/** Callback when session expires - use to set error state */
|
|
46
|
+
onExpired?: (message: string) => void;
|
|
47
|
+
/** Delay before redirect in milliseconds (default: 1500) */
|
|
48
|
+
redirectDelay?: number;
|
|
49
|
+
/** Custom redirect URL (default: /account-auth/login) */
|
|
50
|
+
loginUrl?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Detects stale sessions and redirects to login
|
|
55
|
+
*
|
|
56
|
+
* Returns:
|
|
57
|
+
* - `true` if session is valid (has accessToken)
|
|
58
|
+
* - `false` if session is loading (no session yet)
|
|
59
|
+
* - `null` if session is stale (will trigger redirect)
|
|
60
|
+
*/
|
|
61
|
+
export function useSessionExpiration({
|
|
62
|
+
session,
|
|
63
|
+
router,
|
|
64
|
+
callbackUrl = '/dashboard',
|
|
65
|
+
onExpired,
|
|
66
|
+
redirectDelay = 1500,
|
|
67
|
+
loginUrl = '/account-auth/login'
|
|
68
|
+
}: UseSessionExpirationOptions): boolean | null {
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
// If session exists but no accessToken, the token is stale/expired
|
|
71
|
+
if (session && !(session as any).accessToken) {
|
|
72
|
+
const message = 'Your session has expired. Redirecting to login...';
|
|
73
|
+
if (onExpired) {
|
|
74
|
+
onExpired(message);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
setTimeout(async () => {
|
|
78
|
+
// Clear the session before redirecting
|
|
79
|
+
await authClient.signOut();
|
|
80
|
+
|
|
81
|
+
const params = new URLSearchParams({
|
|
82
|
+
callbackUrl,
|
|
83
|
+
error: 'SessionExpired'
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
router.push(`${loginUrl}?${params.toString()}`);
|
|
87
|
+
}, redirectDelay);
|
|
88
|
+
}
|
|
89
|
+
}, [session, router, callbackUrl, onExpired, redirectDelay, loginUrl]);
|
|
90
|
+
|
|
91
|
+
// Return session validity state
|
|
92
|
+
if (session && !(session as any).accessToken) {
|
|
93
|
+
return null; // Stale session - will redirect
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if ((session as any)?.accessToken) {
|
|
97
|
+
return true; // Valid session
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return false; // No session yet - loading
|
|
101
|
+
}
|