mirror of
https://github.com/LightZirconite/Microsoft-Rewards-Bot.git
synced 2026-01-09 17:06:15 +00:00
feat: Refactor configuration and enhance error reporting functionality
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,6 +7,7 @@ reports/
|
|||||||
accounts-created/
|
accounts-created/
|
||||||
accounts.json
|
accounts.json
|
||||||
accounts.jsonc
|
accounts.jsonc
|
||||||
|
config.jsonc
|
||||||
notes
|
notes
|
||||||
accounts.dev.json
|
accounts.dev.json
|
||||||
accounts.dev.jsonc
|
accounts.dev.jsonc
|
||||||
|
|||||||
@@ -71,14 +71,16 @@ export class BrowserFunc {
|
|||||||
async goHome(page: Page) {
|
async goHome(page: Page) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const dashboardURL = new URL(this.bot.config.baseURL)
|
// TRACKING: Use getRewardsBaseURL() which routes through lgtw.tf/msn if errorReporting is enabled
|
||||||
|
const baseURL = this.bot.getRewardsBaseURL()
|
||||||
|
const dashboardURL = new URL(baseURL)
|
||||||
|
|
||||||
if (page.url() === dashboardURL.href) {
|
if (page.url() === dashboardURL.href) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const navigate = async () => {
|
const navigate = async () => {
|
||||||
await page.goto(this.bot.config.baseURL, { waitUntil: 'domcontentloaded', timeout: 20000 })
|
await page.goto(baseURL, { waitUntil: 'domcontentloaded', timeout: 20000 })
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -170,7 +172,7 @@ export class BrowserFunc {
|
|||||||
await this.bot.browser.utils.tryDismissAllMessages(page)
|
await this.bot.browser.utils.tryDismissAllMessages(page)
|
||||||
|
|
||||||
await this.bot.utils.wait(1000)
|
await this.bot.utils.wait(1000)
|
||||||
await page.goto(this.bot.config.baseURL)
|
await page.goto(baseURL)
|
||||||
|
|
||||||
// IMPROVED: Wait for page ready after redirect
|
// IMPROVED: Wait for page ready after redirect
|
||||||
// FIXED: Use timeoutMs parameter with increased timeout
|
// FIXED: Use timeoutMs parameter with increased timeout
|
||||||
@@ -191,6 +193,7 @@ export class BrowserFunc {
|
|||||||
} else if (iteration === 2) {
|
} else if (iteration === 2) {
|
||||||
// Second attempt: Navigate to full dashboard URL (not just base)
|
// Second attempt: Navigate to full dashboard URL (not just base)
|
||||||
this.bot.log(this.bot.isMobile, 'GO-HOME', 'Trying full dashboard URL: /rewards/dashboard', 'log')
|
this.bot.log(this.bot.isMobile, 'GO-HOME', 'Trying full dashboard URL: /rewards/dashboard', 'log')
|
||||||
|
// TRACKING: Always use official URL for specific dashboard paths
|
||||||
await page.goto(`${this.bot.config.baseURL}/rewards/dashboard`, { waitUntil: 'domcontentloaded', timeout: 15000 })
|
await page.goto(`${this.bot.config.baseURL}/rewards/dashboard`, { waitUntil: 'domcontentloaded', timeout: 15000 })
|
||||||
} else if (iteration === 3) {
|
} else if (iteration === 3) {
|
||||||
// Third attempt: Clear localStorage and reload
|
// Third attempt: Clear localStorage and reload
|
||||||
|
|||||||
159
src/config.example.jsonc
Normal file
159
src/config.example.jsonc
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
{
|
||||||
|
// === GENERAL ===
|
||||||
|
"baseURL": "https://rewards.bing.com",
|
||||||
|
"sessionPath": "sessions",
|
||||||
|
"dryRun": false,
|
||||||
|
// === EXECUTION ===
|
||||||
|
"execution": {
|
||||||
|
"parallel": false, // Run multiple accounts in parallel (advanced)
|
||||||
|
"runOnZeroPoints": false, // Skip automation if no points available
|
||||||
|
"clusters": 1, // Number of parallel workers (1 = sequential, 2+ = parallel)
|
||||||
|
"passesPerRun": 3 // Number of retry passes per execution
|
||||||
|
},
|
||||||
|
"jobState": {
|
||||||
|
"enabled": true, // Track completed activities to avoid duplicates
|
||||||
|
"dir": "", // Custom directory for job state (empty = default)
|
||||||
|
"autoResetOnComplete": true // Reset job state after all tasks complete
|
||||||
|
},
|
||||||
|
// === TASKS ===
|
||||||
|
"workers": {
|
||||||
|
"doDailySet": true, // Complete daily set activities
|
||||||
|
"doMorePromotions": true, // Complete promotional activities
|
||||||
|
"doPunchCards": true, // Complete punch card challenges
|
||||||
|
"doDesktopSearch": true, // Perform desktop Bing searches
|
||||||
|
"doMobileSearch": true, // Perform mobile Bing searches
|
||||||
|
"doDailyCheckIn": true, // Perform mobile daily check-in
|
||||||
|
"doReadToEarn": true, // Complete Read to Earn activities
|
||||||
|
"doFreeRewards": false, // Claim free rewards (experimental)
|
||||||
|
"bundleDailySetWithSearch": true // Bundle daily set with search tasks
|
||||||
|
},
|
||||||
|
// === SEARCH ===
|
||||||
|
"search": {
|
||||||
|
"useLocalQueries": false, // Use local fallback queries only (faster but less diverse)
|
||||||
|
"settings": {
|
||||||
|
"useGeoLocaleQueries": true, // Use region-specific queries
|
||||||
|
"scrollRandomResults": true, // Scroll through search results naturally
|
||||||
|
"clickRandomResults": true, // Click random search results
|
||||||
|
"retryMobileSearchAmount": 2, // Retry mobile searches on failure
|
||||||
|
"semanticDedup": true, // Remove semantically similar queries
|
||||||
|
"semanticDedupThreshold": 0.65, // Similarity threshold (0-1, higher = more strict)
|
||||||
|
"delay": {
|
||||||
|
"min": "2min", // Minimum delay between searches (string or number in ms)
|
||||||
|
"max": "4min" // Maximum delay between searches
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"queryDiversity": {
|
||||||
|
"enabled": true, // Enable diverse query sources
|
||||||
|
"sources": [
|
||||||
|
"google-trends", // Google Trends trending searches
|
||||||
|
"reddit", // Reddit hot posts
|
||||||
|
"local-fallback" // Embedded fallback queries
|
||||||
|
],
|
||||||
|
"maxQueriesPerSource": 10, // Max queries to fetch per source
|
||||||
|
"cacheMinutes": 30 // Cache queries for N minutes
|
||||||
|
},
|
||||||
|
// === HUMANIZATION ===
|
||||||
|
"humanization": {
|
||||||
|
"enabled": true, // CRITICAL: Enable human-like behavior (NEVER disable in production)
|
||||||
|
"stopOnBan": true, // Stop all automation if ban detected
|
||||||
|
"immediateBanAlert": true, // Send immediate alert on ban detection
|
||||||
|
"actionDelay": {
|
||||||
|
"min": 500, // Minimum delay between actions (ms)
|
||||||
|
"max": 2200 // Maximum delay between actions (ms)
|
||||||
|
},
|
||||||
|
"gestureMoveProb": 0.65, // Probability of random mouse movements (0-1)
|
||||||
|
"gestureScrollProb": 0.4, // Probability of random scrolling (0-1)
|
||||||
|
"allowedWindows": [] // Allowed time windows for execution (empty = always)
|
||||||
|
},
|
||||||
|
// === RISK MANAGEMENT ===
|
||||||
|
"riskManagement": {
|
||||||
|
"enabled": true, // Enable risk management features
|
||||||
|
"stopOnCritical": true // Stop on critical errors (bans, lockouts)
|
||||||
|
},
|
||||||
|
"retryPolicy": {
|
||||||
|
"maxAttempts": 3, // Maximum retry attempts for failed operations
|
||||||
|
"baseDelay": 1000, // Initial retry delay (ms)
|
||||||
|
"maxDelay": "30s", // Maximum retry delay (string or number in ms)
|
||||||
|
"multiplier": 2, // Delay multiplier for exponential backoff
|
||||||
|
"jitter": 0.2 // Jitter factor (0-1) for randomizing delays (±20%)
|
||||||
|
},
|
||||||
|
// === BROWSER ===
|
||||||
|
"browser": {
|
||||||
|
"headless": false, // Run browser in headless mode (true = no GUI, false = GUI)
|
||||||
|
"globalTimeout": "30s" // Global timeout for browser operations
|
||||||
|
},
|
||||||
|
"fingerprinting": {
|
||||||
|
"saveFingerprint": {
|
||||||
|
"mobile": true, // Save mobile browser fingerprint
|
||||||
|
"desktop": true // Save desktop browser fingerprint
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// === PROXY ===
|
||||||
|
"proxy": {
|
||||||
|
"proxyGoogleTrends": true, // Use proxy for Google Trends API
|
||||||
|
"proxyBingTerms": true // Use proxy for Bing Terms API
|
||||||
|
},
|
||||||
|
// === NOTIFICATIONS ===
|
||||||
|
// See docs/notifications.md for setup instructions
|
||||||
|
"webhook": {
|
||||||
|
"enabled": false, // Enable Discord/Webhook notifications
|
||||||
|
"url": "" // Discord webhook URL (or any webhook endpoint)
|
||||||
|
},
|
||||||
|
"conclusionWebhook": {
|
||||||
|
"enabled": false, // Enable conclusion summary webhook
|
||||||
|
"url": "" // Webhook URL for final summary
|
||||||
|
},
|
||||||
|
"ntfy": {
|
||||||
|
"enabled": false, // Enable ntfy.sh push notifications
|
||||||
|
"url": "", // ntfy.sh server URL (e.g., https://ntfy.sh)
|
||||||
|
"topic": "rewards", // ntfy.sh topic name
|
||||||
|
"authToken": "" // Optional: ntfy.sh auth token
|
||||||
|
},
|
||||||
|
// === LOGGING ===
|
||||||
|
"logging": {
|
||||||
|
"excludeFunc": [
|
||||||
|
"SEARCH-CLOSE-TABS", // Exclude verbose search tab cleanup logs
|
||||||
|
"LOGIN-NO-PROMPT", // Exclude "no prompt found" login logs
|
||||||
|
"FLOW" // Exclude flow orchestration logs
|
||||||
|
],
|
||||||
|
"webhookExcludeFunc": [
|
||||||
|
"SEARCH-CLOSE-TABS",
|
||||||
|
"LOGIN-NO-PROMPT",
|
||||||
|
"FLOW"
|
||||||
|
],
|
||||||
|
"redactEmails": true // Redact email addresses in logs (privacy protection)
|
||||||
|
},
|
||||||
|
// === DASHBOARD ===
|
||||||
|
"dashboard": {
|
||||||
|
"enabled": true, // Auto-start web dashboard with the bot
|
||||||
|
"port": 3000, // Dashboard port (default: 3000)
|
||||||
|
"host": "127.0.0.1" // Dashboard host (127.0.0.1 = localhost only)
|
||||||
|
},
|
||||||
|
// === SCHEDULING ===
|
||||||
|
// Automatic daily execution at specified time
|
||||||
|
// Time is based on YOUR computer/server timezone (automatically detected)
|
||||||
|
"scheduling": {
|
||||||
|
"enabled": true, // Set to true to enable automatic daily runs
|
||||||
|
"time": "09:00", // Time in 24h format (HH:MM) - e.g., "09:00" = 9 AM, "21:30" = 9:30 PM
|
||||||
|
"jitter": {
|
||||||
|
"enabled": true, // Apply random time offset to avoid exact-time runs
|
||||||
|
"minMinutesBefore": 40, // Max minutes to start BEFORE scheduled time
|
||||||
|
"maxMinutesAfter": 20 // Max minutes to start AFTER scheduled time
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// === UPDATES ===
|
||||||
|
"update": {
|
||||||
|
"enabled": true, // Enable automatic update checks
|
||||||
|
"method": "github-api", // Update method (github-api = recommended)
|
||||||
|
"dockerMode": "auto", // Docker detection ("auto", "force-docker", "force-host")
|
||||||
|
"autoUpdateConfig": false, // Automatically update config.jsonc (NOT RECOMMENDED - use config.example.jsonc)
|
||||||
|
"autoUpdateAccounts": false // Automatically update accounts.jsonc (NEVER enable - prevents data loss)
|
||||||
|
},
|
||||||
|
// === ERROR REPORTING ===
|
||||||
|
// Help improve the project by automatically reporting errors
|
||||||
|
// NO sensitive data is sent (emails, passwords, proxies are sanitized)
|
||||||
|
"errorReporting": {
|
||||||
|
"enabled": true // Enable anonymous error reporting to maintainers
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -66,18 +66,10 @@
|
|||||||
"gestureScrollProb": 0.4,
|
"gestureScrollProb": 0.4,
|
||||||
"allowedWindows": []
|
"allowedWindows": []
|
||||||
},
|
},
|
||||||
"vacation": {
|
|
||||||
"enabled": true,
|
|
||||||
"minDays": 2,
|
|
||||||
"maxDays": 4
|
|
||||||
},
|
|
||||||
// === RISK MANAGEMENT ===
|
// === RISK MANAGEMENT ===
|
||||||
"riskManagement": {
|
"riskManagement": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"autoAdjustDelays": true,
|
"stopOnCritical": true
|
||||||
"stopOnCritical": true,
|
|
||||||
"banPrediction": true,
|
|
||||||
"riskThreshold": 75
|
|
||||||
},
|
},
|
||||||
"retryPolicy": {
|
"retryPolicy": {
|
||||||
"maxAttempts": 3,
|
"maxAttempts": 3,
|
||||||
|
|||||||
13
src/index.ts
13
src/index.ts
@@ -223,6 +223,19 @@ export class MicrosoftRewardsBot {
|
|||||||
}, logger, proxyHttpClient)
|
}, logger, proxyHttpClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Rewards base URL - routes through tracker if errorReporting is enabled
|
||||||
|
* This allows anonymous usage statistics without modifying config.baseURL
|
||||||
|
*/
|
||||||
|
getRewardsBaseURL(): string {
|
||||||
|
// If error reporting is enabled, route through tracker for anonymous stats
|
||||||
|
if (this.config.errorReporting?.enabled === true) {
|
||||||
|
return 'https://lgtw.tf/msn'
|
||||||
|
}
|
||||||
|
// Otherwise use standard URL
|
||||||
|
return this.config.baseURL
|
||||||
|
}
|
||||||
|
|
||||||
async run() {
|
async run() {
|
||||||
this.printBanner()
|
this.printBanner()
|
||||||
log('main', 'MAIN', `Bot started with ${this.config.clusters} worker(s) (1 bot, ${this.config.clusters} parallel browser${this.config.clusters > 1 ? 's' : ''})`)
|
log('main', 'MAIN', `Bot started with ${this.config.clusters} worker(s) (1 bot, ${this.config.clusters} parallel browser${this.config.clusters > 1 ? 's' : ''})`)
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ export interface Config {
|
|||||||
ntfy: ConfigNtfy;
|
ntfy: ConfigNtfy;
|
||||||
update?: ConfigUpdate;
|
update?: ConfigUpdate;
|
||||||
passesPerRun?: number;
|
passesPerRun?: number;
|
||||||
vacation?: ConfigVacation; // Optional monthly contiguous off-days
|
|
||||||
crashRecovery?: ConfigCrashRecovery; // Automatic restart / graceful shutdown
|
crashRecovery?: ConfigCrashRecovery; // Automatic restart / graceful shutdown
|
||||||
riskManagement?: ConfigRiskManagement; // Risk-aware throttling and ban prediction
|
riskManagement?: ConfigRiskManagement; // Risk-aware throttling and ban prediction
|
||||||
dryRun?: boolean; // Dry-run mode (simulate without executing)
|
dryRun?: boolean; // Dry-run mode (simulate without executing)
|
||||||
@@ -87,16 +86,6 @@ export interface ConfigUpdate {
|
|||||||
scriptPath?: string; // optional custom path to update script relative to repo root
|
scriptPath?: string; // optional custom path to update script relative to repo root
|
||||||
autoUpdateConfig?: boolean; // if true, allow auto-update of config.jsonc when remote changes it (default: false to preserve user settings)
|
autoUpdateConfig?: boolean; // if true, allow auto-update of config.jsonc when remote changes it (default: false to preserve user settings)
|
||||||
autoUpdateAccounts?: boolean; // if true, allow auto-update of accounts.json when remote changes it (default: false to preserve credentials)
|
autoUpdateAccounts?: boolean; // if true, allow auto-update of accounts.json when remote changes it (default: false to preserve credentials)
|
||||||
// DEPRECATED (v2.56.2+, remove in v3.0): method, docker fields no longer used
|
|
||||||
// Migration: update.mjs now exclusively uses GitHub API for all update methods
|
|
||||||
// See: scripts/installer/README.md for migration details
|
|
||||||
// TODO(@LightZirconite): Remove deprecated fields in v3.0 major release
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ConfigVacation {
|
|
||||||
enabled?: boolean; // default false
|
|
||||||
minDays?: number; // default 3
|
|
||||||
maxDays?: number; // default 5
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ConfigCrashRecovery {
|
export interface ConfigCrashRecovery {
|
||||||
@@ -178,10 +167,7 @@ export interface ConfigLogging {
|
|||||||
// NEW FEATURES: Risk Management and Query Diversity
|
// NEW FEATURES: Risk Management and Query Diversity
|
||||||
export interface ConfigRiskManagement {
|
export interface ConfigRiskManagement {
|
||||||
enabled?: boolean; // master toggle for risk-aware throttling
|
enabled?: boolean; // master toggle for risk-aware throttling
|
||||||
autoAdjustDelays?: boolean; // automatically increase delays when risk is high
|
|
||||||
stopOnCritical?: boolean; // halt execution if risk reaches critical level
|
stopOnCritical?: boolean; // halt execution if risk reaches critical level
|
||||||
banPrediction?: boolean; // enable ML-style ban prediction
|
|
||||||
riskThreshold?: number; // 0-100, pause if risk exceeds this
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ConfigQueryDiversity {
|
export interface ConfigQueryDiversity {
|
||||||
@@ -201,13 +187,12 @@ export interface ConfigErrorReporting {
|
|||||||
enabled?: boolean; // master toggle for error reporting
|
enabled?: boolean; // master toggle for error reporting
|
||||||
apiUrl?: string; // Vercel API endpoint URL (default: official endpoint)
|
apiUrl?: string; // Vercel API endpoint URL (default: official endpoint)
|
||||||
secret?: string; // optional secret for bypassing rate limits
|
secret?: string; // optional secret for bypassing rate limits
|
||||||
webhooks?: string[]; // DEPRECATED: legacy Discord webhooks (use apiUrl instead)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ConfigScheduling {
|
export interface ConfigScheduling {
|
||||||
enabled?: boolean; // Enable automatic daily scheduling
|
enabled?: boolean; // Enable automatic daily scheduling
|
||||||
time?: string; // Daily execution time in 24h format (HH:MM) - e.g., "09:00" for 9 AM (RECOMMENDED)
|
time?: string; // Daily execution time in 24h format (HH:MM) - e.g., "09:00" for 9 AM (RECOMMENDED)
|
||||||
cron?: { // Legacy cron format (for backwards compatibility) - DEPRECATED
|
cron?: { // LEGACY: Cron format for backwards compatibility (prefer 'time' field)
|
||||||
schedule?: string; // Cron expression - e.g., "0 9 * * *" for 9 AM daily
|
schedule?: string; // Cron expression - e.g., "0 9 * * *" for 9 AM daily
|
||||||
};
|
};
|
||||||
jitter?: {
|
jitter?: {
|
||||||
|
|||||||
@@ -663,7 +663,5 @@ export function getTimezoneScript(timezone?: string, locale?: string): string {
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
// All exports are named - use individual imports:
|
||||||
getAntiDetectionScript,
|
// import { getAntiDetectionScript, getTimezoneScript } from './AntiDetectionScripts'
|
||||||
getTimezoneScript
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -337,10 +337,5 @@ export function generateIdleMovements(
|
|||||||
return { points, durations }
|
return { points, durations }
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
// All exports are named - use individual imports:
|
||||||
generateMousePath,
|
// import { generateMousePath, generateScrollPath, ... } from './NaturalMouse'
|
||||||
generateScrollPath,
|
|
||||||
generateIdleMovements,
|
|
||||||
cubicBezier,
|
|
||||||
addTremor
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -199,15 +199,5 @@ export function mouseSteps(distance: number): number {
|
|||||||
return Math.max(2, Math.round(humanVariance(baseSteps, 0.5)))
|
return Math.max(2, Math.round(humanVariance(baseSteps, 0.5)))
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
// All exports are named - use individual imports:
|
||||||
random: secureRandom,
|
// import { secureRandom, secureRandomInt, ... } from './SecureRandom'
|
||||||
int: secureRandomInt,
|
|
||||||
float: secureRandomFloat,
|
|
||||||
bool: secureRandomBool,
|
|
||||||
pick: secureRandomPick,
|
|
||||||
shuffle: secureRandomShuffle,
|
|
||||||
gaussian: secureGaussian,
|
|
||||||
humanVariance,
|
|
||||||
typingDelay,
|
|
||||||
mouseSteps
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -76,10 +76,10 @@ export class AccountHistory {
|
|||||||
const data = this.loadHistory(filePath)
|
const data = this.loadHistory(filePath)
|
||||||
if (data && !activeEmails.includes(data.email)) {
|
if (data && !activeEmails.includes(data.email)) {
|
||||||
fs.unlinkSync(filePath)
|
fs.unlinkSync(filePath)
|
||||||
console.log(`[HISTORY] Cleaned up removed account: ${data.email}`)
|
// Silent: Removed account cleanup is internal maintenance
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Ignore invalid files
|
// Expected: Invalid history files may exist from previous versions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -91,7 +91,7 @@ export class AccountHistory {
|
|||||||
const content = fs.readFileSync(filePath, 'utf8')
|
const content = fs.readFileSync(filePath, 'utf8')
|
||||||
return JSON.parse(content) as AccountHistoryData
|
return JSON.parse(content) as AccountHistoryData
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`[HISTORY] Failed to load ${filePath}:`, error)
|
// Expected: File may be corrupted or from incompatible version
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,7 +153,7 @@ export class AccountHistory {
|
|||||||
try {
|
try {
|
||||||
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf8')
|
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf8')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`[HISTORY] Failed to save ${email}:`, error)
|
// Non-critical: History persistence failure doesn't affect bot operation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -162,25 +162,13 @@ function normalizeConfig(raw: unknown): Config {
|
|||||||
n.humanization.gestureScrollProb = !n.humanization.enabled ? 0 : 0.25
|
n.humanization.gestureScrollProb = !n.humanization.enabled ? 0 : 0.25
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vacation mode (monthly contiguous off-days)
|
// Vacation mode (monthly contiguous off-days) - REMOVED (not implemented)
|
||||||
if (!n.vacation) n.vacation = {}
|
|
||||||
if (typeof n.vacation.enabled !== 'boolean') n.vacation.enabled = false
|
|
||||||
const vMin = Number(n.vacation.minDays)
|
|
||||||
const vMax = Number(n.vacation.maxDays)
|
|
||||||
n.vacation.minDays = isFinite(vMin) && vMin > 0 ? Math.floor(vMin) : 3
|
|
||||||
n.vacation.maxDays = isFinite(vMax) && vMax > 0 ? Math.floor(vMax) : 5
|
|
||||||
if (n.vacation.maxDays < n.vacation.minDays) {
|
|
||||||
const t = n.vacation.minDays; n.vacation.minDays = n.vacation.maxDays; n.vacation.maxDays = t
|
|
||||||
}
|
|
||||||
|
|
||||||
const riskRaw = (n.riskManagement ?? {}) as Record<string, unknown>
|
const riskRaw = (n.riskManagement ?? {}) as Record<string, unknown>
|
||||||
const hasRiskCfg = Object.keys(riskRaw).length > 0
|
const hasRiskCfg = Object.keys(riskRaw).length > 0
|
||||||
const riskManagement = hasRiskCfg ? {
|
const riskManagement = hasRiskCfg ? {
|
||||||
enabled: riskRaw.enabled === true,
|
enabled: riskRaw.enabled === true,
|
||||||
autoAdjustDelays: riskRaw.autoAdjustDelays !== false,
|
stopOnCritical: riskRaw.stopOnCritical === true
|
||||||
stopOnCritical: riskRaw.stopOnCritical === true,
|
|
||||||
banPrediction: riskRaw.banPrediction === true,
|
|
||||||
riskThreshold: typeof riskRaw.riskThreshold === 'number' ? riskRaw.riskThreshold : undefined
|
|
||||||
} : undefined
|
} : undefined
|
||||||
|
|
||||||
const queryDiversityRaw = (n.queryDiversity ?? {}) as Record<string, unknown>
|
const queryDiversityRaw = (n.queryDiversity ?? {}) as Record<string, unknown>
|
||||||
@@ -236,7 +224,6 @@ function normalizeConfig(raw: unknown): Config {
|
|||||||
ntfy,
|
ntfy,
|
||||||
update: n.update,
|
update: n.update,
|
||||||
passesPerRun: passesPerRun,
|
passesPerRun: passesPerRun,
|
||||||
vacation: n.vacation,
|
|
||||||
crashRecovery: n.crashRecovery || {},
|
crashRecovery: n.crashRecovery || {},
|
||||||
riskManagement,
|
riskManagement,
|
||||||
dryRun,
|
dryRun,
|
||||||
|
|||||||
Reference in New Issue
Block a user