@djangocfg/api 2.1.580 → 2.1.582

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.
@@ -15,7 +15,7 @@ export type { WebmailLink };
15
15
  // Step Types
16
16
  // ─────────────────────────────────────────────────────────────────────────────
17
17
 
18
- export type AuthStep = 'identifier' | 'otp' | '2fa' | '2fa-setup' | 'success';
18
+ export type AuthStep = 'identifier' | 'otp' | 'success';
19
19
 
20
20
  // ─────────────────────────────────────────────────────────────────────────────
21
21
  // OTP Result Types
@@ -28,6 +28,8 @@ export interface OTPRequestResult {
28
28
  retryAfter?: number;
29
29
  /** Webmail deep-link for the recipient's provider, or null if unknown. */
30
30
  webmail?: WebmailLink | null;
31
+ /** Seconds until a new code may be requested. */
32
+ resendIn?: number;
31
33
  }
32
34
 
33
35
  /**
@@ -103,20 +105,16 @@ export interface AuthFormState {
103
105
  step: AuthStep;
104
106
  /** Error message */
105
107
  error: string;
106
- /** 2FA session ID from OTP/OAuth verification */
107
- twoFactorSessionId: string | null;
108
- /** Whether user should be prompted to enable 2FA */
109
- shouldPrompt2FA: boolean;
110
- /** 2FA code input */
111
- twoFactorCode: string;
112
- /** Using backup code instead of TOTP */
113
- useBackupCode: boolean;
114
108
  /** Seconds remaining until rate limit lifts (0 = not rate limited) */
115
109
  rateLimitSeconds: number;
116
110
  /** True when rateLimitSeconds > 0 — submit should be disabled */
117
111
  isRateLimited: boolean;
118
112
  /** Formatted countdown label, e.g. "19:00" or "42s" */
119
113
  rateLimitLabel: string;
114
+ /** Seconds until another code may be requested (0 = may resend now) */
115
+ resendSeconds: number;
116
+ /** Formatted resend countdown, e.g. "28s" */
117
+ resendLabel: string;
120
118
  /** Webmail deep-link for the current identifier's provider (null = no button). */
121
119
  webmail: WebmailLink | null;
122
120
  }
@@ -136,12 +134,10 @@ export interface AuthFormStateHandlers {
136
134
  clearError: () => void;
137
135
  setStep: (step: AuthStep) => void;
138
136
  setIsLoading: (loading: boolean) => void;
139
- setTwoFactorSessionId: (sessionId: string | null) => void;
140
- setShouldPrompt2FA: (prompt: boolean) => void;
141
- setTwoFactorCode: (code: string) => void;
142
- setUseBackupCode: (useBackup: boolean) => void;
143
137
  /** Start a countdown timer that disables submit for `seconds` seconds */
144
138
  startRateLimitCountdown: (seconds: number) => void;
139
+ /** Start the countdown before another code may be requested */
140
+ startResendCountdown: (seconds: number) => void;
145
141
  /** Set (or clear) the webmail deep-link for the current identifier */
146
142
  setWebmail: (webmail: WebmailLink | null) => void;
147
143
  }
@@ -154,12 +150,6 @@ export interface AuthFormSubmitHandlers {
154
150
  handleResendOTP: () => Promise<void>;
155
151
  handleBackToIdentifier: () => void;
156
152
  forceOTPStep: () => void;
157
- /** Handle 2FA TOTP/backup code verification */
158
- handle2FASubmit: (e: React.FormEvent) => Promise<void>;
159
- /** Switch to backup code input */
160
- handleUseBackupCode: () => void;
161
- /** Switch back to TOTP input */
162
- handleUseTOTP: () => void;
163
153
  }
164
154
 
165
155
  // ─────────────────────────────────────────────────────────────────────────────
@@ -180,19 +170,6 @@ export interface AuthFormAutoSubmit {
180
170
  isAutoSubmittingFromUrl: MutableRefObject<boolean>;
181
171
  }
182
172
 
183
- // ─────────────────────────────────────────────────────────────────────────────
184
- // 2FA State (from useTwoFactor hook)
185
- // ─────────────────────────────────────────────────────────────────────────────
186
-
187
- export interface AuthForm2FAState {
188
- /** Loading state for 2FA verification */
189
- is2FALoading: boolean;
190
- /** Warning message from 2FA (e.g., low backup codes) */
191
- twoFactorWarning: string | null;
192
- /** Remaining attempts before 2FA lockout (null = unknown) */
193
- twoFactorAttemptsRemaining: number | null;
194
- }
195
-
196
173
  // ─────────────────────────────────────────────────────────────────────────────
