UNPKG

polyv-live-cli

Version:

CLI tool for managing PolyV live streaming services.

319 lines 12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.defaultConfigVersionManager = exports.ConfigVersionManager = exports.MINIMUM_SUPPORTED_VERSION = exports.CURRENT_VERSION = void 0; const SUPPORTED_VERSIONS = { '1.0': { version: '1.0', description: 'Initial secure configuration format with AES-256-GCM encryption', features: [ 'AES-256-GCM encryption for appSecret', 'File permission management', 'Account metadata tracking', 'Environment variable key support' ], breakingChanges: [] }, '0.9': { version: '0.9', description: 'Legacy format with basic encryption (migration target)', features: [ 'Basic AES-256-CBC encryption', 'Simple account storage' ], breakingChanges: [] }, '0.8': { version: '0.8', description: 'Pre-encryption format (plain text storage)', features: [ 'Plain text account storage', 'Basic metadata' ], breakingChanges: [] } }; exports.CURRENT_VERSION = '1.0'; exports.MINIMUM_SUPPORTED_VERSION = '0.8'; class ConfigVersionManager { getCurrentVersion() { return exports.CURRENT_VERSION; } getSupportedVersions() { return Object.values(SUPPORTED_VERSIONS); } isVersionSupported(version) { return version in SUPPORTED_VERSIONS; } getVersionInfo(version) { return SUPPORTED_VERSIONS[version] || null; } compareVersions(version1, version2) { const v1Parts = version1.split('.').map(Number); const v2Parts = version2.split('.').map(Number); const maxLength = Math.max(v1Parts.length, v2Parts.length); for (let i = 0; i < maxLength; i++) { const v1Part = v1Parts[i] || 0; const v2Part = v2Parts[i] || 0; if (v1Part < v2Part) return -1; if (v1Part > v2Part) return 1; } return 0; } detectVersion(config) { if (!config || typeof config !== 'object') { throw new Error('Invalid configuration object'); } const configObj = config; if (configObj['version'] && typeof configObj['version'] === 'string') { return configObj['version']; } if (configObj['accounts'] && configObj['metadata']) { const accounts = configObj['accounts']; const firstAccount = Object.values(accounts)[0]; if (firstAccount && typeof firstAccount.appSecret === 'object') { return '1.0'; } else if (firstAccount && typeof firstAccount.appSecret === 'string') { try { const decoded = Buffer.from(firstAccount.appSecret, 'base64').toString('utf8'); const parsed = JSON.parse(decoded); if (parsed.data && parsed.meta) { return '0.9'; } } catch { return '0.8'; } } } return exports.MINIMUM_SUPPORTED_VERSION; } validateVersion(config) { try { const detectedVersion = this.detectVersion(config); const currentVersion = this.getCurrentVersion(); if (!this.isVersionSupported(detectedVersion)) { return { isValid: false, message: `Unsupported configuration version: ${detectedVersion}`, detectedVersion, compatibility: 'incompatible', requiredActions: [ 'Configuration version is not supported', 'Please create a new configuration or contact support' ] }; } const comparison = this.compareVersions(detectedVersion, currentVersion); if (comparison === 0) { return { isValid: true, message: `Configuration is using current version: ${detectedVersion}`, detectedVersion, compatibility: 'compatible', requiredActions: [] }; } else if (comparison < 0) { return { isValid: true, message: `Configuration is using older version: ${detectedVersion}. Migration is available.`, detectedVersion, compatibility: 'upgradeable', requiredActions: [ `Run: polyv-live-cli config migrate --from ${detectedVersion} --to ${currentVersion}`, 'Backup your configuration before migration' ] }; } else { return { isValid: false, message: `Configuration is using newer version: ${detectedVersion}. Please update the CLI.`, detectedVersion, compatibility: 'incompatible', requiredActions: [ 'Update PolyV CLI to the latest version', 'Check for CLI updates: npm update -g polyv-live-cli' ] }; } } catch (error) { return { isValid: false, message: `Failed to validate version: ${error instanceof Error ? error.message : 'Unknown error'}`, compatibility: 'incompatible', requiredActions: [ 'Check configuration file format', 'Verify file is not corrupted' ] }; } } migrateConfiguration(config, fromVersion, toVersion) { const steps = []; const warnings = []; try { if (!this.isVersionSupported(fromVersion)) { return { success: false, message: `Source version ${fromVersion} is not supported`, fromVersion, toVersion, steps: [], warnings: [] }; } if (!this.isVersionSupported(toVersion)) { return { success: false, message: `Target version ${toVersion} is not supported`, fromVersion, toVersion, steps: [], warnings: [] }; } if (fromVersion === toVersion) { return { success: true, message: 'No migration needed - versions are the same', fromVersion, toVersion, steps: ['No migration required'], warnings: [], migratedConfig: config }; } let migratedConfig = this.deepClone(config); if (fromVersion === '0.8' && this.compareVersions(toVersion, '0.9') >= 0) { migratedConfig = this.migrateFrom08To09(migratedConfig); steps.push('Migrated from v0.8 to v0.9: Added basic encryption'); warnings.push('App secrets have been encrypted using basic encryption'); } if ((fromVersion === '0.8' || fromVersion === '0.9') && toVersion === '1.0') { migratedConfig = this.migrateFrom09To10(migratedConfig); steps.push('Migrated from v0.9 to v1.0: Upgraded to AES-256-GCM encryption'); warnings.push('Encryption has been upgraded to AES-256-GCM for better security'); } if (typeof migratedConfig === 'object' && migratedConfig !== null) { migratedConfig.version = toVersion; steps.push(`Set configuration version to ${toVersion}`); } return { success: true, message: `Successfully migrated configuration from ${fromVersion} to ${toVersion}`, fromVersion, toVersion, steps, warnings, migratedConfig: migratedConfig }; } catch (error) { return { success: false, message: `Migration failed: ${error instanceof Error ? error.message : 'Unknown error'}`, fromVersion, toVersion, steps, warnings }; } } migrateFrom08To09(config) { if (!config.accounts) { return config; } for (const accountName in config.accounts) { const account = config.accounts[accountName]; if (typeof account.appSecret === 'string' && !account.appSecret.includes('base64')) { account._needsEncryption = true; } } config.version = '0.9'; return config; } migrateFrom09To10(config) { if (!config.accounts) { return config; } if (!config.metadata) { const now = new Date().toISOString(); config.metadata = { createdAt: now, updatedAt: now }; } for (const accountName in config.accounts) { const account = config.accounts[accountName]; account._needsReencryption = true; } config.version = '1.0'; return config; } getMigrationPath(fromVersion, toVersion) { if (fromVersion === toVersion) { return []; } const path = []; if (fromVersion === '0.8' && toVersion === '0.9') { path.push('0.8 → 0.9: Encrypt plain text secrets'); } else if (fromVersion === '0.9' && toVersion === '1.0') { path.push('0.9 → 1.0: Upgrade to AES-256-GCM encryption'); } else if (fromVersion === '0.8' && toVersion === '1.0') { path.push('0.8 → 0.9: Encrypt plain text secrets'); path.push('0.9 → 1.0: Upgrade to AES-256-GCM encryption'); } return path; } createNewConfiguration() { const now = new Date().toISOString(); return { version: this.getCurrentVersion(), accounts: {}, metadata: { createdAt: now, updatedAt: now } }; } deepClone(obj) { return JSON.parse(JSON.stringify(obj)); } isMigrationRequired(config) { try { const detectedVersion = this.detectVersion(config); const currentVersion = this.getCurrentVersion(); return this.compareVersions(detectedVersion, currentVersion) < 0; } catch { return false; } } getBreakingChanges(fromVersion, toVersion) { const changes = []; const versions = Object.keys(SUPPORTED_VERSIONS).sort(this.compareVersions.bind(this)); const fromIndex = versions.indexOf(fromVersion); const toIndex = versions.indexOf(toVersion); if (fromIndex === -1 || toIndex === -1 || fromIndex >= toIndex) { return changes; } for (let i = fromIndex + 1; i <= toIndex; i++) { const version = versions[i]; if (version && SUPPORTED_VERSIONS[version]) { const versionInfo = SUPPORTED_VERSIONS[version]; changes.push(...versionInfo.breakingChanges); } } return changes; } } exports.ConfigVersionManager = ConfigVersionManager; exports.defaultConfigVersionManager = new ConfigVersionManager(); //# sourceMappingURL=config-version-manager.js.map