@lamalibre/create-portlama 1.0.23 → 1.0.25

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.
Files changed (86) hide show
  1. package/LICENSE.md +2 -1
  2. package/README.md +7 -7
  3. package/package.json +1 -1
  4. package/scripts/bundle-vendor.js +2 -6
  5. package/src/index.js +5 -8
  6. package/src/lib/env.js +3 -7
  7. package/src/lib/service-config.js +1 -4
  8. package/src/tasks/harden.js +3 -12
  9. package/src/tasks/mtls.js +27 -28
  10. package/src/tasks/nginx.js +3 -12
  11. package/src/tasks/node.js +1 -3
  12. package/src/tasks/panel.js +5 -22
  13. package/src/tasks/redeploy.js +6 -23
  14. package/vendor/panel-client/dist/assets/index-C0A3Xsrf.js +619 -0
  15. package/vendor/panel-client/dist/docs/00-introduction/how-it-works.md +55 -55
  16. package/vendor/panel-client/dist/docs/00-introduction/quickstart.md +50 -36
  17. package/vendor/panel-client/dist/docs/00-introduction/what-is-portlama.md +27 -21
  18. package/vendor/panel-client/dist/docs/01-concepts/authentication.md +56 -55
  19. package/vendor/panel-client/dist/docs/01-concepts/certificates.md +59 -49
  20. package/vendor/panel-client/dist/docs/01-concepts/dns-and-domains.md +61 -61
  21. package/vendor/panel-client/dist/docs/01-concepts/mtls.md +105 -76
  22. package/vendor/panel-client/dist/docs/01-concepts/nginx-reverse-proxy.md +54 -54
  23. package/vendor/panel-client/dist/docs/01-concepts/security-model.md +136 -96
  24. package/vendor/panel-client/dist/docs/01-concepts/tunneling.md +27 -27
  25. package/vendor/panel-client/dist/docs/02-guides/certificate-management.md +65 -62
  26. package/vendor/panel-client/dist/docs/02-guides/desktop-app-setup.md +172 -0
  27. package/vendor/panel-client/dist/docs/02-guides/disaster-recovery.md +52 -52
  28. package/vendor/panel-client/dist/docs/02-guides/first-tunnel.md +31 -27
  29. package/vendor/panel-client/dist/docs/02-guides/installation.md +41 -41
  30. package/vendor/panel-client/dist/docs/02-guides/mac-client-setup.md +50 -23
  31. package/vendor/panel-client/dist/docs/02-guides/managing-users.md +39 -39
  32. package/vendor/panel-client/dist/docs/02-guides/onboarding.md +47 -43
  33. package/vendor/panel-client/dist/docs/02-guides/remote-shell.md +277 -0
  34. package/vendor/panel-client/dist/docs/02-guides/static-sites.md +93 -55
  35. package/vendor/panel-client/dist/docs/03-architecture/installer.md +74 -49
  36. package/vendor/panel-client/dist/docs/03-architecture/management-flow.md +43 -42
  37. package/vendor/panel-client/dist/docs/03-architecture/nginx-configuration.md +24 -17
  38. package/vendor/panel-client/dist/docs/03-architecture/overview.md +46 -45
  39. package/vendor/panel-client/dist/docs/03-architecture/panel-client.md +67 -57
  40. package/vendor/panel-client/dist/docs/03-architecture/panel-server.md +45 -33
  41. package/vendor/panel-client/dist/docs/03-architecture/state-management.md +52 -42
  42. package/vendor/panel-client/dist/docs/04-api-reference/certificates.md +150 -95
  43. package/vendor/panel-client/dist/docs/04-api-reference/onboarding.md +101 -64
  44. package/vendor/panel-client/dist/docs/04-api-reference/overview.md +105 -75
  45. package/vendor/panel-client/dist/docs/04-api-reference/services.md +50 -49
  46. package/vendor/panel-client/dist/docs/04-api-reference/sites.md +136 -95
  47. package/vendor/panel-client/dist/docs/04-api-reference/system.md +35 -33
  48. package/vendor/panel-client/dist/docs/04-api-reference/tunnels.md +51 -51
  49. package/vendor/panel-client/dist/docs/04-api-reference/users.md +65 -65
  50. package/vendor/panel-client/dist/docs/05-operations/backup-and-restore.md +58 -58
  51. package/vendor/panel-client/dist/docs/05-operations/monitoring.md +64 -61
  52. package/vendor/panel-client/dist/docs/05-operations/uninstalling.md +21 -15
  53. package/vendor/panel-client/dist/docs/05-operations/upgrades.md +16 -16
  54. package/vendor/panel-client/dist/docs/06-reference/config-files.md +78 -78
  55. package/vendor/panel-client/dist/docs/06-reference/glossary.md +74 -47
  56. package/vendor/panel-client/dist/docs/06-reference/installer-flags.md +45 -45
  57. package/vendor/panel-client/dist/docs/06-reference/ports-and-services.md +102 -102
  58. package/vendor/panel-client/dist/docs/06-reference/troubleshooting.md +45 -45
  59. package/vendor/panel-client/dist/docs/_index.json +155 -29
  60. package/vendor/panel-client/dist/index.html +1 -1
  61. package/vendor/panel-server/package.json +1 -1
  62. package/vendor/panel-server/src/index.js +1 -3
  63. package/vendor/panel-server/src/lib/authelia.js +122 -78
  64. package/vendor/panel-server/src/lib/certbot.js +32 -21
  65. package/vendor/panel-server/src/lib/chisel.js +8 -6
  66. package/vendor/panel-server/src/lib/config.js +9 -5
  67. package/vendor/panel-server/src/lib/files.js +113 -20
  68. package/vendor/panel-server/src/lib/mtls.js +264 -173
  69. package/vendor/panel-server/src/lib/nginx.js +12 -7
  70. package/vendor/panel-server/src/lib/services.js +1 -6
  71. package/vendor/panel-server/src/lib/shell.js +487 -0
  72. package/vendor/panel-server/src/middleware/mtls.js +19 -3
  73. package/vendor/panel-server/src/routes/invite.js +7 -1
  74. package/vendor/panel-server/src/routes/management/certs.js +330 -205
  75. package/vendor/panel-server/src/routes/management/invitations.js +139 -128
  76. package/vendor/panel-server/src/routes/management/logs.js +7 -13
  77. package/vendor/panel-server/src/routes/management/services.js +39 -31
  78. package/vendor/panel-server/src/routes/management/shell.js +1012 -0
  79. package/vendor/panel-server/src/routes/management/sites.js +463 -378
  80. package/vendor/panel-server/src/routes/management/system.js +14 -10
  81. package/vendor/panel-server/src/routes/management/tunnels.js +249 -227
  82. package/vendor/panel-server/src/routes/management/users.js +218 -191
  83. package/vendor/panel-server/src/routes/management.js +2 -0
  84. package/vendor/panel-server/src/routes/onboarding/domain.js +1 -1
  85. package/vendor/panel-server/src/routes/onboarding/provision.js +24 -8
  86. package/vendor/panel-client/dist/assets/index-Di5bjQ77.js +0 -619
