navflow-browser-server
Version:
Standalone Playwright browser server for NavFlow - enables browser automation with API key authentication, workspace device management, session sync, and requires Node.js v22+
180 lines • 7.54 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UpdateService = void 0;
const axios_1 = __importDefault(require("axios"));
const child_process_1 = require("child_process");
const util_1 = require("util");
const execAsync = (0, util_1.promisify)(child_process_1.exec);
class UpdateService {
constructor(packageName = 'navflow-browser-server', currentVersion, onShutdown) {
this.packageName = packageName;
this.currentVersion = currentVersion;
this.onShutdown = onShutdown;
}
/**
* Check the latest version available on npm
*/
async getLatestVersion() {
try {
console.log(`🔍 Checking latest version for ${this.packageName}...`);
const response = await axios_1.default.get(`https://registry.npmjs.org/${this.packageName}`, {
timeout: 10000,
headers: {
'Accept': 'application/json'
}
});
const latestVersion = response.data['dist-tags'].latest;
console.log(`📦 Latest version on npm: ${latestVersion}`);
return latestVersion;
}
catch (error) {
console.error('❌ Failed to check latest version from npm:', error.message);
return null;
}
}
/**
* Compare version strings (semver-like comparison)
*/
compareVersions(version1, version2) {
const v1parts = version1.split('.').map(Number);
const v2parts = version2.split('.').map(Number);
for (let i = 0; i < Math.max(v1parts.length, v2parts.length); i++) {
const v1part = v1parts[i] || 0;
const v2part = v2parts[i] || 0;
if (v1part < v2part)
return -1;
if (v1part > v2part)
return 1;
}
return 0;
}
/**
* Check if an update is available
*/
async isUpdateAvailable() {
const latestVersion = await this.getLatestVersion();
if (!latestVersion) {
return { available: false };
}
const comparison = this.compareVersions(this.currentVersion, latestVersion);
const available = comparison < 0; // Current version is older than latest
if (available) {
console.log(`🆙 Update available: ${this.currentVersion} → ${latestVersion}`);
}
else {
console.log(`✅ Already running latest version: ${this.currentVersion}`);
}
return {
available,
latestVersion: available ? latestVersion : undefined
};
}
/**
* Perform the update by restarting with the latest version
*/
async performUpdate() {
try {
console.log('🚀 Starting auto-update process...');
// Debug: Show process arguments
console.log('🔍 Process info:');
console.log(' - argv[0]:', process.argv[0]);
console.log(' - argv[1]:', process.argv[1]);
console.log(' - npm_execpath:', process.env.npm_execpath);
console.log(' - npm_command:', process.env.npm_command);
// Check if we're running via npx
const isNpx = process.argv[0].includes('npx') ||
process.env.npm_execpath ||
process.env.npm_command === 'exec' ||
process.argv[1]?.includes('navflow-browser-server');
console.log('🔧 NPX detection result:', isNpx);
if (!isNpx) {
console.warn('⚠️ Auto-update only supported when running via npx');
console.log('💡 To enable auto-updates, run: npx navflow-browser-server@latest');
console.log('📋 Current execution method appears to be direct node execution');
return false;
}
console.log('🔄 Restarting with latest version...');
console.log('📋 Command: npx --yes navflow-browser-server@latest');
// Get current process arguments (excluding node and script path)
const args = process.argv.slice(2);
const argsString = args.length > 0 ? ` ${args.join(' ')}` : '';
// Execute the update command
// Note: This will terminate the current process and start a new one
const updateCommand = `npx --yes navflow-browser-server@latest${argsString}`;
console.log(`🎯 Executing: ${updateCommand}`);
console.log('👋 Current process will terminate...');
// Method 1: Try direct spawn approach
try {
const child = (0, child_process_1.spawn)('npx', ['--yes', 'navflow-browser-server@latest', ...args], {
detached: true,
stdio: 'inherit',
shell: true
});
child.unref();
console.log(`✅ New process spawned (PID: ${child.pid})`);
// Give the new process time to start
setTimeout(async () => {
console.log('🔄 Shutting down current process...');
// Call shutdown handler if provided
if (this.onShutdown) {
await this.onShutdown();
}
process.exit(0);
}, 2000);
return true;
}
catch (spawnError) {
console.warn('⚠️ Spawn method failed, trying exec method...', spawnError);
// Method 2: Fallback to exec with shell
(0, child_process_1.exec)(updateCommand, (error, stdout, stderr) => {
if (error) {
console.error('❌ Exec method also failed:', error.message);
}
});
setTimeout(async () => {
console.log('🔄 Shutting down current process (exec method)...');
// Call shutdown handler if provided
if (this.onShutdown) {
await this.onShutdown();
}
process.exit(0);
}, 2000);
return true;
}
return true;
}
catch (error) {
console.error('❌ Auto-update failed:', error.message);
return false;
}
}
/**
* Schedule automatic update check
*/
scheduleUpdateCheck(intervalMinutes = 60) {
console.log(`⏰ Scheduling update checks every ${intervalMinutes} minutes`);
return setInterval(async () => {
try {
const { available, latestVersion } = await this.isUpdateAvailable();
if (available && latestVersion) {
console.log(`🔔 New version ${latestVersion} is available!`);
console.log('💡 Update will be applied automatically when no flows are running');
}
}
catch (error) {
console.warn('⚠️ Scheduled update check failed:', error);
}
}, intervalMinutes * 60 * 1000);
}
/**
* Get current version
*/
getCurrentVersion() {
return this.currentVersion;
}
}
exports.UpdateService = UpdateService;
//# sourceMappingURL=UpdateService.js.map