@soundsright/user
Version:
soundsright user sdk
357 lines (356 loc) • 14.1 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UserEvent = void 0;
const events_1 = require("events");
const js_cookie_1 = __importDefault(require("js-cookie"));
const jwt_decode_1 = __importDefault(require("jwt-decode"));
const connector_1 = __importStar(require("@soundsright/connector"));
const utils_1 = require("@soundsright/utils");
const invite_1 = __importDefault(require("@soundsright/invite"));
const types_1 = require("./types");
__exportStar(require("./types"), exports);
const COOKIE_KEY_ACCESS_TOKEN = 'ACCESS_TOKEN';
const COOKIE_KEY_REFRESH_TOKEN = 'REFRESH_TOKEN';
const COOKIE_KEY_REMEMBER_USER = 'REMEMBER_USER';
const COOKIE_EXPIRES_DEFAULT = 7;
const ERROR_CODE_REFRESH_TOKEN_EXPIRED = 400001007;
const ERROR_CODE_ACCESS_TOKEN_EXPIRED = 400001006;
const ERROR_CODE_ACCESS_TOKEN_EMPTY = 400001008;
exports.UserEvent = {
TokenExpired: 'tokenExpired',
LoginSuccess: 'loginSuccess',
Logout: 'logout',
UserUpdate: 'userUpdate',
};
class User extends events_1.EventEmitter {
constructor(auth, service) {
super();
this.auth = auth;
this.service = service;
this.refreshing = null;
service.onBeforeRequest((options) => {
const headers = Object.assign(Object.assign({}, options.headers), { Authorization: this.accessToken || '' });
if (headers.refreshToken) {
headers.Authorization = '';
}
return Object.assign(Object.assign({}, options), { headers });
});
service.onBeforeResponse((req, res) => __awaiter(this, void 0, void 0, function* () {
if (res.code === ERROR_CODE_ACCESS_TOKEN_EXPIRED || res.code === ERROR_CODE_ACCESS_TOKEN_EMPTY) {
yield this.refresh().catch((e) => {
if (e instanceof types_1.UnauthorizedError) {
this.removeToken();
this.emit(exports.UserEvent.TokenExpired);
}
throw e;
});
const data = yield this.service.request(req);
return this.service.wrapSuccessResponse(data);
}
if (res.code === ERROR_CODE_REFRESH_TOKEN_EXPIRED) {
this.removeToken();
this.emit(exports.UserEvent.TokenExpired);
throw new types_1.UnauthorizedError();
}
return res;
}));
}
authLogin(authResult) {
return __awaiter(this, void 0, void 0, function* () {
const inviter = invite_1.default.getInviter();
const res = yield this.service.request({
url: '/ucenter/user/login',
method: 'post',
data: Object.assign(Object.assign({}, authResult), { inviter }),
});
this.updateToken(res);
const user = this.getCurrentUser();
this.emit(exports.UserEvent.LoginSuccess, user);
return user;
});
}
/**
* 通过第三方平台登录
* @param type - 第三方登录类型:'Google' | 'Facebook' | 'Twitter'
* @returns 用户信息
*/
loginByThirdPlatform(type) {
return __awaiter(this, void 0, void 0, function* () {
const res = yield this.auth.authByThirdPlatform(type);
return this.authLogin(res);
});
}
/**
* 通过钱包连接和签名登录
* @param options - 钱包授权的选项
* ```ts
* {
* connectType?: ConnectType枚举或"MetaMask"|"WalletConnect",
* signMessage?: 签名消息
* }
* @returns 用户信息
* ```
*/
loginByWallet(options) {
return __awaiter(this, void 0, void 0, function* () {
const res = yield this.auth.authByWallet(options);
return this.authLogin(res);
});
}
/**
* 通过cookie记录的token进行登录
* @returns 用户信息
*/
loginByCookie() {
return __awaiter(this, void 0, void 0, function* () {
this.accessToken = js_cookie_1.default.get(COOKIE_KEY_ACCESS_TOKEN);
this.refreshToken = js_cookie_1.default.get(COOKIE_KEY_REFRESH_TOKEN);
if (!this.accessToken) {
yield this.refresh();
}
const user = this.getCurrentUser();
this.emit(exports.UserEvent.LoginSuccess, user);
return user;
});
}
updateToken(res) {
this.accessToken = res.accessToken;
this.refreshToken = res.refreshToken;
const baseCookieOptions = (0, utils_1.getBaseCookieOptions)();
js_cookie_1.default.set(COOKIE_KEY_ACCESS_TOKEN, this.accessToken, baseCookieOptions);
js_cookie_1.default.set(COOKIE_KEY_REFRESH_TOKEN, this.refreshToken, Object.assign(Object.assign({}, baseCookieOptions), { expires: this.getRememberDays() || undefined }));
}
removeToken() {
this.refreshToken = undefined;
this.accessToken = undefined;
const baseCookieOptions = (0, utils_1.getBaseCookieOptions)();
js_cookie_1.default.remove(COOKIE_KEY_REFRESH_TOKEN, baseCookieOptions);
js_cookie_1.default.remove(COOKIE_KEY_ACCESS_TOKEN, baseCookieOptions);
}
/**
* 设置是否记住用户登录状态
* @param remember - 是否记住用户登录状态
* @param days - 记住的天数,默认为7天
*/
setRememberState(remember, days = COOKIE_EXPIRES_DEFAULT) {
var _a;
const domain = (_a = window.location.hostname.match(/[^.]+\.([a-zA-Z]+(:\d+)*)$/)) === null || _a === void 0 ? void 0 : _a[0];
if (remember && days > 0) {
js_cookie_1.default.set(COOKIE_KEY_REMEMBER_USER, days.toString(), { path: '/', domain, expires: 3650 });
}
else {
// cookie.remove(COOKIE_KEY_REMEMBER_USER); // alter:如果不需要默认记住登录态
js_cookie_1.default.set(COOKIE_KEY_REMEMBER_USER, '0', { path: '/', domain, expires: 3650 }); // alter:如果需要默认记住状态
}
}
/**
* 查询记住用户状态的天数
* @returns number,返回记住的天数。如果为0,则仅在Session期有效。
*/
getRememberDays() {
const remember = js_cookie_1.default.get(COOKIE_KEY_REMEMBER_USER);
// if (!remember) return 0; // alter:如果不需要默认记住登录态
if (!remember)
return COOKIE_EXPIRES_DEFAULT; // alter:如果需要默认记住状态
return +remember;
}
/**
* 查询是否记住用户的状态
* @returns boolean
*/
getRememberState() {
return !!this.getRememberDays();
}
_refresh() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.refreshToken) {
throw new types_1.UnauthorizedError();
}
const res = yield this.service.request({
url: '/ucenter/user/refreshToken',
method: 'post',
headers: {
Authorization: '',
refreshToken: this.refreshToken,
},
});
this.updateToken(res);
return res;
});
}
/**
* 刷新用户Token
* @returns
* ```ts
* { accessToken: string, refreshToken: string }
* ```
*/
refresh() {
return __awaiter(this, void 0, void 0, function* () {
if (this.refreshing)
return this.refreshing;
this.refreshing = this._refresh();
const res = yield this.refreshing;
this.refreshing = null;
return res;
});
}
/**
* 获取当前登录的用户基本信息
* @returns 包括 { UserCode, NickName, Picture, Email, Phone, WalletAddr, NewUser }
*/
getCurrentUser() {
if (!this.accessToken) {
return null;
}
try {
return (0, jwt_decode_1.default)(this.accessToken).userInfo;
}
catch (e) {
return null;
}
}
/**
* 用户退出
*/
logout() {
return __awaiter(this, void 0, void 0, function* () {
const refreshToken = this.refreshToken;
this.removeToken();
this.emit(exports.UserEvent.Logout);
if (refreshToken) {
yield this.service.post('/ucenter/user/logout', {}, {
refreshToken,
});
}
});
}
/**
* 查询用户是否登录
* @returns boolean
*/
isLogin() {
return !!this.accessToken;
}
/**
* 查询用户是否已经绑定钱包
* @returns boolean
*/
isWalletBound() {
if (!this.isLogin())
return false;
return !!this.getCurrentUser().WalletAddr;
}
authBind(authResult) {
return __awaiter(this, void 0, void 0, function* () {
const res = yield this.service.post('/ucenter/user/bindAccount', authResult);
this.updateToken(res);
const user = this.getCurrentUser();
this.emit(exports.UserEvent.UserUpdate, user);
return user;
});
}
/**
* 绑定第三方平台账号
* @param type - 第三方登录类型:'Google' | 'Facebook' | 'Twitter'
* @returns 用户信息
*/
bindThirdPlatform(type) {
return __awaiter(this, void 0, void 0, function* () {
const res = yield this.auth.authByThirdPlatform(type);
return this.authBind(res);
});
}
/**
* 通过钱包连接和签名绑定钱包
* @param options - 钱包授权的选项
* ```ts
* {
* connectType?: ConnectType枚举或"MetaMask"|"WalletConnect",
* signMessage?: 签名消息
* }
* @returns 用户信息
* ```
*/
bindWallet(options) {
return __awaiter(this, void 0, void 0, function* () {
const res = yield this.auth.authByWallet(options);
return this.authBind(res);
});
}
/**
* 检查用户是否具备执行合约的条件。若不符合条件,则抛出相应的异常 - 该方法应作为执行合约的前置检测方法(模板方法)
* Error类型有:
* - UnauthorizedError,用户未登录,需要弹出登录窗口
* - WalletNotBoundError,用户未绑定钱包,需要弹出绑定钱包
* - WalletNotConnectedError,用户未连接钱包,需要弹出钱包连接
* - WalletNotMatchError,用户已连接的钱包地址与绑定的钱包地址不匹配
* 可以使用try catch 来处理相应的错误,可以通过error.name 来方便的判定类型。
* 在项目中结合界面操作逻辑,对该方法做进一步封装
* ```ts
* try {
* sdk.user.checkUserWeb3Condition();
* } catch (e) {
* if(e.name === 'UnauthorizedError') {
* // do something
* }
* ...
* }
* ```
*/
checkUserWeb3Condition() {
if (!this.isLogin()) {
throw new types_1.UnauthorizedError();
}
const user = this.getCurrentUser();
if (!user.WalletAddr) {
throw new types_1.WalletNotBoundError();
}
const connector = connector_1.default.getInstance();
if (!connector.state.connected) {
throw new connector_1.WalletNotConnectedError();
}
if (connector.state.account.toLowerCase() !== user.WalletAddr.toLowerCase()) {
throw new types_1.WalletNotMatchError();
}
}
}
exports.default = User;