@tomei/finance
Version:
NestJS package for finance module
301 lines (253 loc) âĸ 9.35 kB
JavaScript
const { execSync, spawn } = require('child_process');
const fs = require('fs');
const path = require('path');
const os = require('os');
/**
* Post-install script for @tomei/finance package
* Ensures Puppeteer and Chrome are properly configured for PDF generation
* Supports Linux, Windows, and macOS environments
*/
console.log('đ§ Setting up @tomei/finance package...');
async function setupPuppeteer() {
try {
const platform = os.platform();
console.log(`đą Detected platform: ${platform}`);
// Check if we're in a CI environment
const isCI = process.env.CI === 'true' || process.env.GITHUB_ACTIONS === 'true' || process.env.GITLAB_CI === 'true';
if (isCI) {
console.log('đ¤ CI environment detected. Skipping interactive Chrome setup.');
console.log('âšī¸ Chrome will be installed on first PDF generation attempt.');
return;
}
console.log('đĻ Checking Puppeteer Chrome installation...');
// Determine appropriate cache directory based on platform
const cacheDir = getCacheDirectory(platform);
console.log(` Cache directory: ${cacheDir}`);
// Check if Chrome is already installed
const chromeExists = await checkChromeInstallation(cacheDir, platform);
if (chromeExists) {
console.log('â
Chrome is already installed and ready for PDF generation');
return;
}
console.log('đĨ Installing Chrome browser for PDF generation...');
// Install system dependencies first (Linux only, and only if we have permissions)
if (platform === 'linux') {
await installLinuxDependencies();
}
// Install Chrome
await installChrome(cacheDir, platform);
console.log('â
Puppeteer Chrome setup completed successfully!');
} catch (error) {
console.error('â ī¸ Warning: Puppeteer setup encountered issues:', error.message);
console.log('');
console.log('đ Manual setup instructions:');
console.log(' 1. Run: npx puppeteer browsers install chrome');
if (os.platform() === 'linux') {
console.log(' 2. Install dependencies: sudo apt-get install -y libxfixes3 libnss3 libatk-bridge2.0-0t64');
}
console.log(' 3. Set environment: export PUPPETEER_CACHE_DIR=' + getCacheDirectory(os.platform()));
console.log('');
console.log('đ PDF generation may not work until Chrome is properly installed.');
}
}
function getCacheDirectory(platform) {
const userId = process.getuid ? process.getuid() : null;
const isRoot = userId === 0;
switch (platform) {
case 'win32':
return process.env.PUPPETEER_CACHE_DIR ||
path.join(process.env.USERPROFILE || process.env.HOME || os.tmpdir(), '.cache', 'puppeteer');
case 'darwin':
return process.env.PUPPETEER_CACHE_DIR ||
path.join(process.env.HOME || os.tmpdir(), '.cache', 'puppeteer');
case 'linux':
default:
if (isRoot) {
return process.env.PUPPETEER_CACHE_DIR || '/root/.cache/puppeteer';
} else {
return process.env.PUPPETEER_CACHE_DIR ||
path.join(process.env.HOME || os.tmpdir(), '.cache', 'puppeteer');
}
}
}
async function checkChromeInstallation(cacheDir, platform) {
try {
// Check if cache directory exists
if (!fs.existsSync(cacheDir)) {
return false;
}
// Look for Chrome executable based on platform
let chromePaths = [];
if (platform === 'win32') {
// Windows Chrome paths
chromePaths = [
path.join(cacheDir, '**/chrome.exe'),
'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe'
];
} else if (platform === 'darwin') {
// macOS Chrome paths
chromePaths = [
path.join(cacheDir, '**/chrome'),
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'
];
} else {
// Linux Chrome paths
chromePaths = [
path.join(cacheDir, '**/chrome'),
'/usr/bin/google-chrome',
'/usr/bin/google-chrome-stable',
'/usr/bin/chromium-browser'
];
}
// Check each possible path
for (const chromePath of chromePaths) {
try {
if (chromePath.includes('**')) {
// Use find command for glob patterns
const findCommand = platform === 'win32'
? `dir "${cacheDir}" /s /b | findstr chrome.exe`
: `find "${cacheDir}" -name "chrome" -type f -executable 2>/dev/null | head -1`;
const result = execSync(findCommand, { encoding: 'utf8' }).trim();
if (result && fs.existsSync(result.split('\n')[0])) {
const foundPath = result.split('\n')[0];
console.log(` Found Chrome at: ${foundPath}`);
// Test if Chrome can start (with timeout)
if (await testChromeStartup(foundPath, platform)) {
return true;
}
}
} else {
// Direct path check
if (fs.existsSync(chromePath)) {
console.log(` Found Chrome at: ${chromePath}`);
// Test if Chrome can start
if (await testChromeStartup(chromePath, platform)) {
return true;
}
}
}
} catch (e) {
// Continue checking other paths
}
}
return false;
} catch (error) {
return false;
}
}
async function testChromeStartup(chromePath, platform) {
try {
const versionArg = platform === 'win32' ? '--version' : '--version --no-sandbox';
execSync(`"${chromePath}" ${versionArg}`, {
stdio: 'pipe',
timeout: 10000
});
console.log(` â
Chrome startup test successful`);
return true;
} catch (e) {
console.log(` â ī¸ Chrome found but startup test failed`);
return false;
}
}
async function installLinuxDependencies() {
try {
const userId = process.getuid ? process.getuid() : null;
const isRoot = userId === 0;
if (!isRoot) {
console.log(' âšī¸ Skipping system dependencies (not running as root)');
console.log(' đĄ If you encounter Chrome issues, run: sudo apt-get install -y libxfixes3 libnss3 libatk-bridge2.0-0t64');
return;
}
console.log('đĻ Installing Linux system dependencies...');
// Check if apt-get is available
try {
execSync('which apt-get', { stdio: 'pipe' });
} catch (e) {
console.log(' âšī¸ apt-get not found, skipping system dependencies');
return;
}
// Install Chrome dependencies (with error handling for different Ubuntu versions)
const dependencies = [
'libxfixes3',
'libnss3',
'ca-certificates',
'fonts-liberation',
'xdg-utils'
];
// Try modern Ubuntu packages first, fallback to older ones
const modernDeps = [
'libatk-bridge2.0-0t64',
'libasound2t64',
'libatspi2.0-0t64',
'libgtk-3-0t64'
];
const fallbackDeps = [
'libatk-bridge2.0-0',
'libasound2',
'libatspi2.0-0',
'libgtk-3-0'
];
try {
// Try modern packages first
execSync(`apt-get update -qq && apt-get install -y ${dependencies.concat(modernDeps).join(' ')}`, {
stdio: 'pipe',
timeout: 120000
});
console.log(' â
Modern system dependencies installed');
} catch (e) {
try {
// Fallback to older packages
execSync(`apt-get install -y ${dependencies.concat(fallbackDeps).join(' ')}`, {
stdio: 'pipe',
timeout: 120000
});
console.log(' â
Fallback system dependencies installed');
} catch (e2) {
console.log(' â ī¸ Could not install some system dependencies');
}
}
} catch (error) {
console.log(' â ī¸ Could not install system dependencies:', error.message);
}
}
async function installChrome(cacheDir, platform) {
try {
// Create cache directory
fs.mkdirSync(cacheDir, { recursive: true });
// Set environment for installation
const installEnv = {
...process.env,
PUPPETEER_CACHE_DIR: cacheDir
};
// Set HOME appropriately for different platforms
if (platform === 'linux') {
const userId = process.getuid ? process.getuid() : null;
const isRoot = userId === 0;
installEnv.HOME = isRoot ? '/root' : process.env.HOME;
}
console.log(' Installing Chrome browser...');
// Install Chrome using Puppeteer with longer timeout
execSync('npx puppeteer browsers install chrome', {
stdio: 'pipe',
env: installEnv,
timeout: 300000 // 5 minutes timeout
});
// Verify installation
const chromeExists = await checkChromeInstallation(cacheDir, platform);
if (!chromeExists) {
throw new Error('Chrome installation verification failed');
}
console.log(' â
Chrome browser installed successfully');
} catch (error) {
throw new Error(`Chrome installation failed: ${error.message}`);
}
}
// Run setup
setupPuppeteer().then(() => {
console.log('đ @tomei/finance package setup complete!');
}).catch((error) => {
console.error('â Setup failed:', error.message);
process.exit(0); // Don't fail the npm install
});