fix(auth): transfer WeChat id on merge; stop false phone prompts
CI / verify (pull_request) Has been cancelled
CI / verify (pull_request) Has been cancelled
Merge used to drop wxOpenId so OAuth created a new guest without phone every time. Now migrate WeChat identity, recover legacy merged openIds, return accountMerged and force page reload, and only soft-prompt when phone is truly unbound.
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import Taro from '@tarojs/taro';
|
import Taro from '@tarojs/taro';
|
||||||
import { captureIosJssdkEntryUrl } from '@dukang/weixin-sdk';
|
import { captureIosJssdkEntryUrl } from '@dukang/weixin-sdk';
|
||||||
import { useEffect, useRef } from 'react';
|
import { useEffect, useRef } from 'react';
|
||||||
import { finishLoginNavigate, goLogin } from '../lib/auth-nav';
|
import { finishLoginNavigate, forceReloadAfterAccountMerge, goLogin } from '../lib/auth-nav';
|
||||||
import { toast } from '../lib/api';
|
import { toast } from '../lib/api';
|
||||||
import { saveWechatLoginResult } from '../lib/pay-wechat';
|
import { saveWechatLoginResult } from '../lib/pay-wechat';
|
||||||
import { applyWechatShare } from '../lib/wechat-share';
|
import { applyWechatShare } from '../lib/wechat-share';
|
||||||
@@ -70,11 +70,16 @@ export default function WechatShareBootstrap() {
|
|||||||
if (!result) return;
|
if (!result) return;
|
||||||
if (saveWechatLoginResult(result)) {
|
if (saveWechatLoginResult(result)) {
|
||||||
toast('微信授权成功', 'success');
|
toast('微信授权成功', 'success');
|
||||||
|
const ret = returnFromLogin || params.get('return') || undefined;
|
||||||
|
if (result.accountMerged) {
|
||||||
|
forceReloadAfterAccountMerge(ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
returnFromLogin !== undefined ||
|
returnFromLogin !== undefined ||
|
||||||
currentPagePathWithQuery().includes('/pages/login/')
|
currentPagePathWithQuery().includes('/pages/login/')
|
||||||
) {
|
) {
|
||||||
finishLoginNavigate(returnFromLogin || params.get('return') || undefined);
|
finishLoginNavigate(ret);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import Taro from '@tarojs/taro';
|
import Taro from '@tarojs/taro';
|
||||||
import { ClientApp } from '@dukang/shared-types';
|
import { ClientApp } from '@dukang/shared-types';
|
||||||
import { goLogin } from './auth-nav';
|
import { goLogin, forceReloadAfterAccountMerge } from './auth-nav';
|
||||||
|
|
||||||
function resolveApiBase(): string {
|
function resolveApiBase(): string {
|
||||||
const origin =
|
const origin =
|
||||||
@@ -111,7 +111,13 @@ export async function request<T = unknown>(path: string, options: ReqOptions = {
|
|||||||
const stillCurrent = !!token && getToken() === token;
|
const stillCurrent = !!token && getToken() === token;
|
||||||
if (stillCurrent) {
|
if (stillCurrent) {
|
||||||
clearAuth();
|
clearAuth();
|
||||||
if (!isOnLoginPage()) redirectToLogin();
|
const mergedMsg = body?.message || '';
|
||||||
|
if (/账号已合并/.test(mergedMsg)) {
|
||||||
|
// 合并后旧 JWT 失效:强制刷新,不引导「重新登录」
|
||||||
|
forceReloadAfterAccountMerge();
|
||||||
|
} else if (!isOnLoginPage()) {
|
||||||
|
redirectToLogin();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
throw new Error(body?.message || '登录已过期,请重新登录');
|
throw new Error(body?.message || '登录已过期,请重新登录');
|
||||||
}
|
}
|
||||||
@@ -131,6 +137,8 @@ export function toast(title: string, icon: 'success' | 'error' | 'none' = 'none'
|
|||||||
export type SessionPayload = {
|
export type SessionPayload = {
|
||||||
accessToken: string;
|
accessToken: string;
|
||||||
refreshToken?: string;
|
refreshToken?: string;
|
||||||
|
phoneVerified?: boolean;
|
||||||
|
accountMerged?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UserProfile = {
|
export type UserProfile = {
|
||||||
|
|||||||
@@ -70,3 +70,46 @@ export function finishLoginNavigate(returnTo?: string) {
|
|||||||
|
|
||||||
Taro.reLaunch({ url: '/pages/home/index' });
|
Taro.reLaunch({ url: '/pages/home/index' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 账号合并后强制整页刷新,避免旧会话栈 / 旧用户缓存继续提示绑定手机号。
|
||||||
|
* H5:按当前路径推算出落地 URL 后 location.replace;小程序:reLaunch。
|
||||||
|
*/
|
||||||
|
export function forceReloadAfterAccountMerge(returnTo?: string) {
|
||||||
|
const raw = (returnTo || '').trim();
|
||||||
|
let target = '';
|
||||||
|
try {
|
||||||
|
target = raw ? decodeURIComponent(raw) : '';
|
||||||
|
} catch {
|
||||||
|
target = raw;
|
||||||
|
}
|
||||||
|
const pathOnly = target.split('?')[0];
|
||||||
|
const safePath =
|
||||||
|
pathOnly && pathOnly.startsWith('/pages/') && !pathOnly.includes('/pages/login')
|
||||||
|
? target
|
||||||
|
: '/pages/home/index';
|
||||||
|
const launchPath = safePath.split('?')[0];
|
||||||
|
|
||||||
|
if (process.env.TARO_ENV === 'h5' && typeof window !== 'undefined') {
|
||||||
|
const { origin, pathname, search } = window.location;
|
||||||
|
const marker = '/pages/';
|
||||||
|
const idx = pathname.indexOf(marker);
|
||||||
|
let href: string;
|
||||||
|
if (idx >= 0) {
|
||||||
|
href = `${origin}${pathname.slice(0, idx)}${safePath}`;
|
||||||
|
} else if (window.location.hash.includes('/pages/')) {
|
||||||
|
href = `${origin}${pathname}${search}#${safePath}`;
|
||||||
|
} else {
|
||||||
|
const base = pathname.replace(/\/$/, '') || '';
|
||||||
|
href = `${origin}${base}${safePath.startsWith('/') ? safePath : `/${safePath}`}`;
|
||||||
|
}
|
||||||
|
window.location.replace(href);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TAB_PAGES.has(launchPath)) {
|
||||||
|
Taro.reLaunch({ url: launchPath });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Taro.reLaunch({ url: safePath.startsWith('/') ? safePath : `/${safePath}` });
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
import PageShell from '../../components/PageShell';
|
import PageShell from '../../components/PageShell';
|
||||||
import WechatLoginButton from '../../components/WechatLoginButton';
|
import WechatLoginButton from '../../components/WechatLoginButton';
|
||||||
import { BRAND_LOGO_WIDE_URL } from '@dukang/shared-types';
|
import { BRAND_LOGO_WIDE_URL } from '@dukang/shared-types';
|
||||||
import { finishLoginNavigate } from '../../lib/auth-nav';
|
import { finishLoginNavigate, forceReloadAfterAccountMerge } from '../../lib/auth-nav';
|
||||||
import {
|
import {
|
||||||
bindWechatForUser,
|
bindWechatForUser,
|
||||||
loginWithWechat,
|
loginWithWechat,
|
||||||
@@ -126,6 +126,10 @@ export default function LoginPage() {
|
|||||||
.catch(() => {});
|
.catch(() => {});
|
||||||
}
|
}
|
||||||
toast(successToast, 'success');
|
toast(successToast, 'success');
|
||||||
|
if (data.accountMerged) {
|
||||||
|
forceReloadAfterAccountMerge(returnTo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
finishLoginNavigate(returnTo);
|
finishLoginNavigate(returnTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -168,7 +168,10 @@ export default function OrderConfirmPage() {
|
|||||||
if (!phonePromptSkipped.current) {
|
if (!phonePromptSkipped.current) {
|
||||||
try {
|
try {
|
||||||
const profile = await fetchUserProfile();
|
const profile = await fetchUserProfile();
|
||||||
if (!profile.phoneVerified) {
|
const phoneBound =
|
||||||
|
!!profile.phoneVerified ||
|
||||||
|
(!!profile.phone && /^1[3-9]\d{9}$/.test(String(profile.phone)));
|
||||||
|
if (!phoneBound) {
|
||||||
const { confirm, cancel } = await Taro.showModal({
|
const { confirm, cancel } = await Taro.showModal({
|
||||||
title: '建议绑定手机号',
|
title: '建议绑定手机号',
|
||||||
content: '绑定后便于订单通知与售后联系;也可跳过,不绑定也能继续下单。',
|
content: '绑定后便于订单通知与售后联系;也可跳过,不绑定也能继续下单。',
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ export interface WechatLoginResult {
|
|||||||
actorType?: string;
|
actorType?: string;
|
||||||
actorId?: string;
|
actorId?: string;
|
||||||
phoneVerified?: boolean;
|
phoneVerified?: boolean;
|
||||||
|
/** 本次登录/绑定触发了账号合并,客户端应强制刷新页面 */
|
||||||
|
accountMerged?: boolean;
|
||||||
needBindPhone?: boolean;
|
needBindPhone?: boolean;
|
||||||
wxSessionKey?: string;
|
wxSessionKey?: string;
|
||||||
user?: Record<string, unknown>;
|
user?: Record<string, unknown>;
|
||||||
|
|||||||
@@ -784,6 +784,15 @@ export class AuthService {
|
|||||||
}
|
}
|
||||||
if (guestId && guestId !== user.id) {
|
if (guestId && guestId !== user.id) {
|
||||||
user = await this.mergeUsers(guestId, user.id);
|
user = await this.mergeUsers(guestId, user.id);
|
||||||
|
this.analyticsService.trackOneSafe(user.id, clientApp, {
|
||||||
|
eventName: 'sms_login',
|
||||||
|
extraJson: { method: 'sms', accountMerged: true },
|
||||||
|
});
|
||||||
|
this.analyticsService.trackOneSafe(user.id, clientApp, {
|
||||||
|
eventName: 'login_success',
|
||||||
|
extraJson: { method: 'sms', accountMerged: true },
|
||||||
|
});
|
||||||
|
return this.buildSessionResponse(user, clientApp, user.deviceKey, { accountMerged: true });
|
||||||
} else {
|
} else {
|
||||||
await this.assertActiveUser(user.id);
|
await this.assertActiveUser(user.id);
|
||||||
}
|
}
|
||||||
@@ -817,6 +826,7 @@ export class AuthService {
|
|||||||
|
|
||||||
const existing = await this.prisma.user.findUnique({ where: { phone: normalizedPhone } });
|
const existing = await this.prisma.user.findUnique({ where: { phone: normalizedPhone } });
|
||||||
let targetUser: UserRow;
|
let targetUser: UserRow;
|
||||||
|
let accountMerged = false;
|
||||||
|
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
targetUser = await this.prisma.user.update({
|
targetUser = await this.prisma.user.update({
|
||||||
@@ -834,6 +844,14 @@ export class AuthService {
|
|||||||
targetUser = existing;
|
targetUser = existing;
|
||||||
} else {
|
} else {
|
||||||
targetUser = await this.mergeUsers(guest.id, existing.id);
|
targetUser = await this.mergeUsers(guest.id, existing.id);
|
||||||
|
accountMerged = true;
|
||||||
|
if (!targetUser.phoneVerifiedAt) {
|
||||||
|
targetUser = await this.prisma.user.update({
|
||||||
|
where: { id: targetUser.id },
|
||||||
|
data: { phoneVerifiedAt: new Date() },
|
||||||
|
include: { avatar: true },
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -841,7 +859,9 @@ export class AuthService {
|
|||||||
phone: this.maskPhone(normalizedPhone),
|
phone: this.maskPhone(normalizedPhone),
|
||||||
});
|
});
|
||||||
|
|
||||||
return this.buildSessionResponse(targetUser, clientApp, targetUser.deviceKey);
|
return this.buildSessionResponse(targetUser, clientApp, targetUser.deviceKey, {
|
||||||
|
accountMerged,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async loginStore(phone: string, code: string, clientApp: ClientApp) {
|
async loginStore(phone: string, code: string, clientApp: ClientApp) {
|
||||||
@@ -1061,8 +1081,14 @@ export class AuthService {
|
|||||||
|
|
||||||
// 微信登录不再强制绑定手机号;phoneVerified=false 也可签发会话,下单页仅提示可选绑定
|
// 微信登录不再强制绑定手机号;phoneVerified=false 也可签发会话,下单页仅提示可选绑定
|
||||||
if (user) {
|
if (user) {
|
||||||
let activeUser: UserRow =
|
let accountMerged = false;
|
||||||
guestId && guestId !== user.id ? await this.mergeUsers(guestId, user.id) : (user as UserRow);
|
let activeUser: UserRow;
|
||||||
|
if (guestId && guestId !== user.id) {
|
||||||
|
activeUser = await this.mergeUsers(guestId, user.id);
|
||||||
|
accountMerged = true;
|
||||||
|
} else {
|
||||||
|
activeUser = user as UserRow;
|
||||||
|
}
|
||||||
activeUser = await this.prisma.user.update({
|
activeUser = await this.prisma.user.update({
|
||||||
where: { id: activeUser.id },
|
where: { id: activeUser.id },
|
||||||
data: {
|
data: {
|
||||||
@@ -1076,13 +1102,54 @@ export class AuthService {
|
|||||||
}
|
}
|
||||||
this.analyticsService.trackOneSafe(activeUser.id, clientApp, {
|
this.analyticsService.trackOneSafe(activeUser.id, clientApp, {
|
||||||
eventName: 'wechat_login',
|
eventName: 'wechat_login',
|
||||||
extraJson: { platform },
|
extraJson: { platform, accountMerged },
|
||||||
});
|
});
|
||||||
this.analyticsService.trackOneSafe(activeUser.id, clientApp, {
|
this.analyticsService.trackOneSafe(activeUser.id, clientApp, {
|
||||||
eventName: 'login_success',
|
eventName: 'login_success',
|
||||||
extraJson: { method: 'wechat', platform },
|
extraJson: { method: 'wechat', platform, accountMerged },
|
||||||
});
|
});
|
||||||
return this.buildSessionResponse(activeUser, clientApp, activeUser.deviceKey);
|
return this.buildSessionResponse(activeUser, clientApp, activeUser.deviceKey, { accountMerged });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 历史脏数据:openId 仍在已合并访客上 → 跟随主账号并补挂微信身份
|
||||||
|
const legacyMerged = await this.prisma.user.findFirst({
|
||||||
|
where: { wxOpenId: session.openId, mergedIntoUserId: { not: null } },
|
||||||
|
select: { mergedIntoUserId: true },
|
||||||
|
});
|
||||||
|
if (legacyMerged?.mergedIntoUserId) {
|
||||||
|
let primary = await this.assertActiveUser(legacyMerged.mergedIntoUserId);
|
||||||
|
if (!primary.wxOpenId) {
|
||||||
|
primary = await this.prisma.user.update({
|
||||||
|
where: { id: primary.id },
|
||||||
|
data: {
|
||||||
|
wxOpenId: session.openId,
|
||||||
|
wxUnionId: session.unionId ?? primary.wxUnionId,
|
||||||
|
},
|
||||||
|
include: { avatar: true },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await this.prisma.user.updateMany({
|
||||||
|
where: { wxOpenId: session.openId, id: { not: primary.id } },
|
||||||
|
data: { wxOpenId: null, wxUnionId: null },
|
||||||
|
});
|
||||||
|
let accountMerged = false;
|
||||||
|
if (guestId && guestId !== primary.id) {
|
||||||
|
primary = await this.mergeUsers(guestId, primary.id);
|
||||||
|
accountMerged = true;
|
||||||
|
}
|
||||||
|
if (session.accessToken) {
|
||||||
|
const synced = await this.syncWechatUserProfile(primary.id, session.accessToken, session.openId);
|
||||||
|
if (synced) primary = synced as UserRow;
|
||||||
|
}
|
||||||
|
this.analyticsService.trackOneSafe(primary.id, clientApp, {
|
||||||
|
eventName: 'wechat_login',
|
||||||
|
extraJson: { platform, accountMerged, recoveredFromMerge: true },
|
||||||
|
});
|
||||||
|
this.analyticsService.trackOneSafe(primary.id, clientApp, {
|
||||||
|
eventName: 'login_success',
|
||||||
|
extraJson: { method: 'wechat', platform, accountMerged },
|
||||||
|
});
|
||||||
|
return this.buildSessionResponse(primary, clientApp, primary.deviceKey, { accountMerged });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (guestId) {
|
if (guestId) {
|
||||||
@@ -1201,9 +1268,29 @@ export class AuthService {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
targetUserId = updated.id;
|
targetUserId = updated.id;
|
||||||
|
let accountMerged = false;
|
||||||
if (guestId && guestId !== updated.id) {
|
if (guestId && guestId !== updated.id) {
|
||||||
targetUserId = (await this.mergeUsers(guestId, updated.id)).id;
|
targetUserId = (await this.mergeUsers(guestId, updated.id)).id;
|
||||||
|
accountMerged = true;
|
||||||
}
|
}
|
||||||
|
if (wxSession.accessToken) {
|
||||||
|
await this.syncWechatUserProfile(targetUserId, wxSession.accessToken, wxSession.openId);
|
||||||
|
}
|
||||||
|
const user = await this.assertActiveUser(targetUserId);
|
||||||
|
await this.redis.del(`wx:session:${wxSessionKey}`);
|
||||||
|
this.trackSmsUserEvent(user.id, clientApp, 'bind_phone', {
|
||||||
|
phone: this.maskPhone(phone),
|
||||||
|
method: 'wechat',
|
||||||
|
});
|
||||||
|
this.analyticsService.trackOneSafe(user.id, clientApp, {
|
||||||
|
eventName: 'wechat_phone',
|
||||||
|
extraJson: { method: 'bind_phone', accountMerged },
|
||||||
|
});
|
||||||
|
this.analyticsService.trackOneSafe(user.id, clientApp, {
|
||||||
|
eventName: 'login_success',
|
||||||
|
extraJson: { method: 'wechat_bind', accountMerged },
|
||||||
|
});
|
||||||
|
return this.buildSessionResponse(user, clientApp, user.deviceKey, { accountMerged });
|
||||||
} else if (wxUser) {
|
} else if (wxUser) {
|
||||||
if (wxUser.phone && wxUser.phone !== phone) {
|
if (wxUser.phone && wxUser.phone !== phone) {
|
||||||
throw new BadRequestException('手机号已被其他账号占用');
|
throw new BadRequestException('手机号已被其他账号占用');
|
||||||
@@ -1531,6 +1618,30 @@ export class AuthService {
|
|||||||
throw new BadRequestException('目标账号无效');
|
throw new BadRequestException('目标账号无效');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 先迁微信身份到主账号,再清空访客,否则下次 OAuth 找不到 openId 又会建无手机号访客
|
||||||
|
const guestWxOpenId = guest.wxOpenId;
|
||||||
|
const guestWxUnionId = guest.wxUnionId;
|
||||||
|
if (guestWxOpenId || guestWxUnionId) {
|
||||||
|
await tx.user.update({
|
||||||
|
where: { id: guestId },
|
||||||
|
data: { wxOpenId: null, wxUnionId: null },
|
||||||
|
});
|
||||||
|
if (guestWxOpenId && !primary.wxOpenId) {
|
||||||
|
await tx.user.update({
|
||||||
|
where: { id: primaryId },
|
||||||
|
data: {
|
||||||
|
wxOpenId: guestWxOpenId,
|
||||||
|
wxUnionId: guestWxUnionId ?? primary.wxUnionId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else if (guestWxUnionId && !primary.wxUnionId) {
|
||||||
|
await tx.user.update({
|
||||||
|
where: { id: primaryId },
|
||||||
|
data: { wxUnionId: guestWxUnionId },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await tx.order.updateMany({ where: { userId: guestId }, data: { userId: primaryId } });
|
await tx.order.updateMany({ where: { userId: guestId }, data: { userId: primaryId } });
|
||||||
await tx.userAddress.updateMany({ where: { userId: guestId }, data: { userId: primaryId } });
|
await tx.userAddress.updateMany({ where: { userId: guestId }, data: { userId: primaryId } });
|
||||||
await tx.benefitCoupon.updateMany({ where: { userId: guestId }, data: { userId: primaryId } });
|
await tx.benefitCoupon.updateMany({ where: { userId: guestId }, data: { userId: primaryId } });
|
||||||
@@ -1588,12 +1699,34 @@ export class AuthService {
|
|||||||
await tx.user.update({ where: { id: primaryId }, data: { deviceKey: deviceKeyToTransfer } });
|
await tx.user.update({ where: { id: primaryId }, data: { deviceKey: deviceKeyToTransfer } });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!primary.avatarResourceId && guest.avatarResourceId) {
|
||||||
|
await tx.user.update({
|
||||||
|
where: { id: primaryId },
|
||||||
|
data: { avatarResourceId: guest.avatarResourceId },
|
||||||
|
});
|
||||||
|
await tx.user.update({
|
||||||
|
where: { id: guestId },
|
||||||
|
data: { avatarResourceId: null },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!primary.nickname || primary.nickname === '访客' || /^用户\d{4}$/.test(primary.nickname))
|
||||||
|
&& guest.nickname
|
||||||
|
&& guest.nickname !== '访客') {
|
||||||
|
await tx.user.update({
|
||||||
|
where: { id: primaryId },
|
||||||
|
data: { nickname: guest.nickname },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
await tx.user.update({
|
await tx.user.update({
|
||||||
where: { id: guestId },
|
where: { id: guestId },
|
||||||
data: {
|
data: {
|
||||||
mergedIntoUserId: primaryId,
|
mergedIntoUserId: primaryId,
|
||||||
status: 0,
|
status: 0,
|
||||||
deviceKey: null,
|
deviceKey: null,
|
||||||
|
wxOpenId: null,
|
||||||
|
wxUnionId: null,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1617,9 +1750,26 @@ export class AuthService {
|
|||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
private buildSessionResponse(user: UserRow, clientApp: ClientApp, deviceKey: string | null) {
|
private buildSessionResponse(
|
||||||
|
user: UserRow,
|
||||||
|
clientApp: ClientApp,
|
||||||
|
deviceKey: string | null,
|
||||||
|
extras?: { accountMerged?: boolean },
|
||||||
|
) {
|
||||||
const phoneVerified = !!user.phoneVerifiedAt;
|
const phoneVerified = !!user.phoneVerifiedAt;
|
||||||
return this.issueToken('USER', user.id, clientApp, phoneVerified, this.formatUserProfile(user), undefined, undefined, deviceKey);
|
return {
|
||||||
|
...this.issueToken(
|
||||||
|
'USER',
|
||||||
|
user.id,
|
||||||
|
clientApp,
|
||||||
|
phoneVerified,
|
||||||
|
this.formatUserProfile(user),
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
deviceKey,
|
||||||
|
),
|
||||||
|
...(extras?.accountMerged ? { accountMerged: true as const } : {}),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private isDefaultNickname(nickname: string | null | undefined) {
|
private isDefaultNickname(nickname: string | null | undefined) {
|
||||||
|
|||||||
Reference in New Issue
Block a user