#!/usr/bin/env node /** * Universal Service Worker Generator for OneUptime Services * * This script can be used by any OneUptime service to generate * a service worker from a template with dynamic versioning. * * Usage: * node generate-service-worker.js [template-path] [output-path] * * Example: * node generate-service-worker.js sw.js.template public/sw.js */ const fs = require('fs'); const path = require('path'); const crypto = require('crypto'); // Default values const DEFAULT_APP_VERSION = '1.0.0'; const DEFAULT_GIT_SHA = 'local'; /** * Get app version from environment or package.json */ function getAppVersion(packageJsonPath) { // First try environment variable (Docker build) if (process.env.APP_VERSION) { return process.env.APP_VERSION; } // Fallback to package.json version try { const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); return packageJson.version || DEFAULT_APP_VERSION; } catch (error) { console.warn('Could not read package.json, using default version'); return DEFAULT_APP_VERSION; } } /** * Get git SHA from environment */ function getGitSha() { // Try environment variable first (Docker build) if (process.env.GIT_SHA) { return process.env.GIT_SHA.substring(0, 8); // Short SHA } // Try to get from git command if available try { const { execSync } = require('child_process'); const gitSha = execSync('git rev-parse --short HEAD', { encoding: 'utf8' }).trim(); return gitSha; } catch (error) { // Fallback to timestamp-based hash for local development const timestamp = Date.now().toString(); const hash = crypto.createHash('md5').update(timestamp).digest('hex'); return hash.substring(0, 8); } } /** * Generate service worker from template */ function generateServiceWorker(templatePath, outputPath, serviceName = 'OneUptime') { // Check if template exists if (!fs.existsSync(templatePath)) { console.error('❌ Service worker template not found:', templatePath); process.exit(1); } // Read template const template = fs.readFileSync(templatePath, 'utf8'); // Get version information const packageJsonPath = path.join(path.dirname(templatePath), 'package.json'); const appVersion = getAppVersion(packageJsonPath); const gitSha = getGitSha(); const buildTimestamp = new Date().toISOString(); console.log(`🔧 Generating service worker for ${serviceName}...`); console.log(` App Version: ${appVersion}`); console.log(` Git SHA: ${gitSha}`); console.log(` Build Time: ${buildTimestamp}`); // Replace placeholders const generatedContent = template .replace(/\{\{APP_VERSION\}\}/g, appVersion) .replace(/\{\{GIT_SHA\}\}/g, gitSha) .replace(/\{\{BUILD_TIMESTAMP\}\}/g, buildTimestamp) .replace(/\{\{SERVICE_NAME\}\}/g, serviceName); // Add generation comment at the top const header = `/* * Generated Service Worker for ${serviceName} * * Generated at: ${buildTimestamp} * App Version: ${appVersion} * Git SHA: ${gitSha} * * DO NOT EDIT THIS FILE DIRECTLY * Edit the template file instead and run the generator script */ `; const finalContent = header + generatedContent; // Ensure output directory exists const outputDir = path.dirname(outputPath); if (!fs.existsSync(outputDir)) { fs.mkdirSync(outputDir, { recursive: true }); } // Write generated service worker fs.writeFileSync(outputPath, finalContent, 'utf8'); console.log('✅ Service worker generated successfully:', outputPath); console.log(` Cache version: oneuptime-v${appVersion}-${gitSha}`); } // Command line interface if (require.main === module) { const args = process.argv.slice(2); const templatePath = args[0] || 'sw.js.template'; const outputPath = args[1] || 'public/sw.js'; const serviceName = args[2] || path.basename(process.cwd()); try { // Resolve paths relative to current working directory const resolvedTemplatePath = path.resolve(templatePath); const resolvedOutputPath = path.resolve(outputPath); generateServiceWorker(resolvedTemplatePath, resolvedOutputPath, serviceName); } catch (error) { console.error('❌ Failed to generate service worker:', error.message); process.exit(1); } } module.exports = { generateServiceWorker, getAppVersion, getGitSha };