portok 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "portok",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "Zero-downtime deployment proxy - routes traffic through a stable port to internal app instances with health-gated switching",
5
5
  "main": "portokd.js",
6
6
  "bin": {
package/portok.js CHANGED
@@ -353,33 +353,53 @@ async function cmdInit(options) {
353
353
  results.push({ path: stateDir, status: 'error', error: err.message });
354
354
  }
355
355
 
356
- // Install systemd template unit
356
+ // Install systemd template unit from external file
357
357
  const systemdDest = path.join(systemdDir, serviceFileName);
358
- try {
359
- // Find the service file relative to this script
360
- const scriptDir = path.dirname(process.argv[1]);
361
- const possiblePaths = [
362
- path.join(scriptDir, serviceFileName),
363
- path.join(scriptDir, '..', serviceFileName),
364
- '/opt/portok/' + serviceFileName,
365
- ];
366
-
367
- let sourceFile = null;
368
- for (const p of possiblePaths) {
369
- if (fs.existsSync(p)) {
370
- sourceFile = p;
371
- break;
372
- }
358
+
359
+ // Find portok@.service file relative to this script
360
+ const scriptDir = path.dirname(process.argv[1]);
361
+ const possibleServicePaths = [
362
+ path.join(scriptDir, serviceFileName),
363
+ path.join(scriptDir, '..', serviceFileName),
364
+ path.join(__dirname, serviceFileName),
365
+ path.join(__dirname, '..', serviceFileName),
366
+ ];
367
+
368
+ let serviceSourcePath = null;
369
+ for (const p of possibleServicePaths) {
370
+ if (fs.existsSync(p)) {
371
+ serviceSourcePath = p;
372
+ break;
373
373
  }
374
+ }
374
375
 
375
- if (sourceFile) {
376
- const content = fs.readFileSync(sourceFile, 'utf-8');
376
+ // Check if systemd directory exists
377
+ if (!fs.existsSync(systemdDir)) {
378
+ results.push({ path: systemdDest, status: 'skipped', error: 'systemd not available' });
379
+ } else if (!serviceSourcePath) {
380
+ results.push({ path: systemdDest, status: 'error', error: `${serviceFileName} not found in package` });
381
+ } else {
382
+ try {
383
+ // Read template and replace placeholders with actual paths
384
+ let serviceContent = fs.readFileSync(serviceSourcePath, 'utf-8');
385
+
386
+ // Get actual node path (supports nvm, fnm, volta, etc.)
387
+ const nodePath = process.execPath;
388
+
389
+ // Get actual portok installation directory
390
+ const portokDir = path.dirname(serviceSourcePath);
391
+
392
+ // Replace hardcoded paths with actual paths
393
+ serviceContent = serviceContent.replace(/\/usr\/bin\/node/g, nodePath);
394
+ serviceContent = serviceContent.replace(/WorkingDirectory=\/opt\/portok/g, `WorkingDirectory=${portokDir}`);
395
+ serviceContent = serviceContent.replace(/\/opt\/portok\/portokd\.js/g, `${portokDir}/portokd.js`);
396
+
377
397
  const existingContent = fs.existsSync(systemdDest) ? fs.readFileSync(systemdDest, 'utf-8') : null;
378
398
 
379
- if (existingContent === content) {
399
+ if (existingContent && existingContent.trim() === serviceContent.trim()) {
380
400
  results.push({ path: systemdDest, status: 'exists' });
381
401
  } else {
382
- fs.writeFileSync(systemdDest, content, { mode: 0o644 });
402
+ fs.writeFileSync(systemdDest, serviceContent, { mode: 0o644 });
383
403
  results.push({ path: systemdDest, status: 'created' });
384
404
 
385
405
  // Reload systemd daemon
@@ -388,14 +408,12 @@ async function cmdInit(options) {
388
408
  execSync('systemctl daemon-reload', { stdio: 'pipe' });
389
409
  results.push({ path: 'systemctl daemon-reload', status: 'created' });
390
410
  } catch (e) {
391
- // Ignore if systemctl not available (e.g., in Docker)
411
+ results.push({ path: 'systemctl daemon-reload', status: 'skipped', error: 'systemctl failed' });
392
412
  }
393
413
  }
394
- } else {
395
- results.push({ path: systemdDest, status: 'skipped', error: 'Template file not found' });
414
+ } catch (err) {
415
+ results.push({ path: systemdDest, status: 'error', error: err.message });
396
416
  }
397
- } catch (err) {
398
- results.push({ path: systemdDest, status: 'error', error: err.message });
399
417
  }
400
418
 
401
419
  if (options.json) {
package/portok@.service CHANGED
@@ -1,5 +1,9 @@
1
1
  # Portok systemd template unit for multi-instance deployments
2
- # Place this file at /etc/systemd/system/portok@.service
2
+ #
3
+ # This file is used as a template by 'portok init'.
4
+ # The following paths are automatically replaced:
5
+ # - /usr/bin/node -> actual node path (supports nvm, fnm, volta)
6
+ # - /opt/portok -> actual portok installation directory
3
7
  #
4
8
  # Usage:
5
9
  # systemctl start portok@api # Start instance "api"