()
| 332 | } |
| 333 | |
| 334 | function loadAccounts() { |
| 335 | try { |
| 336 | migrateReplicaAccountsTo({ |
| 337 | sharedDir: config.sharedDataDir || config.dataDir, |
| 338 | accountsFile: ACCOUNTS_FILE, |
| 339 | }); |
| 340 | if (!existsSync(ACCOUNTS_FILE)) return; |
| 341 | const data = JSON.parse(readFileSync(ACCOUNTS_FILE, 'utf-8')); |
| 342 | for (const a of data) { |
| 343 | if (accounts.find(x => x.apiKey === a.apiKey)) continue; |
| 344 | accounts.push({ |
| 345 | id: a.id || randomUUID().slice(0, 8), |
| 346 | email: a.email, apiKey: a.apiKey, |
| 347 | apiServerUrl: a.apiServerUrl || '', |
| 348 | method: a.method || 'api_key', |
| 349 | status: a.status || 'active', |
| 350 | lastUsed: 0, errorCount: 0, |
| 351 | refreshToken: a.refreshToken || '', expiresAt: 0, refreshTimer: null, |
| 352 | addedAt: a.addedAt || Date.now(), |
| 353 | tier: a.tier || 'unknown', |
| 354 | capabilities: a.capabilities || {}, |
| 355 | lastProbed: a.lastProbed || 0, |
| 356 | credits: a.credits || null, |
| 357 | blockedModels: Array.isArray(a.blockedModels) ? a.blockedModels : [], |
| 358 | tierManual: !!a.tierManual, |
| 359 | userStatus: a.userStatus || null, |
| 360 | userStatusLastFetched: a.userStatusLastFetched || 0, |
| 361 | }); |
| 362 | } |
| 363 | if (data.length > 0) log.info(`Loaded ${data.length} account(s) from disk`); |
| 364 | } catch (e) { |
| 365 | log.error('Failed to load accounts:', e.message); |
| 366 | } |
| 367 | } |
| 368 | |
| 369 | // ─── Dynamic model catalog from cloud ───────────────────── |
| 370 |
no test coverage detected