package/LICENSE.md CHANGED
@@ -13,6 +13,7 @@ You may use, copy, modify, and distribute this software for any **noncommercial*
13
13
  Commercial use of this software requires a commercial license, available by contacting licence@codelama.com.tr.
14
14
 
15
15
  Commercial use includes, but is not limited to:
16
+
16
17
  - Using Portlama in a business to serve data to clients or partners
17
18
  - Deploying Portlama as part of a revenue-generating service or product
18
19
  - Using Portlama internally at a for-profit organization
@@ -85,7 +86,7 @@ The first time you are notified in writing that you have violated any of these t
85
86
 
86
87
  ### No Liability
87
88
 
88
- ***As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.***
89
+ **_As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim._**
89
90
 
90
91
  ### Definitions
91
92
 
package/README.md CHANGED
@@ -30,13 +30,13 @@ configured through the browser-based onboarding wizard after installation.
30
30
 
31
31
  ## Requirements
32
32
 
33
- | Requirement | Details |
34
- | ----------------- | -------------------- |
35
- | OS | Ubuntu 24.04 LTS |
36
- | Access | root |
37
- | Node.js | >= 20.0.0 |
38
- | RAM | 512 MB minimum |
39
- | Recommended | DigitalOcean $4 droplet |
33
+ | Requirement | Details |
34
+ | ----------- | ----------------------- |
35
+ | OS | Ubuntu 24.04 LTS |
36
+ | Access | root |
37
+ | Node.js | >= 20.0.0 |
38
+ | RAM | 512 MB minimum |
39
+ | Recommended | DigitalOcean $4 droplet |
40
40
 
