UNPKG

@chiraitori/hoyolab-core

Version:

Core utilities for HoYoLab automation - daily check-ins and code redemption with smart rate limiting

457 lines (352 loc) 11.6 kB
# Advanced Usage Guide ## Table of Contents - [Installation](#installation) - [Cookie Setup](#cookie-setup) - [Basic Usage](#basic-usage) - [Advanced Features](#advanced-features) - [Error Handling](#error-handling) - [Utilities](#utilities) - [Best Practices](#best-practices) - [Troubleshooting](#troubleshooting) ## Installation ```bash npm install @chiraitori/hoyolab-core ``` ## Cookie Setup ### Obtaining Your Cookie 1. **Visit HoYoLab**: Go to [hoyolab.com](https://www.hoyolab.com/) and log in 2. **Open DevTools**: Press F12 or right-click → Inspect 3. **Navigate to Storage**: - Chrome/Edge: Application → Cookies - Firefox: Storage → Cookies 4. **Copy Required Values**: - `ltoken_v2` (required) - `ltuid_v2` (required) - `ltmid_v2` (required) - `cookie_token_v2` (for code redemption) - `account_mid_v2` (for code redemption) - `account_id_v2` (for code redemption) ### Cookie Format ```javascript const cookie = "ltoken_v2=v2_xxx; ltuid_v2=123456; ltmid_v2=xxx; cookie_token_v2=xxx; account_mid_v2=xxx; account_id_v2=123456"; ``` ### Validating Your Cookie ```javascript const { utils } = require('@chiraitori/hoyolab-core'); const validation = utils.validateCookie(yourCookie); if (!validation.valid) { console.error('Invalid cookie:', validation.error); } else { console.log('Cookie valid!'); console.log('Can redeem codes:', validation.hasRedeemTokens); } ``` ## Basic Usage ### Simple Check-in ```javascript const { HoyoLabClient, Games } = require('@chiraitori/hoyolab-core'); const client = new HoyoLabClient({ cookie: 'your_cookie_here' }); // Check in to Genshin Impact const result = await client.dailyCheckIn(Games.GENSHIN_IMPACT); console.log(utils.formatCheckInResult(result)); ``` ### Code Redemption ```javascript // Redeem a specific code const redeemResult = await client.redeemCode(Games.GENSHIN_IMPACT, 'PROMOCODE123'); // Fetch and redeem all available codes const codes = await client.fetchAvailableCodes(Games.GENSHIN_IMPACT); for (const code of codes) { try { await client.redeemCode(Games.GENSHIN_IMPACT, code.code); console.log(`Redeemed: ${code.code}`); } catch (error) { console.error(`Failed: ${code.code} - ${error.message}`); } } ``` ## Advanced Features ### Multi-Account Support ```javascript const { HoyoLabClient, Games } = require('@chiraitori/hoyolab-core'); const accounts = [ { cookie: 'account1_cookie', name: 'Main Account' }, { cookie: 'account2_cookie', name: 'Alt Account' } ]; for (const account of accounts) { const client = new HoyoLabClient({ cookie: account.cookie }); try { const result = await client.dailyCheckIn(Games.GENSHIN_IMPACT); console.log(`${account.name}: ${utils.formatCheckInResult(result)}`); } catch (error) { console.error(`${account.name}: ${error.message}`); } } ``` ### Rate Limiting ```javascript const { utils } = require('@chiraitori/hoyolab-core'); // Create rate limiter (10 calls per minute) const rateLimiter = new utils.RateLimiter(10, 60000); for (const code of codes) { await rateLimiter.waitIfNeeded(); try { await client.redeemCode(Games.GENSHIN_IMPACT, code.code); } catch (error) { console.error(error.message); } } ``` ### Retry with Backoff ```javascript const { utils } = require('@chiraitori/hoyolab-core'); const performCheckIn = () => client.dailyCheckIn(Games.GENSHIN_IMPACT); const result = await utils.retryWithBackoff(performCheckIn, { maxRetries: 3, baseDelay: 1000, maxDelay: 10000 }); ``` ### Caching ```javascript const { utils } = require('@chiraitori/hoyolab-core'); // Cache for 10 minutes const cache = new utils.SimpleCache(600000); // Check cache first let codes = cache.get('genshin_codes'); if (!codes) { codes = await client.fetchAvailableCodes(Games.GENSHIN_IMPACT); cache.set('genshin_codes', codes); } ``` ### Timezone-Aware Operations ```javascript const { utils } = require('@chiraitori/hoyolab-core'); const lastCheckIn = new Date('2025-06-01T10:00:00Z'); const userRegion = 'NA'; if (utils.isNewDay(userRegion, lastCheckIn)) { console.log('New day detected, performing check-in...'); await client.dailyCheckIn(Games.GENSHIN_IMPACT); } ``` ### Region Mapping Each HoYoverse game uses different region codes. The package provides game-specific region mapping: ```javascript const { getRegionName, Games } = require('@chiraitori/hoyolab-core'); // Map game-specific region codes to readable names const genshinRegion = getRegionName(Games.GENSHIN_IMPACT, 'os_usa'); // 'NA' const starrailRegion = getRegionName(Games.HONKAI_STAR_RAIL, 'prod_official_eur'); // 'EU' const zenlessRegion = getRegionName(Games.ZENLESS_ZONE_ZERO, 'prod_gf_jp'); // 'SEA' // Handle account information with proper region names const accounts = await client.getAccounts(Games.GENSHIN_IMPACT); for (const account of accounts) { console.log(`Account: ${account.nickname}`); console.log(`Region: ${getRegionName(Games.GENSHIN_IMPACT, account.region)}`); console.log(`UID: ${account.uid}`); } ``` #### Supported Region Mappings | Game | Region Code | Display Name | |------|-------------|--------------| | **Genshin Impact** | `os_usa` | NA | | | `os_euro` | EU | | | `os_asia` | SEA | | | `os_cht` | TW/HK/MO | | **Honkai Star Rail** | `prod_official_usa` | NA | | | `prod_official_eur` | EU | | | `prod_official_asia` | SEA | | | `prod_official_cht` | TW/HK/MO | | **Zenless Zone Zero** | `prod_gf_us` | NA | | | `prod_gf_eu` | EU | | | `prod_gf_jp` | SEA | | | `prod_gf_sg` | TW/HK/MO | ## Error Handling ### Comprehensive Error Handling ```javascript const { ErrorCodes } = require('@chiraitori/hoyolab-core'); try { await client.dailyCheckIn(Games.GENSHIN_IMPACT); } catch (error) { switch (error.code) { case ErrorCodes.INVALID_COOKIE: console.log('🚫 Cookie expired. Please update your cookie.'); // Trigger cookie refresh logic break; case ErrorCodes.ALREADY_CHECKED_IN: console.log('✅ Already checked in today.'); break; case ErrorCodes.RATE_LIMITED: console.log('⏰ Rate limited. Waiting 60 seconds...'); await utils.sleep(60000); // Retry logic here break; case ErrorCodes.NETWORK_ERROR: console.log('🌐 Network error. Check your connection.'); break; default: console.error('❌ Unexpected error:', error.message); console.error('Details:', error.details); } } ``` ### Graceful Degradation ```javascript const games = [Games.GENSHIN_IMPACT, Games.HONKAI_STAR_RAIL, Games.ZENLESS_ZONE_ZERO]; const results = {}; for (const game of games) { try { results[game] = await client.dailyCheckIn(game); } catch (error) { results[game] = { error: error.message, code: error.code }; // Continue with other games even if one fails if (error.code !== ErrorCodes.INVALID_COOKIE) { continue; } else { // Stop if cookie is invalid for all games break; } } } ``` ## Utilities ### Helper Functions ```javascript const { utils } = require('@chiraitori/hoyolab-core'); // Format results for display const result = await client.dailyCheckIn(Games.GENSHIN_IMPACT); console.log(utils.formatCheckInResult(result)); // Sleep/delay await utils.sleep(5000); // 5 seconds // Get timezone offset const offset = utils.getTimezoneOffset('NA'); // -300 minutes // Check if new day const isNewDay = utils.isNewDay('EU', lastCheckDate); ``` ## Best Practices ### 1. Cookie Management ```javascript // Store cookies securely const cookies = { main: process.env.HOYOLAB_COOKIE_MAIN, alt: process.env.HOYOLAB_COOKIE_ALT }; // Validate before use for (const [name, cookie] of Object.entries(cookies)) { const validation = utils.validateCookie(cookie); if (!validation.valid) { console.error(`Invalid cookie for ${name}: ${validation.error}`); } } ``` ### 2. Scheduled Operations ```javascript // Use node-cron for scheduling const cron = require('node-cron'); // Run daily at 1 AM cron.schedule('0 1 * * *', async () => { console.log('Running daily check-ins...'); const games = [Games.GENSHIN_IMPACT, Games.HONKAI_STAR_RAIL]; for (const game of games) { try { const result = await client.dailyCheckIn(game); console.log(`${game}: ${utils.formatCheckInResult(result)}`); } catch (error) { console.error(`${game}: ${error.message}`); } } }); ``` ### 3. Logging ```javascript const fs = require('fs'); function logResult(game, result, error = null) { const timestamp = new Date().toISOString(); const logEntry = { timestamp, game, success: !error, result: error ? error.message : result, errorCode: error ? error.code : null }; fs.appendFileSync('hoyolab.log', JSON.stringify(logEntry) + '\n'); } try { const result = await client.dailyCheckIn(Games.GENSHIN_IMPACT); logResult(Games.GENSHIN_IMPACT, result); } catch (error) { logResult(Games.GENSHIN_IMPACT, null, error); } ``` ### 4. Configuration Management ```javascript const config = { cookies: { main: process.env.HOYOLAB_COOKIE_MAIN }, games: [Games.GENSHIN_IMPACT, Games.HONKAI_STAR_RAIL], retryOptions: { maxRetries: 3, baseDelay: 1000 }, rateLimiting: { maxCalls: 10, windowMs: 60000 } }; const client = new HoyoLabClient({ cookie: config.cookies.main, userAgent: 'MyApp/1.0.0' }); ``` ## Troubleshooting ### Common Issues 1. **"Missing required cookie token"** - Ensure all required tokens are present in cookie - Check cookie format and spelling 2. **"Invalid or expired cookie"** - Re-obtain cookie from browser - Ensure you're logged in to HoYoLab 3. **"Rate limited"** - Add delays between requests - Use the built-in RateLimiter utility 4. **"Already checked in today"** - Normal behavior, check-in only once per day - Consider timezone differences 5. **"Code redemption not supported"** - Some games don't support code redemption - Ensure you have redemption tokens in cookie ### Debug Mode ```javascript const client = new HoyoLabClient({ cookie: 'your_cookie', userAgent: 'MyApp/1.0.0 (debug)' }); // Enable verbose logging process.env.DEBUG = 'hoyolab-core:*'; ``` ### Testing ```javascript // Test with a minimal example const { HoyoLabClient, Games, utils } = require('@chiraitori/hoyolab-core'); async function test() { const cookie = 'your_test_cookie'; // Validate cookie first const validation = utils.validateCookie(cookie); console.log('Cookie validation:', validation); if (!validation.valid) { console.error('Invalid cookie, stopping test'); return; } const client = new HoyoLabClient({ cookie }); try { const accounts = await client.getAccounts(); console.log('Accounts:', accounts); const result = await client.dailyCheckIn(Games.GENSHIN_IMPACT); console.log('Check-in result:', result); } catch (error) { console.error('Test failed:', error.message); console.error('Error code:', error.code); } } test(); ```