File size: 3,022 Bytes
85270f9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
"use client";

import { refreshSession } from "@/lib/api";
import { buildSessionExpiresAt, clearStoredAuthSession, getStoredAuthSession, setStoredAuthSession, type StoredAuthSession } from "@/store/auth";

const VALIDATION_CACHE_MS = 10_000;
let cachedSession: StoredAuthSession | null = null;
let cachedAt = 0;
let validationPromise: Promise<StoredAuthSession | null> | null = null;
let validationKey = "";

function isUnauthorizedError(error: unknown) {
  if (!error || typeof error !== "object") {
    return false;
  }
  const item = error as { status?: unknown };
  return item.status === 401;
}

export async function getValidatedAuthSession(options: { force?: boolean } = {}): Promise<StoredAuthSession | null> {
  const storedSession = await getStoredAuthSession();
  if (!storedSession) {
    cachedSession = null;
    cachedAt = 0;
    return null;
  }

  const now = Date.now();
  if (!options.force && cachedSession?.key === storedSession.key && now - cachedAt < VALIDATION_CACHE_MS) {
    return cachedSession;
  }

  if (validationPromise && validationKey === storedSession.key) {
    return validationPromise;
  }

  validationKey = storedSession.key;
  validationPromise = validateStoredSession(storedSession).finally(() => {
    validationPromise = null;
    validationKey = "";
  });
  return validationPromise;
}

async function validateStoredSession(storedSession: StoredAuthSession): Promise<StoredAuthSession | null> {
  try {
    const data = await refreshSession(storedSession.key);
    const nextSession: StoredAuthSession = {
      key: storedSession.key,
      role: data.role,
      subjectId: data.subject_id,
      name: data.name,
      accountPoolEnabled: Boolean(data.account_pool_enabled),
      imageMemoryButtonEnabled: data.image_memory_button_enabled === true,
      imageShareEvidenceEnabled: data.image_share_evidence_enabled === true,
      wechatOpenid: storedSession.wechatOpenid,
      expiresAt: storedSession.expiresAt || buildSessionExpiresAt(data.login_session_duration_hours),
    };
    const sessionChanged =
      storedSession.role !== nextSession.role
      || storedSession.subjectId !== nextSession.subjectId
      || storedSession.name !== nextSession.name
      || storedSession.accountPoolEnabled !== nextSession.accountPoolEnabled
      || storedSession.imageMemoryButtonEnabled !== nextSession.imageMemoryButtonEnabled
      || storedSession.imageShareEvidenceEnabled !== nextSession.imageShareEvidenceEnabled
      || storedSession.wechatOpenid !== nextSession.wechatOpenid
      || storedSession.expiresAt !== nextSession.expiresAt;
    if (sessionChanged) {
      await setStoredAuthSession(nextSession);
    }
    cachedSession = nextSession;
    cachedAt = Date.now();
    return nextSession;
  } catch (error) {
    if (isUnauthorizedError(error)) {
      await clearStoredAuthSession();
      cachedSession = null;
      cachedAt = 0;
      return null;
    }
    cachedSession = storedSession;
    cachedAt = Date.now();
    return storedSession;
  }
}