feat: 登录设备管理与编辑器图片上传
- 新增登录设备列表与会话下线(ListLoginDevices/RevokeLoginDevice),按设备指纹识别当前会话 - Markdown 编辑器新增图片插入弹窗与图片上传(ImageInsertModal) - 实时总线、账号守卫与用户事件适配
This commit is contained in:
@@ -3,12 +3,15 @@
|
||||
// - 单条 WebSocket(浏览器握手自动携带 HttpOnly cookie 鉴权),后续群聊/通知/
|
||||
// 审核角标都复用本连接,按 message type 路由。
|
||||
// - 连接状态机 + 指数退避重连;应用层心跳(协议层 Ping 由浏览器自动应答)。
|
||||
// - 鉴权失效关闭码 4401 不自动重连(封禁/强制下线由 AccountGuard 统一处理)。
|
||||
// - 鉴权失效关闭码 4401 不自动重连;转一次 /api/me 探测(封禁走现有弹窗链路,
|
||||
// 被顶下线由 AccountGuard 弹"登录已失效",见 lib/api 的统一判定)。
|
||||
// - 在线集合:hello 帧给 staff 全量快照,之后 presence:update 增量维护。
|
||||
// - 群聊:进入群详情页调用 joinRoom(roomID) 订阅 chat:{id} 房间,
|
||||
// 重连后会自动重订当前已订阅集合;离开页面/退出群调用 leaveRoom。
|
||||
// - HTTP 仅作回前台 / 进页校准;实时靠 WS(通知、待审、主题、群聊未读)。
|
||||
|
||||
import { apiMe } from "./api";
|
||||
|
||||
export const RT_HELLO = "hello";
|
||||
export const RT_PONG = "pong";
|
||||
export const RT_SETTINGS_CHANGED = "settings:changed";
|
||||
@@ -20,6 +23,8 @@ export const RT_CHAT_UNREAD = "chat:unread";
|
||||
export const RT_NOTIFICATION_NEW = "notification:new";
|
||||
export const RT_FEED_CHANGED = "feed:changed";
|
||||
export const RT_MODERATION_CHANGED = "moderation:changed";
|
||||
// 登录态被顶/被剔除(其他浏览器登录、安全设置剔除设备),推 user:{id}
|
||||
export const RT_SESSION_REPLACED = "session:replaced";
|
||||
|
||||
export interface RtEnvelope<T = unknown> {
|
||||
type: string;
|
||||
@@ -323,10 +328,13 @@ class RealtimeClient {
|
||||
this.clearHeartbeat();
|
||||
if (this.ws === ws) this.ws = null;
|
||||
this.state = "closed";
|
||||
// 鉴权失效:账号封禁/角色变更导致 token_version 失效,
|
||||
// 不重连(强制下线/重新登录由现有 HTTP 拦截链路处理)
|
||||
// 鉴权失效:账号封禁/角色变更/会话被顶导致 claims 校验失效,
|
||||
// 不重连;探测一次登录态(封禁→现有弹窗链路;被顶→"登录已失效"提示)
|
||||
if (!this.wanted || ev.code === CLOSE_AUTH_INVALID) {
|
||||
this.wanted = false;
|
||||
if (ev.code === CLOSE_AUTH_INVALID) {
|
||||
void apiMe().catch(() => {});
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.scheduleReconnect();
|
||||
|
||||
Reference in New Issue
Block a user