41
41
  ## Further Reading
42
42
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lamalibre/create-portlama",
3
- "version": "1.0.23",
3
+ "version": "1.0.25",
4
4
  "description": "One-command setup for secure reverse tunnels with a management dashboard",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE.md",
@@ -23,9 +23,7 @@ async function main() {
23
23
  // --- panel-server: package.json + src/ ---
24
24
  const serverSrc = join(monorepoRoot, 'packages', 'panel-server');
25
25
  if (!existsSync(serverSrc)) {
26
- throw new Error(
27
- `panel-server not found at ${serverSrc}. Run from the monorepo root.`,
28
- );
26
+ throw new Error(`panel-server not found at ${serverSrc}. Run from the monorepo root.`);
29
27
  }
30
28
 
31
29
  const serverDest = join(vendorDir, 'panel-server');
@@ -40,9 +38,7 @@ async function main() {
40
38
  // --- panel-client: dist/ (pre-built assets) ---
41
39
  const clientDist = join(monorepoRoot, 'packages', 'panel-client', 'dist');
42
40
  if (!existsSync(clientDist)) {
43
- throw new Error(
44
- `panel-client/dist/ not found at ${clientDist}. Run "npm run build" first.`,
45
- );
41
+ throw new Error(`panel-client/dist/ not found at ${clientDist}. Run "npm run build" first.`);
46
42
  }
47
43
 
48
44
  const clientDest = join(vendorDir, 'panel-client');
package/src/index.js CHANGED
@@ -167,7 +167,7 @@ ${b('9. Remove swap file (optional)')}
167
167
  ${c('sudo rm /swapfile')}
168
168
  ${d('Remove the /swapfile line from /etc/fstab')}
169
169
 
170
- ${b('10. Remove Let\'s Encrypt certificates (optional)')}
170
+ ${b("10. Remove Let's Encrypt certificates (optional)")}
171
171
 
172
172
  ${d('List Portlama-issued certs:')}
173
173
  ${c('sudo certbot certificates')}
@@ -364,13 +364,10 @@ ${chalk.cyan.bold('└───────────────────
364
364
  });
365
365
 
366
366
  await new Promise((resolve) => {
367
- rl.question(
368
- `\n ${chalk.white.bold('Press Enter to continue or Ctrl+C to abort...')} `,
369
- () => {
370
- rl.close();
371
- resolve();
372
- },
373
- );
367
+ rl.question(`\n ${chalk.white.bold('Press Enter to continue or Ctrl+C to abort...')} `, () => {
368
+ rl.close();
369
+ resolve();
370
+ });
374
371
  });
375
372
  }
376
373
 
package/src/lib/env.js CHANGED
@@ -10,9 +10,7 @@ export async function detectOS() {
10
10
  try {
11
11
  content = await readFile('/etc/os-release', 'utf8');
12
12
  } catch {
13
- throw new Error(
14
- 'Could not read /etc/os-release. Portlama requires Ubuntu 24.04.',
15
- );
13
+ throw new Error('Could not read /etc/os-release. Portlama requires Ubuntu 24.04.');
16
14
  }
17
15
 
18
16
  const fields = {};
@@ -29,9 +27,7 @@ export async function detectOS() {
29
27
  const prettyName = fields.PRETTY_NAME || `${id} ${versionId}`;
30
28
 
31
29
  if (id !== 'ubuntu' || !versionId.startsWith('24.04')) {
32
- throw new Error(
33
- `Portlama requires Ubuntu 24.04. Detected: ${prettyName}`,
34
- );
30
+ throw new Error(`Portlama requires Ubuntu 24.04. Detected: ${prettyName}`);
35
31
  }
36
32
 
37
33
  return { id, versionId, prettyName };
@@ -45,7 +41,7 @@ export async function detectOS() {
45
41
  * @returns {string} The IPv4 address.
46
42
  */
47
43
  export async function detectIP({ allowPrivate = false } = {}) {
48
- const isAcceptable = (ip) => allowPrivate ? isValidIPv4(ip) : isPublicIP(ip);
44
+ const isAcceptable = (ip) => (allowPrivate ? isValidIPv4(ip) : isPublicIP(ip));
49
45
 
50
46
  // Try DigitalOcean metadata API first
51
47
  try {
@@ -47,9 +47,6 @@ WantedBy=multi-user.target
47
47
  * @returns {string}
48
48
  */
49
49
  export function generateSudoersContent() {
50
- const processUid = process.getuid?.() ?? 0;
51
- const processGid = process.getgid?.() ?? 0;
52
-
53
50
  return `# Portlama panel-server sudo rules
54
51
  # Allows the portlama user to manage specific services and run specific commands
55
52
 
@@ -120,7 +117,7 @@ portlama ALL=(root) NOPASSWD: /usr/local/bin/authelia storage *
120
117
  portlama ALL=(root) NOPASSWD: /usr/bin/mkdir -p /var/www/portlama/*
121
118
  portlama ALL=(root) NOPASSWD: /usr/bin/chown -R www-data\\:www-data /var/www/portlama/*
122
119
  portlama ALL=(root) NOPASSWD: /usr/bin/chown www-data\\:www-data /var/www/portlama/*
123
- portlama ALL=(root) NOPASSWD: /usr/bin/chown ${processUid}\\:${processGid} /var/www/portlama/*
120
+ portlama ALL=(root) NOPASSWD: /usr/bin/chown portlama\\:portlama /var/www/portlama/*
124
121
  portlama ALL=(root) NOPASSWD: /usr/bin/chmod -R 755 /var/www/portlama/*
125
122
  portlama ALL=(root) NOPASSWD: /usr/bin/chmod 644 /var/www/portlama/*
126
123
  portlama ALL=(root) NOPASSWD: /usr/bin/rm -rf /var/www/portlama/*
@@ -31,18 +31,12 @@ export function hardenTasks(ctx, task) {
31
31
  // Add to /etc/fstab if not already present
32
32
  const fstab = await readFile('/etc/fstab', 'utf8');
33
33
  if (!fstab.includes('/swapfile')) {
34
- await writeFile(
35
- '/etc/fstab',
36
- fstab.trimEnd() + '\n/swapfile none swap sw 0 0\n',
37
- );
34
+ await writeFile('/etc/fstab', fstab.trimEnd() + '\n/swapfile none swap sw 0 0\n');
38
35
  }
39
36
 
40
37
  // Set swappiness
41
38
  await execa('sysctl', ['vm.swappiness=10']);
42
- await writeFile(
43
- '/etc/sysctl.d/99-portlama.conf',
44
- 'vm.swappiness=10\n',
45
- );
39
+ await writeFile('/etc/sysctl.d/99-portlama.conf', 'vm.swappiness=10\n');
46
40
 
47
41
  subtask.output = 'Swap file created and activated';
48
42
  },
@@ -177,10 +171,7 @@ bantime = 3600
177
171
  subtask.output = 'Restarting fail2ban...';
178
172
  await execa('systemctl', ['restart', 'fail2ban']);
179
173
 
180
- const { stdout: status } = await execa('systemctl', [
181
- 'is-active',
182
- 'fail2ban',
183
- ]);
174
+ const { stdout: status } = await execa('systemctl', ['is-active', 'fail2ban']);
184
175
  subtask.output = `fail2ban status: ${status.trim()}`;
185
176
  },
186
177
  rendererOptions: { persistentOutput: true },
package/src/tasks/mtls.js CHANGED
@@ -17,8 +17,7 @@ import { generatePassword } from '../lib/secrets.js';
17
17
  */
18
18
  export function mtlsTasks(ctx, task) {
19
19
  const pkiDir = ctx.pkiDir;
20
- const alreadyProvisioned =
21
- existsSync(`${pkiDir}/ca.key`) && existsSync(`${pkiDir}/client.p12`);
20
+ const alreadyProvisioned = existsSync(`${pkiDir}/ca.key`) && existsSync(`${pkiDir}/client.p12`);
22
21
 
23
22
  if (alreadyProvisioned) {
24
23
  return task.newListr([
@@ -26,10 +25,7 @@ export function mtlsTasks(ctx, task) {
26
25
  title: 'mTLS certificates already exist — skipping generation',
27
26
  task: async () => {
28
27
  // Read the existing p12 password so the summary can display it.
29
- ctx.p12Password = await readFile(
30
- `${pkiDir}/.p12-password`,
31
- 'utf8',
32
- );
28
+ ctx.p12Password = await readFile(`${pkiDir}/.p12-password`, 'utf8');
33
29
  },
34
30
  },
35
31
  ]);
@@ -83,12 +79,7 @@ export function mtlsTasks(ctx, task) {
83
79
  title: 'Generating client key and CSR',
84
80
  task: async (_ctx, subtask) => {
85
81
  subtask.output = 'Generating 4096-bit RSA client key...';
86
- await execa('openssl', [
87
- 'genrsa',
88
- '-out',
89
- `${pkiDir}/client.key`,
90
- '4096',
91
- ]);
82
+ await execa('openssl', ['genrsa', '-out', `${pkiDir}/client.key`, '4096']);
92
83
 
93
84
  subtask.output = 'Creating certificate signing request...';
94
85
  await execa('openssl', [
@@ -149,22 +140,30 @@ export function mtlsTasks(ctx, task) {
149
140
  const password = generatePassword();
150
141
 
151
142
  subtask.output = 'Creating PKCS12 bundle for browser import...';
152
- await execa('openssl', [
153
- 'pkcs12',
154
- '-export',
155
- '-keypbe', 'PBE-SHA1-3DES',
156
- '-certpbe', 'PBE-SHA1-3DES',
157
- '-macalg', 'sha1',
158
- '-out',
159
- `${pkiDir}/client.p12`,
160
- '-inkey',
161
- `${pkiDir}/client.key`,
162
- '-in',
163
- `${pkiDir}/client.crt`,
164
- '-certfile',
165
- `${pkiDir}/ca.crt`,
166
- '-passout', 'stdin',
167
- ], { input: password });
143
+ await execa(
144
+ 'openssl',
145
+ [
146
+ 'pkcs12',
147
+ '-export',
148
+ '-keypbe',
149
+ 'PBE-SHA1-3DES',
150
+ '-certpbe',
151
+ 'PBE-SHA1-3DES',
152
+ '-macalg',
153
+ 'sha1',
154
+ '-out',
155
+ `${pkiDir}/client.p12`,
156
+ '-inkey',
157
+ `${pkiDir}/client.key`,
158
+ '-in',
159
+ `${pkiDir}/client.crt`,
160
+ '-certfile',
161
+ `${pkiDir}/ca.crt`,
162
+ '-passout',
163
+ 'stdin',
164
+ ],
165
+ { input: password },
166
+ );
168
167
 
169
168
  // Save password to file (no trailing newline)
170
169
  await writeFile(`${pkiDir}/.p12-password`, password, { mode: 0o600 });
@@ -54,10 +54,7 @@ export function nginxTasks(ctx, task) {
54
54
  const mtlsSnippet = `ssl_client_certificate ${pkiDir}/ca.crt;
55
55
  ssl_verify_client on;
56
56
  `;
57
- await writeFile(
58
- '/etc/nginx/snippets/portlama-mtls.conf',
59
- mtlsSnippet,
60
- );
57
+ await writeFile('/etc/nginx/snippets/portlama-mtls.conf', mtlsSnippet);
61
58
 
62
59
  subtask.output = 'mTLS snippet written to /etc/nginx/snippets/portlama-mtls.conf';
63
60
  },
@@ -130,10 +127,7 @@ server {
130
127
  }
131
128
  }
132
129
  `;
133
- await writeFile(
134
- '/etc/nginx/sites-available/portlama-panel-ip',
135
- vhostConfig,
136
- );
130
+ await writeFile('/etc/nginx/sites-available/portlama-panel-ip', vhostConfig);
137
131
 
138
132
  subtask.output = 'Vhost written to /etc/nginx/sites-available/portlama-panel-ip';
139
133
  },
@@ -187,10 +181,7 @@ server {
187
181
  await execa('systemctl', ['enable', 'nginx']);
188
182
  await execa('systemctl', ['restart', 'nginx']);
189
183
 
190
- const { stdout: status } = await execa('systemctl', [
191
- 'is-active',
192
- 'nginx',
193
- ]);
184
+ const { stdout: status } = await execa('systemctl', ['is-active', 'nginx']);
194
185
  if (status.trim() !== 'active') {
195
186
  throw new Error(`nginx failed to start. Status: ${status.trim()}`);
196
187
  }
package/src/tasks/node.js CHANGED
@@ -54,9 +54,7 @@ export function nodeTasks(ctx, task) {
54
54
  try {
55
55
  await execa('bash', [setupScript]);
56
56
  } catch (error) {
57
- throw new Error(
58
- `NodeSource setup script failed.\n${error.stderr || error.message}`,
59
- );
57
+ throw new Error(`NodeSource setup script failed.\n${error.stderr || error.message}`);
60
58
  }
61
59
 
62
60
  await unlink(setupScript).catch(() => {});
@@ -92,11 +92,7 @@ export function panelTasks(ctx, task) {
92
92
  );
93
93
  }
94
94
 
95
- await execa('chown', [
96
- '-R',
97
- 'portlama:portlama',
98
- serverDest,
99
- ]);
95
+ await execa('chown', ['-R', 'portlama:portlama', serverDest]);
100
96
 
101
97
  subtask.output = 'Panel server deployed';
102
98
  },
@@ -203,16 +199,9 @@ export function panelTasks(ctx, task) {
203
199
  };
204
200
  }
205
201
 
206
- await writeFile(
207
- configPath,
208
- JSON.stringify(config, null, 2) + '\n',
209
- { mode: 0o640 },
210
- );
202
+ await writeFile(configPath, JSON.stringify(config, null, 2) + '\n', { mode: 0o640 });
211
203
 
212
- await execa('chown', [
213
- 'portlama:portlama',
214
- configPath,
215
- ]);
204
+ await execa('chown', ['portlama:portlama', configPath]);
216
205
 
217
206
  subtask.output = `Configuration written to ${configPath}`;
218
207
  },
@@ -222,10 +211,7 @@ export function panelTasks(ctx, task) {
222
211
  title: 'Writing systemd service unit',
223
212
  task: async (_ctx, subtask) => {
224
213
  const serviceUnit = generateServiceUnit({ installDir, configDir });
225
- await writeFile(
226
- '/etc/systemd/system/portlama-panel.service',
227
- serviceUnit,
228
- );
214
+ await writeFile('/etc/systemd/system/portlama-panel.service', serviceUnit);
229
215
 
230
216
  subtask.output = 'Systemd service unit written';
231
217
  },
@@ -267,10 +253,7 @@ export function panelTasks(ctx, task) {
267
253
  subtask.output = 'Waiting for service to start...';
268
254
  await sleep(3000);
269
255
 
270
- const { stdout: status } = await execa('systemctl', [
271
- 'is-active',
272
- 'portlama-panel',
273
- ]);
256
+ const { stdout: status } = await execa('systemctl', ['is-active', 'portlama-panel']);
274
257
  if (status.trim() !== 'active') {
275
258
  const { stdout: logs } = await execa('journalctl', [
276
259
  '-u',
@@ -70,10 +70,7 @@ export function redeployTasks(ctx, task) {
70
70
  title: 'Stopping panel service',
71
71
  task: async (_ctx, subtask) => {
72
72
  try {
73
- const { stdout: status } = await execa('systemctl', [
74
- 'is-active',
75
- 'portlama-panel',
76
- ]);
73
+ const { stdout: status } = await execa('systemctl', ['is-active', 'portlama-panel']);
77
74
  if (status.trim() === 'active') {
78
75
  await execa('systemctl', ['stop', 'portlama-panel']);
79
76
  subtask.output = 'Service stopped';
@@ -134,9 +131,7 @@ export function redeployTasks(ctx, task) {
134
131
 
135
132
  const prebuiltDist = join(clientSrc, 'dist');
136
133
  if (!existsSync(join(prebuiltDist, 'index.html'))) {
137
- throw new Error(
138
- 'Pre-built panel-client dist not found. The package may be corrupted.',
139
- );
134
+ throw new Error('Pre-built panel-client dist not found. The package may be corrupted.');
140
135
  }
141
136
 
142
137
  subtask.output = 'Copying panel-client dist...';
@@ -169,11 +164,7 @@ export function redeployTasks(ctx, task) {
169
164
  staticDir: join(installDir, 'panel-client', 'dist'),
170
165
  };
171
166
 
172
- await writeFile(
173
- configPath,
174
- JSON.stringify(config, null, 2) + '\n',
175
- { mode: 0o640 },
176
- );
167
+ await writeFile(configPath, JSON.stringify(config, null, 2) + '\n', { mode: 0o640 });
177
168
  await execa('chown', ['portlama:portlama', configPath]);
178
169
 
179
170
  subtask.output = 'Configuration updated';
@@ -185,10 +176,7 @@ export function redeployTasks(ctx, task) {
185
176
  task: async (_ctx, subtask) => {
186
177
  subtask.output = 'Writing systemd service unit...';
187
178
  const serviceUnit = generateServiceUnit({ installDir, configDir });
188
- await writeFile(
189
- '/etc/systemd/system/portlama-panel.service',
190
- serviceUnit,
191
- );
179
+ await writeFile('/etc/systemd/system/portlama-panel.service', serviceUnit);
192
180
 
193
181
  subtask.output = 'Writing sudoers rules...';
194
182
  const sudoersContent = generateSudoersContent();
@@ -220,10 +208,7 @@ export function redeployTasks(ctx, task) {
220
208
  subtask.output = 'Waiting for service to start...';
221
209
  await sleep(3000);
222
210
 
223
- const { stdout: status } = await execa('systemctl', [
224
- 'is-active',
225
- 'portlama-panel',
226
- ]);
211
+ const { stdout: status } = await execa('systemctl', ['is-active', 'portlama-panel']);
227
212
  if (status.trim() !== 'active') {
228
213
  const { stdout: logs } = await execa('journalctl', [
229
214
  '-u',
@@ -254,9 +239,7 @@ export function redeployTasks(ctx, task) {
254
239
  '-n',
255
240
  '20',
256
241
  ]);
257
- throw new Error(
258
- `Panel health check failed.\nRecent logs:\n${logs}\n${error.message}`,
259
- );
242
+ throw new Error(`Panel health check failed.\nRecent logs:\n${logs}\n${error.message}`);
260
243
  }
261
244
  },
262
245
  rendererOptions: { persistentOutput: true },