@payez/next-mvp 4.1.10 → 4.1.12

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 (89) hide show
  1. package/dist/api-handlers/auth/refresh.js +15 -38
  2. package/dist/auth/better-auth.js +9 -18
  3. package/dist/client/better-auth-client.d.ts +14 -2
  4. package/dist/lib/ensure-fresh-access-token.js +7 -30
  5. package/dist/lib/session-store.d.ts +0 -1
  6. package/dist/lib/session-store.js +29 -33
  7. package/dist/lib/startup-init.js +19 -19
  8. package/package.json +4 -3
  9. package/scripts/check-internal-url-usage.sh +73 -73
  10. package/src/api/index.ts +17 -17
  11. package/src/api-handlers/account/masked-info.ts +45 -45
  12. package/src/api-handlers/account/profile.ts +80 -80
  13. package/src/api-handlers/account/recovery/initiate.ts +23 -23
  14. package/src/api-handlers/account/recovery/send-code.ts +25 -25
  15. package/src/api-handlers/account/recovery/verify-code.ts +25 -25
  16. package/src/api-handlers/account/reset-password.ts +23 -23
  17. package/src/api-handlers/account/send-code.ts +76 -76
  18. package/src/api-handlers/account/validate-password.ts +118 -118
  19. package/src/api-handlers/admin/stats.ts +249 -249
  20. package/src/api-handlers/anon/preferences.ts +123 -123
  21. package/src/api-handlers/auth/jwks.ts +20 -20
  22. package/src/api-handlers/auth/login.ts +240 -240
  23. package/src/api-handlers/auth/refresh.ts +15 -38
  24. package/src/api-handlers/auth/validate.ts +43 -43
  25. package/src/api-handlers/session/viability.ts +142 -142
  26. package/src/auth/better-auth.ts +9 -14
  27. package/src/auth/unauthenticated-routes.ts +2 -2
  28. package/src/client/better-auth-client.ts +70 -70
  29. package/src/client/fetchWithSession.ts +21 -21
  30. package/src/client/index.ts +13 -13
  31. package/src/client/useAnonSession.ts +131 -131
  32. package/src/components/admin/VibeAdminContext.tsx +87 -87
  33. package/src/config/logging-config.ts +82 -82
  34. package/src/config/unauthenticated-routes.ts +19 -19
  35. package/src/edge/internal-api-url.ts +65 -65
  36. package/src/edge/middleware.ts +42 -42
  37. package/src/hooks/useProfile.ts +75 -75
  38. package/src/lib/anon-session.ts +213 -213
  39. package/src/lib/auth-secret.ts +137 -137
  40. package/src/lib/demo-mode.ts +17 -17
  41. package/src/lib/ensure-fresh-access-token.ts +7 -30
  42. package/src/lib/idp-client-config.ts +559 -559
  43. package/src/lib/idp-fetch.ts +126 -126
  44. package/src/lib/internal-api.ts +171 -171
  45. package/src/lib/jwt-decode-client.ts +45 -45
  46. package/src/lib/rate-limit-service.ts +9 -9
  47. package/src/lib/redis.ts +26 -26
  48. package/src/lib/refresh-token-validator.ts +64 -64
  49. package/src/lib/secret-validation.ts +8 -8
  50. package/src/lib/session-store.ts +692 -695
  51. package/src/lib/session.ts +34 -34
  52. package/src/lib/startup-init.ts +251 -251
  53. package/src/lib/token-expiry.ts +40 -40
  54. package/src/lib/token-lifecycle.ts +470 -470
  55. package/src/lib/types/api-responses.ts +336 -336
  56. package/src/middleware/auth-decision.ts +43 -43
  57. package/src/models/DecodedAccessToken.ts +16 -16
  58. package/src/models/SessionModel.ts +264 -264
  59. package/src/pages/admin-roles/index.ts +9 -9
  60. package/src/pages/security/EnhancedSecurityPage.tsx +9 -9
  61. package/src/routes/account/index.ts +31 -31
  62. package/src/routes/account/masked-info.ts +36 -36
  63. package/src/routes/account/send-code.ts +39 -39
  64. package/src/routes/account/verify-email.ts +40 -40
  65. package/src/routes/account/verify-sms.ts +40 -40
  66. package/src/routes/auth/index.ts +22 -22
  67. package/src/routes/auth/refresh.ts +48 -48
  68. package/src/routes/auth/session.ts +166 -166
  69. package/src/routes/index.ts +17 -17
  70. package/src/routes/session/index.ts +7 -7
  71. package/src/routes/session/refresh-viability.ts +17 -17
  72. package/src/server/auth.ts +373 -373
  73. package/src/server/decode-session.ts +202 -202
  74. package/src/services/signalrActivityService.ts +258 -258
  75. package/src/theme/ThemeProvider.tsx +39 -39
  76. package/src/theme/default.ts +33 -33
  77. package/src/theme/index.ts +31 -31
  78. package/src/theme/types.ts +69 -69
  79. package/src/theme/useTheme.ts +57 -57
  80. package/src/theme/utils.ts +40 -40
  81. package/src/types/api.ts +12 -12
  82. package/src/types/auth.d.ts +23 -23
  83. package/src/types/auth.ts +22 -22
  84. package/src/types/logging.ts +11 -11
  85. package/src/types/recovery.ts +54 -54
  86. package/src/utils/api.ts +353 -353
  87. package/src/utils/circuitBreaker.ts +40 -40
  88. package/src/utils/error-message.ts +108 -108
  89. package/src/utils/layout/reservedSpace.ts +124 -124
