// src/query-login.ts import { Query } from "@kevisual/query"; import { setBaseResponse } from "@kevisual/query/query"; // src/login-cache.ts import { MyCache } from "@kevisual/cache"; var LoginCacheStore = class { cache; name; cacheData; constructor(name) { this.cache = new MyCache(name); this.cacheData = { loginUsers: [], user: void 0, id: void 0, accessToken: void 0, refreshToken: void 0 }; this.name = name; } /** * 设置缓存 * @param key * @param value * @returns */ async set(key, value) { await this.cache.set(key, value); return value; } /** * 删除缓存 */ async del() { await this.cache.del(); } get(key) { return this.cache.get(key); } async init() { this.cacheData = await this.get(this.name) || { loginUsers: [], user: null, id: null, accessToken: null, refreshToken: null }; } /** * 设置当前用户 * @param user */ async setLoginUser(user) { const has = this.cacheData.loginUsers.find((u) => u.id === user.id); if (has) { this.cacheData.loginUsers = this.cacheData?.loginUsers?.filter((u) => u?.id && u.id !== user.id); } this.cacheData.loginUsers.push(user); this.cacheData.user = user.user; this.cacheData.id = user.id; this.cacheData.accessToken = user.accessToken; this.cacheData.refreshToken = user.refreshToken; await this.set(this.name, this.cacheData); } getCurrentUser() { const cacheData = this.cacheData; return Promise.resolve(cacheData.user); } getCurrentUserList() { return Promise.resolve(this.cacheData.loginUsers.filter((u) => u?.id)); } getRefreshToken() { const cacheData = this.cacheData; return Promise.resolve(cacheData.refreshToken || ""); } getAccessToken() { const cacheData = this.cacheData; return Promise.resolve(cacheData.accessToken || ""); } async clearCurrentUser() { const user = await this.getCurrentUser(); const has = this.cacheData.loginUsers.find((u) => u.id === user.id); if (has) { this.cacheData.loginUsers = this.cacheData?.loginUsers?.filter((u) => u?.id && u.id !== user.id); } this.cacheData.user = void 0; this.cacheData.id = void 0; this.cacheData.accessToken = void 0; this.cacheData.refreshToken = void 0; await this.set(this.name, this.cacheData); } async clearAll() { this.cacheData.loginUsers = []; this.cacheData.user = void 0; this.cacheData.id = void 0; this.cacheData.accessToken = void 0; this.cacheData.refreshToken = void 0; await this.set(this.name, this.cacheData); } }; // src/query-login.ts var QueryLogin = class { query; cache; isBrowser; load; storage; onLoad; constructor(opts) { this.query = opts?.query || new Query(); this.cache = new LoginCacheStore("login"); this.isBrowser = opts?.isBrowser ?? true; this.init(); this.onLoad = opts?.onLoad; this.storage = opts?.storage || localStorage; } setQuery(query) { this.query = query; } async init() { await this.cache.init(); this.load = true; this.onLoad?.(); } async post(data, opts) { return this.query.post({ path: "user", ...data }, opts); } /** * 登录, * @param data * @returns */ async login(data) { const res = await this.post({ key: "login", ...data }); if (res.code === 200) { const { accessToken, refreshToken } = res?.data || {}; this.storage.setItem("token", accessToken || ""); await this.beforeSetLoginUser({ accessToken, refreshToken }); } return res; } /** * 登陆成功,需要获取用户信息进行缓存 * @param param0 */ async beforeSetLoginUser({ accessToken, refreshToken, check401 }) { if (accessToken && refreshToken) { const resUser = await this.getMe(accessToken, check401); if (resUser.code === 200) { const user = resUser.data; if (user) { this.cache.setLoginUser({ user, id: user.id, accessToken, refreshToken }); } else { console.error("\u767B\u5F55\u5931\u8D25"); } } } } async queryRefreshToken(refreshToken) { const _refreshToken = refreshToken || this.cache.getRefreshToken(); let data = { refreshToken: _refreshToken }; if (!_refreshToken) { await this.cache.clearCurrentUser(); return { code: 401, message: "\u8BF7\u5148\u767B\u5F55", data: {} }; } return this.post( { key: "refreshToken", data }, { afterResponse: async (response, ctx) => { setBaseResponse(response); return response; } } ); } /** * 检查401错误,并刷新token, 如果refreshToken存在,则刷新token, 否则返回401 * @param response * @param ctx * @param refetch * @returns */ async afterCheck401ToRefreshToken(response, ctx, refetch) { const that = this; if (response?.code === 401) { const hasRefreshToken = await that.cache.getRefreshToken(); if (hasRefreshToken) { const res = await that.queryRefreshToken(hasRefreshToken); if (res.code === 200) { const { accessToken, refreshToken } = res?.data || {}; that.storage.setItem("token", accessToken || ""); await that.beforeSetLoginUser({ accessToken, refreshToken, check401: false }); if (refetch && ctx && ctx.req && ctx.req.url && ctx.fetch) { await new Promise((resolve) => setTimeout(resolve, 1500)); const url = ctx.req?.url; const body = ctx.req?.body; const headers = ctx.req?.headers; const res2 = await ctx.fetch(url, { method: "POST", body, headers: { ...headers, Authorization: `Bearer ${accessToken}` } }); setBaseResponse(res2); return res2; } } else { that.storage.removeItem("token"); await that.cache.clearCurrentUser(); } return res; } } return response; } /** * 获取用户信息 * @param token * @returns */ async getMe(token, check401 = true) { const _token = token || this.storage.getItem("token"); const that = this; return that.post( { key: "me" }, { beforeRequest: async (config) => { if (config.headers) { config.headers["Authorization"] = `Bearer ${_token}`; } return config; }, afterResponse: async (response, ctx) => { if (response?.code === 401 && check401) { return await that.afterCheck401ToRefreshToken(response, ctx); } return response; } } ); } /** * 请求更新,切换用户, 使用switchUser * @param username * @returns */ async postSwitchUser(username) { return this.post({ key: "switchCheck", data: { username } }); } /** * 切换用户 * @param username * @returns */ async switchUser(username) { const localUserList = await this.cache.getCurrentUserList(); const user = localUserList.find((userItem) => userItem.user.username === username); if (user) { this.storage.setItem("token", user.accessToken || ""); await this.beforeSetLoginUser({ accessToken: user.accessToken, refreshToken: user.refreshToken }); return { code: 200, data: { accessToken: user.accessToken, refreshToken: user.refreshToken }, success: true, message: "\u5207\u6362\u7528\u6237\u6210\u529F" }; } const res = await this.postSwitchUser(username); if (res.code === 200) { const { accessToken, refreshToken } = res?.data || {}; this.storage.setItem("token", accessToken || ""); await this.beforeSetLoginUser({ accessToken, refreshToken }); } return res; } async logout() { this.storage.removeItem("token"); this.cache.del(); return this.post({ key: "logout" }); } async hasUser(username) { const that = this; return this.post( { path: "org", key: "hasUser", data: { username } }, { afterResponse: async (response, ctx) => { if (response?.code === 401) { const res = await that.afterCheck401ToRefreshToken(response, ctx, true); return res; } return response; } } ); } }; export { QueryLogin };