#!/usr/bin/env node /** * 数据迁移脚本:为现有 API Key 设置默认有效期 * * 使用方法: * node scripts/migrate-apikey-expiry.js [--days=30] [--dry-run] * * 参数: * --days: 设置默认有效期天数(默认30天) * --dry-run: 仅模拟运行,不实际修改数据 */ const redis = require('../src/models/redis') const logger = require('../src/utils/logger') const readline = require('readline') // 解析命令行参数 const args = process.argv.slice(2) const params = {} args.forEach((arg) => { const [key, value] = arg.split('=') params[key.replace('--', '')] = value || true }) const DEFAULT_DAYS = params.days ? parseInt(params.days) : 30 const DRY_RUN = params['dry-run'] === true // 创建 readline 接口用于用户确认 const rl = readline.createInterface({ input: process.stdin, output: process.stdout }) async function askConfirmation(question) { return new Promise((resolve) => { rl.question(`${question} (yes/no): `, (answer) => { resolve(answer.toLowerCase() === 'yes' || answer.toLowerCase() === 'y') }) }) } async function migrateApiKeys() { try { logger.info('🔄 Starting API Key expiry migration...') logger.info(`📅 Default expiry period: ${DEFAULT_DAYS} days`) logger.info(`🔍 Mode: ${DRY_RUN ? 'DRY RUN (no changes will be made)' : 'LIVE RUN'}`) // 连接 Redis await redis.connect() logger.success('✅ Connected to Redis') // 获取所有 API Keys const apiKeys = await redis.getAllApiKeys() logger.info(`📊 Found ${apiKeys.length} API Keys in total`) // 统计信息 const stats = { total: apiKeys.length, needsMigration: 0, alreadyHasExpiry: 0, migrated: 0, errors: 0 } // 需要迁移的 Keys const keysToMigrate = [] // 分析每个 API Key for (const key of apiKeys) { if (!key.expiresAt || key.expiresAt === 'null' || key.expiresAt === '') { keysToMigrate.push(key) stats.needsMigration++ logger.info(`📌 API Key "${key.name}" (${key.id}) needs migration`) } else { stats.alreadyHasExpiry++ const expiryDate = new Date(key.expiresAt) logger.info( `✓ API Key "${key.name}" (${key.id}) already has expiry: ${expiryDate.toLocaleString()}` ) } } if (keysToMigrate.length === 0) { logger.success('✨ No API Keys need migration!') return } // 显示迁移摘要 console.log(`\n${'='.repeat(60)}`) console.log('📋 Migration Summary:') console.log('='.repeat(60)) console.log(`Total API Keys: ${stats.total}`) console.log(`Already have expiry: ${stats.alreadyHasExpiry}`) console.log(`Need migration: ${stats.needsMigration}`) console.log(`Default expiry: ${DEFAULT_DAYS} days from now`) console.log(`${'='.repeat(60)}\n`) // 如果不是 dry run,请求确认 if (!DRY_RUN) { const confirmed = await askConfirmation( `⚠️ This will set expiry dates for ${keysToMigrate.length} API Keys. Continue?` ) if (!confirmed) { logger.warn('❌ Migration cancelled by user') return } } // 计算新的过期时间 const newExpiryDate = new Date() newExpiryDate.setDate(newExpiryDate.getDate() + DEFAULT_DAYS) const newExpiryISO = newExpiryDate.toISOString() logger.info(`\n🚀 Starting migration... New expiry date: ${newExpiryDate.toLocaleString()}`) // 执行迁移 for (const key of keysToMigrate) { try { if (!DRY_RUN) { // 直接更新 Redis 中的数据 // 使用 hset 更新单个字段 await redis.client.hset(`apikey:${key.id}`, 'expiresAt', newExpiryISO) logger.success(`✅ Migrated: "${key.name}" (${key.id})`) } else { logger.info(`[DRY RUN] Would migrate: "${key.name}" (${key.id})`) } stats.migrated++ } catch (error) { logger.error(`❌ Error migrating "${key.name}" (${key.id}):`, error.message) stats.errors++ } } // 显示最终结果 console.log(`\n${'='.repeat(60)}`) console.log('✅ Migration Complete!') console.log('='.repeat(60)) console.log(`Successfully migrated: ${stats.migrated}`) console.log(`Errors: ${stats.errors}`) console.log(`New expiry date: ${newExpiryDate.toLocaleString()}`) console.log(`${'='.repeat(60)}\n`) if (DRY_RUN) { logger.warn('⚠️ This was a DRY RUN. No actual changes were made.') logger.info('💡 Run without --dry-run flag to apply changes.') } } catch (error) { logger.error('💥 Migration failed:', error) process.exit(1) } finally { // 清理 rl.close() await redis.disconnect() logger.info('👋 Disconnected from Redis') } } // 显示帮助信息 if (params.help) { console.log(` API Key Expiry Migration Script This script adds expiry dates to existing API Keys that don't have one. Usage: node scripts/migrate-apikey-expiry.js [options] Options: --days=NUMBER Set default expiry days (default: 30) --dry-run Simulate the migration without making changes --help Show this help message Examples: # Set 30-day expiry for all API Keys without expiry node scripts/migrate-apikey-expiry.js # Set 90-day expiry node scripts/migrate-apikey-expiry.js --days=90 # Test run without making changes node scripts/migrate-apikey-expiry.js --dry-run `) process.exit(0) } // 运行迁移 migrateApiKeys().catch((error) => { logger.error('💥 Unexpected error:', error) process.exit(1) })