mirror of
https://github.com/LightZirconite/Microsoft-Rewards-Bot.git
synced 2026-01-10 17:26:17 +00:00
Refactor: Enhance error handling and logging in Browser and MicrosoftRewardsBot classes; remove unused luxon declarations
This commit is contained in:
@@ -21,7 +21,9 @@ class Browser {
|
|||||||
// Dynamically import child_process to avoid overhead otherwise
|
// Dynamically import child_process to avoid overhead otherwise
|
||||||
const { execSync } = await import('child_process')
|
const { execSync } = await import('child_process')
|
||||||
execSync('npx playwright install chromium', { stdio: 'ignore' })
|
execSync('npx playwright install chromium', { stdio: 'ignore' })
|
||||||
} catch { /* silent */ }
|
} catch (e) {
|
||||||
|
this.bot.log(this.bot.isMobile, 'BROWSER', `Auto-install failed: ${e instanceof Error ? e.message : String(e)}`, 'warn')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let browser: import('rebrowser-playwright').Browser
|
let browser: import('rebrowser-playwright').Browser
|
||||||
@@ -114,11 +116,18 @@ class Browser {
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
document.documentElement.appendChild(style)
|
document.documentElement.appendChild(style)
|
||||||
} catch { /* ignore */ }
|
} catch (e) {
|
||||||
|
// Style injection failed - not critical, page will still function
|
||||||
|
}
|
||||||
})
|
})
|
||||||
} catch { /* ignore */ }
|
} catch (e) {
|
||||||
|
// Viewport/script setup failed - log for debugging but continue
|
||||||
|
this.bot.log(this.bot.isMobile, 'BROWSER', `Page setup warning: ${e instanceof Error ? e.message : String(e)}`, 'warn')
|
||||||
|
}
|
||||||
})
|
})
|
||||||
} catch { /* ignore */ }
|
} catch (e) {
|
||||||
|
this.bot.log(this.bot.isMobile, 'BROWSER', `Context event handler setup warning: ${e instanceof Error ? e.message : String(e)}`, 'warn')
|
||||||
|
}
|
||||||
|
|
||||||
await context.addCookies(sessionData.cookies)
|
await context.addCookies(sessionData.cookies)
|
||||||
|
|
||||||
|
|||||||
33
src/index.ts
33
src/index.ts
@@ -300,7 +300,9 @@ export class MicrosoftRewardsBot {
|
|||||||
this.log(false, 'BUY-MODE', 'Monitor tab was closed; reopening in background...', 'warn')
|
this.log(false, 'BUY-MODE', 'Monitor tab was closed; reopening in background...', 'warn')
|
||||||
await recreateMonitor()
|
await recreateMonitor()
|
||||||
}
|
}
|
||||||
} catch { /* ignore */ }
|
} catch (e) {
|
||||||
|
this.log(false, 'BUY-MODE', `Failed to check/recreate monitor tab: ${e instanceof Error ? e.message : String(e)}`, 'warn')
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await this.browser.func.getDashboardData(monitor)
|
const data = await this.browser.func.getDashboardData(monitor)
|
||||||
@@ -321,9 +323,14 @@ export class MicrosoftRewardsBot {
|
|||||||
const msg = err instanceof Error ? err.message : String(err)
|
const msg = err instanceof Error ? err.message : String(err)
|
||||||
if (/Target closed|page has been closed|browser has been closed/i.test(msg)) {
|
if (/Target closed|page has been closed|browser has been closed/i.test(msg)) {
|
||||||
this.log(false, 'BUY-MODE', 'Monitor page closed or lost; recreating...', 'warn')
|
this.log(false, 'BUY-MODE', 'Monitor page closed or lost; recreating...', 'warn')
|
||||||
try { await recreateMonitor() } catch { /* ignore */ }
|
try {
|
||||||
|
await recreateMonitor()
|
||||||
|
} catch (e) {
|
||||||
|
this.log(false, 'BUY-MODE', `Failed to recreate monitor: ${e instanceof Error ? e.message : String(e)}`, 'warn')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.log(false, 'BUY-MODE', `Dashboard check error: ${msg}`, 'warn')
|
||||||
}
|
}
|
||||||
// Swallow other errors to avoid disrupting the user
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,7 +340,11 @@ export class MicrosoftRewardsBot {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(false, 'BUY-MODE', `Failed to save session: ${e instanceof Error ? e.message : String(e)}`, 'warn')
|
log(false, 'BUY-MODE', `Failed to save session: ${e instanceof Error ? e.message : String(e)}`, 'warn')
|
||||||
}
|
}
|
||||||
try { if (!monitor.isClosed()) await monitor.close() } catch {/* ignore */}
|
try {
|
||||||
|
if (!monitor.isClosed()) await monitor.close()
|
||||||
|
} catch (e) {
|
||||||
|
log(false, 'BUY-MODE', `Failed to close monitor tab: ${e instanceof Error ? e.message : String(e)}`, 'warn')
|
||||||
|
}
|
||||||
|
|
||||||
// Send a final minimal conclusion webhook for this manual session
|
// Send a final minimal conclusion webhook for this manual session
|
||||||
const summary: AccountSummary = {
|
const summary: AccountSummary = {
|
||||||
@@ -351,7 +362,7 @@ export class MicrosoftRewardsBot {
|
|||||||
|
|
||||||
this.log(false, 'BUY-MODE', 'Buy mode session finished (monitoring period ended). You can close the browser when done.')
|
this.log(false, 'BUY-MODE', 'Buy mode session finished (monitoring period ended). You can close the browser when done.')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.log(false, 'BUY-MODE', `Error in buy mode: ${e instanceof Error ? e.message : e}`, 'error')
|
this.log(false, 'BUY-MODE', `Error in buy mode: ${e instanceof Error ? e.message : String(e)}`, 'error')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,10 +517,14 @@ export class MicrosoftRewardsBot {
|
|||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
await this.sendConclusion(this.accountSummaries)
|
await this.sendConclusion(this.accountSummaries)
|
||||||
} catch {/* ignore */}
|
} catch (e) {
|
||||||
|
log('main', 'CONCLUSION', `Failed to send conclusion: ${e instanceof Error ? e.message : String(e)}`, 'warn')
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
await this.runAutoUpdate()
|
await this.runAutoUpdate()
|
||||||
} catch {/* ignore */}
|
} catch (e) {
|
||||||
|
log('main', 'UPDATE', `Auto-update failed: ${e instanceof Error ? e.message : String(e)}`, 'warn')
|
||||||
|
}
|
||||||
log('main', 'MAIN-WORKER', 'All workers destroyed. Exiting main process!', 'warn')
|
log('main', 'MAIN-WORKER', 'All workers destroyed. Exiting main process!', 'warn')
|
||||||
process.exit(0)
|
process.exit(0)
|
||||||
})()
|
})()
|
||||||
@@ -806,7 +821,9 @@ export class MicrosoftRewardsBot {
|
|||||||
// Single process mode -> build and send conclusion directly
|
// Single process mode -> build and send conclusion directly
|
||||||
await this.sendConclusion(this.accountSummaries)
|
await this.sendConclusion(this.accountSummaries)
|
||||||
// After conclusion, run optional auto-update
|
// After conclusion, run optional auto-update
|
||||||
await this.runAutoUpdate().catch(() => {/* ignore update errors */})
|
await this.runAutoUpdate().catch((e) => {
|
||||||
|
log('main', 'UPDATE', `Auto-update failed: ${e instanceof Error ? e.message : String(e)}`, 'warn')
|
||||||
|
})
|
||||||
}
|
}
|
||||||
process.exit()
|
process.exit()
|
||||||
}
|
}
|
||||||
|
|||||||
7
src/luxon.d.ts
vendored
7
src/luxon.d.ts
vendored
@@ -1,7 +0,0 @@
|
|||||||
/* Minimal ambient declarations to unblock TypeScript when @types/luxon is absent. */
|
|
||||||
declare module 'luxon' {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
export const DateTime: any
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
export const IANAZone: any
|
|
||||||
}
|
|
||||||
@@ -19,13 +19,19 @@ export class Humanizer {
|
|||||||
if (Math.random() < moveProb) {
|
if (Math.random() < moveProb) {
|
||||||
const x = Math.floor(Math.random() * 40) + 5
|
const x = Math.floor(Math.random() * 40) + 5
|
||||||
const y = Math.floor(Math.random() * 30) + 5
|
const y = Math.floor(Math.random() * 30) + 5
|
||||||
await page.mouse.move(x, y, { steps: 2 }).catch(() => {})
|
await page.mouse.move(x, y, { steps: 2 }).catch(() => {
|
||||||
|
// Mouse move failed - page may be closed or unavailable
|
||||||
|
})
|
||||||
}
|
}
|
||||||
if (Math.random() < scrollProb) {
|
if (Math.random() < scrollProb) {
|
||||||
const dy = (Math.random() < 0.5 ? 1 : -1) * (Math.floor(Math.random() * 150) + 50)
|
const dy = (Math.random() < 0.5 ? 1 : -1) * (Math.floor(Math.random() * 150) + 50)
|
||||||
await page.mouse.wheel(0, dy).catch(() => {})
|
await page.mouse.wheel(0, dy).catch(() => {
|
||||||
|
// Mouse wheel failed - page may be closed or unavailable
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} catch {/* noop */}
|
} catch {
|
||||||
|
// Gesture execution failed - not critical for operation
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async actionPause(): Promise<void> {
|
async actionPause(): Promise<void> {
|
||||||
@@ -40,7 +46,10 @@ export class Humanizer {
|
|||||||
try {
|
try {
|
||||||
const n = this.util.stringToMs(String(v))
|
const n = this.util.stringToMs(String(v))
|
||||||
return Math.max(0, Math.min(n, 10_000))
|
return Math.max(0, Math.min(n, 10_000))
|
||||||
} catch { return defMin }
|
} catch (e) {
|
||||||
|
// Parse failed - use default minimum
|
||||||
|
return defMin
|
||||||
|
}
|
||||||
}
|
}
|
||||||
min = parse(this.cfg.actionDelay.min)
|
min = parse(this.cfg.actionDelay.min)
|
||||||
max = parse(this.cfg.actionDelay.max)
|
max = parse(this.cfg.actionDelay.max)
|
||||||
|
|||||||
@@ -260,7 +260,15 @@ export function loadAccounts(): Account[] {
|
|||||||
]
|
]
|
||||||
let chosen: string | null = null
|
let chosen: string | null = null
|
||||||
for (const p of candidates) {
|
for (const p of candidates) {
|
||||||
try { if (fs.existsSync(p)) { chosen = p; break } } catch { /* ignore */ }
|
try {
|
||||||
|
if (fs.existsSync(p)) {
|
||||||
|
chosen = p
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Filesystem check failed for this path, try next
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!chosen) throw new Error(`accounts file not found in: ${candidates.join(' | ')}`)
|
if (!chosen) throw new Error(`accounts file not found in: ${candidates.join(' | ')}`)
|
||||||
raw = fs.readFileSync(chosen, 'utf-8')
|
raw = fs.readFileSync(chosen, 'utf-8')
|
||||||
@@ -349,7 +357,15 @@ export function loadConfig(): Config {
|
|||||||
|
|
||||||
let cfgPath: string | null = null
|
let cfgPath: string | null = null
|
||||||
for (const p of candidates) {
|
for (const p of candidates) {
|
||||||
try { if (fs.existsSync(p)) { cfgPath = p; break } } catch { /* ignore */ }
|
try {
|
||||||
|
if (fs.existsSync(p)) {
|
||||||
|
cfgPath = p
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Filesystem check failed for this path, try next
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!cfgPath) throw new Error(`config.json not found in: ${candidates.join(' | ')}`)
|
if (!cfgPath) throw new Error(`config.json not found in: ${candidates.join(' | ')}`)
|
||||||
const config = fs.readFileSync(cfgPath, 'utf-8')
|
const config = fs.readFileSync(cfgPath, 'utf-8')
|
||||||
@@ -377,6 +393,8 @@ export async function loadSessionData(sessionPath: string, email: string, isMobi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fetch fingerprint file (support both legacy typo "fingerpint" and corrected "fingerprint")
|
// Fetch fingerprint file (support both legacy typo "fingerpint" and corrected "fingerprint")
|
||||||
|
// NOTE: "fingerpint" is a historical typo that must be maintained for backwards compatibility
|
||||||
|
// with existing session files. We check for the corrected name first, then fall back to the typo.
|
||||||
const baseDir = path.join(__dirname, '../browser/', sessionPath, email)
|
const baseDir = path.join(__dirname, '../browser/', sessionPath, email)
|
||||||
const legacyFile = path.join(baseDir, `${isMobile ? 'mobile_fingerpint' : 'desktop_fingerpint'}.json`)
|
const legacyFile = path.join(baseDir, `${isMobile ? 'mobile_fingerpint' : 'desktop_fingerpint'}.json`)
|
||||||
const correctFile = path.join(baseDir, `${isMobile ? 'mobile_fingerprint' : 'desktop_fingerprint'}.json`)
|
const correctFile = path.join(baseDir, `${isMobile ? 'mobile_fingerprint' : 'desktop_fingerprint'}.json`)
|
||||||
@@ -436,11 +454,18 @@ export async function saveFingerprintData(sessionPath: string, email: string, is
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Save fingerprint to files (write both legacy and corrected names for compatibility)
|
// Save fingerprint to files (write both legacy and corrected names for compatibility)
|
||||||
|
// NOTE: Writing to both "fingerpint" (typo) and "fingerprint" (correct) ensures backwards
|
||||||
|
// compatibility with older bot versions that expect the typo filename.
|
||||||
const legacy = path.join(sessionDir, `${isMobile ? 'mobile_fingerpint' : 'desktop_fingerpint'}.json`)
|
const legacy = path.join(sessionDir, `${isMobile ? 'mobile_fingerpint' : 'desktop_fingerpint'}.json`)
|
||||||
const correct = path.join(sessionDir, `${isMobile ? 'mobile_fingerprint' : 'desktop_fingerprint'}.json`)
|
const correct = path.join(sessionDir, `${isMobile ? 'mobile_fingerprint' : 'desktop_fingerprint'}.json`)
|
||||||
const payload = JSON.stringify(fingerprint)
|
const payload = JSON.stringify(fingerprint)
|
||||||
await fs.promises.writeFile(correct, payload)
|
await fs.promises.writeFile(correct, payload)
|
||||||
try { await fs.promises.writeFile(legacy, payload) } catch { /* ignore */ }
|
try {
|
||||||
|
await fs.promises.writeFile(legacy, payload)
|
||||||
|
} catch (e) {
|
||||||
|
// Legacy file write failed - not critical since correct file was written
|
||||||
|
// Silently continue to maintain compatibility
|
||||||
|
}
|
||||||
|
|
||||||
return sessionDir
|
return sessionDir
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -1,72 +1,44 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||||
|
|
||||||
/* Basic Options */
|
/* Basic Options */
|
||||||
"target": "ES2020", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
|
"target": "ES2020",
|
||||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
"module": "commonjs",
|
||||||
// "lib": [], /* Specify library files to be included in the compilation. */
|
"declaration": true,
|
||||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
"declarationMap": true,
|
||||||
// "checkJs": true, /* Report errors in .js files. */
|
"sourceMap": true,
|
||||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
|
"outDir": "./dist",
|
||||||
"declaration": true, /* Generates corresponding '.d.ts' file. */
|
"rootDir": "./src",
|
||||||
"declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
|
||||||
"sourceMap": true, /* Generates corresponding '.map' file. */
|
|
||||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
|
||||||
"outDir": "./dist", /* Redirect output structure to the directory. */
|
|
||||||
"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
|
||||||
// "composite": true, /* Enable project compilation */
|
|
||||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
|
||||||
// "removeComments": true, /* Do not emit comments to output. */
|
|
||||||
// "noEmit": true, /* Do not emit outputs. */
|
|
||||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
|
||||||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
|
||||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
|
||||||
/* Strict Type-Checking Options */
|
/* Strict Type-Checking Options */
|
||||||
"strict": true, /* Enable all strict type-checking options. */
|
"strict": true,
|
||||||
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
"noImplicitAny": true,
|
||||||
"strictNullChecks": true, /* Enable strict null checks. */
|
"strictNullChecks": true,
|
||||||
"strictFunctionTypes": true, /* Enable strict checking of function types. */
|
"strictFunctionTypes": true,
|
||||||
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
"noImplicitThis": true,
|
||||||
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
|
"alwaysStrict": true,
|
||||||
"noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
|
||||||
"alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
|
||||||
/* Additional Checks */
|
/* Additional Checks */
|
||||||
"noUnusedLocals": true, /* Report errors on unused locals. */
|
"noUnusedLocals": true,
|
||||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
"noImplicitReturns": true,
|
||||||
"noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
"noFallthroughCasesInSwitch": true,
|
||||||
"noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
"noUncheckedIndexedAccess": true,
|
||||||
"noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
|
"noImplicitOverride": true,
|
||||||
"noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */
|
|
||||||
// "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */
|
|
||||||
/* Module Resolution Options */
|
/* Module Resolution Options */
|
||||||
"moduleResolution":"node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
"moduleResolution": "node",
|
||||||
"types": ["node"],
|
"types": ["node"],
|
||||||
// Keep explicit typeRoots to ensure resolution in environments that don't auto-detect before full install.
|
"esModuleInterop": true,
|
||||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
|
||||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
|
||||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
|
||||||
// "typeRoots": [], /* List of folders to include type definitions from. */
|
|
||||||
// "types": [], /* Type declaration files to be included in compilation. */
|
|
||||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
|
||||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
|
||||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
|
||||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
|
||||||
/* Source Map Options */
|
|
||||||
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
|
||||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
|
||||||
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
|
||||||
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
|
||||||
/* Experimental Options */
|
|
||||||
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
|
||||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
|
||||||
/* Advanced Options */
|
/* Advanced Options */
|
||||||
"skipLibCheck": true, /* Skip type checking of declaration files. */
|
"skipLibCheck": true,
|
||||||
"forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
|
"forceConsistentCasingInFileNames": true,
|
||||||
"resolveJsonModule": true
|
"resolveJsonModule": true
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src/**/*.ts",
|
"src/**/*.ts",
|
||||||
"src/**/*.d.ts",
|
"src/**/*.d.ts",
|
||||||
"src/functions/queries.json"
|
"src/functions/queries.json"
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
|
|||||||
Reference in New Issue
Block a user