@djangocfg/api 2.1.450 → 2.1.453

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/dist/auth.cjs CHANGED
@@ -46,9 +46,18 @@ __export(auth_exports, {
46
46
  formatAuthError: () => formatAuthError,
47
47
  getCacheMetadata: () => getCacheMetadata,
48
48
  getCachedProfile: () => getCachedProfile,
49
+ getTokenExpiry: () => getTokenExpiry,
49
50
  hasValidCache: () => hasValidCache,
51
+ isAllowedAuthPath: () => isAllowedAuthPath,
52
+ isTokenExpired: () => isTokenExpired,
53
+ isTokenExpiringSoon: () => isTokenExpiringSoon,
50
54
  logger: () => logger,
55
+ nextAuthEvaluationDelay: () => nextAuthEvaluationDelay,
56
+ normalizePath: () => normalizePath,
57
+ resolveGuardIsAuthenticated: () => resolveGuardIsAuthenticated,
58
+ resolveGuardIsLoading: () => resolveGuardIsLoading,
51
59
  setCachedProfile: () => setCachedProfile,
60
+ shouldRedirectToAuth: () => shouldRedirectToAuth,
52
61
  useAccountsContext: () => useAccountsContext,
53
62
  useAuth: () => useAuth,
54
63
  useAuthForm: () => useAuthForm,
@@ -348,21 +357,28 @@ var authLogger = logger.withTag("auth");
348
357
  // src/auth/hooks/useAutoAuth.ts
349
358
  var import_navigation3 = require("next/navigation");
350
359
  var import_react5 = require("react");
360
+
361
+ // src/auth/utils/path.ts
351
362
  var normalizePath = /* @__PURE__ */ __name((path) => {
352
363
  if (!path) return "";
353
364
  const withoutLocale = path.replace(/^\/[a-z]{2}(?=\/|$)/, "");
354
365
  const trimmed = withoutLocale.replace(/\/+$/, "");
355
366
  return trimmed || "/";
356
367
  }, "normalizePath");
368
+ var isAllowedAuthPath = /* @__PURE__ */ __name((pathname, allowedPaths) => {
369
+ const normalized = normalizePath(pathname);
370
+ return allowedPaths.some(
371
+ (p) => normalized === p || normalized.startsWith(p + "/")
372
+ );
373
+ }, "isAllowedAuthPath");
374
+
375
+ // src/auth/hooks/useAutoAuth.ts
357
376
  var useAutoAuth = /* @__PURE__ */ __name((options = {}) => {
358
377
  const { onOTPDetected, cleanupUrl = true, allowedPaths = ["/auth"] } = options;
359
378
  const queryParams = useQueryParams();
360
379
  const pathname = (0, import_navigation3.usePathname)();
361
380
  const router = useCfgRouter();
362
- const normalizedPath = normalizePath(pathname);
363
- const isAllowedPath = allowedPaths.some(
364
- (path) => normalizedPath === path || normalizedPath.startsWith(path + "/")
365
- );
381
+ const isAllowedPath = isAllowedAuthPath(pathname, allowedPaths);
366
382
  const queryOtp = queryParams.get("otp") || "";
367
383
  const queryEmail = queryParams.get("email") || void 0;
368
384
  const hasOTP = !!queryOtp;
@@ -4002,6 +4018,30 @@ var useDeleteAccount = /* @__PURE__ */ __name(() => {
4002
4018
  };
4003
4019
  }, "useDeleteAccount");
4004
4020
 
4021
+ // src/auth/utils/guard.ts
4022
+ function resolveGuardIsLoading(s) {
4023
+ if (!s.mounted) return true;
4024
+ if (!s.requireAuth) return false;
4025
+ return s.authLoading || s.isRedirecting || !s.isAuthenticated;
4026
+ }
4027
+ __name(resolveGuardIsLoading, "resolveGuardIsLoading");
4028
+ function shouldRedirectToAuth(s) {
4029
+ return s.mounted && s.requireAuth && !s.authLoading && !s.isAuthenticated && !s.isRedirecting;
4030
+ }
4031
+ __name(shouldRedirectToAuth, "shouldRedirectToAuth");
4032
+ function resolveGuardIsAuthenticated(s) {
4033
+ return !s.requireAuth || s.isAuthenticated;
4034
+ }
4035
+ __name(resolveGuardIsAuthenticated, "resolveGuardIsAuthenticated");
4036
+ function nextAuthEvaluationDelay(accessExp, refreshExp, now) {
4037
+ const future = [accessExp, refreshExp].filter(
4038
+ (d) => d !== null && d > now
4039
+ );
4040
+ if (future.length === 0) return null;
4041
+ return Math.max(0, Math.min(...future) - now) + 1e3;
4042
+ }
4043
+ __name(nextAuthEvaluationDelay, "nextAuthEvaluationDelay");
4044
+
4005
4045
  // src/auth/context/AccountsContext.tsx
4006
4046
  var import_react16 = require("react");
4007
4047
 
@@ -4764,6 +4804,14 @@ var isSessionDeadOnBootstrap = /* @__PURE__ */ __name((accessToken, refreshToken
4764
4804
  const refreshDead = isTokenExpired(refreshToken, 0, now);
4765
4805
  return refreshDead;
4766
4806
  }, "isSessionDeadOnBootstrap");
4807
+ var isSessionAlive = /* @__PURE__ */ __name((now = Date.now()) => {
4808
+ if (typeof window === "undefined") return false;
4809
+ return !isSessionDeadOnBootstrap(
4810
+ CfgAccountsApi.getToken(),
4811
+ CfgAccountsApi.getRefreshToken(),
4812
+ now
4813
+ );
4814
+ }, "isSessionAlive");
4767
4815
  var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
4768
4816
  const accounts = useAccountsContext();
4769
4817
  ensureRefreshHandler();
@@ -4781,6 +4829,17 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
4781
4829
  const [initialized, setInitialized] = (0, import_react17.useState)(false);
4782
4830
  const [authTick, setAuthTick] = (0, import_react17.useState)(0);
4783
4831
  const bumpAuthTick = (0, import_react17.useCallback)(() => setAuthTick((t) => t + 1), []);
4832
+ (0, import_react17.useEffect)(() => {
4833
+ if (typeof window === "undefined") return;
4834
+ const delay = nextAuthEvaluationDelay(
4835
+ getTokenExpiry(CfgAccountsApi.getToken()),
4836
+ getTokenExpiry(CfgAccountsApi.getRefreshToken()),
4837
+ Date.now()
4838
+ );
4839
+ if (delay === null) return;
4840
+ const timer = setTimeout(bumpAuthTick, Math.min(delay, 2e9));
4841
+ return () => clearTimeout(timer);
4842
+ }, [authTick, bumpAuthTick]);
4784
4843
  const onUnauthorizedRef = (0, import_react17.useRef)(false);
4785
4844
  const router = useCfgRouter();
4786
4845
  const pathname = (0, import_navigation4.usePathname)();
@@ -5170,10 +5229,13 @@ var AuthProviderInternal = /* @__PURE__ */ __name(({ children, config }) => {
5170
5229
  () => ({
5171
5230
  user,
5172
5231
  isLoading,
5173
- // Consider authenticated if we have valid tokens, even without user profile.
5174
- // `authTick` (in deps) forces recompute after tokens are cleared/set, since
5175
- // token state lives in storage, not React state.
5176
- isAuthenticated: CfgAccountsApi.isAuthenticated(),
5232
+ // Authenticated iff the session is locally alive (access valid OR a usable
5233
+ // refresh token) validated by `exp`, NOT by mere token presence. This is
5234
+ // what makes the guard self-sufficient: an expired session reads as
5235
+ // unauthenticated WITHOUT waiting for a server 401 (which CSP / a hung
5236
+ // request / offline can swallow). `authTick` (in deps) forces recompute
5237
+ // after tokens are cleared/set, since token state lives in storage.
5238
+ isAuthenticated: isSessionAlive(),
5177
5239
  isAdminUser,
5178
5240
  loadCurrentProfile,
5179
5241
  checkAuthAndRedirect,