@djangocfg/api 2.1.598 → 2.1.600

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 (61) hide show
  1. package/README.md +2 -1
  2. package/dist/OAuthProvidersResponse-QZ566OYR.mjs +25 -0
  3. package/dist/OAuthProvidersResponse-QZ566OYR.mjs.map +1 -0
  4. package/dist/auth.cjs +526 -288
  5. package/dist/auth.cjs.map +1 -1
  6. package/dist/auth.d.cts +144 -31
  7. package/dist/auth.d.ts +144 -31
  8. package/dist/auth.mjs +409 -213
  9. package/dist/auth.mjs.map +1 -1
  10. package/dist/cfg_accounts_oauth_connections_response_200_AutoRef-N532BRPN.mjs +28 -0
  11. package/dist/cfg_accounts_oauth_connections_response_200_AutoRef-N532BRPN.mjs.map +1 -0
  12. package/dist/chunk-PCOSFQTH.mjs +10 -0
  13. package/dist/chunk-PCOSFQTH.mjs.map +1 -0
  14. package/dist/clients.cjs +34 -3
  15. package/dist/clients.cjs.map +1 -1
  16. package/dist/clients.d.cts +135 -14
  17. package/dist/clients.d.ts +135 -14
  18. package/dist/clients.mjs +34 -3
  19. package/dist/clients.mjs.map +1 -1
  20. package/dist/hooks.cjs +1 -0
  21. package/dist/hooks.cjs.map +1 -1
  22. package/dist/hooks.mjs +1 -0
  23. package/dist/hooks.mjs.map +1 -1
  24. package/dist/index.cjs +34 -3
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.cts +169 -17
  27. package/dist/index.d.ts +169 -17
  28. package/dist/index.mjs +34 -3
  29. package/dist/index.mjs.map +1 -1
  30. package/dist/storage.cjs +1 -0
  31. package/dist/storage.cjs.map +1 -1
  32. package/dist/storage.d.cts +1 -0
  33. package/dist/storage.d.ts +1 -0
  34. package/dist/storage.mjs +1 -0
  35. package/dist/storage.mjs.map +1 -1
  36. package/package.json +2 -2
  37. package/src/__tests__/noStorageLiterals.test.ts +1 -1
  38. package/src/_api/generated/_cfg_accounts/hooks/index.ts +2 -0
  39. package/src/_api/generated/_cfg_accounts/hooks/useCfgAccountsOauthGoogleAuthorizeCreate.ts +68 -0
  40. package/src/_api/generated/_cfg_accounts/hooks/useCfgAccountsOauthGoogleCallbackCreate.ts +68 -0
  41. package/src/_api/generated/_cfg_accounts/openapi.json +263 -19
  42. package/src/_api/generated/_cfg_accounts/schemas/OAuthCallbackRequestRequest.ts +2 -2
  43. package/src/_api/generated/_cfg_accounts/schemas/OAuthError.ts +2 -1
  44. package/src/_api/generated/_cfg_accounts/schemas/OAuthErrorCodeEnum.ts +9 -0
  45. package/src/_api/generated/_cfg_accounts/schemas/OAuthProviderEnum.ts +1 -1
  46. package/src/_api/generated/_cfg_accounts/schemas/OAuthProviderInfo.ts +14 -0
  47. package/src/_api/generated/_cfg_accounts/schemas/OAuthProvidersResponse.ts +2 -1
  48. package/src/_api/generated/_cfg_accounts/schemas/index.ts +2 -0
  49. package/src/_api/generated/helpers/keys.ts +1 -0
  50. package/src/_api/generated/openapi.json +263 -19
  51. package/src/_api/generated/sdk.gen.ts +36 -4
  52. package/src/_api/generated/types.gen.ts +136 -11
  53. package/src/auth/__tests__/oauthErrors.test.ts +23 -0
  54. package/src/auth/__tests__/passwordLogin.test.tsx +1 -0
  55. package/src/auth/__tests__/useOAuthLogin.test.tsx +387 -0
  56. package/src/auth/hooks/index.ts +12 -1
  57. package/src/auth/hooks/useGithubAuth.ts +15 -225
  58. package/src/auth/hooks/useOAuthLogin.ts +237 -0
  59. package/src/auth/hooks/useOAuthProviders.ts +76 -0
  60. package/src/auth/utils/index.ts +8 -0
  61. package/src/auth/utils/oauthErrors.ts +45 -0
package/dist/auth.mjs CHANGED
@@ -20,11 +20,11 @@ import { usePathname as usePathname3 } from "next/navigation";
20
20
  import {
21
21
  createContext as createContext2,
22
22
  memo,
23
- useCallback as useCallback12,
23
+ useCallback as useCallback13,
24
24
  useContext as useContext2,
25
- useEffect as useEffect6,
26
- useMemo as useMemo3,
27
- useRef as useRef6,
25
+ useEffect as useEffect7,
26
+ useMemo as useMemo4,
27
+ useRef as useRef7,
28
28
  useState as useState11
29
29
  } from "react";
30
30
 
@@ -105,6 +105,7 @@ var CFG_KEYS = {
105
105
  redirectUrlTs: k("cfg.auth.redirect_url_ts", "session", true),
106
106
  oauthState: k("cfg.auth.oauth_state", "session", true),
107
107
  oauthProvider: k("cfg.auth.oauth_provider", "session", true),
108
+ oauthProviders: k("cfg.auth.oauth_providers", "session", false),
108
109
  profileCache: k("cfg.profile.cache", "local", true),
109
110
  monitorSessionId: k("cfg.monitor.session_id", "local", false),
110
111
  monitorSessionCookie: k("cfg.monitor.session_id", "cookie", false),
@@ -1692,8 +1693,8 @@ var useAuthForm = /* @__PURE__ */ __name((options) => {
1692
1693
  };
1693
1694
  }, "useAuthForm");
1694
1695
 
1695
- // src/auth/hooks/useGithubAuth.ts
1696
- import { useCallback as useCallback6, useState as useState3 } from "react";
1696
+ // src/auth/hooks/useOAuthLogin.ts
1697
+ import { useCallback as useCallback6, useEffect as useEffect5, useRef as useRef5, useState as useState4 } from "react";
1697
1698
 
1698
1699
  // src/_api/generated/core/bodySerializer.gen.ts
