polyv-live-cli
Version:
CLI tool for managing PolyV live streaming services.
319 lines • 12 kB
JavaScript
;
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