@payez/next-mvp 4.1.11 → 4.1.13

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 (92) hide show
  1. package/dist/api-handlers/auth/refresh.js +15 -38
  2. package/dist/auth/better-auth.d.ts +0 -3
  3. package/dist/auth/better-auth.js +164 -69
  4. package/dist/client/better-auth-client.d.ts +14 -2
  5. package/dist/lib/ensure-fresh-access-token.js +8 -42
  6. package/dist/lib/session-store.d.ts +0 -1
  7. package/dist/lib/session-store.js +29 -33
  8. package/dist/lib/startup-init.js +19 -19
  9. package/dist/lib/token-lifecycle.d.ts +0 -2
  10. package/dist/lib/token-lifecycle.js +3 -21
  11. package/package.json +5 -4
  12. package/scripts/check-internal-url-usage.sh +73 -73
  13. package/src/api/index.ts +17 -17
  14. package/src/api-handlers/account/masked-info.ts +45 -45
  15. package/src/api-handlers/account/profile.ts +80 -80
  16. package/src/api-handlers/account/recovery/initiate.ts +23 -23
  17. package/src/api-handlers/account/recovery/send-code.ts +25 -25
  18. package/src/api-handlers/account/recovery/verify-code.ts +25 -25
  19. package/src/api-handlers/account/reset-password.ts +23 -23
  20. package/src/api-handlers/account/send-code.ts +76 -76
  21. package/src/api-handlers/account/validate-password.ts +118 -118
  22. package/src/api-handlers/admin/stats.ts +249 -249
  23. package/src/api-handlers/anon/preferences.ts +123 -123
  24. package/src/api-handlers/auth/jwks.ts +20 -20
  25. package/src/api-handlers/auth/login.ts +240 -240
  26. package/src/api-handlers/auth/refresh.ts +15 -38
  27. package/src/api-handlers/auth/validate.ts +43 -43
  28. package/src/api-handlers/session/viability.ts +142 -142
  29. package/src/auth/better-auth.ts +130 -29
  30. package/src/auth/unauthenticated-routes.ts +2 -2
  31. package/src/client/better-auth-client.ts +70 -70
  32. package/src/client/fetchWithSession.ts +21 -21
  33. package/src/client/index.ts +13 -13
  34. package/src/client/useAnonSession.ts +131 -131
  35. package/src/components/admin/VibeAdminContext.tsx +87 -87
  36. package/src/config/logging-config.ts +82 -82
  37. package/src/config/unauthenticated-routes.ts +19 -19
  38. package/src/edge/internal-api-url.ts +65 -65
  39. package/src/edge/middleware.ts +42 -42
  40. package/src/hooks/useProfile.ts +75 -75
  41. package/src/lib/anon-session.ts +213 -213
  42. package/src/lib/auth-secret.ts +137 -137
  43. package/src/lib/demo-mode.ts +17 -17
  44. package/src/lib/ensure-fresh-access-token.ts +8 -42
  45. package/src/lib/idp-client-config.ts +559 -559
  46. package/src/lib/idp-fetch.ts +126 -126
  47. package/src/lib/internal-api.ts +171 -171
  48. package/src/lib/jwt-decode-client.ts +45 -45
  49. package/src/lib/rate-limit-service.ts +9 -9
  50. package/src/lib/redis.ts +26 -26
  51. package/src/lib/refresh-token-validator.ts +64 -64
  52. package/src/lib/secret-validation.ts +8 -8
  53. package/src/lib/session-store.ts +692 -695
  54. package/src/lib/session.ts +34 -34
  55. package/src/lib/startup-init.ts +251 -251
  56. package/src/lib/token-expiry.ts +40 -40
  57. package/src/lib/token-lifecycle.ts +470 -497
  58. package/src/lib/types/api-responses.ts +336 -336
  59. package/src/middleware/auth-decision.ts +43 -43
  60. package/src/models/DecodedAccessToken.ts +16 -16
  61. package/src/models/SessionModel.ts +264 -264
  62. package/src/pages/admin-roles/index.ts +9 -9
  63. package/src/pages/security/EnhancedSecurityPage.tsx +9 -9
  64. package/src/routes/account/index.ts +31 -31
  65. package/src/routes/account/masked-info.ts +36 -36
  66. package/src/routes/account/send-code.ts +39 -39
  67. package/src/routes/account/verify-email.ts +40 -40
  68. package/src/routes/account/verify-sms.ts +40 -40
  69. package/src/routes/auth/index.ts +22 -22
  70. package/src/routes/auth/refresh.ts +48 -48
  71. package/src/routes/auth/session.ts +166 -166
  72. package/src/routes/index.ts +17 -17
  73. package/src/routes/session/index.ts +7 -7
  74. package/src/routes/session/refresh-viability.ts +17 -17
  75. package/src/server/auth.ts +373 -373
  76. package/src/server/decode-session.ts +202 -202
  77. package/src/services/signalrActivityService.ts +258 -258
  78. package/src/theme/ThemeProvider.tsx +39 -39
  79. package/src/theme/default.ts +33 -33
  80. package/src/theme/index.ts +31 -31
  81. package/src/theme/types.ts +69 -69
  82. package/src/theme/useTheme.ts +57 -57
  83. package/src/theme/utils.ts +40 -40
  84. package/src/types/api.ts +12 -12
  85. package/src/types/auth.d.ts +23 -23
  86. package/src/types/auth.ts +22 -22
  87. package/src/types/logging.ts +11 -11
  88. package/src/types/recovery.ts +54 -54
  89. package/src/utils/api.ts +353 -353
  90. package/src/utils/circuitBreaker.ts +40 -40
  91. package/src/utils/error-message.ts +108 -108
  92. 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';