1699
1700
  var serializeFormDataPair = /* @__PURE__ */ __name((data, key, value) => {
@@ -2559,7 +2560,7 @@ var CfgAccountsOauth = class {
2559
2560
  /**
2560
2561
  * Start GitHub OAuth
2561
2562
  *
2562
- * Generate GitHub OAuth authorization URL. Redirect user to this URL to start authentication.
2563
+ * Generate the GitHub authorization URL. Redirect the user to it to start authentication. The redirect URI is derived from the request Origin.
2563
2564
  */
2564
2565
  static cfgAccountsOauthGithubAuthorizeCreate(options) {
2565
2566
  return (options?.client ?? client).post({
@@ -2574,7 +2575,7 @@ var CfgAccountsOauth = class {
2574
2575
  /**
2575
2576
  * Complete GitHub OAuth
2576
2577
  *
2577
- * Exchange authorization code for JWT tokens. Call this after GitHub redirects back with code.
2578
+ * Exchange the authorization code for JWT tokens. Call this after GitHub redirects back with a code. The state is single use.
2578
2579
  */
2579
2580
  static cfgAccountsOauthGithubCallbackCreate(options) {
2580
2581
  return (options.client ?? client).post({
@@ -2586,10 +2587,40 @@ var CfgAccountsOauth = class {
2586
2587
  }
2587
2588
  });
2588
2589
  }
2590
+ /**
2591
+ * Start Google OAuth
2592
+ *
2593
+ * Generate the Google authorization URL. Redirect the user to it to start authentication. The redirect URI is derived from the request Origin.
2594
+ */
2595
+ static cfgAccountsOauthGoogleAuthorizeCreate(options) {
2596
+ return (options?.client ?? client).post({
2597
+ url: "/cfg/accounts/oauth/google/authorize/",
2598
+ ...options,
2599
+ headers: {
2600
+ "Content-Type": "application/json",
2601
+ ...options?.headers
2602
+ }
2603
+ });
2604
+ }
2605
+ /**
2606
+ * Complete Google OAuth
2607
+ *
2608
+ * Exchange the authorization code for JWT tokens. Call this after Google redirects back with a code. The state is single use.
2609
+ */
2610
+ static cfgAccountsOauthGoogleCallbackCreate(options) {
2611
+ return (options.client ?? client).post({
2612
+ url: "/cfg/accounts/oauth/google/callback/",
2613
+ ...options,
2614
+ headers: {
2615
+ "Content-Type": "application/json",
2616
+ ...options.headers
2617
+ }
2618
+ });
2619
+ }
2589
2620
  /**
2590
2621
  * List OAuth providers
2591
2622
  *
2592
- * Get list of available OAuth providers for authentication.
2623
+ * Providers that are configured, in display order. The login screen shows exactly these buttons.
2593
2624
  */
2594
2625
  static cfgAccountsOauthProvidersRetrieve(options) {
2595
2626
  return (options?.client ?? client).get({ url: "/cfg/accounts/oauth/providers/", ...options });
@@ -3060,6 +3091,27 @@ var Analytics = {
3060
3091
  }
3061
3092
  };
3062
3093
 
3094
+ // src/_api/generated/types.gen.ts
3095
+ var OAuthErrorCodeEnum = /* @__PURE__ */ ((OAuthErrorCodeEnum2) => {
3096
+ OAuthErrorCodeEnum2["OAUTH_DISABLED"] = "oauth_disabled";
3097
+ OAuthErrorCodeEnum2["GITHUB_OAUTH_DISABLED"] = "github_oauth_disabled";
3098
+ OAuthErrorCodeEnum2["ORIGIN_NOT_ALLOWED"] = "origin_not_allowed";
3099
+ OAuthErrorCodeEnum2["MISSING_REDIRECT_URI"] = "missing_redirect_uri";
3100
+ OAuthErrorCodeEnum2["INVALID_STATE"] = "invalid_state";
3101
+ OAuthErrorCodeEnum2["OAUTH_EXCHANGE_FAILED"] = "oauth_exchange_failed";
3102
+ OAuthErrorCodeEnum2["INVALID_ID_TOKEN"] = "invalid_id_token";
3103
+ OAuthErrorCodeEnum2["EMAIL_MISSING"] = "email_missing";
3104
+ OAuthErrorCodeEnum2["EMAIL_NOT_VERIFIED"] = "email_not_verified";
3105
+ OAuthErrorCodeEnum2["HOSTED_DOMAIN_NOT_ALLOWED"] = "hosted_domain_not_allowed";
3106
+ OAuthErrorCodeEnum2["ACCOUNT_INACTIVE"] = "account_inactive";
3107
+ OAuthErrorCodeEnum2["LINK_NOT_ALLOWED"] = "link_not_allowed";
3108
+ OAuthErrorCodeEnum2["RATE_LIMITED"] = "rate_limited";
3109
+ OAuthErrorCodeEnum2["PROVIDER_UNAVAILABLE"] = "provider_unavailable";
3110
+ OAuthErrorCodeEnum2["SERVER_ERROR"] = "server_error";
3111
+ OAuthErrorCodeEnum2["NOT_FOUND"] = "not_found";
3112
+ return OAuthErrorCodeEnum2;
3113
+ })(OAuthErrorCodeEnum || {});
3114
+
3063
3115
  // src/auth/utils/errors.ts
3064
3116
  var prop = /* @__PURE__ */ __name((value, key) => typeof value === "object" && value !== null ? value[key] : void 0, "prop");
3065
3117
  var TRANSPORT_FALLBACK = /^HTTP \d{3}:\s*/;
@@ -3121,126 +3173,24 @@ var logAuthFailure = /* @__PURE__ */ __name((log, message, error) => {
3121
3173
  log.error(message, error);
3122
3174
  }, "logAuthFailure");
3123
3175
 
3124
- // src/auth/hooks/useGithubAuth.ts
3125
- var OAUTH_STATE_KEY = CFG_KEYS.oauthState.key;
3126
- var OAUTH_PROVIDER_KEY = CFG_KEYS.oauthProvider.key;
3127
- var useGithubAuth = /* @__PURE__ */ __name((options = {}) => {
3128
- const { sourceUrl, onSuccess, onError, onRequires2FA, redirectUrl, skipRedirect = false } = options;
3129
- const router = useCfgRouter();
3130
- const [isLoading, setIsLoading] = useState3(false);
3131
- const [error, setError] = useState3(null);
3132
- const startGithubAuth = useCallback6(async () => {
3133
- setIsLoading(true);
3134
- setError(null);
3135
- auth.clearSession();
3136
- try {
3137
- authLogger.info("Starting GitHub OAuth flow...");
3138
- Analytics.event("auth_oauth_start" /* AUTH_OAUTH_START */, {
3139
- category: "auth" /* AUTH */,
3140
- label: "github"
3141
- });
3142
- const result = await CfgAccountsOauth.cfgAccountsOauthGithubAuthorizeCreate({
3143
- body: {
3144
- source_url: sourceUrl || (typeof window !== "undefined" ? window.location.href : "")
3145
- },
3146
- throwOnError: true
3147
- });
3148
- const response = result.data;
3149
- if (!response.authorization_url) {
3150
- throw new Error("Failed to get authorization URL");
3151
- }
3152
- authLogger.info("Redirecting to GitHub...", response.authorization_url);
3153
- if (typeof window !== "undefined") {
3154
- sessionStorage.setItem(OAUTH_STATE_KEY, response.state);
3155
- sessionStorage.setItem(OAUTH_PROVIDER_KEY, "github");
3156
- }
3157
- window.location.href = response.authorization_url;
3158
- } catch (err) {
3159
- const errorMessage = formatAuthError(err, "Failed to start GitHub authentication");
3160
- authLogger.error("GitHub OAuth start error:", err);
3161
- setError(errorMessage);
3162
- onError?.(errorMessage);
3163
- Analytics.event("auth_oauth_fail" /* AUTH_OAUTH_FAIL */, {
3164
- category: "auth" /* AUTH */,
3165
- label: "github"
3166
- });
3167
- } finally {
3168
- setIsLoading(false);
3169
- }
3170
- }, [sourceUrl, onError]);
3171
- const handleGithubCallback = useCallback6(async (code, state) => {
3172
- setIsLoading(true);
3173
- setError(null);
3174
- try {
3175
- authLogger.info("Processing GitHub OAuth callback...");
3176
- if (typeof window !== "undefined") {
3177
- const storedState = sessionStorage.getItem(OAUTH_STATE_KEY);
3178
- if (storedState && storedState !== state) {
3179
- throw new Error("Invalid OAuth state - possible CSRF attack");
3180
- }
3181
- sessionStorage.removeItem(OAUTH_STATE_KEY);
3182
- sessionStorage.removeItem(OAUTH_PROVIDER_KEY);
3183
- }
3184
- const result = await CfgAccountsOauth.cfgAccountsOauthGithubCallbackCreate({
3185
- body: { code, state },
3186
- throwOnError: true
3187
- });
3188
- const response = result.data;
3189
- if (response.requires_2fa && response.session_id) {
3190
- authLogger.info("GitHub OAuth requires 2FA, session:", response.session_id);
3191
- Analytics.event("auth_oauth_start" /* AUTH_OAUTH_START */, {
3192
- category: "auth" /* AUTH */,
3193
- label: "github-2fa-required"
3194
- });
3195
- onRequires2FA?.(response.session_id, response.should_prompt_2fa || false);
3196
- return;
3197
- }
3198
- if (!response.access || !response.refresh) {
3199
- throw new Error("Invalid response from OAuth callback");
3200
- }
3201
- authLogger.info("GitHub OAuth successful, user:", response.user);
3202
- auth.setSession({ access: response.access, refresh: response.refresh });
3203
- Analytics.event("auth_login_success" /* AUTH_LOGIN_SUCCESS */, {
3204
- category: "auth" /* AUTH */,
3205
- label: "github"
3206
- });
3207
- if (response.user?.id) {
3208
- Analytics.setUser(String(response.user.id));
3209
- }
3210
- if (response.user) {
3211
- onSuccess?.(response.user, response.is_new_user || false);
3212
- }
3213
- if (!skipRedirect) {
3214
- const finalRedirectUrl = redirectUrl || "/private";
3215
- router.hardPush(finalRedirectUrl);
3216
- }
3217
- return;
3218
- } catch (err) {
3219
- const errorMessage = formatAuthError(err, "GitHub authentication failed");
3220
- authLogger.error("GitHub OAuth callback error:", err);
3221
- setError(errorMessage);
3222
- onError?.(errorMessage);
3223
- Analytics.event("auth_oauth_fail" /* AUTH_OAUTH_FAIL */, {
3224
- category: "auth" /* AUTH */,
3225
- label: "github"
3226
- });
3227
- } finally {
3228
- setIsLoading(false);
3229
- }
3230
- }, [onSuccess, onError, onRequires2FA, redirectUrl, router, skipRedirect]);
3231
- return {
3232
- isLoading,
3233
- error,
3234
- startGithubAuth,
3235
- handleGithubCallback
3236
- };
3237
- }, "useGithubAuth");
3238
-
3239
- // src/auth/hooks/useTwoFactorVerify.ts
3240
- import { useCallback as useCallback7, useState as useState5 } from "react";
3176
+ // src/auth/utils/oauthErrors.ts
3177
+ var SERVER_CODES = new Set(Object.values(OAuthErrorCodeEnum));
3178
+ var record = /* @__PURE__ */ __name((value) => typeof value === "object" && value !== null ? value : null, "record");
3179
+ var readOAuthFailure = /* @__PURE__ */ __name((err, fallback) => {
3180
+ const body = record(record(err)?.response);
3181
+ const code = body?.error;
3182
+ if (typeof code === "string" && SERVER_CODES.has(code)) {
3183
+ const description = body?.error_description;
3184
+ return {
3185
+ code,
3186
+ message: typeof description === "string" && description ? description : fallback
3187
+ };
3188
+ }
3189
+ return { message: formatAuthError(err, fallback) };
3190
+ }, "readOAuthFailure");
3241
3191
 
3242
3192
  // src/auth/hooks/useSessionStorage.ts
3243
- import { useState as useState4 } from "react";
3193
+ import { useState as useState3 } from "react";
3244
3194
 
3245
3195
  // src/auth/utils/storage.ts
3246
3196
  var MAX_ITEM_KB = 1024;
@@ -3269,7 +3219,7 @@ __name(isWithinSizeLimit, "isWithinSizeLimit");
3269
3219
 
3270
3220
  // src/auth/hooks/useSessionStorage.ts
3271
3221
  function useSessionStorage(key, initialValue) {
3272
- const [storedValue, setStoredValue] = useState4(() => {
3222
+ const [storedValue, setStoredValue] = useState3(() => {
3273
3223
  if (typeof window === "undefined") {
3274
3224
  return initialValue;
3275
3225
  }
@@ -3457,6 +3407,243 @@ var useAuthRedirectManager = /* @__PURE__ */ __name((options = {}) => {
3457
3407
  };
3458
3408
  }, "useAuthRedirectManager");
3459
3409
 
3410
+ // src/auth/hooks/useOAuthLogin.ts
3411
+ var ADAPTERS = {
3412
+ github: {
3413
+ authorize: /* @__PURE__ */ __name(async (body) => (await CfgAccountsOauth.cfgAccountsOauthGithubAuthorizeCreate({ body, throwOnError: true })).data, "authorize"),
3414
+ callback: /* @__PURE__ */ __name(async (body) => (await CfgAccountsOauth.cfgAccountsOauthGithubCallbackCreate({ body, throwOnError: true })).data, "callback")
3415
+ },
3416
+ google: {
3417
+ authorize: /* @__PURE__ */ __name(async (body) => (await CfgAccountsOauth.cfgAccountsOauthGoogleAuthorizeCreate({ body, throwOnError: true })).data, "authorize"),
3418
+ callback: /* @__PURE__ */ __name(async (body) => (await CfgAccountsOauth.cfgAccountsOauthGoogleCallbackCreate({ body, throwOnError: true })).data, "callback")
3419
+ }
3420
+ };
3421
+ var OAUTH_PROVIDER_IDS = Object.keys(ADAPTERS);
3422
+ var isOAuthProviderId = /* @__PURE__ */ __name((value) => typeof value === "string" && Object.hasOwn(ADAPTERS, value), "isOAuthProviderId");
3423
+ var STATE_KEY = CFG_KEYS.oauthState.key;
3424
+ var PROVIDER_KEY = CFG_KEYS.oauthProvider.key;
3425
+ var clearOAuthAttempt = /* @__PURE__ */ __name(() => {
3426
+ cfgStorage.remove(STATE_KEY);
3427
+ cfgStorage.remove(PROVIDER_KEY);
3428
+ }, "clearOAuthAttempt");
3429
+ var useOAuthLogin = /* @__PURE__ */ __name((options = {}) => {
3430
+ const router = useCfgRouter();
3431
+ const optionsRef = useRef5(options);
3432
+ optionsRef.current = options;
3433
+ const routerRef = useRef5(router);
3434
+ routerRef.current = router;
3435
+ const [loadingProvider, setLoadingProvider] = useState4(null);
3436
+ const [error, setError] = useState4(null);
3437
+ const [errorCode, setErrorCode] = useState4(null);
3438
+ useEffect5(() => {
3439
+ const onShow = /* @__PURE__ */ __name((event) => {
3440
+ if (event.persisted) setLoadingProvider(null);
3441
+ }, "onShow");
3442
+ window.addEventListener("pageshow", onShow);
3443
+ return () => window.removeEventListener("pageshow", onShow);
3444
+ }, []);
3445
+ const fail = useCallback6((provider, message, code) => {
3446
+ setError(message);
3447
+ setErrorCode(code ?? null);
3448
+ setLoadingProvider(null);
3449
+ optionsRef.current.onError?.(message, code);
3450
+ Analytics.event("auth_oauth_fail" /* AUTH_OAUTH_FAIL */, {
3451
+ category: "auth" /* AUTH */,
3452
+ label: provider
3453
+ });
3454
+ }, []);
3455
+ const start = useCallback6(async (provider) => {
3456
+ setLoadingProvider(provider);
3457
+ setError(null);
3458
+ setErrorCode(null);
3459
+ auth.clearSession();
3460
+ try {
3461
+ Analytics.event("auth_oauth_start" /* AUTH_OAUTH_START */, {
3462
+ category: "auth" /* AUTH */,
3463
+ label: provider
3464
+ });
3465
+ const sourceUrl = optionsRef.current.sourceUrl || window.location.href;
3466
+ const response = await ADAPTERS[provider].authorize({ source_url: sourceUrl });
3467
+ if (!response.authorization_url || !response.state) {
3468
+ throw new Error("Failed to get authorization URL");
3469
+ }
3470
+ cfgStorage.write(STATE_KEY, response.state);
3471
+ cfgStorage.write(PROVIDER_KEY, provider);
3472
+ authLogger.info(`Redirecting to ${provider}...`);
3473
+ window.location.href = response.authorization_url;
3474
+ } catch (err) {
3475
+ authLogger.error(`${provider} OAuth start error:`, err);
3476
+ const failure = readOAuthFailure(err, "Failed to start authentication");
3477
+ fail(provider, failure.message, failure.code);
3478
+ }
3479
+ }, [fail]);
3480
+ const complete = useCallback6(async (provider, code, state) => {
3481
+ setLoadingProvider(provider);
3482
+ setError(null);
3483
+ setErrorCode(null);
3484
+ const storedState = cfgStorage.read(STATE_KEY);
3485
+ const storedProvider = cfgStorage.read(PROVIDER_KEY);
3486
+ clearOAuthAttempt();
3487
+ if (!storedState || storedState !== state || storedProvider && storedProvider !== provider) {
3488
+ authLogger.warn(`${provider} OAuth callback rejected: state does not match this browser`);
3489
+ fail(provider, "Invalid sign-in attempt. Please try again.", "invalid_state");
3490
+ return;
3491
+ }
3492
+ try {
3493
+ const response = await ADAPTERS[provider].callback({ code, state });
3494
+ if (response.requires_2fa && response.session_id) {
3495
+ Analytics.event("auth_oauth_start" /* AUTH_OAUTH_START */, {
3496
+ category: "auth" /* AUTH */,
3497
+ label: `${provider}-2fa-required`
3498
+ });
3499
+ optionsRef.current.onRequires2FA?.(response.session_id, response.should_prompt_2fa || false);
3500
+ setLoadingProvider(null);
3501
+ return;
3502
+ }
3503
+ if (!response.access || !response.refresh) {
3504
+ throw new Error("Invalid response from OAuth callback");
3505
+ }
3506
+ auth.setSession({ access: response.access, refresh: response.refresh });
3507
+ Analytics.event("auth_login_success" /* AUTH_LOGIN_SUCCESS */, {
3508
+ category: "auth" /* AUTH */,
3509
+ label: provider
3510
+ });
3511
+ if (response.user?.id) {
3512
+ Analytics.setUser(String(response.user.id));
3513
+ }
3514
+ if (response.user) {
3515
+ optionsRef.current.onSuccess?.(response.user, response.is_new_user || false, provider);
3516
+ }
3517
+ setLoadingProvider(null);
3518
+ if (!optionsRef.current.skipRedirect) {
3519
+ routerRef.current.hardPush(consumeSavedRedirect() || optionsRef.current.redirectUrl || "/private");
3520
+ }
3521
+ } catch (err) {
3522
+ authLogger.error(`${provider} OAuth callback error:`, err);
3523
+ const failure = readOAuthFailure(err, "Authentication failed");
3524
+ fail(provider, failure.message, failure.code);
3525
+ }
3526
+ }, [fail]);
3527
+ return {
3528
+ isLoading: loadingProvider !== null,
3529
+ loadingProvider,
3530
+ error,
3531
+ errorCode,
3532
+ start,
3533
+ complete
3534
+ };
3535
+ }, "useOAuthLogin");
3536
+
3537
+ // src/auth/hooks/useOAuthProviders.ts
3538
+ import { useMemo as useMemo2, useSyncExternalStore as useSyncExternalStore4 } from "react";
3539
+
3540
+ // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsOauthProvidersRetrieve.ts
3541
+ import useSWR from "swr";
3542
+ function useCfgAccountsOauthProvidersRetrieve(args, config) {
3543
+ const { enabled = true, ...swrConfig } = config ?? {};
3544
+ const key = enabled ? ["cfg_accounts_oauth_providers_retrieve", args ?? {}] : null;
3545
+ return useSWR(
3546
+ key,
3547
+ async () => {
3548
+ const res = await CfgAccountsOauth.cfgAccountsOauthProvidersRetrieve({ ...args ?? {}, throwOnError: true });
3549
+ const data = res.data;
3550
+ void import("./OAuthProvidersResponse-QZ566OYR.mjs").then(({ OAuthProvidersResponseSchema }) => {
3551
+ const parsed = OAuthProvidersResponseSchema.safeParse(data);
3552
+ if (parsed.success) return;
3553
+ console.warn(
3554
+ "[zod] response did not match schema",
3555
+ {
3556
+ operation: "cfg_accounts_oauth_providers_retrieve",
3557
+ method: "GET",
3558
+ path: "/cfg/accounts/oauth/providers/",
3559
+ issues: parsed.error.issues,
3560
+ data
3561
+ }
3562
+ );
3563
+ if (typeof window !== "undefined") {
3564
+ try {
3565
+ window.dispatchEvent(
3566
+ new CustomEvent("zod-validation-error", {
3567
+ detail: {
3568
+ operation: "cfg_accounts_oauth_providers_retrieve",
3569
+ method: "GET",
3570
+ path: "/cfg/accounts/oauth/providers/",
3571
+ issues: parsed.error.issues,
3572
+ data,
3573
+ timestamp: /* @__PURE__ */ new Date()
3574
+ },
3575
+ bubbles: true,
3576
+ cancelable: false
3577
+ })
3578
+ );
3579
+ } catch {
3580
+ }
3581
+ }
3582
+ }).catch(() => {
3583
+ });
3584
+ return data;
3585
+ },
3586
+ swrConfig
3587
+ );
3588
+ }
3589
+ __name(useCfgAccountsOauthProvidersRetrieve, "useCfgAccountsOauthProvidersRetrieve");
3590
+
3591
+ // src/auth/hooks/useOAuthProviders.ts
3592
+ var EMPTY = [];
3593
+ var CACHE_KEY = CFG_KEYS.oauthProviders.key;
3594
+ var isInfo = /* @__PURE__ */ __name((value) => typeof value === "object" && value !== null && typeof value.id === "string", "isInfo");
3595
+ var lastRaw = null;
3596
+ var lastParsed;
3597
+ var readCached = /* @__PURE__ */ __name(() => {
3598
+ const raw = cfgStorage.read(CACHE_KEY);
3599
+ if (raw === lastRaw) return lastParsed;
3600
+ lastRaw = raw;
3601
+ try {
3602
+ const parsed = raw === null ? null : JSON.parse(raw);
3603
+ lastParsed = Array.isArray(parsed) && parsed.every(isInfo) ? parsed : void 0;
3604
+ } catch {
3605
+ lastParsed = void 0;
3606
+ }
3607
+ return lastParsed;
3608
+ }, "readCached");
3609
+ var subscribe3 = /* @__PURE__ */ __name(() => () => {
3610
+ }, "subscribe");
3611
+ var serverSnapshot = /* @__PURE__ */ __name(() => void 0, "serverSnapshot");
3612
+ var useOAuthProviders = /* @__PURE__ */ __name(() => {
3613
+ const cached = useSyncExternalStore4(subscribe3, readCached, serverSnapshot);
3614
+ const { data, error, isLoading } = useCfgAccountsOauthProvidersRetrieve(void 0, {
3615
+ revalidateOnFocus: false,
3616
+ revalidateOnReconnect: false,
3617
+ revalidateOnMount: true,
3618
+ shouldRetryOnError: false,
3619
+ dedupingInterval: 60 * 60 * 1e3,
3620
+ fallbackData: cached && { providers: cached },
3621
+ onSuccess: /* @__PURE__ */ __name((response) => {
3622
+ cfgStorage.writeJSON(CACHE_KEY, response.providers);
3623
+ }, "onSuccess")
3624
+ });
3625
+ const providers = useMemo2(
3626
+ () => data?.providers.filter((p) => OAUTH_PROVIDER_IDS.includes(p.id)) ?? EMPTY,
3627
+ [data]
3628
+ );
3629
+ return { providers, isReady: !isLoading || Boolean(error) || cached !== void 0 };
3630
+ }, "useOAuthProviders");
3631
+
3632
+ // src/auth/hooks/useGithubAuth.ts
3633
+ import { useCallback as useCallback7 } from "react";
3634
+ var useGithubAuth = /* @__PURE__ */ __name((options = {}) => {
3635
+ const { isLoading, error, start, complete } = useOAuthLogin(options);
3636
+ const startGithubAuth = useCallback7(() => start("github"), [start]);
3637
+ const handleGithubCallback = useCallback7(
3638
+ (code, state) => complete("github", code, state),
3639
+ [complete]
3640
+ );
3641
+ return { isLoading, error, startGithubAuth, handleGithubCallback };
3642
+ }, "useGithubAuth");
3643
+
3644
+ // src/auth/hooks/useTwoFactorVerify.ts
3645
+ import { useCallback as useCallback8, useState as useState5 } from "react";
3646
+
3460
3647
  // src/auth/hooks/twoFactor.shared.ts
3461
3648
  var TOTP_CODE_LENGTH = 6;
3462
3649
  function extractAttemptsRemaining(err) {
@@ -3481,10 +3668,10 @@ var useTwoFactorVerify = /* @__PURE__ */ __name((options = {}) => {
3481
3668
  const [warning, setWarning] = useState5(null);
3482
3669
  const [remainingBackupCodes, setRemainingBackupCodes] = useState5(null);
3483
3670
  const [attemptsRemaining, setAttemptsRemaining] = useState5(null);
3484
- const clearError = useCallback7(() => {
3671
+ const clearError = useCallback8(() => {
3485
3672
  setError(null);
3486
3673
  }, []);
3487
- const handleSuccess = useCallback7((response) => {
3674
+ const handleSuccess = useCallback8((response) => {
3488
3675
  auth.setSession({ access: response.access_token, refresh: response.refresh_token });
3489
3676
  if (response.warning) {
3490
3677
  setWarning(response.warning);
@@ -3506,7 +3693,7 @@ var useTwoFactorVerify = /* @__PURE__ */ __name((options = {}) => {
3506
3693
  router.hardPush(finalRedirectUrl);
3507
3694
  }
3508
3695
  }, [onSuccess, redirectUrl, router, skipRedirect]);
3509
- const verifyTOTP = useCallback7(async (sessionId, code) => {
3696
+ const verifyTOTP = useCallback8(async (sessionId, code) => {
3510
3697
  if (!sessionId) {
3511
3698
  const msg = "Missing 2FA session ID";
3512
3699
  setError(msg);
@@ -3549,7 +3736,7 @@ var useTwoFactorVerify = /* @__PURE__ */ __name((options = {}) => {
3549
3736
  setIsLoading(false);
3550
3737
  }
3551
3738
  }, [handleSuccess, onError]);
3552
- const verifyBackupCode = useCallback7(async (sessionId, backupCode) => {
3739
+ const verifyBackupCode = useCallback8(async (sessionId, backupCode) => {
3553
3740
  if (!sessionId) {
3554
3741
  const msg = "Missing 2FA session ID";
3555
3742
  setError(msg);
@@ -3608,7 +3795,7 @@ var useTwoFactorVerify = /* @__PURE__ */ __name((options = {}) => {
3608
3795
  }, "useTwoFactorVerify");
3609
3796
 
3610
3797
  // src/auth/hooks/useTwoFactorSetup.ts
3611
- import { useCallback as useCallback8, useState as useState6 } from "react";
3798
+ import { useCallback as useCallback9, useState as useState6 } from "react";
3612
3799
  var useTwoFactorSetup = /* @__PURE__ */ __name((options = {}) => {
3613
3800
  const { onComplete, onError } = options;
3614
3801
  const [isLoading, setIsLoading] = useState6(false);
@@ -3617,17 +3804,17 @@ var useTwoFactorSetup = /* @__PURE__ */ __name((options = {}) => {
3617
3804
  const [backupCodes, setBackupCodes] = useState6(null);
3618
3805
  const [backupCodesWarning, setBackupCodesWarning] = useState6(null);
3619
3806
  const [setupStep, setSetupStep] = useState6("idle");
3620
- const clearError = useCallback8(() => {
3807
+ const clearError = useCallback9(() => {
3621
3808
  setError(null);
3622
3809
  }, []);
3623
- const resetSetup = useCallback8(() => {
3810
+ const resetSetup = useCallback9(() => {
3624
3811
  setSetupData(null);
3625
3812
  setBackupCodes(null);
3626
3813
  setBackupCodesWarning(null);
3627
3814
  setSetupStep("idle");
3628
3815
  setError(null);
3629
3816
  }, []);
3630
- const startSetup = useCallback8(async (deviceName) => {
3817
+ const startSetup = useCallback9(async (deviceName) => {
3631
3818
  setIsLoading(true);
3632
3819
  setError(null);
3633
3820
  setSetupStep("scanning");
@@ -3659,7 +3846,7 @@ var useTwoFactorSetup = /* @__PURE__ */ __name((options = {}) => {
3659
3846
  setIsLoading(false);
3660
3847
  }
3661
3848
  }, [onError]);
3662
- const confirmSetup = useCallback8(async (code) => {
3849
+ const confirmSetup = useCallback9(async (code) => {
3663
3850
  if (!setupData) {
3664
3851
  const msg = "Setup not started. Call startSetup() first.";
3665
3852
  setError(msg);
@@ -3715,16 +3902,16 @@ var useTwoFactorSetup = /* @__PURE__ */ __name((options = {}) => {
3715
3902
  }, "useTwoFactorSetup");
3716
3903
 
3717
3904
  // src/auth/hooks/useTwoFactorStatus.ts
3718
- import { useCallback as useCallback9, useState as useState7 } from "react";
3905
+ import { useCallback as useCallback10, useState as useState7 } from "react";
3719
3906
  var useTwoFactorStatus = /* @__PURE__ */ __name(() => {
3720
3907
  const [isLoading, setIsLoading] = useState7(false);
3721
3908
  const [error, setError] = useState7(null);
3722
3909
  const [has2FAEnabled, setHas2FAEnabled] = useState7(null);
3723
3910
  const [devices, setDevices] = useState7([]);
3724
- const clearError = useCallback9(() => {
3911
+ const clearError = useCallback10(() => {
3725
3912
  setError(null);
3726
3913
  }, []);
3727
- const fetchStatus = useCallback9(async () => {
3914
+ const fetchStatus = useCallback10(async () => {
3728
3915
  setIsLoading(true);
3729
3916
  setError(null);
3730
3917
  try {
@@ -3749,7 +3936,7 @@ var useTwoFactorStatus = /* @__PURE__ */ __name(() => {
3749
3936
  setIsLoading(false);
3750
3937
  }
3751
3938
  }, []);
3752
- const disable2FA = useCallback9(async (code) => {
3939
+ const disable2FA = useCallback10(async (code) => {
3753
3940
  if (!isValidTotpCode(code)) {
3754
3941
  setError("Please enter a 6-digit code");
3755
3942
  return false;
@@ -3986,13 +4173,13 @@ function useBase64() {
3986
4173
  __name(useBase64, "useBase64");
3987
4174
 
3988
4175
  // src/auth/hooks/useProfileCache.ts
3989
- var CACHE_KEY = CFG_KEYS.profileCache.key;
4176
+ var CACHE_KEY2 = CFG_KEYS.profileCache.key;
3990
4177
  var CACHE_VERSION = 1;
3991
4178
  var DEFAULT_TTL = 144e5;
3992
4179
  function getCachedProfile() {
3993
4180
  try {
3994
4181
  if (typeof window === "undefined") return null;
3995
- const cached = localStorage.getItem(CACHE_KEY);
4182
+ const cached = localStorage.getItem(CACHE_KEY2);
3996
4183
  if (!cached) {
3997
4184
  authLogger.debug("No cached profile found");
3998
4185
  return null;
@@ -4030,7 +4217,7 @@ function setCachedProfile(profile, options) {
4030
4217
  ttl: options?.ttl || DEFAULT_TTL
4031
4218
  };
4032
4219
  const encoded = encodeBase64(JSON.stringify(cachedData));
4033
- localStorage.setItem(CACHE_KEY, encoded);
4220
+ localStorage.setItem(CACHE_KEY2, encoded);
4034
4221
  authLogger.debug("Profile cached, TTL:", cachedData.ttl / 1e3, "seconds");
4035
4222
  } catch (error) {
4036
4223
  authLogger.error("Error writing cache:", error);
@@ -4040,7 +4227,7 @@ __name(setCachedProfile, "setCachedProfile");
4040
4227
  function clearProfileCache() {
4041
4228
  try {
4042
4229
  if (typeof window === "undefined") return;
4043
- localStorage.removeItem(CACHE_KEY);
4230
+ localStorage.removeItem(CACHE_KEY2);
4044
4231
  authLogger.debug("Cache cleared");
4045
4232
  } catch (error) {
4046
4233
  authLogger.error("Error clearing cache:", error);
@@ -4054,7 +4241,7 @@ __name(hasValidCache, "hasValidCache");
4054
4241
  function getCacheMetadata() {
4055
4242
  try {
4056
4243
  if (typeof window === "undefined") return null;
4057
- const cached = localStorage.getItem(CACHE_KEY);
4244
+ const cached = localStorage.getItem(CACHE_KEY2);
4058
4245
  if (!cached) return { exists: false };
4059
4246
  const decoded = decodeBase64(cached);
4060
4247
  const cachedData = JSON.parse(decoded);
@@ -4075,15 +4262,15 @@ function getCacheMetadata() {
4075
4262
  __name(getCacheMetadata, "getCacheMetadata");
4076
4263
 
4077
4264
  // src/auth/hooks/useDeleteAccount.ts
4078
- import { useCallback as useCallback10, useState as useState9 } from "react";
4265
+ import { useCallback as useCallback11, useState as useState9 } from "react";
4079
4266
  var useDeleteAccount = /* @__PURE__ */ __name(() => {
4080
4267
  const [isLoading, setIsLoading] = useState9(false);
4081
4268
  const [error, setError] = useState9(null);
4082
4269
  const { logout } = useAuth();
4083
- const clearError = useCallback10(() => {
4270
+ const clearError = useCallback11(() => {
4084
4271
  setError(null);
4085
4272
  }, []);
4086
- const deleteAccount = useCallback10(async () => {
4273
+ const deleteAccount = useCallback11(async () => {
4087
4274
  setIsLoading(true);
4088
4275
  setError(null);
4089
4276
  try {
@@ -4115,11 +4302,11 @@ var useDeleteAccount = /* @__PURE__ */ __name(() => {
4115
4302
  // src/auth/context/AccountsContext.tsx
4116
4303
  import {
4117
4304
  createContext,
4118
- useCallback as useCallback11,
4305
+ useCallback as useCallback12,
4119
4306
  useContext,
4120
- useEffect as useEffect5,
4121
- useMemo as useMemo2,
4122
- useRef as useRef5,
4307
+ useEffect as useEffect6,
4308
+ useMemo as useMemo3,
4309
+ useRef as useRef6,
4123
4310
  useState as useState10
4124
4311
  } from "react";
4125
4312
 
@@ -4127,7 +4314,7 @@ import {
4127
4314
  import useSWRMutation from "swr/mutation";
4128
4315
 
4129
4316
  // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsApiKeyRetrieve.ts
4130
- import useSWR from "swr";
4317
+ import useSWR2 from "swr";
4131
4318
 
4132
4319
  // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsApiKeyRevealCreate.ts
4133
4320
  import useSWRMutation2 from "swr/mutation";
@@ -4136,7 +4323,7 @@ import useSWRMutation2 from "swr/mutation";
4136
4323
  import useSWRMutation3 from "swr/mutation";
4137
4324
 
4138
4325
  // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsOauthConnectionsList.ts
4139
- import useSWR2 from "swr";
4326
+ import useSWR3 from "swr";
4140
4327
 
4141
4328
  // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsOauthDisconnectCreate.ts
4142
4329
  import useSWRMutation4 from "swr/mutation";
@@ -4147,16 +4334,19 @@ import useSWRMutation5 from "swr/mutation";
4147
4334
  // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsOauthGithubCallbackCreate.ts
4148
4335
  import useSWRMutation6 from "swr/mutation";
4149
4336
 
4150
- // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsOauthProvidersRetrieve.ts
4151
- import useSWR3 from "swr";
4337
+ // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsOauthGoogleAuthorizeCreate.ts
4338
+ import useSWRMutation7 from "swr/mutation";
4339
+
4340
+ // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsOauthGoogleCallbackCreate.ts
4341
+ import useSWRMutation8 from "swr/mutation";
4152
4342
 
4153
4343
  // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsOtpConsentPolicyRetrieve.ts
4154
4344
  import useSWR4 from "swr";
4155
4345
 
4156
4346
  // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsOtpRequestCreate.ts
4157
- import useSWRMutation7 from "swr/mutation";
4347
+ import useSWRMutation9 from "swr/mutation";
4158
4348
  function useCfgAccountsOtpRequestCreate(config) {
4159
- return useSWRMutation7(
4349
+ return useSWRMutation9(
4160
4350
  ["cfg_accounts_otp_request_create"],
4161
4351
  async (_key, { arg }) => {
4162
4352
  const res = await CfgAccountsOtp.cfgAccountsOtpRequestCreate({ ...arg, throwOnError: true });
@@ -4203,9 +4393,9 @@ function useCfgAccountsOtpRequestCreate(config) {
4203
4393
  __name(useCfgAccountsOtpRequestCreate, "useCfgAccountsOtpRequestCreate");
4204
4394
 
4205
4395
  // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsOtpVerifyCreate.ts
4206
- import useSWRMutation8 from "swr/mutation";
4396
+ import useSWRMutation10 from "swr/mutation";
4207
4397
  function useCfgAccountsOtpVerifyCreate(config) {
4208
- return useSWRMutation8(
4398
+ return useSWRMutation10(
4209
4399
  ["cfg_accounts_otp_verify_create"],
4210
4400
  async (_key, { arg }) => {
4211
4401
  const res = await CfgAccountsOtp.cfgAccountsOtpVerifyCreate({ ...arg, throwOnError: true });
@@ -4252,9 +4442,9 @@ function useCfgAccountsOtpVerifyCreate(config) {
4252
4442
  __name(useCfgAccountsOtpVerifyCreate, "useCfgAccountsOtpVerifyCreate");
4253
4443
 
4254
4444
  // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsProfileAvatarCreate.ts
4255
- import useSWRMutation9 from "swr/mutation";
4445
+ import useSWRMutation11 from "swr/mutation";
4256
4446
  function useCfgAccountsProfileAvatarCreate(config) {
4257
- return useSWRMutation9(
4447
+ return useSWRMutation11(
4258
4448
  ["cfg_accounts_profile_avatar_create"],
4259
4449
  async (_key, { arg }) => {
4260
4450
  const res = await CfgAccountsProfile.cfgAccountsProfileAvatarCreate({ ...arg, throwOnError: true });
@@ -4301,15 +4491,15 @@ function useCfgAccountsProfileAvatarCreate(config) {
4301
4491
  __name(useCfgAccountsProfileAvatarCreate, "useCfgAccountsProfileAvatarCreate");
4302
4492
 
4303
4493
  // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsProfileDeleteCreate.ts
4304
- import useSWRMutation10 from "swr/mutation";
4494
+ import useSWRMutation12 from "swr/mutation";
4305
4495
 
4306
4496
  // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsProfilePartialPartialUpdate.ts
4307
- import useSWRMutation11 from "swr/mutation";
4497
+ import useSWRMutation13 from "swr/mutation";
4308
4498
 
4309
4499
  // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsProfilePartialUpdate.ts
4310
- import useSWRMutation12 from "swr/mutation";
4500
+ import useSWRMutation14 from "swr/mutation";
4311
4501
  function useCfgAccountsProfilePartialUpdate(config) {
4312
- return useSWRMutation12(
4502
+ return useSWRMutation14(
4313
4503
  ["cfg_accounts_profile_partial_update"],
4314
4504
  async (_key, { arg }) => {
4315
4505
  const res = await CfgAccountsProfile.cfgAccountsProfilePartialUpdate({ ...arg, throwOnError: true });
@@ -4359,12 +4549,12 @@ __name(useCfgAccountsProfilePartialUpdate, "useCfgAccountsProfilePartialUpdate")
4359
4549
  import useSWR5 from "swr";
4360
4550
 
4361
4551
  // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsProfileUpdatePartialUpdate.ts
4362
- import useSWRMutation13 from "swr/mutation";
4552
+ import useSWRMutation15 from "swr/mutation";
4363
4553
 
4364
4554
  // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsProfileUpdateUpdate.ts
4365
- import useSWRMutation14 from "swr/mutation";
4555
+ import useSWRMutation16 from "swr/mutation";
4366
4556
  function useCfgAccountsProfileUpdateUpdate(config) {
4367
- return useSWRMutation14(
4557
+ return useSWRMutation16(
4368
4558
  ["cfg_accounts_profile_update_update"],
4369
4559
  async (_key, { arg }) => {
4370
4560
  const res = await CfgAccountsProfile.cfgAccountsProfileUpdateUpdate({ ...arg, throwOnError: true });
@@ -4411,12 +4601,12 @@ function useCfgAccountsProfileUpdateUpdate(config) {
4411
4601
  __name(useCfgAccountsProfileUpdateUpdate, "useCfgAccountsProfileUpdateUpdate");
4412
4602
 
4413
4603
  // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsTokenBlacklistCreate.ts
4414
- import useSWRMutation15 from "swr/mutation";
4604
+ import useSWRMutation17 from "swr/mutation";
4415
4605
 
4416
4606
  // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsTokenCreate.ts
4417
- import useSWRMutation16 from "swr/mutation";
4607
+ import useSWRMutation18 from "swr/mutation";
4418
4608
  function useCfgAccountsTokenCreate(config) {
4419
- return useSWRMutation16(
4609
+ return useSWRMutation18(
4420
4610
  ["cfg_accounts_token_create"],
4421
4611
  async (_key, { arg }) => {
4422
4612
  const res = await CfgAccountsAuth.cfgAccountsTokenCreate({ ...arg, throwOnError: true });
@@ -4463,7 +4653,7 @@ function useCfgAccountsTokenCreate(config) {
4463
4653
  __name(useCfgAccountsTokenCreate, "useCfgAccountsTokenCreate");
4464
4654
 
4465
4655
  // src/_api/generated/_cfg_accounts/hooks/useCfgAccountsTokenRefreshCreate.ts
4466
- import useSWRMutation17 from "swr/mutation";
4656
+ import useSWRMutation19 from "swr/mutation";
4467
4657
 
4468
4658
  // src/auth/context/AccountsContext.tsx
4469
4659
  import { jsx } from "react/jsx-runtime";
@@ -4486,13 +4676,13 @@ function AccountsProvider({ children }) {
4486
4676
  });
4487
4677
  const [isLoadingProfile, setIsLoadingProfile] = useState10(false);
4488
4678
  const [profileError, setProfileError] = useState10(null);
4489
- const profileRef = useRef5(profile);
4490
- const isLoadingRef = useRef5(false);
4491
- const fetchSeqRef = useRef5(0);
4492
- useEffect5(() => {
4679
+ const profileRef = useRef6(profile);
4680
+ const isLoadingRef = useRef6(false);
4681
+ const fetchSeqRef = useRef6(0);
4682
+ useEffect6(() => {
4493
4683
  profileRef.current = profile;
4494
4684
  }, [profile]);
4495
- useEffect5(() => {
4685
+ useEffect6(() => {
4496
4686
  isLoadingRef.current = isLoadingProfile;
4497
4687
  }, [isLoadingProfile]);
4498
4688
  const { trigger: triggerProfileUpdate } = useCfgAccountsProfileUpdateUpdate();
@@ -4501,7 +4691,7 @@ function AccountsProvider({ children }) {
4501
4691
  const { trigger: triggerOtpRequest } = useCfgAccountsOtpRequestCreate();
4502
4692
  const { trigger: triggerOtpVerify } = useCfgAccountsOtpVerifyCreate();
4503
4693
  const { trigger: triggerPasswordLogin } = useCfgAccountsTokenCreate();
4504
- const refreshProfile = useCallback11(async (options) => {
4694
+ const refreshProfile = useCallback12(async (options) => {
4505
4695
  const { callerId, force } = options || {};
4506
4696
  if (!hasApiOrigin()) {
4507
4697
  authLogger.debug(`No API origin configured, skipping profile fetch (caller: ${callerId})`);
@@ -4535,26 +4725,26 @@ function AccountsProvider({ children }) {
4535
4725
  }
4536
4726
  }
4537
4727
  }, []);
4538
- const updateProfile = useCallback11(async (data) => {
4728
+ const updateProfile = useCallback12(async (data) => {
4539
4729
  await triggerProfileUpdate({ body: data });
4540
4730
  const user = await refreshProfile({ callerId: "updateProfile", force: true });
4541
4731
  return user;
4542
4732
  }, [triggerProfileUpdate, refreshProfile]);
4543
- const partialUpdateProfile = useCallback11(async (data) => {
4733
+ const partialUpdateProfile = useCallback12(async (data) => {
4544
4734
  await triggerProfilePartialUpdate({ body: data });
4545
4735
  const user = await refreshProfile({ callerId: "partialUpdateProfile", force: true });
4546
4736
  return user;
4547
4737
  }, [triggerProfilePartialUpdate, refreshProfile]);
4548
- const uploadAvatar = useCallback11(async (avatar) => {
4738
+ const uploadAvatar = useCallback12(async (avatar) => {
4549
4739
  await triggerAvatar({ body: { avatar } });
4550
4740
  const user = await refreshProfile({ callerId: "uploadAvatar", force: true });
4551
4741
  return user;
4552
4742
  }, [triggerAvatar, refreshProfile]);
4553
- const requestOTP = useCallback11(async (data) => {
4743
+ const requestOTP = useCallback12(async (data) => {
4554
4744
  const result = await triggerOtpRequest({ body: data });
4555
4745
  return result;
4556
4746
  }, [triggerOtpRequest]);
4557
- const settleLoginEnvelope = useCallback11(async (result, callerId) => {
4747
+ const settleLoginEnvelope = useCallback12(async (result, callerId) => {
4558
4748
  if (result.requires_2fa && result.session_id) {
4559
4749
  authLogger.info("2FA required, session:", result.session_id);
4560
4750
  return;
@@ -4568,17 +4758,17 @@ function AccountsProvider({ children }) {
4568
4758
  }
4569
4759
  }
4570
4760
  }, [refreshProfile]);
4571
- const verifyOTP = useCallback11(async (data) => {
4761
+ const verifyOTP = useCallback12(async (data) => {
4572
4762
  const result = await triggerOtpVerify({ body: data });
4573
4763
  await settleLoginEnvelope(result, "verifyOTP");
4574
4764
  return result;
4575
4765
  }, [triggerOtpVerify, settleLoginEnvelope]);
4576
- const loginWithPassword = useCallback11(async (data) => {
4766
+ const loginWithPassword = useCallback12(async (data) => {
4577
4767
  const result = await triggerPasswordLogin({ body: data });
4578
4768
  await settleLoginEnvelope(result, "loginWithPassword");
4579
4769
  return result;
4580
4770
  }, [triggerPasswordLogin, settleLoginEnvelope]);
4581
- const logout = useCallback11(() => {
4771
+ const logout = useCallback12(() => {
4582
4772
  const refresh = auth.getRefreshToken();
4583
4773
  if (refresh) {
4584
4774
  CfgAccountsAuth.cfgAccountsTokenBlacklistCreate({ body: { refresh } }).catch(() => {
@@ -4590,7 +4780,7 @@ function AccountsProvider({ children }) {
4590
4780
  setProfileError(null);
4591
4781
  clearProfileCache();
4592
4782
  }, []);
4593
- const value = useMemo2(() => ({
4783
+ const value = useMemo3(() => ({
4594
4784
  profile,
4595
4785
  isLoadingProfile,
4596
4786
  profileError,
@@ -4652,28 +4842,28 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
4652
4842
  EMAIL_STORAGE_KEY,
4653
4843
  null
4654
4844
  );
4655
- const routes = useMemo3(() => resolveAuthRoutes(config?.routes), [config?.routes]);
4656
- const routesRef = useRef6(routes);
4657
- useEffect6(() => {
4845
+ const routes = useMemo4(() => resolveAuthRoutes(config?.routes), [config?.routes]);
4846
+ const routesRef = useRef7(routes);
4847
+ useEffect7(() => {
4658
4848
  routesRef.current = routes;
4659
4849
  }, [routes]);
4660
4850
  const redirectManager = useAuthRedirectManager({
4661
4851
  fallbackUrl: routes.defaultCallback,
4662
4852
  clearOnUse: true
4663
4853
  });
4664
- const configRef = useRef6(config);
4665
- useEffect6(() => {
4854
+ const configRef = useRef7(config);
4855
+ useEffect7(() => {
4666
4856
  configRef.current = config;
4667
4857
  }, [config]);
4668
- const accountsRef = useRef6(accounts);
4669
- useEffect6(() => {
4858
+ const accountsRef = useRef7(accounts);
4859
+ useEffect7(() => {
4670
4860
  accountsRef.current = accounts;
4671
4861
  }, [accounts]);
4672
- const pendingManualNavRef = useRef6(false);
4862
+ const pendingManualNavRef = useRef7(false);
4673
4863
  const [profileSettled, setProfileSettled] = useState11(false);
4674
4864
  const hasProfile = Boolean(accounts.profile);
4675
- const profileAttemptedRef = useRef6(false);
4676
- useEffect6(() => {
4865
+ const profileAttemptedRef = useRef7(false);
4866
+ useEffect7(() => {
4677
4867
  if (!isAuthenticated) {
4678
4868
  profileAttemptedRef.current = false;
4679
4869
  const hasTokens = Boolean(auth.getToken() || auth.getRefreshToken());
@@ -4701,8 +4891,8 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
4701
4891
  };
4702
4892
  }, [isAuthenticated, hasProfile]);
4703
4893
  const isLoading = !profileSettled;
4704
- const expiredHandledRef = useRef6(false);
4705
- useEffect6(() => {
4894
+ const expiredHandledRef = useRef7(false);
4895
+ useEffect7(() => {
4706
4896
  const unsubscribe = auth.onSessionExpired(() => {
4707
4897
  if (expiredHandledRef.current) return;
4708
4898
  expiredHandledRef.current = true;
@@ -4715,7 +4905,7 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
4715
4905
  });
4716
4906
  return unsubscribe;
4717
4907
  }, [router]);
4718
- useEffect6(() => {
4908
+ useEffect7(() => {
4719
4909
  if (!isAuthenticated || pendingManualNavRef.current) return;
4720
4910
  if (pathname === routes.auth && !queryParams.get("flow")) {
4721
4911
  const saved = redirectManager.hasRedirect() ? redirectManager.getRedirect() : null;
@@ -4723,7 +4913,7 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
4723
4913
  router.push(saved || routes.defaultCallback);
4724
4914
  }
4725
4915
  }, [isAuthenticated, pathname, queryParams, routes, router, redirectManager]);
4726
- const loadCurrentProfile = useCallback12(async (callerId) => {
4916
+ const loadCurrentProfile = useCallback13(async (callerId) => {
4727
4917
  if (!auth.isAuthenticated()) {
4728
4918
  throw new Error("No valid authentication token");
4729
4919
  }
@@ -4731,7 +4921,7 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
4731
4921
  callerId: callerId || "AuthContext.loadCurrentProfile"
4732
4922
  });
4733
4923
  }, []);
4734
- const checkAuthAndRedirect = useCallback12(async () => {
4924
+ const checkAuthAndRedirect = useCallback13(async () => {
4735
4925
  if (auth.isAuthenticated()) {
4736
4926
  try {
4737
4927
  await loadCurrentProfile("checkAuthAndRedirect");
@@ -4743,7 +4933,7 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
4743
4933
  router.push(routesRef.current.defaultAuthCallback);
4744
4934
  }
4745
4935
  }, [loadCurrentProfile, router]);
4746
- const requestOTP = useCallback12(
4936
+ const requestOTP = useCallback13(
4747
4937
  async (identifier, sourceUrl, consent) => {
4748
4938
  auth.clearSession();
4749
4939
  try {
@@ -4785,7 +4975,7 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
4785
4975
  },
4786
4976
  []
4787
4977
  );
4788
- const verifyOTP = useCallback12(
4978
+ const verifyOTP = useCallback13(
4789
4979
  async (identifier, otpCode, sourceUrl, redirectUrl, skipRedirect) => {
4790
4980
  try {
4791
4981
  pendingManualNavRef.current = Boolean(skipRedirect);
@@ -4845,7 +5035,7 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
4845
5035
  },
4846
5036
  [setStoredEmail, redirectManager, router]
4847
5037
  );
4848
- const login = useCallback12(
5038
+ const login = useCallback13(
4849
5039
  async (email, password, options) => {
4850
5040
  const { redirectUrl, skipRedirect } = options || {};
4851
5041
  try {
@@ -4910,7 +5100,7 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
4910
5100
  },
4911
5101
  [setStoredEmail, redirectManager, router]
4912
5102
  );
4913
- const refreshToken = useCallback12(async () => {
5103
+ const refreshToken = useCallback13(async () => {
4914
5104
  const access = await auth.refreshNow();
4915
5105
  if (access) {
4916
5106
  Analytics.event("auth_token_refresh" /* AUTH_TOKEN_REFRESH */, {
@@ -4923,7 +5113,7 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
4923
5113
  });
4924
5114
  return { success: false, message: "Error refreshing token" };
4925
5115
  }, []);
4926
- const logout = useCallback12(() => {
5116
+ const logout = useCallback13(() => {
4927
5117
  Analytics.event("auth_logout" /* AUTH_LOGOUT */, {
4928
5118
  category: "auth" /* AUTH */
4929
5119
  });
@@ -4932,21 +5122,21 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
4932
5122
  }, [router]);
4933
5123
  const user = accounts.profile ?? null;
4934
5124
  const isAdminUser = Boolean(user?.is_staff || user?.is_superuser);
4935
- useEffect6(() => {
5125
+ useEffect7(() => {
4936
5126
  applyRoleLogPolicy({ isAdmin: isAdminUser });
4937
5127
  }, [isAdminUser]);
4938
- const updateProfile = useCallback12(
5128
+ const updateProfile = useCallback13(
4939
5129
  async (data) => {
4940
5130
  const result = await accountsRef.current.partialUpdateProfile(data);
4941
5131
  return result;
4942
5132
  },
4943
5133
  []
4944
5134
  );
4945
- const uploadAvatar = useCallback12(async (avatar) => {
5135
+ const uploadAvatar = useCallback13(async (avatar) => {
4946
5136
  const result = await accountsRef.current.uploadAvatar(avatar);
4947
5137
  return result;
4948
5138
  }, []);
4949
- const value = useMemo3(
5139
+ const value = useMemo4(
4950
5140
  () => ({
4951
5141
  user,
4952
5142
  isLoading,
@@ -5106,8 +5296,10 @@ export {
5106
5296
  AnalyticsEvent,
5107
5297
  AuthContext_default as AuthContext,
5108
5298
  AuthProvider,
5299
+ OAUTH_PROVIDER_IDS,
5109
5300
  authLogger,
5110
5301
  beginTwoFactorChallenge,
5302
+ clearOAuthAttempt,
5111
5303
  clearProfileCache,
5112
5304
  consumeSavedRedirect,
5113
5305
  decodeBase64,
@@ -5119,10 +5311,12 @@ export {
5119
5311
  hasValidCache,
5120
5312
  isAllowedAuthPath,
5121
5313
  isForbidden,
5314
+ isOAuthProviderId,
5122
5315
  logAuthFailure,
5123
5316
  logger,
5124
5317
  normalizePath,
5125
5318
  peekSavedRedirect,
5319
+ readOAuthFailure,
5126
5320
  resolveAuthError,
5127
5321
  resolveGuardIsAuthenticated,
5128
5322
  resolveGuardIsLoading,
@@ -5141,6 +5335,8 @@ export {
5141
5335
  useDeleteAccount,
5142
5336
  useGithubAuth,
5143
5337
  useLocalStorage,
5338
+ useOAuthLogin,
5339
+ useOAuthProviders,
5144
5340
  useQueryParams,
5145
5341
  useSession,
5146
5342
  useSessionStorage,