197
174
  // Combined Form Interface
198
175
  // ─────────────────────────────────────────────────────────────────────────────
@@ -202,8 +179,7 @@ export interface AuthFormReturn extends
202
179
  AuthFormStateHandlers,
203
180
  AuthFormSubmitHandlers,
204
181
  AuthFormValidation,
205
- AuthFormAutoSubmit,
206
- AuthForm2FAState {}
182
+ AuthFormAutoSubmit {}
207
183
 
208
184
  // ─────────────────────────────────────────────────────────────────────────────
209
185
  // Hook Options
@@ -1,106 +0,0 @@
1
- /**
2
- * Tests for useAuthForm 2FA behavior.
3
- *
4
- * The sign-in flow only *verifies* an existing 2FA challenge — it never
5
- * prompts the user to *set up* 2FA (that lives in ProfileLayout). These tests
6
- * cover the step machine and the shouldPrompt2FA state that the verification
7
- * branch relies on.
8
- */
9
-
10
- // @vitest-environment jsdom
11
- import { act, renderHook } from '@testing-library/react';
12
- import { beforeEach, describe, expect, it, vi } from 'vitest';
13
-
14
- import { useAuthForm } from '../hooks/useAuthForm';
15
-
16
- // useAuthForm pulls in useAutoAuth → useCfgRouter → next/navigation, which
17
- // throws outside an app-router provider. Stub the navigation surface it uses.
18
- vi.mock('next/navigation', () => ({
19
- useRouter: () => ({ push: vi.fn(), replace: vi.fn(), prefetch: vi.fn(), back: vi.fn() }),
20
- usePathname: () => '/auth',
21
- useSearchParams: () => new URLSearchParams(),
22
- }));
23
-
24
- // Mock dependencies (migrated from Jest → Vitest)
25
- vi.mock('../context', () => ({
26
- useAuth: () => ({
27
- requestOTP: vi.fn().mockResolvedValue({ success: true }),
28
- verifyOTP: vi.fn(),
29
- getSavedEmail: vi.fn().mockReturnValue(null),
30
- saveEmail: vi.fn(),
31
- clearSavedEmail: vi.fn(),
32
- getSavedPhone: vi.fn().mockReturnValue(null),
33
- savePhone: vi.fn(),
34
- clearSavedPhone: vi.fn(),
35
- }),
36
- }));
37
-
38
- vi.mock('../hooks/useTwoFactorVerify', () => ({
39
- useTwoFactorVerify: () => ({
40
- isLoading: false,
41
- warning: null,
42
- verifyTOTP: vi.fn(),
43
- verifyBackupCode: vi.fn(),
44
- }),
45
- }));
46
-
47
- vi.mock('../utils/logger', () => ({
48
- authLogger: {
49
- info: vi.fn(),
50
- warn: vi.fn(),
51
- error: vi.fn(),
52
- },
53
- }));
54
-
55
- describe('useAuthForm - 2FA', () => {
56
- const defaultOptions = {
57
- sourceUrl: 'http://localhost',
58
- redirectUrl: '/dashboard',
59
- };
60
-
61
- beforeEach(() => {
62
- vi.clearAllMocks();
63
- });
64
-
65
- describe('step transitions', () => {
66
- it('should start on the identifier step', () => {
67
- const { result } = renderHook(() => useAuthForm(defaultOptions));
68
-
69
- expect(result.current.step).toBe('identifier');
70
- });
71
-
72
- it('should expose a setStep handler', () => {
73
- const { result } = renderHook(() => useAuthForm(defaultOptions));
74
-
75
- expect(typeof result.current.setStep).toBe('function');
76
- });
77
-
78
- it('should be able to transition to the success step', () => {
79
- const { result } = renderHook(() => useAuthForm(defaultOptions));
80
-
81
- act(() => {
82
- result.current.setStep('success');
83
- });
84
-
85
- expect(result.current.step).toBe('success');
86
- });
87
- });
88
-
89
- describe('shouldPrompt2FA state', () => {
90
- it('should initialize shouldPrompt2FA as false', () => {
91
- const { result } = renderHook(() => useAuthForm(defaultOptions));
92
-
93
- expect(result.current.shouldPrompt2FA).toBe(false);
94
- });
95
-
96
- it('should be able to set shouldPrompt2FA', () => {
97
- const { result } = renderHook(() => useAuthForm(defaultOptions));
98
-
99
- act(() => {
100
- result.current.setShouldPrompt2FA(true);
101
- });
102
-
103
- expect(result.current.shouldPrompt2FA).toBe(true);
104
- });
105
- });
106
- });