portok 1.0.4 → 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.4",
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,83 +353,67 @@ async function cmdInit(options) {
353
353
  results.push({ path: stateDir, status: 'error', error: err.message });
354
354
  }
355
355
 
356
- // Install systemd template unit (embedded content)
356
+ // Install systemd template unit from external file
357
357
  const systemdDest = path.join(systemdDir, serviceFileName);
358
- const serviceContent = `# Portok systemd template unit for multi-instance deployments
359
- # Auto-generated by: portok init
360
-
361
- [Unit]
362
- Description=Portok Zero-Downtime Proxy (%i)
363
- After=network.target
364
- Documentation=https://github.com/nicatdursunlu/portok
365
-
366
- [Service]
367
- Type=simple
368
- User=www-data
369
- Group=www-data
370
-
371
- # Instance configuration from env file
372
- EnvironmentFile=/etc/portok/%i.env
373
-
374
- # Set instance name automatically from systemd specifier
375
- Environment=INSTANCE_NAME=%i
376
-
377
- # Working directory
378
- WorkingDirectory=/opt/portok
379
-
380
- # Start the daemon
381
- ExecStart=/usr/bin/node /opt/portok/portokd.js
382
-
383
- # Restart policy
384
- Restart=always
385
- RestartSec=5
386
- StartLimitBurst=5
387
- StartLimitIntervalSec=60
388
-
389
- # Logging
390
- StandardOutput=journal
391
- StandardError=journal
392
- SyslogIdentifier=portok-%i
393
-
394
- # Security hardening
395
- NoNewPrivileges=true
396
- ProtectSystem=strict
397
- ProtectHome=true
398
- PrivateTmp=true
399
- ProtectKernelTunables=true
400
- ProtectKernelModules=true
401
- ProtectControlGroups=true
402
-
403
- # Allow writing to state directory
404
- ReadWritePaths=/var/lib/portok
405
-
406
- # Network access (required for proxying)
407
- RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
408
-
409
- [Install]
410
- WantedBy=multi-user.target
411
- `;
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
+ }
374
+ }
412
375
 
413
- try {
414
- const existingContent = fs.existsSync(systemdDest) ? fs.readFileSync(systemdDest, 'utf-8') : null;
415
-
416
- if (existingContent === serviceContent) {
417
- results.push({ path: systemdDest, status: 'exists' });
418
- } else {
419
- fs.writeFileSync(systemdDest, serviceContent, { mode: 0o644 });
420
- results.push({ path: systemdDest, status: 'created' });
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');
421
385
 
422
- // Reload systemd daemon
423
- try {
424
- const { execSync } = require('child_process');
425
- execSync('systemctl daemon-reload', { stdio: 'pipe' });
426
- results.push({ path: 'systemctl daemon-reload', status: 'created' });
427
- } catch (e) {
428
- // Ignore if systemctl not available (e.g., in Docker)
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
+
397
+ const existingContent = fs.existsSync(systemdDest) ? fs.readFileSync(systemdDest, 'utf-8') : null;
398
+
399
+ if (existingContent && existingContent.trim() === serviceContent.trim()) {
400
+ results.push({ path: systemdDest, status: 'exists' });
401
+ } else {
402
+ fs.writeFileSync(systemdDest, serviceContent, { mode: 0o644 });
403
+ results.push({ path: systemdDest, status: 'created' });
404
+
405
+ // Reload systemd daemon
406
+ try {
407
+ const { execSync } = require('child_process');
408
+ execSync('systemctl daemon-reload', { stdio: 'pipe' });
409
+ results.push({ path: 'systemctl daemon-reload', status: 'created' });
410
+ } catch (e) {
411
+ results.push({ path: 'systemctl daemon-reload', status: 'skipped', error: 'systemctl failed' });
412
+ }
429
413
  }
414
+ } catch (err) {
415
+ results.push({ path: systemdDest, status: 'error', error: err.message });
430
416
  }
431
- } catch (err) {
432
- results.push({ path: systemdDest, status: 'error', error: err.message });
433
417
  }
434
418
 
435
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"