Fix npm package installation issues (#377)

This commit is contained in:
Peter Steinberger 2025-07-17 00:50:33 +02:00 committed by GitHub
parent 8173a0f500
commit d69a4c1ef3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 180 additions and 71 deletions

View file

@ -414,4 +414,114 @@ npm install -g vibetunnel --build-from-source
- `scripts/build-npm.js` - Unified npm build process with multi-platform support
- `scripts/postinstall-npm.js` - Fallback compilation logic
- `.prebuildrc` - Prebuild configuration for target platforms
- `package.json` - Package configuration and file inclusions
- `package.json` - Package configuration and file inclusions
## Release Notes
### Version 1.0.0-beta.11 (2025-07-16)
**Published to npm**: Successfully published as `vibetunnel@beta`
**Key Features**:
- Cross-platform support for macOS (x64, arm64) and Linux (x64, arm64)
- Pre-built native binaries for Node.js versions 20, 22, 23, and 24
- Zero-dependency installation experience (no build tools required)
- Comprehensive prebuild system with 24 total binaries included
**Release Process Learnings**:
1. **Version Synchronization**:
- Must update version in both `web/package.json` and `mac/VibeTunnel/version.xcconfig`
- Build process validates version sync to prevent mismatches
- Version mismatch will cause build failure with clear error message
2. **NPM Publishing Requirements**:
- Beta versions require `--tag beta` flag when publishing
- Previously published versions cannot be overwritten (must increment version)
- Use `--access public` flag for public package publishing
3. **Package Build Process**:
- `pnpm run build:npm` creates the complete package with all prebuilds
- Build output filename may show older version in logs but creates correct package
- Always verify package version in `dist-npm/package.json` before publishing
4. **Docker Testing Verification**:
- Successfully tested on Ubuntu 22.04 (both ARM64 and x64 architectures)
- Installation works without any build tools installed
- Server starts correctly with all expected functionality
- HTTP endpoints respond properly
5. **Package Structure**:
- Final package size: 8.3 MB (24.9 MB unpacked)
- Contains 198 files including all prebuilds and web assets
- Proper postinstall script ensures seamless installation
**Installation**:
```bash
npm install -g vibetunnel@beta
```
**Testing Commands Used**:
```bash
# Build the package
cd web && pnpm run build:npm
# Verify package contents
tar -tzf vibetunnel-1.0.0-beta.11.tgz | head -50
# Test with Docker
docker build -t vibetunnel-test .
docker run --rm vibetunnel-test
# Test cross-platform
docker run --rm --platform linux/amd64 vibetunnel-test
```
### Version History
- **1.0.0-beta.11.1** (2025-07-16): Fixed npm installation issues, latest stable release
- **1.0.0-beta.11** (2025-07-16): Initial release with full prebuild system
- **1.0.0-beta.10** (2025-07-14): Previous version (unpublished)
## NPM Distribution Tags
VibeTunnel uses npm dist-tags to manage different release channels:
### Current Tags
- **latest**: Points to the most stable release (currently 1.0.0-beta.11.1)
- **beta**: Points to the latest beta release (currently 1.0.0-beta.11.1)
### Managing Tags
```bash
# View current tags
npm dist-tag ls vibetunnel
# Set a version as latest
npm dist-tag add vibetunnel@1.0.0-beta.11.1 latest
# Add a new tag
npm dist-tag add vibetunnel@1.0.0-beta.12 next
# Remove a tag
npm dist-tag rm vibetunnel next
```
### Installation by Tag
```bash
# Install latest stable (default)
npm install -g vibetunnel
# Install specific tag
npm install -g vibetunnel@beta
npm install -g vibetunnel@latest
# Install specific version
npm install -g vibetunnel@1.0.0-beta.11.1
```
### Best Practices
- Always tag beta releases with `beta` tag
- Only promote to `latest` after testing confirms stability
- Use semantic versioning for beta iterations (e.g., 1.0.0-beta.11.1, 1.0.0-beta.11.2)

View file

@ -1,6 +1,6 @@
{
"name": "vibetunnel",
"version": "1.0.0-beta.10",
"version": "1.0.0-beta.11",
"description": "Terminal sharing server with web interface - supports macOS, Linux, and headless environments",
"main": "lib/cli.js",
"bin": {
@ -48,7 +48,6 @@
"@codemirror/theme-one-dark": "^6.1.3",
"@codemirror/view": "^6.38.0",
"@xterm/headless": "^5.5.0",
"authenticate-pam": "^1.0.5",
"bonjour-service": "^1.3.0",
"chalk": "^5.4.1",
"compression": "^1.8.0",
@ -60,13 +59,14 @@
"mime-types": "^3.0.1",
"monaco-editor": "^0.52.2",
"multer": "^2.0.1",
"node-addon-api": "^7.1.0",
"node-pty": "file:node-pty",
"postject": "1.0.0-alpha.6",
"signal-exit": "^4.1.0",
"web-push": "^3.6.7",
"ws": "^8.18.3"
},
"optionalDependencies": {
"authenticate-pam": "^1.0.5"
},
"keywords": [
"terminal",
"multiplexer",

View file

@ -375,6 +375,60 @@ function mergePrebuilds() {
console.log(`✅ Merged prebuilds: ${nodePtyCount} node-pty + ${pamCount} authenticate-pam = ${allPrebuilds.length} total\n`);
}
// Bundle node-pty with its dependencies
function bundleNodePty() {
console.log('📦 Bundling node-pty with dependencies...\n');
const nodePtyDir = path.join(DIST_DIR, 'node-pty');
const nodeAddonApiDest = path.join(nodePtyDir, 'node_modules', 'node-addon-api');
// Try multiple strategies to find node-addon-api
const possiblePaths = [];
// Strategy 1: Direct dependency in node_modules
const directPath = path.join(ROOT_DIR, 'node_modules', 'node-addon-api');
if (fs.existsSync(directPath)) {
possiblePaths.push(directPath);
}
// Strategy 2: pnpm structure (any version)
const pnpmDir = path.join(ROOT_DIR, 'node_modules', '.pnpm');
if (fs.existsSync(pnpmDir)) {
const pnpmEntries = fs.readdirSync(pnpmDir)
.filter(dir => dir.startsWith('node-addon-api@'))
.map(dir => path.join(pnpmDir, dir, 'node_modules', 'node-addon-api'))
.filter(fs.existsSync);
possiblePaths.push(...pnpmEntries);
}
// Strategy 3: Check if it's a dependency of node-pty
const nodePtyModules = path.join(ROOT_DIR, 'node-pty', 'node_modules', 'node-addon-api');
if (fs.existsSync(nodePtyModules)) {
possiblePaths.push(nodePtyModules);
}
// Strategy 4: Hoisted by npm/yarn (parent directory)
const hoistedPath = path.join(ROOT_DIR, '..', 'node_modules', 'node-addon-api');
if (fs.existsSync(hoistedPath)) {
possiblePaths.push(hoistedPath);
}
if (possiblePaths.length > 0) {
const nodeAddonApiSrc = possiblePaths[0];
fs.mkdirSync(path.dirname(nodeAddonApiDest), { recursive: true });
fs.cpSync(nodeAddonApiSrc, nodeAddonApiDest, { recursive: true });
console.log(` ✅ Bundled node-addon-api from: ${path.relative(ROOT_DIR, nodeAddonApiSrc)}`);
} else {
console.error(' ❌ CRITICAL: node-addon-api not found - source compilation will fail!');
console.error(' Please ensure node-addon-api is installed as a dependency.');
console.error(' Run: pnpm add -D node-addon-api');
// Don't exit during build - let the developer decide
console.warn(' ⚠️ Continuing build, but npm package may have issues if prebuilds are missing.');
}
console.log('✅ node-pty bundled with dependencies\n');
}
// Copy authenticate-pam module for Linux support (OUR LINUX FIX)
function copyAuthenticatePam() {
console.log('📦 Copying authenticate-pam module for Linux support...\n');
@ -577,11 +631,14 @@ async function main() {
copyRecursive(src, dest);
});
// Step 4: Copy authenticate-pam module for Linux support (OUR ENHANCEMENT)
// Step 4: Bundle node-pty with dependencies
bundleNodePty();
// Step 5: Copy authenticate-pam module for Linux support (OUR ENHANCEMENT)
copyAuthenticatePam();
// Step 5: Use package.npm.json if available, otherwise create clean package.json
console.log('\n4️⃣ Creating package.json for npm...\n');
// Step 6: Use package.npm.json if available, otherwise create clean package.json
console.log('\n6️⃣ Creating package.json for npm...\n');
const npmPackageJsonPath = path.join(ROOT_DIR, 'package.npm.json');
let npmPackageJson;

View file

@ -21,23 +21,8 @@ if (isDevelopment) {
return;
}
// Create node_modules directory if it doesn't exist
const nodeModulesDir = path.join(__dirname, '..', 'node_modules');
if (!fs.existsSync(nodeModulesDir)) {
fs.mkdirSync(nodeModulesDir, { recursive: true });
}
// Create symlink for node-pty so it can be required normally
const nodePtySource = path.join(__dirname, '..', 'node-pty');
const nodePtyTarget = path.join(nodeModulesDir, 'node-pty');
if (!fs.existsSync(nodePtyTarget) && fs.existsSync(nodePtySource)) {
try {
fs.symlinkSync(nodePtySource, nodePtyTarget, 'dir');
console.log('✓ Created node-pty symlink in node_modules');
} catch (error) {
console.warn('Warning: Could not create node-pty symlink:', error.message);
}
}
// For npm package, node-pty is bundled in the package root
// No need to create symlinks as it's accessed directly
// Get Node ABI version
const nodeABI = process.versions.modules;
@ -114,51 +99,8 @@ const compileFromSource = (moduleName, moduleDir) => {
execSync('npm install -g node-gyp', { stdio: 'inherit' });
}
// For node-pty, ensure node-addon-api is available
if (moduleName === 'node-pty') {
const nodeAddonApiPath = path.join(moduleDir, 'node_modules', 'node-addon-api');
if (!fs.existsSync(nodeAddonApiPath)) {
console.log(` Setting up node-addon-api for ${moduleName}...`);
// Create node_modules directory
const nodeModulesDir = path.join(moduleDir, 'node_modules');
fs.mkdirSync(nodeModulesDir, { recursive: true });
// Try multiple locations for node-addon-api
const possiblePaths = [
path.join(__dirname, '..', 'node_modules', 'node-addon-api'),
path.join(__dirname, '..', '..', 'node_modules', 'node-addon-api'),
path.join(__dirname, '..', '..', '..', 'node_modules', 'node-addon-api'),
'/usr/local/lib/node_modules/vibetunnel/node_modules/node-addon-api',
'/usr/lib/node_modules/vibetunnel/node_modules/node-addon-api'
];
let found = false;
for (const sourcePath of possiblePaths) {
if (fs.existsSync(sourcePath)) {
console.log(` Found node-addon-api at: ${sourcePath}`);
console.log(` Copying to ${nodeAddonApiPath}...`);
fs.cpSync(sourcePath, nodeAddonApiPath, { recursive: true });
found = true;
break;
}
}
if (!found) {
// As a fallback, install it
console.log(` Installing node-addon-api package...`);
try {
execSync('npm install node-addon-api@^7.1.0 --no-save --no-package-lock', {
cwd: moduleDir,
stdio: 'inherit'
});
} catch (e) {
console.error(' Failed to install node-addon-api:', e.message);
console.error(' Trying to continue anyway...');
}
}
}
}
// For node-pty, node-addon-api is included as a dependency in its package.json
// npm should handle it automatically during source compilation
execSync('node-gyp rebuild', {
cwd: moduleDir,
@ -186,7 +128,7 @@ const modules = [
version: '1.0.5',
dir: path.join(__dirname, '..', 'node_modules', 'authenticate-pam'),
build: path.join(__dirname, '..', 'node_modules', 'authenticate-pam', 'build', 'Release', 'authenticate_pam.node'),
essential: true, // PAM is essential for server environments
essential: false, // Optional - falls back to other auth methods
platforms: ['linux', 'darwin'] // Needed on Linux and macOS
}
];