@@ -1,167 +1,167 @@
1
- /**
2
- * Ready-to-Use Session Management Route
3
- *
4
- * Provides pre-configured session handlers for checking and updating session state.
5
- *
6
- * @example
7
- * ```typescript
8
- * // app/api/auth/session/route.ts
9
- * export { GET, POST } from '@payez/next-mvp/routes/auth/session';
10
- * ```
11
- *
12
- * @version 2.0.0
13
- * @since auth-ready-v2
14
- */
15
-
16
- import { NextRequest, NextResponse } from 'next/server';
17
- import { getSession as getBetterAuthSession } from '../../server/auth';
18
- import { getSession as getRedisSession, updateSession } from '../../lib/session-store';
19
-
20
- /**
21
- * GET /api/auth/session - Check current session status
22
- *
23
- * Returns the current session information including:
24
- * - User details
25
- * - Token expiry status
26
- * - Session validity
27
- */
28
- export async function GET(req: NextRequest) {
29
- try {
30
- const authSession = await getBetterAuthSession(req);
31
-
32
- if (!authSession) {
33
- console.warn('[SESSION_ROUTE] Better Auth session not found');
34
- // MUST return empty {} — useSession() treats any non-empty
35
- // response object as "authenticated", causing redirect loops on login page.
36
- return NextResponse.json({});
37
- }
38
-
39
- const redisSessionId = authSession.session?.token;
40
-
41
- console.log('[SESSION_ROUTE] Session found:', {
42
- userId: authSession.user?.id,
43
- email: authSession.user?.email,
44
- name: authSession.user?.name,
45
- redisSessionId: redisSessionId ? redisSessionId.substring(0, 8) + '...' : 'MISSING',
46
- });
47
-
48
- // Fetch full session data from Redis
49
- const session = redisSessionId ? await getRedisSession(redisSessionId) : null;
50
-
51
- console.log('[SESSION_ROUTE] Redis session:', {
52
- found: !!session,
53
- userId: session?.userId,
54
- roles: session?.roles,
55
- hasAccessToken: !!session?.idpAccessToken,
56
- });
57
-
58
- // Return session format with Redis data
59
- // useSession() expects: { user: {...}, expires: "..." }
60
- // We enrich with all session data from Redis
61
- return NextResponse.json({
62
- user: {
63
- id: session?.userId || authSession.user?.id,
64
- email: session?.email || authSession.user?.email,
65
- name: session?.name || authSession.user?.name,
66
- image: authSession.user?.image || session?.image || null,
67
- // Redis session data
68
- roles: session?.roles || [],
69
- twoFactorSessionVerified: session?.mfaVerified || false,
70
- requiresTwoFactor: !session?.mfaVerified,
71
- authenticationMethods: session?.authenticationMethods,
72
- authenticationLevel: session?.authenticationLevel,
73
- mfaCompletedAt: session?.mfaCompletedAt,
74
- mfaExpiresAt: session?.mfaExpiresAt,
75
- mfaValidityHours: session?.mfaValidityHours,
76
- oauthProvider: session?.oauthProvider,
77
- idpClientId: session?.idpClientId,
78
- merchantId: session?.merchantId,
79
- },
80
- // Session tokens
81
- sessionToken: redisSessionId,
82
- accessToken: session?.idpAccessToken,
83
- refreshToken: session?.idpRefreshToken,
84
- accessTokenExpires: session?.idpAccessTokenExpires,
85
- expires: authSession.session?.expiresAt
86
- ? new Date(authSession.session.expiresAt).toISOString()
87
- : new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(),
88
- });
89
- } catch (error) {
90
- console.error('[SESSION_ROUTE] Error checking session:', error);
91
- return NextResponse.json({
92
- error: 'Failed to check session',
93
- details: error instanceof Error ? error.message : 'Unknown error'
94
- }, { status: 500 });
95
- }
96
- }
97
-
98
- /**
99
- * POST /api/auth/session - Update session data
100
- *
101
- * Allows updating session metadata (not tokens).
102
- * Token refresh should use the /api/auth/refresh endpoint.
103
- *
104
- * Body:
105
- * - metadata: object - Custom metadata to store in session
106
- */
107
- export async function POST(req: NextRequest) {
108
- try {
109
- const authSession = await getBetterAuthSession(req);
110
-
111
- if (!authSession) {
112
- return NextResponse.json({
113
- error: 'No session found',
114
- code: 'UNAUTHORIZED'
115
- }, { status: 401 });
116
- }
117
-
118
- const sessionToken = authSession.session?.token;
119
- if (!sessionToken) {
120
- return NextResponse.json({
121
- error: 'Invalid session',
122
- code: 'INVALID_SESSION'
123
- }, { status: 400 });
124
- }
125
-
126
- const body = await req.json();
127
- const { metadata, access_token, refresh_token, twoFactorComplete, twoFactorMethod } = body;
128
-
129
- // Get current session from Redis
130
- const session = await getRedisSession(sessionToken);
131
- if (!session) {
132
- return NextResponse.json({
133
- error: 'Session not found',
134
- code: 'SESSION_NOT_FOUND'
135
- }, { status: 404 });
136
- }
137
-
138
- // Update session with new data
139
- const updatedSession = {
140
- ...session,
141
- ...(access_token ? { accessToken: access_token } : {}),
142
- ...(refresh_token ? { refreshToken: refresh_token } : {}),
143
- ...(typeof twoFactorComplete === 'boolean' ? { twoFactorComplete } : {}),
144
- ...(twoFactorMethod ? { twoFactorMethod } : {}),
145
- ...(metadata ? {
146
- metadata: {
147
- ...(session.metadata || {}),
148
- ...metadata,
149
- updatedAt: new Date().toISOString()
150
- }
151
- } : {})
152
- };
153
-
154
- await updateSession(sessionToken, updatedSession);
155
-
156
- return NextResponse.json({
157
- success: true,
158
- message: 'Session updated successfully'
159
- });
160
- } catch (error) {
161
- console.error('[SESSION_ROUTE] Error updating session:', error);
162
- return NextResponse.json({
163
- error: 'Failed to update session',
164
- details: error instanceof Error ? error.message : 'Unknown error'
165
- }, { status: 500 });
166
- }
1
+ /**
2
+ * Ready-to-Use Session Management Route
3
+ *
4
+ * Provides pre-configured session handlers for checking and updating session state.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * // app/api/auth/session/route.ts
9
+ * export { GET, POST } from '@payez/next-mvp/routes/auth/session';
10
+ * ```
11
+ *
12
+ * @version 2.0.0
13
+ * @since auth-ready-v2
14
+ */
15
+
16
+ import { NextRequest, NextResponse } from 'next/server';
17
+ import { getSession as getBetterAuthSession } from '../../server/auth';
18
+ import { getSession as getRedisSession, updateSession } from '../../lib/session-store';
19
+
20
+ /**
21
+ * GET /api/auth/session - Check current session status
22
+ *
23
+ * Returns the current session information including:
24
+ * - User details
25
+ * - Token expiry status
26
+ * - Session validity
27
+ */
28
+ export async function GET(req: NextRequest) {
29
+ try {
30
+ const authSession = await getBetterAuthSession(req);
31
+
32
+ if (!authSession) {
33
+ console.warn('[SESSION_ROUTE] Better Auth session not found');
34
+ // MUST return empty {} — useSession() treats any non-empty
35
+ // response object as "authenticated", causing redirect loops on login page.
36
+ return NextResponse.json({});
37
+ }
38
+
39
+ const redisSessionId = authSession.session?.token;
40
+
41
+ console.log('[SESSION_ROUTE] Session found:', {
42
+ userId: authSession.user?.id,
43
+ email: authSession.user?.email,
44
+ name: authSession.user?.name,
45
+ redisSessionId: redisSessionId ? redisSessionId.substring(0, 8) + '...' : 'MISSING',
46
+ });
47
+
48
+ // Fetch full session data from Redis
49
+ const session = redisSessionId ? await getRedisSession(redisSessionId) : null;
50
+
51
+ console.log('[SESSION_ROUTE] Redis session:', {
52
+ found: !!session,
53
+ userId: session?.userId,
54
+ roles: session?.roles,
55
+ hasAccessToken: !!session?.idpAccessToken,
56
+ });
57
+
58
+ // Return session format with Redis data
59
+ // useSession() expects: { user: {...}, expires: "..." }
60
+ // We enrich with all session data from Redis
61
+ return NextResponse.json({
62
+ user: {
63
+ id: session?.userId || authSession.user?.id,
64
+ email: session?.email || authSession.user?.email,
65
+ name: session?.name || authSession.user?.name,
66
+ image: authSession.user?.image || session?.image || null,
67
+ // Redis session data
68
+ roles: session?.roles || [],
69
+ twoFactorSessionVerified: session?.mfaVerified || false,
70
+ requiresTwoFactor: !session?.mfaVerified,
71
+ authenticationMethods: session?.authenticationMethods,
72
+ authenticationLevel: session?.authenticationLevel,
73
+ mfaCompletedAt: session?.mfaCompletedAt,
74
+ mfaExpiresAt: session?.mfaExpiresAt,
75
+ mfaValidityHours: session?.mfaValidityHours,
76
+ oauthProvider: session?.oauthProvider,
77
+ idpClientId: session?.idpClientId,
78
+ merchantId: session?.merchantId,
79
+ },
80
+ // Session tokens
81
+ sessionToken: redisSessionId,
82
+ accessToken: session?.idpAccessToken,
83
+ refreshToken: session?.idpRefreshToken,
84
+ accessTokenExpires: session?.idpAccessTokenExpires,
85
+ expires: authSession.session?.expiresAt
86
+ ? new Date(authSession.session.expiresAt).toISOString()
87
+ : new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(),
88
+ });
89
+ } catch (error) {
90
+ console.error('[SESSION_ROUTE] Error checking session:', error);
91
+ return NextResponse.json({
92
+ error: 'Failed to check session',
93
+ details: error instanceof Error ? error.message : 'Unknown error'
94
+ }, { status: 500 });
95
+ }
96
+ }
97
+
98
+ /**
99
+ * POST /api/auth/session - Update session data
100
+ *
101
+ * Allows updating session metadata (not tokens).
102
+ * Token refresh should use the /api/auth/refresh endpoint.
103
+ *
104
+ * Body:
105
+ * - metadata: object - Custom metadata to store in session
106
+ */
107
+ export async function POST(req: NextRequest) {
108
+ try {
109
+ const authSession = await getBetterAuthSession(req);
110
+
111
+ if (!authSession) {
112
+ return NextResponse.json({
113
+ error: 'No session found',
114
+ code: 'UNAUTHORIZED'
115
+ }, { status: 401 });
116
+ }
117
+
118
+ const sessionToken = authSession.session?.token;
119
+ if (!sessionToken) {
120
+ return NextResponse.json({
121
+ error: 'Invalid session',
122
+ code: 'INVALID_SESSION'
123
+ }, { status: 400 });
124
+ }
125
+
126
+ const body = await req.json();
127
+ const { metadata, access_token, refresh_token, twoFactorComplete, twoFactorMethod } = body;
128
+
129
+ // Get current session from Redis
130
+ const session = await getRedisSession(sessionToken);
131
+ if (!session) {
132
+ return NextResponse.json({
133
+ error: 'Session not found',
134
+ code: 'SESSION_NOT_FOUND'
135
+ }, { status: 404 });
136
+ }
137
+
138
+ // Update session with new data
139
+ const updatedSession = {
140
+ ...session,
141
+ ...(access_token ? { accessToken: access_token } : {}),
142
+ ...(refresh_token ? { refreshToken: refresh_token } : {}),
143
+ ...(typeof twoFactorComplete === 'boolean' ? { twoFactorComplete } : {}),
144
+ ...(twoFactorMethod ? { twoFactorMethod } : {}),
145
+ ...(metadata ? {
146
+ metadata: {
147
+ ...(session.metadata || {}),
148
+ ...metadata,
149
+ updatedAt: new Date().toISOString()
150
+ }
151
+ } : {})
152
+ };
153
+
154
+ await updateSession(sessionToken, updatedSession);
155
+
156
+ return NextResponse.json({
157
+ success: true,
158
+ message: 'Session updated successfully'
159
+ });
160
+ } catch (error) {
161
+ console.error('[SESSION_ROUTE] Error updating session:', error);
162
+ return NextResponse.json({
163
+ error: 'Failed to update session',
164
+ details: error instanceof Error ? error.message : 'Unknown error'
165
+ }, { status: 500 });
166
+ }
167
167
  }
@@ -1,18 +1,18 @@
1
- /**
2
- * @payez/next-mvp Route Module Exports
3
- *
4
- * Ready-to-use route handlers for quick integration
5
- *
6
- * @version 2.3.0
7
- * @since auth-ready-v2
8
- */
9
-
10
- // Export auth routes
11
- export * from './auth';
12
-
13
- // Export account/2FA routes
14
- export * from './account';
15
-
16
- // Namespace exports for cleaner imports
17
- export * as auth from './auth';
1
+ /**
2
+ * @payez/next-mvp Route Module Exports
3
+ *
4
+ * Ready-to-use route handlers for quick integration
5
+ *
6
+ * @version 2.3.0
7
+ * @since auth-ready-v2
8
+ */
9
+
10
+ // Export auth routes
11
+ export * from './auth';
12
+
13
+ // Export account/2FA routes
14
+ export * from './account';
15
+
16
+ // Namespace exports for cleaner imports
17
+ export * as auth from './auth';
18
18
  export * as account from './account';
@@ -1,7 +1,7 @@
1
- /**
2
- * Session Routes Index
3
- *
4
- * Re-exports all session-related route handlers for easy importing.
5
- */
6
-
7
- export { GET as refreshViabilityGET } from './refresh-viability';
1
+ /**
2
+ * Session Routes Index
3
+ *
4
+ * Re-exports all session-related route handlers for easy importing.
5
+ */
6
+
7
+ export { GET as refreshViabilityGET } from './refresh-viability';
@@ -1,17 +1,17 @@
1
- /**
2
- * Ready-to-Use Refresh Viability Route
3
- *
4
- * Checks if a session has a valid refresh token for automatic refresh.
5
- * Used by middleware to decide whether to attempt refresh or redirect to login.
6
- *
7
- * @example
8
- * ```typescript
9
- * // app/api/session/refresh-viability/route.ts
10
- * export { GET } from '@payez/next-mvp/routes/session/refresh-viability';
11
- * ```
12
- *
13
- * @version 2.0.0
14
- * @since auth-ready-v2
15
- */
16
-
17
- export { GET } from '../../api-handlers/session/refresh-viability';
1
+ /**
2
+ * Ready-to-Use Refresh Viability Route
3
+ *
4
+ * Checks if a session has a valid refresh token for automatic refresh.
5
+ * Used by middleware to decide whether to attempt refresh or redirect to login.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * // app/api/session/refresh-viability/route.ts
10
+ * export { GET } from '@payez/next-mvp/routes/session/refresh-viability';
11
+ * ```
12
+ *
13
+ * @version 2.0.0
14
+ * @since auth-ready-v2
15
+ */
16
+
17
+ export { GET } from '../../api-handlers/session/refresh-viability';