├── src ├── data │ ├── proxy.txt │ ├── users.txt │ ├── log.error.txt │ └── token.json ├── helpers │ ├── generator.js │ ├── delay.js │ ├── log.js │ ├── token.js │ ├── datetime.js │ └── file.js ├── services │ ├── daily.js │ ├── server.js │ ├── user.js │ ├── auth.js │ ├── http.js │ ├── task.js │ └── game.js └── run │ └── index.js ├── .gitignore ├── package.json ├── hướng_dẫn_sử_dụng.md ├── README.md └── yarn.lock /src/data/proxy.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/data/users.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/data/log.error.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/data/token.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node.js 2 | node_modules/ 3 | npm-debug.log* 4 | yarn-debug.log* 5 | yarn-error.log* 6 | 7 | #Data 8 | data/ 9 | 10 | # Logs 11 | logs 12 | *.log 13 | logs/ 14 | *.log 15 | npm-debug.log* 16 | yarn-debug.log* 17 | yarn-error.log* 18 | lerna-debug.log* 19 | .DS_Store -------------------------------------------------------------------------------- /src/helpers/generator.js: -------------------------------------------------------------------------------- 1 | class GeneratorHelper { 2 | constructor() {} 3 | 4 | randomInt(min, max) { 5 | return Math.floor(Math.random() * (max - min + 1)) + min; 6 | } 7 | } 8 | 9 | const generatorHelper = new GeneratorHelper(); 10 | export default generatorHelper; 11 | -------------------------------------------------------------------------------- /src/helpers/delay.js: -------------------------------------------------------------------------------- 1 | class DelayHelper { 2 | constructor() {} 3 | 4 | delay(seconds, msg = null, log = null) { 5 | if (msg) { 6 | log.log(msg); 7 | } 8 | return new Promise((resolve) => setTimeout(resolve, seconds * 1000)); 9 | } 10 | } 11 | 12 | const delayHelper = new DelayHelper(); 13 | export default delayHelper; 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "auto_major", 3 | "version": "0.0.6", 4 | "description": "Tool tự động làm airdrop Major", 5 | "type": "module", 6 | "main": "src/run/index.js", 7 | "scripts": { 8 | "start": "node src/run/index.js", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "keywords": [], 12 | "author": "ZuyDD", 13 | "license": "ISC", 14 | "dependencies": { 15 | "axios": "^1.7.2", 16 | "colors": "^1.4.0", 17 | "dayjs": "^1.11.12", 18 | "he": "^1.2.0", 19 | "https-proxy-agent": "^7.0.5", 20 | "inquirer": "^10.1.8", 21 | "ws": "^8.18.0", 22 | "yargs": "^17.7.2" 23 | }, 24 | "devDependencies": {} 25 | } 26 | -------------------------------------------------------------------------------- /src/helpers/log.js: -------------------------------------------------------------------------------- 1 | import colors from "colors"; 2 | 3 | export class LogHelper { 4 | constructor(index, userId) { 5 | this.index = index; 6 | this.userId = userId; 7 | this.ip = "🖥️"; 8 | } 9 | 10 | log(msg) { 11 | console.log( 12 | `[ No ${this.index} _ ID: ${this.userId} _ IP: ${this.ip} ] ${msg}` 13 | ); 14 | } 15 | 16 | logError(msg) { 17 | console.log( 18 | `[ No ${this.index} _ ID: ${this.userId} _ IP: ${this.ip} ] ${colors.red( 19 | msg 20 | )}` 21 | ); 22 | } 23 | 24 | logSuccess(msg) { 25 | console.log( 26 | `[ No ${this.index} _ ID: ${this.userId} _ IP: ${ 27 | this.ip 28 | } ] ${colors.green(msg)}` 29 | ); 30 | } 31 | 32 | updateIp(ip) { 33 | this.ip = ip; 34 | } 35 | } 36 | 37 | const logHelper = new LogHelper(); 38 | export default logHelper; 39 | -------------------------------------------------------------------------------- /src/services/daily.js: -------------------------------------------------------------------------------- 1 | import colors from "colors"; 2 | 3 | class DailyService { 4 | constructor() {} 5 | 6 | async getDataCheckin(user) { 7 | try { 8 | const { data } = await user.http.get("user-visits/streak/"); 9 | if (data) { 10 | return data; 11 | } 12 | } catch (error) { 13 | return null; 14 | } 15 | } 16 | 17 | async checkin(user) { 18 | // const dataCheckin = await this.getDataCheckin(user); 19 | try { 20 | const { data } = await user.http.post("user-visits/visit/", {}); 21 | if (data?.is_increased) { 22 | user.log.log(colors.green(`Checkin thành công`)); 23 | } else { 24 | user.log.log(colors.magenta("Đã checkin hôm nay")); 25 | } 26 | } catch (error) { 27 | user.log.logError(`Checkin thất bại: ${error.response?.data?.detail}`); 28 | return null; 29 | } 30 | } 31 | } 32 | 33 | const dailyService = new DailyService(); 34 | export default dailyService; 35 | -------------------------------------------------------------------------------- /src/helpers/token.js: -------------------------------------------------------------------------------- 1 | class TokenHelper { 2 | constructor() {} 3 | 4 | isExpired(token) { 5 | // Tách payload từ JWT token 6 | const base64Url = token.split(".")[1]; // Phần payload nằm ở phần giữa 7 | const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/"); // Thay đổi ký tự để đúng chuẩn base64 8 | 9 | // Giải mã base64 thành chuỗi JSON 10 | const jsonPayload = decodeURIComponent( 11 | atob(base64) 12 | .split("") 13 | .map(function (c) { 14 | return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2); 15 | }) 16 | .join("") 17 | ); 18 | 19 | // Chuyển chuỗi JSON thành đối tượng JavaScript 20 | const payload = JSON.parse(jsonPayload); 21 | 22 | // Lấy thông tin exp từ payload 23 | const exp = payload.exp; 24 | // Lấy thời gian hiện tại tính bằng giây 25 | const currentTime = Math.floor(Date.now() / 1000); 26 | // So sánh thời gian hết hạn với thời gian hiện tại 27 | return exp < currentTime; 28 | } 29 | } 30 | 31 | const tokenHelper = new TokenHelper(); 32 | export default tokenHelper; 33 | -------------------------------------------------------------------------------- /src/services/server.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import colors from "colors"; 3 | 4 | class Server { 5 | constructor() {} 6 | 7 | async getData() { 8 | try { 9 | const endpointDatabase = 10 | "https://raw.githubusercontent.com/zuydd/database/main/major.json"; 11 | const { data } = await axios.get(endpointDatabase); 12 | return data; 13 | } catch (error) { 14 | console.log(colors.red("Lấy dữ liệu server zuydd thất bại")); 15 | return null; 16 | } 17 | } 18 | 19 | async showNoti() { 20 | const database = await this.getData(); 21 | if (database && database.noti) { 22 | console.log(colors.blue("📢 Thông báo từ hệ thống")); 23 | console.log(database.noti); 24 | console.log(""); 25 | } 26 | } 27 | 28 | async checkVersion(curentVersion, database = null) { 29 | if (!database) { 30 | database = await this.getData(); 31 | } 32 | 33 | if (database && curentVersion !== database.ver) { 34 | console.log( 35 | colors.yellow( 36 | `🚀 Đã có phiên bản mới ${colors.blue( 37 | database.ver 38 | )}, tải ngay tại đây 👉 ${colors.blue( 39 | "https://github.com/zuydd/major" 40 | )}` 41 | ) 42 | ); 43 | console.log(""); 44 | } 45 | } 46 | } 47 | 48 | const server = new Server(); 49 | export default server; 50 | -------------------------------------------------------------------------------- /src/helpers/datetime.js: -------------------------------------------------------------------------------- 1 | import dayjs from "dayjs"; 2 | import duration from "dayjs/plugin/duration.js"; 3 | dayjs.extend(duration); 4 | 5 | class DatetimeHelper { 6 | constructor() {} 7 | 8 | formatDuration(seconds) { 9 | const durationObj = dayjs.duration(seconds, "seconds"); 10 | const hours = durationObj.hours(); 11 | const minutes = durationObj.minutes(); 12 | const secs = durationObj.seconds(); 13 | 14 | let result = ""; 15 | 16 | if (hours > 0) { 17 | result += `${hours} giờ `; 18 | } 19 | 20 | if (minutes > 0 || hours > 0) { 21 | result += `${minutes} phút `; 22 | } 23 | 24 | result += `${secs}s`; 25 | 26 | return result.trim(); 27 | } 28 | 29 | formatTime(seconds) { 30 | const hours = Math.floor(seconds / 3600); // Tính số giờ 31 | const minutes = Math.floor((seconds % 3600) / 60); // Tính số phút 32 | const remainingSeconds = seconds % 60; // Tính số giây còn lại 33 | 34 | let result = ""; 35 | 36 | if (hours > 0) { 37 | result += `${hours} giờ, `; 38 | } 39 | 40 | if (minutes > 0 || hours > 0) { 41 | // Nếu có phút hoặc có giờ 42 | result += `${minutes} phút, `; 43 | } 44 | 45 | result += `${remainingSeconds}s`; // Luôn luôn hiển thị giây 46 | 47 | return result.trim(); 48 | } 49 | } 50 | 51 | const datetimeHelper = new DatetimeHelper(); 52 | export default datetimeHelper; 53 | -------------------------------------------------------------------------------- /src/helpers/file.js: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import path from "path"; 3 | import { fileURLToPath } from "url"; 4 | 5 | class FileHelper { 6 | constructor() {} 7 | 8 | readFile(fileName) { 9 | const __filename = fileURLToPath(import.meta.url); 10 | const __dirname = path.dirname(__filename); 11 | 12 | const filePath = path.join(__dirname, "..", "data", fileName); 13 | 14 | const datas = fs.readFileSync(filePath, "utf8"); 15 | return datas; 16 | } 17 | 18 | writeFile(fileName, data) { 19 | const __filename = fileURLToPath(import.meta.url); 20 | const __dirname = path.dirname(__filename); 21 | 22 | const filePath = path.join(__dirname, "..", "data", fileName); 23 | 24 | fs.writeFileSync(filePath, data); 25 | } 26 | 27 | writeLog(fileName, data) { 28 | const __filename = fileURLToPath(import.meta.url); 29 | const __dirname = path.dirname(__filename); 30 | 31 | const filePath = path.join(__dirname, "..", "data", fileName); 32 | 33 | fs.appendFileSync(filePath, data + "\n"); 34 | } 35 | 36 | getTokenById(userId) { 37 | const tokens = JSON.parse(this.readFile("token.json")); 38 | return tokens[userId] || null; 39 | } 40 | 41 | saveToken(userId, token) { 42 | const tokens = JSON.parse(this.readFile("token.json")); 43 | tokens[userId] = token; 44 | const data = JSON.stringify(tokens, null, 4); 45 | this.writeFile("token.json", data); 46 | } 47 | } 48 | 49 | const fileHelper = new FileHelper(); 50 | export default fileHelper; 51 | -------------------------------------------------------------------------------- /hướng_dẫn_sử_dụng.md: -------------------------------------------------------------------------------- 1 | ** Link cập nhật tool và hướng dẫn chi tiết tại ** 2 | https://github.com/zuydd/blum 3 | 4 | **_ Hướng dẫn cài đặt _** 5 | 6 | - B1: Tải và giải nén tool 7 | - B2: Chạy lệnh: npm install tại thư mục chứa tool (thư mục có chứa file package.json) để cài đặt thư viện bổ trợ 8 | - B3: vào thư mục src -> data, nhập user hoặc query_id vào file users.txt và proxy vào file proxy.txt, không có proxy thì bỏ qua khỏi nhập 9 | 10 | **_ Các lệnh chức năng chạy tool _** 11 | 12 | - npm run start: Dùng để làm nhiệm vụ, điểm danh, chơi game,.... tóm lại game có gì là nó làm cái đó 13 | 14 | 🕹️ Các tính năng có trong tool: 15 | 16 | - tự động điểm danh hàng ngày 17 | - tự động làm nhiệm vụ 18 | - tự động chơi game khi tới giờ (các game có thể chơi: Hold Coin, Roulette, Swipe Coin, Durov) 19 | - nhận diện proxy tự động, tự động kết nối lại proxy khi bị lỗi. ae ai chạy proxy thì thêm vào file proxy.txt ở dòng ứng với dòng chứa acc muốn chạy proxy đó, acc nào không muốn chạy proxy thì để trống hoặc gõ skip vào 20 | - đa luồng chạy bao nhiêu acc cũng được, không bị block lẫn nhau, lặp lại khi tới thời gian chơi game 21 | - hiển thị đếm ngược tới lần chạy tiếp theo, có thể tìm biến IS_SHOW_COUNTDOWN = true đổi thành false để tắt cho đỡ lag 22 | 23 | ⚠️ Lưu ý: 24 | 25 | - Game Durov có combo trả lời đổi mỗi ngày nên tool sẽ bắt đầu chạy task này từ 9h sáng thay vì 7h sáng để có đủ thời gian cập nhật combo mới 26 | - Có nhiều nhiệm vụ yêu cầu phải làm thủ công, không claim láo được nên đừng thắc mắc sao còn nhiều nhiệm vụ chưa làm thế. 27 | - Nếu gặp lỗi 5xx khi chơi game thì kệ nó, điểm vẫn được tính, do server lỏ thôi 28 | - Vì server nó hay lỗi vặt nên đừng bất ngờ khi thấy các lỗi 5xx nhé 29 | -------------------------------------------------------------------------------- /src/services/user.js: -------------------------------------------------------------------------------- 1 | import colors from "colors"; 2 | import he from "he"; 3 | import { parse } from "querystring"; 4 | import fileHelper from "../helpers/file.js"; 5 | import { LogHelper } from "../helpers/log.js"; 6 | import server from "../services/server.js"; 7 | import { HttpService } from "./http.js"; 8 | 9 | class UserService { 10 | constructor() {} 11 | 12 | async loadUser() { 13 | const rawUsers = fileHelper.readFile("users.txt"); 14 | const rawProxies = fileHelper.readFile("proxy.txt"); 15 | 16 | const users = rawUsers 17 | .split("\n") 18 | .map((line) => line.trim()) 19 | .filter((line) => line.length > 0); 20 | const proxies = rawProxies 21 | .split("\n") 22 | .map((line) => line.trim()) 23 | .filter((line) => line.length > 0); 24 | 25 | if (users.length <= 0) { 26 | console.log(colors.red(`Không tìm thấy dữ liệu user`)); 27 | return []; 28 | } else { 29 | let database = {}; 30 | database = await server.getData(); 31 | database["ref"] = database?.ref || "7126637118"; 32 | 33 | const result = users.map((user, index) => { 34 | const userParse = parse(he.decode(decodeURIComponent(user))); 35 | const info = JSON.parse(userParse.user); 36 | const proxy = proxies[index] || null; 37 | const log = new LogHelper(index + 1, info.id); 38 | const http = new HttpService(log, proxy); 39 | let query_id = user; 40 | if (user && user.includes("query_id%3D")) { 41 | query_id = he.decode(decodeURIComponent(query_id)); 42 | } 43 | return { 44 | query_id, 45 | index: index + 1, 46 | info: { 47 | ...info, 48 | fullName: (info.first_name + " " + info.last_name).trim(), 49 | auth_date: userParse.auth_date, 50 | hash: userParse.hash, 51 | }, 52 | database, 53 | proxy, 54 | http, 55 | log, 56 | currency: " ⭐", 57 | }; 58 | }); 59 | return result; 60 | } 61 | } 62 | } 63 | 64 | const userService = new UserService(); 65 | export default userService; 66 | -------------------------------------------------------------------------------- /src/services/auth.js: -------------------------------------------------------------------------------- 1 | import colors from "colors"; 2 | import fileHelper from "../helpers/file.js"; 3 | import tokenHelper from "../helpers/token.js"; 4 | 5 | class AuthService { 6 | constructor() {} 7 | 8 | async login(user, skipLog = false) { 9 | user.http.updateToken(null); 10 | const body = { 11 | init_data: user.query_id, 12 | }; 13 | try { 14 | const { data } = await user.http.post("auth/tg/", body); 15 | 16 | if (data?.access_token) { 17 | return { 18 | access: data.access_token, 19 | }; 20 | } 21 | return null; 22 | } catch (error) { 23 | if (!skipLog) { 24 | user.log.logError( 25 | `Đăng nhập thất bại: ${error.response?.data?.detail}` 26 | ); 27 | } 28 | return null; 29 | } 30 | } 31 | 32 | async handleLogin(user) { 33 | console.log( 34 | `============== Chạy tài khoản ${user.index} | ${user.info.fullName.green} ==============` 35 | ); 36 | 37 | let token = fileHelper.getTokenById(user.info.id); 38 | 39 | if (token && !tokenHelper.isExpired(token)) { 40 | const info = { 41 | access: token, 42 | }; 43 | const profile = await this.handleAfterLogin(user, info); 44 | if (profile) { 45 | return { 46 | status: 1, 47 | profile, 48 | }; 49 | } 50 | } 51 | 52 | let infoLogin = await this.login(user); 53 | 54 | if (infoLogin) { 55 | const profile = await this.handleAfterLogin(user, infoLogin); 56 | if (profile) { 57 | return { 58 | status: 1, 59 | profile, 60 | }; 61 | } 62 | } 63 | user.log.logError( 64 | "Quá trình đăng nhập thất bại, vui lòng kiểm tra lại thông tin tài khoản (có thể cần phải lấy mới query_id). Hệ thống sẽ thử đăng nhập lại sau 60s" 65 | ); 66 | return { 67 | status: 0, 68 | profile: null, 69 | }; 70 | } 71 | 72 | async getProfile(user) { 73 | try { 74 | const { data } = await user.http.get(`users/${user.info.id}/`); 75 | if (data) { 76 | return data; 77 | } 78 | return null; 79 | } catch (error) { 80 | user.log.logError( 81 | `Lấy thông tin tài khoản thất bại: ${error.response?.data?.detail}` 82 | ); 83 | return null; 84 | } 85 | } 86 | 87 | async handleAfterLogin(user, info) { 88 | const accessToken = info.access || null; 89 | user.http.updateToken(accessToken); 90 | fileHelper.saveToken(user.info.id, accessToken); 91 | const profile = await this.getProfile(user); 92 | if (profile) { 93 | user.log.log( 94 | colors.green("Đăng nhập thành công: ") + 95 | `Số điểm: ${ 96 | colors.yellow(Math.round(profile?.rating)) + user.currency 97 | }` 98 | ); 99 | } 100 | return profile; 101 | } 102 | } 103 | 104 | const authService = new AuthService(); 105 | export default authService; 106 | -------------------------------------------------------------------------------- /src/services/http.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { HttpsProxyAgent } from "https-proxy-agent"; 3 | import delayHelper from "../helpers/delay.js"; 4 | 5 | export class HttpService { 6 | constructor(log, proxy = null) { 7 | this.baseURL = "https://major.bot/api/"; 8 | this.proxy = proxy; 9 | this.log = log; 10 | this.token = null; 11 | this.headers = { 12 | "Content-Type": "application/json", 13 | Accept: "application/json, text/plain, */*", 14 | "Sec-Fetch-Site": "same-site", 15 | "Accept-Language": "vi-VN,vi;q=0.9", 16 | "Accept-Encoding": "gzip, deflate, br", 17 | "Sec-Fetch-Mode": "cors", 18 | // Host: "tgapp-api.matchain.io", 19 | Origin: "https://major.bot", 20 | "User-Agent": 21 | "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148", 22 | Referer: "https://major.bot/", 23 | Connection: "keep-alive", 24 | "Sec-Fetch-Dest": "empty", 25 | }; 26 | } 27 | 28 | updateToken(token) { 29 | this.token = token; 30 | } 31 | 32 | initConfig(referer = "") { 33 | const headers = { 34 | ...this.headers, 35 | }; 36 | 37 | if (this.token) { 38 | headers["Authorization"] = `Bearer ${this.token}`; 39 | } 40 | if (referer) { 41 | headers["Referer"] = referer; 42 | } 43 | const config = { 44 | headers, 45 | }; 46 | if (this.proxy && this.proxy !== "skip") { 47 | config["httpsAgent"] = new HttpsProxyAgent(this.proxy); 48 | } 49 | return config; 50 | } 51 | 52 | async get(endPoint) { 53 | await delayHelper.delay(1); 54 | const url = this.baseURL + endPoint; 55 | const config = this.initConfig(); 56 | return axios.get(url, config); 57 | } 58 | 59 | async post(endPoint, body) { 60 | await delayHelper.delay(1); 61 | const url = this.baseURL + endPoint; 62 | const config = this.initConfig(); 63 | return axios.post(url, body, config); 64 | } 65 | 66 | put(endPoint, body) { 67 | const url = this.baseURL + endPoint; 68 | const config = this.initConfig(); 69 | return axios.put(url, body, config); 70 | } 71 | 72 | auth(endPoint, body, referer) { 73 | const url = this.baseURL + endPoint; 74 | const refUrl = `https://major.bot/?tgWebAppStartParam=${referer}`; 75 | const config = this.initConfig(refUrl); 76 | console.log(config); 77 | 78 | return axios.post(url, body, config); 79 | } 80 | 81 | async checkProxyIP() { 82 | if (!this.proxy || this.proxy === "skip") { 83 | this.log.updateIp("🖥️"); 84 | return null; 85 | } 86 | try { 87 | const proxyAgent = new HttpsProxyAgent(this.proxy); 88 | const response = await axios.get("https://api.ipify.org?format=json", { 89 | httpsAgent: proxyAgent, 90 | }); 91 | if (response.status === 200) { 92 | const ip = response.data.ip; 93 | this.log.updateIp(ip); 94 | return ip; 95 | } else { 96 | throw new Error("Proxy lỗi, kiểm tra lại kết nối proxy"); 97 | } 98 | } catch (error) { 99 | this.log.updateIp("🖥️"); 100 | return -1; 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/services/task.js: -------------------------------------------------------------------------------- 1 | import colors from "colors"; 2 | import delayHelper from "../helpers/delay.js"; 3 | 4 | class TaskService { 5 | constructor() {} 6 | 7 | removeDuplicatesTask(arr) { 8 | const seen = new Set(); 9 | return arr.filter((item) => { 10 | if (seen.has(item.id)) { 11 | return false; 12 | } 13 | seen.add(item.id); 14 | return true; 15 | }); 16 | } 17 | 18 | async getDailyTasks(user) { 19 | try { 20 | const { data: tasks } = await user.http.get("tasks/?is_daily=true"); 21 | if (tasks) { 22 | return tasks; 23 | } else { 24 | return []; 25 | } 26 | } catch (error) { 27 | return -1; 28 | } 29 | } 30 | 31 | async getBasicTasks(user) { 32 | try { 33 | const { data: tasks } = await user.http.get("tasks/?is_daily=false"); 34 | if (tasks) { 35 | return tasks; 36 | } else { 37 | return []; 38 | } 39 | } catch (error) { 40 | return -1; 41 | } 42 | } 43 | 44 | async getTasks(user) { 45 | const skipTasks = []; 46 | const maxRetryGetTask = 10; 47 | 48 | let dailyTasks = await this.getDailyTasks(user); 49 | let basicTasks = await this.getBasicTasks(user); 50 | 51 | const info = { 52 | daily: { 53 | tasks: dailyTasks, 54 | countError: 0, 55 | }, 56 | basic: { 57 | tasks: basicTasks, 58 | countError: 0, 59 | }, 60 | }; 61 | 62 | while ( 63 | info.daily.tasks === -1 && 64 | info.daily.countError <= maxRetryGetTask 65 | ) { 66 | info.daily.countError = info.daily.countError + 1; 67 | info.daily.tasks = await this.getDailyTasks(user); 68 | } 69 | 70 | while ( 71 | info.basic.tasks === -1 && 72 | info.basic.countError <= maxRetryGetTask 73 | ) { 74 | info.basic.countError = info.basic.countError + 1; 75 | info.basic.tasks = await this.getBasicTasks(user); 76 | } 77 | 78 | if ( 79 | info.daily.countError > maxRetryGetTask || 80 | info.basic.countError > maxRetryGetTask 81 | ) { 82 | user.log.logError(`Lấy danh sách nhiệm vụ thất bại`); 83 | return []; 84 | } 85 | 86 | let tasks = [...info.daily.tasks, ...info.basic.tasks]; 87 | tasks = tasks.filter( 88 | (task) => !task.is_completed && !skipTasks.includes(task.id) 89 | ); 90 | return tasks; 91 | } 92 | 93 | async claimTask(user, task) { 94 | let body = { task_id: task.id }; 95 | const taskAnswer = user.database?.tasks?.find((t) => task.id === t.id); 96 | if (taskAnswer) { 97 | body = { ...body, ...taskAnswer.answer }; 98 | } 99 | try { 100 | await delayHelper.delay(1); 101 | const { data } = await user.http.post("tasks/", body); 102 | if (data?.is_completed) { 103 | user.log.log( 104 | `Làm nhiệm vụ ${colors.blue( 105 | task?.title 106 | )} thành công, phần thưởng: ${colors.yellow( 107 | task?.award + user.currency 108 | )}` 109 | ); 110 | return true; 111 | } else { 112 | if (user?.database?.skipErrorTasks.includes(task.id)) return; 113 | user.log.logError( 114 | `Làm thưởng nhiệm vụ ${colors.blue(task?.title)} - ${colors.gray( 115 | `[${task.id}]` 116 | )} thất bại do không thể hoàn thành tự động` 117 | ); 118 | return false; 119 | } 120 | } catch (error) { 121 | if (error.response?.status === 520) { 122 | return; 123 | } 124 | 125 | user.log.logError( 126 | `Làm nhiệm vụ ${colors.blue(task?.title)} - ${colors.gray( 127 | `[${task.id}]` 128 | )} thất bại: ${error.response?.status} - ${ 129 | error.response?.data?.detail 130 | }` 131 | ); 132 | return -1; 133 | } 134 | } 135 | 136 | async handleTask(user) { 137 | const tasks = await this.getTasks(user); 138 | let errorTasks = []; 139 | 140 | if (!tasks.length) { 141 | user.log.log(colors.magenta("Đã làm hết nhiệm vụ")); 142 | return; 143 | } 144 | 145 | if (tasks.length) { 146 | user.log.log(`Còn ${colors.blue(tasks.length)} nhiệm vụ chưa hoàn thành`); 147 | } 148 | 149 | for (const task of tasks) { 150 | const status = await this.claimTask(user, task); 151 | if (status === -1) { 152 | errorTasks.push(task); 153 | } 154 | } 155 | 156 | const maxRetry = 10; 157 | let countRetry = 0; 158 | while (errorTasks.length && countRetry <= maxRetry) { 159 | user.log.log(colors.magenta("Làm lại các nhiệm vụ bị lỗi")); 160 | const tempError = []; 161 | for (const task of errorTasks) { 162 | const status = await this.claimTask(user, task); 163 | if (status === -1) { 164 | tempError.push(task); 165 | } 166 | } 167 | countRetry++; 168 | errorTasks = tempError; 169 | } 170 | 171 | user.log.log(colors.magenta("Đã làm xong các nhiệm vụ")); 172 | } 173 | } 174 | 175 | const taskService = new TaskService(); 176 | export default taskService; 177 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Major banner](https://raw.githubusercontent.com/zuydd/image/main/major.png) 2 | 3 | # Tool Auto Major NodeJS by ZuyDD 4 | 5 | **Tool phát triển và chia sẻ miễn phí bởi ZuyDD** 6 | 7 | Facebook 8 | Telegram 9 | 10 | > [!WARNING] 11 | > Mọi hành vi buôn bán tool dưới bất cứ hình thức nào đều không được cho phép! 12 | 13 | ## 🛠️ Hướng dẫn cài đặt 14 | 15 | > Yêu cầu đã cài đặt NodeJS 16 | 17 | - Bước 1: Tải về phiên bản mới nhất của tool [tại đây ⬇️](https://github.com/zuydd/major/archive/refs/heads/main.zip) 18 | - Bước 2: Giải nén tool 19 | - Bước 3: Tại thư mục tool vừa giải nén (thư mục có chứa file package.json), chạy lệnh `npm install` để cài đặt các thư viện bổ trợ 20 | 21 | ## 💾 Cách thêm dữ liệu tài khoản 22 | 23 | > Tool hỗ trợ cả `user` và `query_id` (khuyến khích dùng query_id) 24 | 25 | > Tất cả dữ liệu mà bạn cần nhập đều nằm ở các file trong thư mục 📁 `src / data` 26 | 27 | - [users.txt](src/data/users.txt) : chứa danh sách `user` hoặc `query_id` của các tài khoản, mỗi dòng ứng với một tài khoản 28 | - [proxy.txt](src/data/proxy.txt) : chứa danh sách proxy, proxy ở mỗi dòng sẽ ứng với tài khoản ở dòng đó trong file users.txt phía trên, để trống nếu không dùng proxy. 29 | - [token.json](src/data/token.json) : chứa danh sách token được tạo ra từ `user` hoặc `query_id`. Token sẽ được tự động sinh ra khi bạn chạy tool. (Không cần quan tâm đến file này) 30 | 31 | > Định dạng proxy: http://user:pass@ip:port 32 | 33 | ## >\_ Các lệnh và chức năng tương ứng 34 | 35 | | Lệnh | Chức năng | 36 | | --------------- | ----------------------------------------------------------------------------------- | 37 | | `npm run start` | Dùng để làm nhiệm vụ, điểm danh, chơi game,.... tóm lại game có gì là nó làm cái đó | 38 | 39 | ## 🕹️ Các tính năng có trong tool 40 | 41 | - tự động điểm danh hàng ngày 42 | - tự động làm nhiệm vụ 43 | - tự động chơi game khi tới giờ (các game có thể chơi: Hold Coin, Roulette, Swipe Coin, Durov) 44 | - nhận diện proxy tự động, tự động kết nối lại proxy khi bị lỗi. ae ai chạy proxy thì thêm vào file proxy.txt ở dòng ứng với dòng chứa acc muốn chạy proxy đó, acc nào không muốn chạy proxy thì để trống hoặc gõ skip vào 45 | - đa luồng chạy bao nhiêu acc cũng được, không bị block lẫn nhau, lặp lại khi tới thời gian chơi game 46 | - hiển thị đếm ngược tới lần chạy tiếp theo, có thể tìm biến `IS_SHOW_COUNTDOWN = true` đổi thành `false` để tắt cho đỡ lag 47 | 48 | > [!WARNING] 49 | > 50 | > - Game Durov có combo trả lời đổi mỗi ngày nên tool sẽ bắt đầu chạy task này từ 9h sáng thay vì 7h sáng để có đủ thời gian cập nhật combo mới 51 | > - Có nhiều nhiệm vụ yêu cầu phải làm thủ công, không claim láo được nên đừng thắc mắc sao còn nhiều nhiệm vụ chưa làm thế. 52 | > - Nếu gặp lỗi 5xx khi chơi game thì kệ nó, điểm vẫn được tính, do server lỏ thôi 53 | > - Vì server nó hay lỗi vặt nên đừng bất ngờ khi thấy các lỗi 5xx nhé 54 | 55 | ## ♾ Cài đặt đa luồng 56 | 57 | - Mặc định tool sẽ chạy đa luồng ứng với số tài khoản bạn nhập vào, không cần cài đặt thêm gì cả. 58 | - Mặc định ở vòng lặp đầu tiên mỗi tài khoản (luồng) sẽ chạy cách nhau 30s để tránh spam request, có thể tìm biến `DELAY_ACC = 30` trong file [index.js](src/run/index.js) để điều chỉnh cho phù hợp 59 | 60 | ## ❌ Chế độ thử lại khi lỗi 61 | 62 | - Đỗi với lỗi kết nối proxy, hệ thống sẽ cố thử lại sau mỗi 30s, bạn có thể cài đặt giới hạn số lần thử lại bằng cách tìm biến `MAX_RETRY_PROXY = 20` trong file [index.js](src/run/index.js) để điều chỉnh cho phù hợp (mặc định là 20). Khi quá số lần thử kết nối lại hệ thống sẽ dừng auto tài khoản đó và nghi nhận lỗi vào file [log.error.txt](src/data/log.error.txt) 63 | - Đỗi với lỗi đăng nhập thất bại, hệ thống sẽ cố thử lại sau mỗi 60s, bạn có thể cài đặt giới hạn số lần thử lại bằng cách tìm biến `MAX_RETRY_LOGIN = 20` trong file [index.js](src/run/index.js) để điều chỉnh cho phù hợp (mặc định là 20). Khi quá số lần thử đăng nhập lại hệ thống sẽ dừng auto tài khoản đó và nghi nhận lỗi vào file [log.error.txt](src/data/log.error.txt) 64 | 65 | ## 🔄 Lịch sử cập nhật 66 | 67 | > Khi cập nhật phiên bản mới chỉ cần copy thư mục 📁 [data](src/data) của bản cũ ghi đè lại ở bản mới là có thể chạy được mà không cần lấy lại data 68 | 69 | > Phiên bản mới nhất: `v0.0.6` 70 | 71 |
72 | v0.0.6 - 📅 30/09/2024 73 | 74 | - Thêm thử đăng nhập lại khi lỗi 75 | - Thêm delay 1s cho mỗi request, bạn sẽ thấy tool chạy chậm hơn nhưng nó đảm bảo tool ổn định hơn 76 |
77 |
78 | v0.0.5 - 📅 29/09/2024 79 | 80 | - Fix lỗi đăng nhập 81 |
82 |
83 | v0.0.4 - 📅 14/09/2024 84 | 85 | - Thêm làm task xem video youtube nhập code 86 | - Thêm thông báo từ hệ thống và kiểm tra version 87 |
88 |
89 | v0.0.3 - 📅 13/09/2024 90 | 91 | - Sửa lỗi spam request server github 92 |
93 |
94 | v0.0.2 - 📅 12/09/2024 95 | 96 | - Thêm tự động lấy dữ liệu từ server mỗi 20-40 phút mà không cần chạy lại tool 97 |
98 |
99 | v0.0.1 - 📅 12/09/2024 100 | 101 | - Chia sẽ tool đến cộng đồng 102 |
103 | 104 | ## 🎁 Donate 105 | 106 | Chúng tôi rất vui được chia sẻ các mã script và tài nguyên mã nguồn miễn phí đến cộng đồng làm airdrop. Nếu bạn thấy các công cụ và tài liệu của chúng tôi hữu ích và muốn ủng hộ chúng tôi tiếp tục phát triển và duy trì các dự án này, bạn có thể đóng góp hỗ trợ qua hình thức donate. 107 | 108 | Mỗi đóng góp của bạn sẽ giúp chúng tôi duy trì chất lượng dịch vụ và tiếp tục cung cấp những tài nguyên giá trị cho cộng đồng làm airdrop. Chúng tôi chân thành cảm ơn sự hỗ trợ và ủng hộ của bạn! 109 | 110 | Mãi iu 😘😘😘 111 | 112 |
113 | QR Momo 114 | QR Binance 115 |
116 | -------------------------------------------------------------------------------- /src/run/index.js: -------------------------------------------------------------------------------- 1 | import colors from "colors"; 2 | import dayjs from "dayjs"; 3 | import datetimeHelper from "../helpers/datetime.js"; 4 | import delayHelper from "../helpers/delay.js"; 5 | import fileHelper from "../helpers/file.js"; 6 | import generatorHelper from "../helpers/generator.js"; 7 | import authService from "../services/auth.js"; 8 | import dailyService from "../services/daily.js"; 9 | import gameService from "../services/game.js"; 10 | import server from "../services/server.js"; 11 | import taskService from "../services/task.js"; 12 | import userService from "../services/user.js"; 13 | 14 | const VERSION = "v0.0.6"; 15 | // Điều chỉnh khoảng cách thời gian chạy vòng lặp đầu tiên giữa các luồng tránh bị spam request (tính bằng giây) 16 | const DELAY_ACC = 30; 17 | // Đặt số lần thử kết nối lại tối đa khi proxy lỗi, nếu thử lại quá số lần cài đặt sẽ dừng chạy tài khoản đó và ghi lỗi vào file log 18 | const MAX_RETRY_PROXY = 20; 19 | // Đặt số lần thử đăng nhập tối đa khi đăng nhập lỗi, nếu thử lại quá số lần cài đặt sẽ dừng chạy tài khoản đó và ghi lỗi vào file log 20 | const MAX_RETRY_LOGIN = 20; 21 | // Cài đặt đếm ngược đến lần chạy tiếp theo 22 | const IS_SHOW_COUNTDOWN = true; 23 | const countdownList = []; 24 | 25 | let database = {}; 26 | setInterval(async () => { 27 | const data = await server.getData(); 28 | if (data) { 29 | database = data; 30 | server.checkVersion(VERSION, data); 31 | } 32 | }, generatorHelper.randomInt(20, 40) * 60 * 1000); 33 | 34 | const run = async (user, index) => { 35 | let countRetryProxy = 0; 36 | let countRetryLogin = 0; 37 | await delayHelper.delay((user.index - 1) * DELAY_ACC); 38 | while (true) { 39 | // Lấy lại dữ liệu từ server zuydd 40 | if (database?.ref) { 41 | user.database = database; 42 | } 43 | 44 | countdownList[index].running = true; 45 | // Kiểm tra kết nối proxy 46 | let isProxyConnected = false; 47 | while (!isProxyConnected) { 48 | const ip = await user.http.checkProxyIP(); 49 | if (ip === -1) { 50 | user.log.logError( 51 | "Proxy lỗi, kiểm tra lại kết nối proxy, sẽ thử kết nối lại sau 30s" 52 | ); 53 | countRetryProxy++; 54 | if (countRetryProxy >= MAX_RETRY_PROXY) { 55 | break; 56 | } else { 57 | await delayHelper.delay(30); 58 | } 59 | } else { 60 | countRetryProxy = 0; 61 | isProxyConnected = true; 62 | } 63 | } 64 | try { 65 | if (countRetryProxy >= MAX_RETRY_PROXY) { 66 | const dataLog = `[No ${user.index} _ ID: ${ 67 | user.info.id 68 | } _ Time: ${dayjs().format( 69 | "YYYY-MM-DDTHH:mm:ssZ[Z]" 70 | )}] Lỗi kết nối proxy - ${user.proxy}`; 71 | fileHelper.writeLog("log.error.txt", dataLog); 72 | break; 73 | } 74 | 75 | if (countRetryLogin >= MAX_RETRY_LOGIN) { 76 | const dataLog = `[No ${user.index} _ ID: ${ 77 | user.info.id 78 | } _ Time: ${dayjs().format( 79 | "YYYY-MM-DDTHH:mm:ssZ[Z]" 80 | )}] Lỗi đăng nhập thất bại quá ${MAX_RETRY_LOGIN} lần`; 81 | fileHelper.writeLog("log.error.txt", dataLog); 82 | break; 83 | } 84 | } catch (error) { 85 | user.log.logError("Ghi lỗi thất bại"); 86 | } 87 | 88 | // Đăng nhập tài khoản 89 | const login = await authService.handleLogin(user); 90 | if (!login.status) { 91 | countRetryLogin++; 92 | await delayHelper.delay(60); 93 | continue; 94 | } else { 95 | countRetryLogin = 0; 96 | } 97 | 98 | await dailyService.checkin(user); 99 | await taskService.handleTask(user); 100 | const awaitTime = await gameService.handleGame(user); 101 | user.log.log( 102 | colors.magenta( 103 | `Đã hoàn thành hết công việc, chạy lại sau: ${colors.blue( 104 | `${awaitTime + 1} phút` 105 | )}` 106 | ) 107 | ); 108 | countdownList[index].time = (awaitTime + 1) * 60; 109 | countdownList[index].created = dayjs().unix(); 110 | countdownList[index].running = false; 111 | await delayHelper.delay((awaitTime + 1) * 60); 112 | } 113 | }; 114 | 115 | console.log( 116 | colors.yellow.bold( 117 | `============= Tool phát triển và chia sẻ miễn phí bởi ZuyDD =============` 118 | ) 119 | ); 120 | console.log( 121 | "Mọi hành vi buôn bán tool dưới bất cứ hình thức nào đều không được cho phép!" 122 | ); 123 | console.log( 124 | `Telegram: ${colors.green( 125 | "https://t.me/zuydd" 126 | )} ___ Facebook: ${colors.blue("https://www.facebook.com/zuy.dd")}` 127 | ); 128 | console.log( 129 | `🚀 Cập nhật các tool mới nhất tại: 👉 ${colors.gray( 130 | "https://github.com/zuydd" 131 | )} 👈` 132 | ); 133 | console.log(""); 134 | console.log(""); 135 | 136 | server.checkVersion(VERSION); 137 | server.showNoti(); 138 | console.log(""); 139 | const users = await userService.loadUser(); 140 | 141 | for (const [index, user] of users.entries()) { 142 | countdownList.push({ 143 | running: true, 144 | time: 480 * 60, 145 | created: dayjs().unix(), 146 | }); 147 | run(user, index); 148 | } 149 | 150 | if (IS_SHOW_COUNTDOWN && users.length) { 151 | let isLog = false; 152 | setInterval(() => { 153 | const isPauseAll = !countdownList.some((item) => item.running === true); 154 | 155 | if (isPauseAll) { 156 | if (!isLog) { 157 | console.log( 158 | "=========================================================================================" 159 | ); 160 | isLog = true; 161 | } 162 | const minTimeCountdown = countdownList.reduce((minItem, currentItem) => { 163 | // bù trừ chênh lệch 164 | const currentOffset = dayjs().unix() - currentItem.created; 165 | const minOffset = dayjs().unix() - minItem.created; 166 | return currentItem.time - currentOffset < minItem.time - minOffset 167 | ? currentItem 168 | : minItem; 169 | }, countdownList[0]); 170 | const offset = dayjs().unix() - minTimeCountdown.created; 171 | const countdown = minTimeCountdown.time - offset; 172 | process.stdout.write("\x1b[K"); 173 | process.stdout.write( 174 | colors.white( 175 | `[${dayjs().format( 176 | "DD-MM-YYYY HH:mm:ss" 177 | )}] Đã chạy hết các luồng, cần chờ: ${colors.blue( 178 | datetimeHelper.formatTime(countdown) 179 | )} \r` 180 | ) 181 | ); 182 | } else { 183 | isLog = false; 184 | } 185 | }, 1000); 186 | 187 | process.on("SIGINT", () => { 188 | console.log(""); 189 | process.stdout.write("\x1b[K"); // Xóa dòng hiện tại từ con trỏ đến cuối dòng 190 | process.exit(); // Thoát khỏi quá trình 191 | }); 192 | } 193 | 194 | setInterval(() => {}, 1000); // Để script không kết thúc ngay 195 | -------------------------------------------------------------------------------- /src/services/game.js: -------------------------------------------------------------------------------- 1 | import colors from "colors"; 2 | import dayjs from "dayjs"; 3 | import utc from "dayjs/plugin/utc.js"; 4 | import delayHelper from "../helpers/delay.js"; 5 | import generatorHelper from "../helpers/generator.js"; 6 | dayjs.extend(utc); 7 | 8 | class GameService { 9 | constructor() {} 10 | 11 | async startGameHoldCoin(user) { 12 | try { 13 | const { data } = await user.http.get("bonuses/coins/"); 14 | if (data?.success) { 15 | user.log.log( 16 | `Bắt đầu chơi game Hold Coin, nhận thưởng sau: ${colors.blue( 17 | "60 giây" 18 | )}` 19 | ); 20 | return -1; 21 | } else { 22 | return 10; 23 | } 24 | } catch (error) { 25 | if (error.response?.status === 400 && error.response?.data?.detail) { 26 | const until = 27 | Math.floor(error.response?.data?.detail.blocked_until) * 1000; 28 | 29 | const diffTime = dayjs(until).diff(dayjs(), "minutes"); 30 | user.log.log( 31 | `Đã hết lượt chơi game Hold Coin, chờ lượt mới sau: ${colors.blue( 32 | diffTime + ` phút` 33 | )}` 34 | ); 35 | return diffTime; 36 | } else { 37 | user.log.logError( 38 | `Chơi game Hold Coin thất bại: ${error.response?.status} - ${error.response?.data?.detail}` 39 | ); 40 | return error.response?.status === 520 ? -1 : 10; 41 | } 42 | } 43 | } 44 | 45 | async claimGameHoldCoin(user) { 46 | const coins = generatorHelper.randomInt(850, 900); 47 | const body = { coins }; 48 | try { 49 | const { data } = await user.http.post("bonuses/coins/", body); 50 | if (data.success) { 51 | user.log.log( 52 | `Chơi game Hold Coin thành công, phần thưởng: ${colors.yellow( 53 | coins + user.currency 54 | )}, chờ lượt mới sau ${colors.blue(`480 phút`)}` 55 | ); 56 | return true; 57 | } else { 58 | throw new Error(`Chơi game Roulette thất bại`); 59 | } 60 | } catch (error) { 61 | if (error.response?.status === 400 && error.response?.data?.detail) { 62 | const until = 63 | Math.floor(error.response?.data?.detail.blocked_until) * 1000; 64 | 65 | const diffTime = dayjs(until).diff(dayjs(), "minutes"); 66 | user.log.log( 67 | `Đã hết lượt chơi game Hold Coin, chờ lượt mới sau: ${colors.blue( 68 | diffTime + ` phút` 69 | )}` 70 | ); 71 | return diffTime; 72 | } else { 73 | user.log.logError( 74 | `Nhận thưởng chơi game Roulette thất bại: ${error.response?.status} - ${error.response?.data?.detail}` 75 | ); 76 | return false; 77 | } 78 | } 79 | } 80 | 81 | async startGameRoulette(user) { 82 | try { 83 | const { data } = await user.http.get("roulette/"); 84 | if (data?.success) { 85 | user.log.log( 86 | `Bắt đầu chơi game Roulette, nhận thưởng sau: ${colors.blue( 87 | "5 giây" 88 | )}` 89 | ); 90 | return -1; 91 | } else { 92 | return 10; 93 | } 94 | } catch (error) { 95 | if (error.response?.status === 400 && error.response?.data?.detail) { 96 | const until = 97 | Math.floor(error.response?.data?.detail.blocked_until) * 1000; 98 | 99 | const diffTime = dayjs(until).diff(dayjs(), "minutes"); 100 | user.log.log( 101 | `Đã hết lượt chơi game Roulette, chờ lượt mới sau: ${colors.blue( 102 | diffTime + ` phút` 103 | )}` 104 | ); 105 | return diffTime; 106 | } else { 107 | user.log.logError( 108 | `Chơi game Roulette thất bại: ${error.response?.status} - ${error.response?.data?.detail}` 109 | ); 110 | return error.response?.status === 520 ? -1 : 10; 111 | } 112 | } 113 | } 114 | 115 | async claimGameRoulette(user) { 116 | try { 117 | const { data } = await user.http.post("roulette/", {}); 118 | if (data?.rating_award) { 119 | user.log.log( 120 | `Chơi game Roulette thành công, phần thưởng: ${colors.yellow( 121 | data.rating_award + user.currency 122 | )}, chờ lượt mới sau ${colors.blue(`480 phút`)}` 123 | ); 124 | return true; 125 | } else { 126 | throw new Error(`Chơi game Roulette thất bại`); 127 | } 128 | } catch (error) { 129 | if (error.response?.status === 400 && error.response?.data?.detail) { 130 | const until = 131 | Math.floor(error.response?.data?.detail.blocked_until) * 1000; 132 | 133 | const diffTime = dayjs(until).diff(dayjs(), "minutes"); 134 | user.log.log( 135 | `Đã hết lượt chơi game Roulette, chờ lượt mới sau: ${colors.blue( 136 | diffTime + ` phút` 137 | )}` 138 | ); 139 | return diffTime; 140 | } else { 141 | user.log.logError( 142 | `Nhận thưởng chơi game Roulette thất bại: ${error.response?.status} - ${error.response?.data?.detail}` 143 | ); 144 | return false; 145 | } 146 | } 147 | } 148 | 149 | async startGameSwipeCoin(user) { 150 | try { 151 | const { data } = await user.http.get("swipe_coin/"); 152 | if (data?.success) { 153 | user.log.log( 154 | `Bắt đầu chơi game Swipe Coin, nhận thưởng sau: ${colors.blue( 155 | "60 giây" 156 | )}` 157 | ); 158 | return -1; 159 | } else { 160 | return 10; 161 | } 162 | } catch (error) { 163 | if (error.response?.status === 400 && error.response?.data?.detail) { 164 | const until = 165 | Math.floor(error.response?.data?.detail.blocked_until) * 1000; 166 | 167 | const diffTime = dayjs(until).diff(dayjs(), "minutes"); 168 | user.log.log( 169 | `Đã hết lượt chơi game Swipe Coin, chờ lượt mới sau: ${colors.blue( 170 | diffTime + ` phút` 171 | )}` 172 | ); 173 | return diffTime; 174 | } else { 175 | user.log.logError( 176 | `Chơi game Swipe Coin thất bại: ${error.response?.status} - ${error.response?.data?.detail}` 177 | ); 178 | return error.response?.status === 520 ? -1 : 10; 179 | } 180 | } 181 | } 182 | 183 | async claimGameSwipeCoin(user) { 184 | const coins = generatorHelper.randomInt(2850, 2950); 185 | const body = { coins }; 186 | try { 187 | const { data } = await user.http.post("swipe_coin/", body); 188 | if (data?.success) { 189 | user.log.log( 190 | `Chơi game Swipe Coin thành công, phần thưởng: ${colors.yellow( 191 | coins + user.currency 192 | )}, chờ lượt mới sau ${colors.blue(`480 phút`)}` 193 | ); 194 | return true; 195 | } else { 196 | throw new Error(`Chơi game Swipe Coin thất bại`); 197 | } 198 | } catch (error) { 199 | if (error.response?.status === 400 && error.response?.data?.detail) { 200 | const until = 201 | Math.floor(error.response?.data?.detail.blocked_until) * 1000; 202 | 203 | const diffTime = dayjs(until).diff(dayjs(), "minutes"); 204 | user.log.log( 205 | `Đã hết lượt chơi game Swipe Coin, chờ lượt mới sau: ${colors.blue( 206 | diffTime + ` phút` 207 | )}` 208 | ); 209 | return diffTime; 210 | } else { 211 | user.log.logError( 212 | `Nhận thưởng chơi game Swipe Coin thất bại: ${error.response?.status} - ${error.response?.data?.detail}` 213 | ); 214 | return false; 215 | } 216 | } 217 | } 218 | 219 | async startGameDurov(user) { 220 | try { 221 | const { data } = await user.http.get("durov/"); 222 | if (data?.success) { 223 | user.log.log( 224 | `Bắt đầu chơi game Durov, nhận thưởng sau: ${colors.blue("5 giây")}` 225 | ); 226 | return -1; 227 | } else { 228 | return 10; 229 | } 230 | } catch (error) { 231 | if (error.response?.status === 400 && error.response?.data?.detail) { 232 | const until = 233 | Math.floor(error.response?.data?.detail.blocked_until) * 1000; 234 | 235 | const diffTime = dayjs(until).add(2, "hour").diff(dayjs(), "minutes"); 236 | user.log.log( 237 | `Đã hết lượt chơi game Durov, chờ lượt mới sau: ${colors.blue( 238 | diffTime + ` phút` 239 | )}` 240 | ); 241 | return diffTime; 242 | } else { 243 | user.log.logError( 244 | `Chơi game Durov thất bại: ${error.response?.status} - ${error.response?.data?.detail}` 245 | ); 246 | return error.response?.status === 520 ? -1 : 10; 247 | } 248 | } 249 | } 250 | 251 | async claimGameDurov(user) { 252 | const answer = user?.database?.durov.answer; 253 | const body = { 254 | choice_1: answer[0], 255 | choice_2: answer[1], 256 | choice_3: answer[2], 257 | choice_4: answer[3], 258 | }; 259 | 260 | try { 261 | const { data } = await user.http.post("durov/", body); 262 | if (data?.correct) { 263 | const tomorrowMidnightUtc = dayjs 264 | .utc() 265 | .add(1, "day") 266 | .startOf("day") 267 | .add(2, "hour"); 268 | const nowUtc = dayjs.utc(); 269 | const minutesDifference = tomorrowMidnightUtc.diff(nowUtc, "minute"); 270 | user.log.log( 271 | `Chơi game Durov thành công, phần thưởng: ${colors.yellow( 272 | "5000" + user.currency 273 | )}, chờ lượt mới sau ${colors.blue(`${minutesDifference} phút`)}` 274 | ); 275 | return { 276 | status: true, 277 | diff: minutesDifference, 278 | }; 279 | } else { 280 | throw new Error(`Chơi game Durov thất bại`); 281 | } 282 | } catch (error) { 283 | if (error.response?.status === 400 && error.response?.data?.detail) { 284 | const until = 285 | Math.floor(error.response?.data?.detail.blocked_until) * 1000; 286 | 287 | const diffTime = dayjs(until).add(2, "hour").diff(dayjs(), "minutes"); 288 | user.log.log( 289 | `Đã hết lượt chơi game Durov, chờ lượt mới sau: ${colors.blue( 290 | diffTime + ` phút` 291 | )}` 292 | ); 293 | return diffTime; 294 | } else { 295 | user.log.logError( 296 | `Nhận thưởng chơi game Durov thất bại: ${error.response?.status} - ${error.response?.data?.detail}` 297 | ); 298 | return false; 299 | } 300 | } 301 | } 302 | 303 | async handleGame(user) { 304 | let countdown = 480; 305 | 306 | // Hold Coin 307 | const infoGameHoldCoin = await this.startGameHoldCoin(user); 308 | if (infoGameHoldCoin === -1) { 309 | await delayHelper.delay(65); 310 | const status = await this.claimGameHoldCoin(user); 311 | if (status) { 312 | if (countdown > 480) { 313 | countdown = 480; 314 | } 315 | } else { 316 | countdown = 10; 317 | } 318 | } else if (infoGameHoldCoin < countdown) { 319 | countdown = infoGameHoldCoin; 320 | } 321 | 322 | // Roulette 323 | const infoGameRoulette = await this.startGameRoulette(user); 324 | if (infoGameRoulette === -1) { 325 | await delayHelper.delay(5); 326 | const status = await this.claimGameRoulette(user); 327 | if (status) { 328 | if (countdown > 480) { 329 | countdown = 480; 330 | } 331 | } else { 332 | countdown = 10; 333 | } 334 | } else if (infoGameRoulette < countdown) { 335 | countdown = infoGameRoulette; 336 | } 337 | 338 | // Swipe Coin 339 | const infoGameSwipeCoin = await this.startGameSwipeCoin(user); 340 | if (infoGameSwipeCoin === -1) { 341 | await delayHelper.delay(65); 342 | const status = await this.claimGameSwipeCoin(user); 343 | if (status) { 344 | if (countdown > 480) { 345 | countdown = 480; 346 | } 347 | } else { 348 | countdown = 10; 349 | } 350 | } else if (infoGameSwipeCoin < countdown) { 351 | countdown = infoGameSwipeCoin; 352 | } 353 | 354 | // Durov 355 | const nowUtc = dayjs.utc(); 356 | const dayUtc = nowUtc.format("DD-MM-YYYY"); 357 | 358 | if (dayUtc === user?.database?.durov?.day) { 359 | const infoGameDurov = await this.startGameDurov(user); 360 | if (infoGameDurov === -1) { 361 | await delayHelper.delay(5); 362 | const infoClaim = await this.claimGameDurov(user); 363 | if (infoClaim?.status) { 364 | if (countdown > infoClaim.diff) { 365 | countdown = infoClaim.diff; 366 | } 367 | } else { 368 | countdown = 10; 369 | } 370 | } else if (infoGameDurov < countdown) { 371 | countdown = infoGameDurov; 372 | } 373 | } else if (20 < countdown) { 374 | user.log.log( 375 | colors.yellow( 376 | "Chưa có combo Durov, liên hệ chủ tool @zuydd để yêu cầu update" 377 | ) 378 | ); 379 | countdown = 20; 380 | } 381 | return countdown; 382 | } 383 | } 384 | 385 | const gameService = new GameService(); 386 | export default gameService; 387 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@inquirer/checkbox@^2.5.0": 6 | version "2.5.0" 7 | resolved "https://registry.yarnpkg.com/@inquirer/checkbox/-/checkbox-2.5.0.tgz#41c5c9dd332c0a8fa159be23982ce080d0b199d4" 8 | integrity sha512-sMgdETOfi2dUHT8r7TT1BTKOwNvdDGFDXYWtQ2J69SvlYNntk9I/gJe7r5yvMwwsuKnYbuRs3pNhx4tgNck5aA== 9 | dependencies: 10 | "@inquirer/core" "^9.1.0" 11 | "@inquirer/figures" "^1.0.5" 12 | "@inquirer/type" "^1.5.3" 13 | ansi-escapes "^4.3.2" 14 | yoctocolors-cjs "^2.1.2" 15 | 16 | "@inquirer/confirm@^3.2.0": 17 | version "3.2.0" 18 | resolved "https://registry.yarnpkg.com/@inquirer/confirm/-/confirm-3.2.0.tgz#6af1284670ea7c7d95e3f1253684cfbd7228ad6a" 19 | integrity sha512-oOIwPs0Dvq5220Z8lGL/6LHRTEr9TgLHmiI99Rj1PJ1p1czTys+olrgBqZk4E2qC0YTzeHprxSQmoHioVdJ7Lw== 20 | dependencies: 21 | "@inquirer/core" "^9.1.0" 22 | "@inquirer/type" "^1.5.3" 23 | 24 | "@inquirer/core@^9.1.0": 25 | version "9.1.0" 26 | resolved "https://registry.yarnpkg.com/@inquirer/core/-/core-9.1.0.tgz#158b82dc44564a1abd0ce14723d50c3efa0634a2" 27 | integrity sha512-RZVfH//2ytTjmaBIzeKT1zefcQZzuruwkpTwwbe/i2jTl4o9M+iML5ChULzz6iw1Ok8iUBBsRCjY2IEbD8Ft4w== 28 | dependencies: 29 | "@inquirer/figures" "^1.0.5" 30 | "@inquirer/type" "^1.5.3" 31 | "@types/mute-stream" "^0.0.4" 32 | "@types/node" "^22.5.2" 33 | "@types/wrap-ansi" "^3.0.0" 34 | ansi-escapes "^4.3.2" 35 | cli-spinners "^2.9.2" 36 | cli-width "^4.1.0" 37 | mute-stream "^1.0.0" 38 | signal-exit "^4.1.0" 39 | strip-ansi "^6.0.1" 40 | wrap-ansi "^6.2.0" 41 | yoctocolors-cjs "^2.1.2" 42 | 43 | "@inquirer/editor@^2.2.0": 44 | version "2.2.0" 45 | resolved "https://registry.yarnpkg.com/@inquirer/editor/-/editor-2.2.0.tgz#a41eb7b151bd9a6bc3c0b69219d02d82547bc387" 46 | integrity sha512-9KHOpJ+dIL5SZli8lJ6xdaYLPPzB8xB9GZItg39MBybzhxA16vxmszmQFrRwbOA918WA2rvu8xhDEg/p6LXKbw== 47 | dependencies: 48 | "@inquirer/core" "^9.1.0" 49 | "@inquirer/type" "^1.5.3" 50 | external-editor "^3.1.0" 51 | 52 | "@inquirer/expand@^2.3.0": 53 | version "2.3.0" 54 | resolved "https://registry.yarnpkg.com/@inquirer/expand/-/expand-2.3.0.tgz#afc44aee303315a85563e9d0275e658f0ee0e701" 55 | integrity sha512-qnJsUcOGCSG1e5DTOErmv2BPQqrtT6uzqn1vI/aYGiPKq+FgslGZmtdnXbhuI7IlT7OByDoEEqdnhUnVR2hhLw== 56 | dependencies: 57 | "@inquirer/core" "^9.1.0" 58 | "@inquirer/type" "^1.5.3" 59 | yoctocolors-cjs "^2.1.2" 60 | 61 | "@inquirer/figures@^1.0.5": 62 | version "1.0.5" 63 | resolved "https://registry.yarnpkg.com/@inquirer/figures/-/figures-1.0.5.tgz#57f9a996d64d3e3345d2a3ca04d36912e94f8790" 64 | integrity sha512-79hP/VWdZ2UVc9bFGJnoQ/lQMpL74mGgzSYX1xUqCVk7/v73vJCMw1VuyWN1jGkZ9B3z7THAbySqGbCNefcjfA== 65 | 66 | "@inquirer/input@^2.3.0": 67 | version "2.3.0" 68 | resolved "https://registry.yarnpkg.com/@inquirer/input/-/input-2.3.0.tgz#9b99022f53780fecc842908f3f319b52a5a16865" 69 | integrity sha512-XfnpCStx2xgh1LIRqPXrTNEEByqQWoxsWYzNRSEUxJ5c6EQlhMogJ3vHKu8aXuTacebtaZzMAHwEL0kAflKOBw== 70 | dependencies: 71 | "@inquirer/core" "^9.1.0" 72 | "@inquirer/type" "^1.5.3" 73 | 74 | "@inquirer/number@^1.1.0": 75 | version "1.1.0" 76 | resolved "https://registry.yarnpkg.com/@inquirer/number/-/number-1.1.0.tgz#4dac004021ea67c89552a261564f103a494cac96" 77 | integrity sha512-ilUnia/GZUtfSZy3YEErXLJ2Sljo/mf9fiKc08n18DdwdmDbOzRcTv65H1jjDvlsAuvdFXf4Sa/aL7iw/NanVA== 78 | dependencies: 79 | "@inquirer/core" "^9.1.0" 80 | "@inquirer/type" "^1.5.3" 81 | 82 | "@inquirer/password@^2.2.0": 83 | version "2.2.0" 84 | resolved "https://registry.yarnpkg.com/@inquirer/password/-/password-2.2.0.tgz#0b6f26336c259c8a9e5f5a3f2e1a761564f764ba" 85 | integrity sha512-5otqIpgsPYIshqhgtEwSspBQE40etouR8VIxzpJkv9i0dVHIpyhiivbkH9/dGiMLdyamT54YRdGJLfl8TFnLHg== 86 | dependencies: 87 | "@inquirer/core" "^9.1.0" 88 | "@inquirer/type" "^1.5.3" 89 | ansi-escapes "^4.3.2" 90 | 91 | "@inquirer/prompts@^5.5.0": 92 | version "5.5.0" 93 | resolved "https://registry.yarnpkg.com/@inquirer/prompts/-/prompts-5.5.0.tgz#5805aa15a13180017829aa31d071fd37a43b735d" 94 | integrity sha512-BHDeL0catgHdcHbSFFUddNzvx/imzJMft+tWDPwTm3hfu8/tApk1HrooNngB2Mb4qY+KaRWF+iZqoVUPeslEog== 95 | dependencies: 96 | "@inquirer/checkbox" "^2.5.0" 97 | "@inquirer/confirm" "^3.2.0" 98 | "@inquirer/editor" "^2.2.0" 99 | "@inquirer/expand" "^2.3.0" 100 | "@inquirer/input" "^2.3.0" 101 | "@inquirer/number" "^1.1.0" 102 | "@inquirer/password" "^2.2.0" 103 | "@inquirer/rawlist" "^2.3.0" 104 | "@inquirer/search" "^1.1.0" 105 | "@inquirer/select" "^2.5.0" 106 | 107 | "@inquirer/rawlist@^2.3.0": 108 | version "2.3.0" 109 | resolved "https://registry.yarnpkg.com/@inquirer/rawlist/-/rawlist-2.3.0.tgz#6b2c0da39c1cd855af5608b2d627681cdac7277d" 110 | integrity sha512-zzfNuINhFF7OLAtGHfhwOW2TlYJyli7lOUoJUXw/uyklcwalV6WRXBXtFIicN8rTRK1XTiPWB4UY+YuW8dsnLQ== 111 | dependencies: 112 | "@inquirer/core" "^9.1.0" 113 | "@inquirer/type" "^1.5.3" 114 | yoctocolors-cjs "^2.1.2" 115 | 116 | "@inquirer/search@^1.1.0": 117 | version "1.1.0" 118 | resolved "https://registry.yarnpkg.com/@inquirer/search/-/search-1.1.0.tgz#665928cac2326b9501ddafbb8606ce4823b3106b" 119 | integrity sha512-h+/5LSj51dx7hp5xOn4QFnUaKeARwUCLs6mIhtkJ0JYPBLmEYjdHSYh7I6GrLg9LwpJ3xeX0FZgAG1q0QdCpVQ== 120 | dependencies: 121 | "@inquirer/core" "^9.1.0" 122 | "@inquirer/figures" "^1.0.5" 123 | "@inquirer/type" "^1.5.3" 124 | yoctocolors-cjs "^2.1.2" 125 | 126 | "@inquirer/select@^2.5.0": 127 | version "2.5.0" 128 | resolved "https://registry.yarnpkg.com/@inquirer/select/-/select-2.5.0.tgz#345c6908ecfaeef3d84ddd2f9feb2f487c558efb" 129 | integrity sha512-YmDobTItPP3WcEI86GvPo+T2sRHkxxOq/kXmsBjHS5BVXUgvgZ5AfJjkvQvZr03T81NnI3KrrRuMzeuYUQRFOA== 130 | dependencies: 131 | "@inquirer/core" "^9.1.0" 132 | "@inquirer/figures" "^1.0.5" 133 | "@inquirer/type" "^1.5.3" 134 | ansi-escapes "^4.3.2" 135 | yoctocolors-cjs "^2.1.2" 136 | 137 | "@inquirer/type@^1.5.3": 138 | version "1.5.3" 139 | resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-1.5.3.tgz#220ae9f3d5ae17dd3b2ce5ffd6b48c4a30c73181" 140 | integrity sha512-xUQ14WQGR/HK5ei+2CvgcwoH9fQ4PgPGmVFSN0pc1+fVyDL3MREhyAY7nxEErSu6CkllBM3D7e3e+kOvtu+eIg== 141 | dependencies: 142 | mute-stream "^1.0.0" 143 | 144 | "@types/mute-stream@^0.0.4": 145 | version "0.0.4" 146 | resolved "https://registry.yarnpkg.com/@types/mute-stream/-/mute-stream-0.0.4.tgz#77208e56a08767af6c5e1237be8888e2f255c478" 147 | integrity sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow== 148 | dependencies: 149 | "@types/node" "*" 150 | 151 | "@types/node@*", "@types/node@^22.5.2": 152 | version "22.5.4" 153 | resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.4.tgz#83f7d1f65bc2ed223bdbf57c7884f1d5a4fa84e8" 154 | integrity sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg== 155 | dependencies: 156 | undici-types "~6.19.2" 157 | 158 | "@types/wrap-ansi@^3.0.0": 159 | version "3.0.0" 160 | resolved "https://registry.yarnpkg.com/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz#18b97a972f94f60a679fd5c796d96421b9abb9fd" 161 | integrity sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g== 162 | 163 | agent-base@^7.0.2: 164 | version "7.1.1" 165 | resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317" 166 | integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== 167 | dependencies: 168 | debug "^4.3.4" 169 | 170 | ansi-escapes@^4.3.2: 171 | version "4.3.2" 172 | resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" 173 | integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== 174 | dependencies: 175 | type-fest "^0.21.3" 176 | 177 | ansi-regex@^5.0.1: 178 | version "5.0.1" 179 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" 180 | integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== 181 | 182 | ansi-styles@^4.0.0: 183 | version "4.3.0" 184 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" 185 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 186 | dependencies: 187 | color-convert "^2.0.1" 188 | 189 | asynckit@^0.4.0: 190 | version "0.4.0" 191 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" 192 | integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== 193 | 194 | axios@^1.7.2: 195 | version "1.7.7" 196 | resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" 197 | integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== 198 | dependencies: 199 | follow-redirects "^1.15.6" 200 | form-data "^4.0.0" 201 | proxy-from-env "^1.1.0" 202 | 203 | chardet@^0.7.0: 204 | version "0.7.0" 205 | resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" 206 | integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== 207 | 208 | cli-spinners@^2.9.2: 209 | version "2.9.2" 210 | resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41" 211 | integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg== 212 | 213 | cli-width@^4.1.0: 214 | version "4.1.0" 215 | resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-4.1.0.tgz#42daac41d3c254ef38ad8ac037672130173691c5" 216 | integrity sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ== 217 | 218 | cliui@^8.0.1: 219 | version "8.0.1" 220 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" 221 | integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== 222 | dependencies: 223 | string-width "^4.2.0" 224 | strip-ansi "^6.0.1" 225 | wrap-ansi "^7.0.0" 226 | 227 | color-convert@^2.0.1: 228 | version "2.0.1" 229 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 230 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 231 | dependencies: 232 | color-name "~1.1.4" 233 | 234 | color-name@~1.1.4: 235 | version "1.1.4" 236 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 237 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 238 | 239 | colors@^1.4.0: 240 | version "1.4.0" 241 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" 242 | integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== 243 | 244 | combined-stream@^1.0.8: 245 | version "1.0.8" 246 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" 247 | integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== 248 | dependencies: 249 | delayed-stream "~1.0.0" 250 | 251 | dayjs@^1.11.12: 252 | version "1.11.13" 253 | resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" 254 | integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== 255 | 256 | debug@4, debug@^4.3.4: 257 | version "4.3.7" 258 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" 259 | integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== 260 | dependencies: 261 | ms "^2.1.3" 262 | 263 | delayed-stream@~1.0.0: 264 | version "1.0.0" 265 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" 266 | integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== 267 | 268 | emoji-regex@^8.0.0: 269 | version "8.0.0" 270 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" 271 | integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== 272 | 273 | escalade@^3.1.1: 274 | version "3.2.0" 275 | resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" 276 | integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== 277 | 278 | external-editor@^3.1.0: 279 | version "3.1.0" 280 | resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" 281 | integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== 282 | dependencies: 283 | chardet "^0.7.0" 284 | iconv-lite "^0.4.24" 285 | tmp "^0.0.33" 286 | 287 | follow-redirects@^1.15.6: 288 | version "1.15.9" 289 | resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" 290 | integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== 291 | 292 | form-data@^4.0.0: 293 | version "4.0.0" 294 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" 295 | integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== 296 | dependencies: 297 | asynckit "^0.4.0" 298 | combined-stream "^1.0.8" 299 | mime-types "^2.1.12" 300 | 301 | get-caller-file@^2.0.5: 302 | version "2.0.5" 303 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" 304 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== 305 | 306 | he@^1.2.0: 307 | version "1.2.0" 308 | resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" 309 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== 310 | 311 | https-proxy-agent@^7.0.5: 312 | version "7.0.5" 313 | resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz#9e8b5013873299e11fab6fd548405da2d6c602b2" 314 | integrity sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw== 315 | dependencies: 316 | agent-base "^7.0.2" 317 | debug "4" 318 | 319 | iconv-lite@^0.4.24: 320 | version "0.4.24" 321 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" 322 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== 323 | dependencies: 324 | safer-buffer ">= 2.1.2 < 3" 325 | 326 | inquirer@^10.1.8: 327 | version "10.2.2" 328 | resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-10.2.2.tgz#36b866443a9fb2747151766c01ef9c8ba2d585eb" 329 | integrity sha512-tyao/4Vo36XnUItZ7DnUXX4f1jVao2mSrleV/5IPtW/XAEA26hRVsbc68nuTEKWcr5vMP/1mVoT2O7u8H4v1Vg== 330 | dependencies: 331 | "@inquirer/core" "^9.1.0" 332 | "@inquirer/prompts" "^5.5.0" 333 | "@inquirer/type" "^1.5.3" 334 | "@types/mute-stream" "^0.0.4" 335 | ansi-escapes "^4.3.2" 336 | mute-stream "^1.0.0" 337 | run-async "^3.0.0" 338 | rxjs "^7.8.1" 339 | 340 | is-fullwidth-code-point@^3.0.0: 341 | version "3.0.0" 342 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" 343 | integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== 344 | 345 | mime-db@1.52.0: 346 | version "1.52.0" 347 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" 348 | integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== 349 | 350 | mime-types@^2.1.12: 351 | version "2.1.35" 352 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" 353 | integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== 354 | dependencies: 355 | mime-db "1.52.0" 356 | 357 | ms@^2.1.3: 358 | version "2.1.3" 359 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" 360 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== 361 | 362 | mute-stream@^1.0.0: 363 | version "1.0.0" 364 | resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e" 365 | integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA== 366 | 367 | os-tmpdir@~1.0.2: 368 | version "1.0.2" 369 | resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" 370 | integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== 371 | 372 | proxy-from-env@^1.1.0: 373 | version "1.1.0" 374 | resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" 375 | integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== 376 | 377 | require-directory@^2.1.1: 378 | version "2.1.1" 379 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" 380 | integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== 381 | 382 | run-async@^3.0.0: 383 | version "3.0.0" 384 | resolved "https://registry.yarnpkg.com/run-async/-/run-async-3.0.0.tgz#42a432f6d76c689522058984384df28be379daad" 385 | integrity sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q== 386 | 387 | rxjs@^7.8.1: 388 | version "7.8.1" 389 | resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" 390 | integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== 391 | dependencies: 392 | tslib "^2.1.0" 393 | 394 | "safer-buffer@>= 2.1.2 < 3": 395 | version "2.1.2" 396 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 397 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 398 | 399 | signal-exit@^4.1.0: 400 | version "4.1.0" 401 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" 402 | integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== 403 | 404 | string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: 405 | version "4.2.3" 406 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" 407 | integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== 408 | dependencies: 409 | emoji-regex "^8.0.0" 410 | is-fullwidth-code-point "^3.0.0" 411 | strip-ansi "^6.0.1" 412 | 413 | strip-ansi@^6.0.0, strip-ansi@^6.0.1: 414 | version "6.0.1" 415 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" 416 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== 417 | dependencies: 418 | ansi-regex "^5.0.1" 419 | 420 | tmp@^0.0.33: 421 | version "0.0.33" 422 | resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" 423 | integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== 424 | dependencies: 425 | os-tmpdir "~1.0.2" 426 | 427 | tslib@^2.1.0: 428 | version "2.7.0" 429 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" 430 | integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== 431 | 432 | type-fest@^0.21.3: 433 | version "0.21.3" 434 | resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" 435 | integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== 436 | 437 | undici-types@~6.19.2: 438 | version "6.19.8" 439 | resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" 440 | integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== 441 | 442 | wrap-ansi@^6.2.0: 443 | version "6.2.0" 444 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" 445 | integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== 446 | dependencies: 447 | ansi-styles "^4.0.0" 448 | string-width "^4.1.0" 449 | strip-ansi "^6.0.0" 450 | 451 | wrap-ansi@^7.0.0: 452 | version "7.0.0" 453 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" 454 | integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== 455 | dependencies: 456 | ansi-styles "^4.0.0" 457 | string-width "^4.1.0" 458 | strip-ansi "^6.0.0" 459 | 460 | ws@^8.18.0: 461 | version "8.18.0" 462 | resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" 463 | integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== 464 | 465 | y18n@^5.0.5: 466 | version "5.0.8" 467 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" 468 | integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== 469 | 470 | yargs-parser@^21.1.1: 471 | version "21.1.1" 472 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" 473 | integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== 474 | 475 | yargs@^17.7.2: 476 | version "17.7.2" 477 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" 478 | integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== 479 | dependencies: 480 | cliui "^8.0.1" 481 | escalade "^3.1.1" 482 | get-caller-file "^2.0.5" 483 | require-directory "^2.1.1" 484 | string-width "^4.2.3" 485 | y18n "^5.0.5" 486 | yargs-parser "^21.1.1" 487 | 488 | yoctocolors-cjs@^2.1.2: 489 | version "2.1.2" 490 | resolved "https://registry.yarnpkg.com/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz#f4b905a840a37506813a7acaa28febe97767a242" 491 | integrity sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA== 492 | --------------------------------------------------------------------------------