's'
This commit is contained in:
@@ -35,6 +35,8 @@ type RecoveryResult = {
|
|||||||
source?: string;
|
source?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const inflightEmailChecks = new Map<string, Promise<PayjsVipEmailResult | null>>();
|
||||||
|
|
||||||
const PAYJS_CHECK_BY_EMAIL_TIMEOUT =
|
const PAYJS_CHECK_BY_EMAIL_TIMEOUT =
|
||||||
Number(process.env.PAYJSAPI_CHECK_BY_EMAIL_TIMEOUT) || 20000;
|
Number(process.env.PAYJSAPI_CHECK_BY_EMAIL_TIMEOUT) || 20000;
|
||||||
const PAYJS_CHECK_BY_EMAIL_RETRIES =
|
const PAYJS_CHECK_BY_EMAIL_RETRIES =
|
||||||
@@ -62,6 +64,13 @@ async function checkVipByEmailFromPayjsapi(
|
|||||||
password: string,
|
password: string,
|
||||||
userId?: string
|
userId?: string
|
||||||
): Promise<PayjsVipEmailResult | null> {
|
): Promise<PayjsVipEmailResult | null> {
|
||||||
|
const inflightKey = `${email}::${userId || ""}`;
|
||||||
|
const existed = inflightEmailChecks.get(inflightKey);
|
||||||
|
if (existed) {
|
||||||
|
return existed;
|
||||||
|
}
|
||||||
|
|
||||||
|
const task = (async () => {
|
||||||
const payConfig = getPaymentConfig();
|
const payConfig = getPaymentConfig();
|
||||||
const primaryUrl = resolvePayApiUrl(request);
|
const primaryUrl = resolvePayApiUrl(request);
|
||||||
const localUrl = getLocalPayApiUrl();
|
const localUrl = getLocalPayApiUrl();
|
||||||
@@ -125,6 +134,14 @@ async function checkVipByEmailFromPayjsapi(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
})();
|
||||||
|
|
||||||
|
inflightEmailChecks.set(inflightKey, task);
|
||||||
|
try {
|
||||||
|
return await task;
|
||||||
|
} finally {
|
||||||
|
inflightEmailChecks.delete(inflightKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loginPocketBaseUser(
|
async function loginPocketBaseUser(
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ type PayjsVipResult = {
|
|||||||
email?: string;
|
email?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const inflightUserChecks = new Map<string, Promise<PayjsVipResult | null>>();
|
||||||
|
|
||||||
async function fetchPayjsVipWithRetry(
|
async function fetchPayjsVipWithRetry(
|
||||||
url: string,
|
url: string,
|
||||||
timeoutMs: number,
|
timeoutMs: number,
|
||||||
@@ -51,6 +53,12 @@ async function checkVipFromPayjsapi(
|
|||||||
request: NextRequest,
|
request: NextRequest,
|
||||||
userId: string
|
userId: string
|
||||||
): Promise<PayjsVipResult | null> {
|
): Promise<PayjsVipResult | null> {
|
||||||
|
const existed = inflightUserChecks.get(userId);
|
||||||
|
if (existed) {
|
||||||
|
return existed;
|
||||||
|
}
|
||||||
|
|
||||||
|
const task = (async () => {
|
||||||
try {
|
try {
|
||||||
const apiUrl = resolvePayApiUrl(request);
|
const apiUrl = resolvePayApiUrl(request);
|
||||||
const url = `${apiUrl}/nomadvip/check_vip?user_id=${encodeURIComponent(
|
const url = `${apiUrl}/nomadvip/check_vip?user_id=${encodeURIComponent(
|
||||||
@@ -95,6 +103,14 @@ async function checkVipFromPayjsapi(
|
|||||||
);
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
inflightUserChecks.set(userId, task);
|
||||||
|
try {
|
||||||
|
return await task;
|
||||||
|
} finally {
|
||||||
|
inflightUserChecks.delete(userId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function POST(request: NextRequest) {
|
export async function POST(request: NextRequest) {
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ const ANONYMOUS_USER_COOKIE = "nomadvip_anon_uid";
|
|||||||
const ANONYMOUS_USER_COOKIE_MAX_AGE = 60 * 60 * 24 * 30;
|
const ANONYMOUS_USER_COOKIE_MAX_AGE = 60 * 60 * 24 * 30;
|
||||||
const PAY_ORDER_COOKIE = "nomadvip_pay_order";
|
const PAY_ORDER_COOKIE = "nomadvip_pay_order";
|
||||||
const PAY_ORDER_MAX_AGE = 60 * 15;
|
const PAY_ORDER_MAX_AGE = 60 * 15;
|
||||||
|
const EMAIL_VERIFY_TS_KEY = "emailVerifyAt";
|
||||||
|
const EMAIL_VERIFY_COOLDOWN_MS = 60 * 1000;
|
||||||
|
|
||||||
function getStorage(key: string): string | null {
|
function getStorage(key: string): string | null {
|
||||||
if (typeof window === "undefined") return null;
|
if (typeof window === "undefined") return null;
|
||||||
@@ -174,6 +176,7 @@ export default function Home() {
|
|||||||
savePaidType("vip");
|
savePaidType("vip");
|
||||||
setUserEmail(normalizedEmail);
|
setUserEmail(normalizedEmail);
|
||||||
saveUserName(normalizedEmail);
|
saveUserName(normalizedEmail);
|
||||||
|
setStorage(EMAIL_VERIFY_TS_KEY, String(Date.now()));
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
[savePaidType, saveUserName]
|
[savePaidType, saveUserName]
|
||||||
@@ -485,7 +488,10 @@ export default function Home() {
|
|||||||
// 校验逻辑:有本地存储(登录资料+VIP)时优先使用并校验;无身份/VIP 时点击按钮直接进入支付,不校验
|
// 校验逻辑:有本地存储(登录资料+VIP)时优先使用并校验;无身份/VIP 时点击按钮直接进入支付,不校验
|
||||||
const anonymousCandidate = getStoredAnonymousUserId();
|
const anonymousCandidate = getStoredAnonymousUserId();
|
||||||
const hadStoredUserId = !!anonymousCandidate;
|
const hadStoredUserId = !!anonymousCandidate;
|
||||||
if (anonymousCandidate) {
|
const emailVerifiedAt = Number(getStorage(EMAIL_VERIFY_TS_KEY) || "0");
|
||||||
|
const skipAnonymousRecover =
|
||||||
|
!!(getStorage("emailLinked") === "1" && Date.now() - emailVerifiedAt < EMAIL_VERIFY_COOLDOWN_MS);
|
||||||
|
if (anonymousCandidate && !skipAnonymousRecover) {
|
||||||
const recovered = await tryRecoverByAnonymousUserId(anonymousCandidate);
|
const recovered = await tryRecoverByAnonymousUserId(anonymousCandidate);
|
||||||
if (recovered) {
|
if (recovered) {
|
||||||
setStorage("userId", anonymousCandidate);
|
setStorage("userId", anonymousCandidate);
|
||||||
|
|||||||
Reference in New Issue
Block a user