@djangocfg/api 2.1.47 → 2.1.49

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djangocfg/api",
3
- "version": "2.1.47",
3
+ "version": "2.1.49",
4
4
  "description": "Auto-generated TypeScript API client with React hooks, SWR integration, and Zod validation for Django REST Framework backends",
5
5
  "keywords": [
6
6
  "django",
@@ -74,7 +74,7 @@
74
74
  "check": "tsc --noEmit"
75
75
  },
76
76
  "peerDependencies": {
77
- "@djangocfg/ui-nextjs": "^2.1.47",
77
+ "@djangocfg/ui-nextjs": "^2.1.49",
78
78
  "consola": "^3.4.2",
79
79
  "next": "^14 || ^15",
80
80
  "p-retry": "^7.0.0",
@@ -85,7 +85,7 @@
85
85
  "devDependencies": {
86
86
  "@types/node": "^24.7.2",
87
87
  "@types/react": "^19.0.0",
88
- "@djangocfg/typescript-config": "^2.1.47",
88
+ "@djangocfg/typescript-config": "^2.1.49",
89
89
  "next": "^15.0.0",
90
90
  "react": "^19.0.0",
91
91
  "tsup": "^8.5.0",
@@ -43,10 +43,12 @@ export interface UseAuthFormOptions {
43
43
  redirectUrl?: string;
44
44
  /** If true, user must accept terms before submitting. Default: false */
45
45
  requireTermsAcceptance?: boolean;
46
+ /** Path to auth page for auto-OTP detection. Default: '/auth' */
47
+ authPath?: string;
46
48
  }
47
49
 
48
50
  export const useAuthForm = (options: UseAuthFormOptions): AuthFormState & AuthFormHandlers => {
49
- const { onIdentifierSuccess, onOTPSuccess, onError, sourceUrl, redirectUrl, requireTermsAcceptance = false } = options;
51
+ const { onIdentifierSuccess, onOTPSuccess, onError, sourceUrl, redirectUrl, requireTermsAcceptance = false, authPath = '/auth' } = options;
50
52
 
51
53
  // Form state
52
54
  const [identifier, setIdentifier] = useState('');
@@ -273,15 +275,16 @@ export const useAuthForm = (options: UseAuthFormOptions): AuthFormState & AuthFo
273
275
  setSavedTermsAccepted(checked);
274
276
  }, [setSavedTermsAccepted]);
275
277
 
276
- // Auto-detect OTP from URL query parameters
278
+ // Auto-detect OTP from URL query parameters (only on auth page)
277
279
  useAutoAuth({
280
+ allowedPaths: [authPath],
278
281
  onOTPDetected: (otp: string) => {
279
282
  authLogger.info('OTP detected, auto-submitting');
280
-
283
+
281
284
  // Get saved identifier from auth context
282
285
  const savedEmail = getSavedEmail();
283
286
  const savedPhone = getSavedPhone();
284
-
287
+
285
288
  // Prioritize phone over email if both exist
286
289
  if (savedPhone) {
287
290
  setIdentifier(savedPhone);
@@ -290,11 +293,11 @@ export const useAuthForm = (options: UseAuthFormOptions): AuthFormState & AuthFo
290
293
  setIdentifier(savedEmail);
291
294
  setChannel('email');
292
295
  }
293
-
296
+
294
297
  // Set OTP and force OTP step
295
298
  setOtp(otp);
296
299
  setStep('otp');
297
-
300
+
298
301
  // Auto-submit after a short delay to ensure state is updated
299
302
  setTimeout(() => {
300
303
  const fakeEvent = { preventDefault: () => {} } as React.FormEvent;
@@ -10,6 +10,8 @@ import { authLogger } from '../utils/logger';
10
10
  export interface UseAutoAuthOptions {
11
11
  onOTPDetected?: (otp: string) => void;
12
12
  cleanupUrl?: boolean;
13
+ /** Paths where auto-auth should be active. Default: ['/auth'] */
14
+ allowedPaths?: string[];
13
15
  }
14
16
 
15
17
  /**
@@ -17,22 +19,26 @@ export interface UseAutoAuthOptions {
17
19
  * Detects OTP from URL and triggers callback
18
20
  */
19
21
  export const useAutoAuth = (options: UseAutoAuthOptions = {}) => {
20
- const { onOTPDetected, cleanupUrl = true } = options;
22
+ const { onOTPDetected, cleanupUrl = true, allowedPaths = ['/auth'] } = options;
21
23
  const queryParams = useQueryParams();
22
24
  const pathname = usePathname();
23
25
  const router = useCfgRouter();
24
26
 
25
- const isReady = !!pathname && !!queryParams.get('otp');
27
+ // Check if current path is in allowed paths
28
+ const isAllowedPath = allowedPaths.some(path => pathname === path || pathname?.startsWith(path + '/'));
29
+
26
30
  const hasOTP = !!(queryParams.get('otp'));
31
+ const isReady = !!pathname && hasOTP && isAllowedPath;
27
32
 
28
33
  useEffect(() => {
29
34
  if (!isReady) return;
30
35
 
31
36
  const queryOtp = queryParams.get('otp') as string;
32
37
 
33
- // Handle OTP detection
38
+ // Handle OTP detection - only on allowed paths to avoid conflicts with other pages
39
+ // (e.g., /dashboard/device uses ?otp= for device authorization, not user auth)
34
40
  if (queryOtp && typeof queryOtp === 'string' && queryOtp.length === 6) {
35
- authLogger.info('OTP detected in URL:', queryOtp);
41
+ authLogger.info('OTP detected in URL on auth page:', queryOtp);
36
42
  onOTPDetected?.(queryOtp);
37
43
  }
38
44
 
@@ -40,12 +46,14 @@ export const useAutoAuth = (options: UseAutoAuthOptions = {}) => {
40
46
  if (cleanupUrl && queryOtp) {
41
47
  const cleanQuery = Object.fromEntries(queryParams.entries());
42
48
  delete cleanQuery.otp;
43
- router.push(`${pathname}?${new URLSearchParams(cleanQuery).toString()}`);
49
+ const queryString = new URLSearchParams(cleanQuery).toString();
50
+ router.push(queryString ? `${pathname}?${queryString}` : pathname);
44
51
  }
45
- }, [pathname, queryParams, onOTPDetected, cleanupUrl, router]);
52
+ }, [pathname, queryParams, onOTPDetected, cleanupUrl, router, isReady]);
46
53
 
47
54
  return {
48
55
  isReady,
49
56
  hasOTP,
57
+ isAllowedPath,
50
58
  };
51
59
  };