@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,65 +1,65 @@
1
- /**
2
- * Internal API URL Utility for Edge Runtime
3
- *
4
- * INTERNAL_API_URL is REQUIRED. This is the URL for THIS application calling ITSELF.
5
- * Used for middleware to call its own API routes (e.g., /api/session/viability).
6
- *
7
- * WHY HTTP IS REQUIRED (not optional):
8
- * - This is the app calling its OWN backend within the same pod/container
9
- * - NextAuth cookies are encrypted based on request protocol
10
- * - TLS is terminated at ingress, so the pod receives HTTP internally
11
- * - Using HTTPS here causes cookie decryption failures
12
- * - This is NOT about "K8s internal traffic doesn't need TLS" - it's about
13
- * protocol consistency for cookie encryption
14
- *
15
- * This is NOT for calling the IDP - use IDP_URL for that.
16
- *
17
- * For local dev, set INTERNAL_API_URL=http://localhost:3000 (or your dev port).
18
- *
19
- * @module edge/internal-api-url
20
- * @version 3.0.0
21
- */
22
-
23
- import { NextRequest } from 'next/server';
24
-
25
- /**
26
- * Get the internal API base URL for middleware to call its own API routes.
27
- *
28
- * THROWS if INTERNAL_API_URL is not set. No fallbacks.
29
- *
30
- * @param request - The Next.js request object (unused, kept for API compatibility)
31
- * @returns Base URL string for constructing internal API calls
32
- * @throws Error if INTERNAL_API_URL environment variable is not set
33
- *
34
- * @example
35
- * ```typescript
36
- * import { getInternalApiUrl } from '@payez/next-mvp/edge';
37
- *
38
- * export async function middleware(request: NextRequest) {
39
- * const baseUrl = getInternalApiUrl(request);
40
- * const apiUrl = new URL('/api/session/check', baseUrl);
41
- *
42
- * const response = await fetch(apiUrl, {
43
- * headers: {
44
- * 'Cookie': request.headers.get('cookie') || ''
45
- * }
46
- * });
47
- * }
48
- * ```
49
- *
50
- * @environment INTERNAL_API_URL - REQUIRED. URL for this app to call ITSELF.
51
- * MUST be HTTP (not HTTPS) - see module docs for why.
52
- * K8s: http://myapp.namespace.svc.cluster.local:80
53
- * Local: http://localhost:3000
54
- */
55
- export function getInternalApiUrl(request: NextRequest): string {
56
- const internalUrl = process.env.INTERNAL_API_URL;
57
- if (!internalUrl) {
58
- throw new Error(
59
- '[INTERNAL_API_URL] FATAL: INTERNAL_API_URL environment variable is REQUIRED. ' +
60
- 'This is for the app to call ITSELF. MUST be HTTP (not HTTPS). ' +
61
- 'Set to http://myapp.namespace.svc.cluster.local:80 (K8s) or http://localhost:3000 (local).'
62
- );
63
- }
64
- return internalUrl;
65
- }
1
+ /**
2
+ * Internal API URL Utility for Edge Runtime
3
+ *
4
+ * INTERNAL_API_URL is REQUIRED. This is the URL for THIS application calling ITSELF.
5
+ * Used for middleware to call its own API routes (e.g., /api/session/viability).
6
+ *
7
+ * WHY HTTP IS REQUIRED (not optional):
8
+ * - This is the app calling its OWN backend within the same pod/container
9
+ * - NextAuth cookies are encrypted based on request protocol
10
+ * - TLS is terminated at ingress, so the pod receives HTTP internally
11
+ * - Using HTTPS here causes cookie decryption failures
12
+ * - This is NOT about "K8s internal traffic doesn't need TLS" - it's about
13
+ * protocol consistency for cookie encryption
14
+ *
15
+ * This is NOT for calling the IDP - use IDP_URL for that.
16
+ *
17
+ * For local dev, set INTERNAL_API_URL=http://localhost:3000 (or your dev port).
18
+ *
19
+ * @module edge/internal-api-url
20
+ * @version 3.0.0
21
+ */
22
+
23
+ import { NextRequest } from 'next/server';
24
+
25
+ /**
26
+ * Get the internal API base URL for middleware to call its own API routes.
27
+ *
28
+ * THROWS if INTERNAL_API_URL is not set. No fallbacks.
29
+ *
30
+ * @param request - The Next.js request object (unused, kept for API compatibility)
31
+ * @returns Base URL string for constructing internal API calls
32
+ * @throws Error if INTERNAL_API_URL environment variable is not set
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * import { getInternalApiUrl } from '@payez/next-mvp/edge';
37
+ *
38
+ * export async function middleware(request: NextRequest) {
39
+ * const baseUrl = getInternalApiUrl(request);
40
+ * const apiUrl = new URL('/api/session/check', baseUrl);
41
+ *
42
+ * const response = await fetch(apiUrl, {
43
+ * headers: {
44
+ * 'Cookie': request.headers.get('cookie') || ''
45
+ * }
46
+ * });
47
+ * }
48
+ * ```
49
+ *
50
+ * @environment INTERNAL_API_URL - REQUIRED. URL for this app to call ITSELF.
51
+ * MUST be HTTP (not HTTPS) - see module docs for why.
52
+ * K8s: http://myapp.namespace.svc.cluster.local:80
53
+ * Local: http://localhost:3000
54
+ */
55
+ export function getInternalApiUrl(request: NextRequest): string {
56
+ const internalUrl = process.env.INTERNAL_API_URL;
57
+ if (!internalUrl) {
58
+ throw new Error(
59
+ '[INTERNAL_API_URL] FATAL: INTERNAL_API_URL environment variable is REQUIRED. ' +
60
+ 'This is for the app to call ITSELF. MUST be HTTP (not HTTPS). ' +
61
+ 'Set to http://myapp.namespace.svc.cluster.local:80 (K8s) or http://localhost:3000 (local).'
62
+ );
63
+ }
64
+ return internalUrl;
65
+ }
@@ -1,42 +1,42 @@
1
- /**
2
- * Edge Runtime Compatible Exports
3
- *
4
- * This module exports only Edge Runtime compatible code for use in Next.js middleware.
5
- * Client-side utilities that depend on browser APIs or server-only code are excluded.
6
- */
7
-
8
- // Authentication middleware and configuration (Edge Runtime compatible)
9
- export { makeAuthDecision } from '../auth/auth-decision';
10
- export {
11
- isUnauthenticatedRoute,
12
- configurePublicRoutes,
13
- getRouteConfig,
14
- configure2FABypassRoutes,
15
- should2FABypass,
16
- get2FABypassConfig
17
- } from '../auth/route-config';
18
- export type { UnauthenticatedRouteConfig, ProtectedRouteConfig } from '../auth/route-config';
19
- export { createMvpMiddleware } from '../middleware/create-middleware';
20
- export type {
21
- MvpMiddlewareOptions,
22
- CircuitBreakerProvider,
23
- MiddlewareLogger,
24
- AuthContext,
25
- AuthAction,
26
- SessionPointer,
27
- SessionStatus
28
- } from '../middleware/create-middleware';
29
-
30
- // Two-Factor Authentication Presets (Edge Runtime compatible)
31
- export {
32
- TwoFactorPresets,
33
- AMRValues,
34
- ACRLevels,
35
- validateAMR,
36
- validateACR,
37
- checkTwoFactorRequirements
38
- } from '../middleware/twofa-presets';
39
- export type { TwoFactorRequirements, RouteConfig } from '../middleware/twofa-presets';
40
-
41
- // Internal API URL utilities for Edge Runtime
42
- export { getInternalApiUrl } from './internal-api-url';
1
+ /**
2
+ * Edge Runtime Compatible Exports
3
+ *
4
+ * This module exports only Edge Runtime compatible code for use in Next.js middleware.
5
+ * Client-side utilities that depend on browser APIs or server-only code are excluded.
6
+ */
7
+
8
+ // Authentication middleware and configuration (Edge Runtime compatible)
9
+ export { makeAuthDecision } from '../auth/auth-decision';
10
+ export {
11
+ isUnauthenticatedRoute,
12
+ configurePublicRoutes,
13
+ getRouteConfig,
14
+ configure2FABypassRoutes,
15
+ should2FABypass,
16
+ get2FABypassConfig
17
+ } from '../auth/route-config';
18
+ export type { UnauthenticatedRouteConfig, ProtectedRouteConfig } from '../auth/route-config';
19
+ export { createMvpMiddleware } from '../middleware/create-middleware';
20
+ export type {
21
+ MvpMiddlewareOptions,
22
+ CircuitBreakerProvider,
23
+ MiddlewareLogger,
24
+ AuthContext,
25
+ AuthAction,
26
+ SessionPointer,
27
+ SessionStatus
28
+ } from '../middleware/create-middleware';
29
+
30
+ // Two-Factor Authentication Presets (Edge Runtime compatible)
31
+ export {
32
+ TwoFactorPresets,
33
+ AMRValues,
34
+ ACRLevels,
35
+ validateAMR,
36
+ validateACR,
37
+ checkTwoFactorRequirements
38
+ } from '../middleware/twofa-presets';
39
+ export type { TwoFactorRequirements, RouteConfig } from '../middleware/twofa-presets';
40
+
41
+ // Internal API URL utilities for Edge Runtime
42
+ export { getInternalApiUrl } from './internal-api-url';
@@ -1,75 +1,75 @@
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?** This hook depends on useAuth, which requires SessionProvider context that cannot cross package boundaries.
9
- *
10
- * **Solution:** Create a local version in your app (e.g., src/hooks/useProfile.ts):
11
- *
12
- * @example
13
- * ```typescript
14
- * // src/hooks/useProfile.ts (YOUR APP)
15
- * 'use client';
16
- * import { useQuery } from '@tanstack/react-query';
17
- * import { useAuth } from './useAuth'; // Your local useAuth
18
- * import { isApiSuccess } from '@payez/next-mvp/lib/standardized-client-api';
19
- *
20
- * export function useProfile() {
21
- * const { isAuthenticated, apiCall } = useAuth();
22
- * return useQuery({
23
- * queryKey: ['account', 'profile'],
24
- * enabled: isAuthenticated,
25
- * queryFn: async () => {
26
- * const result = await apiCall('/api/account/profile', 'GET');
27
- * if (isApiSuccess(result)) return result.data;
28
- * throw new Error(result.message);
29
- * }
30
- * });
31
- * }
32
- * ```
33
- *
34
- * @see {@link https://github.com/payez/next-mvp/blob/main/docs/centralized-auth-api-pattern.md#usage-patterns Complete documentation}
35
- */
36
-
37
- import { useQuery } from '@tanstack/react-query';
38
- import { useAuth } from './useAuth';
39
- import { isApiSuccess, isApiError } from '../lib/standardized-client-api';
40
-
41
- export type ProfileResponse = {
42
- email: string;
43
- user_id?: string;
44
- first_name?: string;
45
- last_name?: string;
46
- full_name?: string;
47
- phone_number?: string;
48
- email_confirmed?: boolean;
49
- phone_confirmed?: boolean;
50
- two_factor_enabled?: boolean;
51
- roles?: string[];
52
- contact_information?: Record<string, any>;
53
- [key: string]: any;
54
- };
55
-
56
- export function useProfile() {
57
- const { isAuthenticated, apiCall } = useAuth();
58
-
59
- return useQuery<ProfileResponse, Error>({
60
- queryKey: ['account', 'profile'],
61
- enabled: isAuthenticated,
62
- queryFn: async () => {
63
- const result = await apiCall<ProfileResponse>('/api/account/profile', 'GET');
64
- if (isApiSuccess(result)) {
65
- return result.data;
66
- }
67
- // If API returned standardized error
68
- if (isApiError(result)) {
69
- throw new Error(result.message || 'Failed to load profile');
70
- }
71
- throw new Error('Failed to load profile');
72
- },
73
- staleTime: 5 * 60 * 1000,
74
- });
75
- }
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?** This hook depends on useAuth, which requires SessionProvider context that cannot cross package boundaries.
9
+ *
10
+ * **Solution:** Create a local version in your app (e.g., src/hooks/useProfile.ts):
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * // src/hooks/useProfile.ts (YOUR APP)
15
+ * 'use client';
16
+ * import { useQuery } from '@tanstack/react-query';
17
+ * import { useAuth } from './useAuth'; // Your local useAuth
18
+ * import { isApiSuccess } from '@payez/next-mvp/lib/standardized-client-api';
19
+ *
20
+ * export function useProfile() {
21
+ * const { isAuthenticated, apiCall } = useAuth();
22
+ * return useQuery({
23
+ * queryKey: ['account', 'profile'],
24
+ * enabled: isAuthenticated,
25
+ * queryFn: async () => {
26
+ * const result = await apiCall('/api/account/profile', 'GET');
27
+ * if (isApiSuccess(result)) return result.data;
28
+ * throw new Error(result.message);
29
+ * }
30
+ * });
31
+ * }
32
+ * ```
33
+ *
34
+ * @see {@link https://github.com/payez/next-mvp/blob/main/docs/centralized-auth-api-pattern.md#usage-patterns Complete documentation}
35
+ */
36
+
37
+ import { useQuery } from '@tanstack/react-query';
38
+ import { useAuth } from './useAuth';
39
+ import { isApiSuccess, isApiError } from '../lib/standardized-client-api';
40
+
41
+ export type ProfileResponse = {
42
+ email: string;
43
+ user_id?: string;
44
+ first_name?: string;
45
+ last_name?: string;
46
+ full_name?: string;
47
+ phone_number?: string;
48
+ email_confirmed?: boolean;
49
+ phone_confirmed?: boolean;
50
+ two_factor_enabled?: boolean;
51
+ roles?: string[];
52
+ contact_information?: Record<string, any>;
53
+ [key: string]: any;
54
+ };
55
+
56
+ export function useProfile() {
57
+ const { isAuthenticated, apiCall } = useAuth();
58
+
59
+ return useQuery<ProfileResponse, Error>({
60
+ queryKey: ['account', 'profile'],
61
+ enabled: isAuthenticated,
62
+ queryFn: async () => {
63
+ const result = await apiCall<ProfileResponse>('/api/account/profile', 'GET');
64
+ if (isApiSuccess(result)) {
65
+ return result.data;
66
+ }
67
+ // If API returned standardized error
68
+ if (isApiError(result)) {
69
+ throw new Error(result.message || 'Failed to load profile');
70
+ }
71
+ throw new Error('Failed to load profile');
72
+ },
73
+ staleTime: 5 * 60 * 1000,
74
+ });
75
+ }