@woopsy/mcpanel 2.1.2 → 2.1.4

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.
@@ -430,7 +430,14 @@ class CommandRouter {
430
430
  }
431
431
  if (status.address && status.address !== 'None') {
432
432
  output.push(`\nšŸŽ® Connect at: ${colors.bold(colors.green(`${status.address}:${status.port}`))}`);
433
+ output.push(colors.gray(`(Enter the full address WITH ":${status.port}" — the bare domain defaults to 25565 and won't connect.)`));
433
434
  }
435
+ // Persistence diagnostics: whether the agent is claimed/saved, and where.
436
+ // If this says "Not saved", /tunnel will re-claim a new agent every run.
437
+ const hasSecret = !!this.playitManager.getSecret();
438
+ output.push('');
439
+ output.push(`Agent secret: ${hasSecret ? colors.green('Saved (will reuse this agent)') : colors.red('Not saved — /tunnel will claim a new agent')}`);
440
+ output.push(colors.gray(`Config file: ${this.configManager.getConfigPath()}`));
434
441
  output.push('');
435
442
  return output.join('\n');
436
443
  }
@@ -522,9 +529,13 @@ class CommandRouter {
522
529
  },
523
530
  onStatus: (msg) => console.log(colors.info(msg)),
524
531
  });
532
+ const portHint = type === 'java'
533
+ ? colors.gray(`In Minecraft, enter the FULL address including ":${status.port}" — the bare domain defaults to port 25565 and will not connect.`)
534
+ : colors.gray(`In Minecraft Bedrock, enter the address and set the Port field to ${status.port}.`);
525
535
  return [
526
536
  colors.success(`${type === 'java' ? 'Java' : 'Bedrock'} tunnel is online!`),
527
537
  `\nšŸŽ® Connect at: ${colors.bold(colors.green(`${status.address}:${status.port}`))}`,
538
+ portHint,
528
539
  colors.gray('Share this address with players. The tunnel stays up while MCPANEL is running.'),
529
540
  ].join('\n');
530
541
  }
@@ -176,12 +176,19 @@ class ConfigManager {
176
176
  */
177
177
  save() {
178
178
  try {
179
+ // Defensively recreate the data dir — if it's missing at write time the
180
+ // write throws ENOENT and (previously) the secret was lost silently.
181
+ fs.mkdirSync(path.dirname(CONFIG_PATH), { recursive: true });
179
182
  fs.writeFileSync(CONFIG_PATH, JSON.stringify(this.config, null, 2), 'utf-8');
180
183
  }
181
184
  catch (error) {
182
185
  console.error('āŒ Failed to save configuration file:', error);
183
186
  }
184
187
  }
188
+ /** Absolute path of the config file on disk (for status/diagnostics). */
189
+ getConfigPath() {
190
+ return CONFIG_PATH;
191
+ }
185
192
  /**
186
193
  * Retrieves the raw config reference
187
194
  */
@@ -214,6 +221,23 @@ class ConfigManager {
214
221
  setPlayitSecret(secret) {
215
222
  this.config.playitSettings.secret = secret;
216
223
  this.save();
224
+ // The whole point of claiming once is that the secret survives a restart.
225
+ // If it didn't reach disk, fail loudly now instead of silently re-claiming
226
+ // a brand-new agent (and orphaning the old one) on the next launch.
227
+ if (!this.isPlayitSecretPersisted(secret)) {
228
+ throw new Error(`Could not persist the playit agent secret to ${CONFIG_PATH}. ` +
229
+ `Check that the folder exists and is writable, then run /tunnel again.`);
230
+ }
231
+ }
232
+ /** Confirms the agent secret is readable back from disk (not just in memory). */
233
+ isPlayitSecretPersisted(secret) {
234
+ try {
235
+ const onDisk = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8'));
236
+ return onDisk?.playitSettings?.secret === secret;
237
+ }
238
+ catch {
239
+ return false;
240
+ }
217
241
  }
218
242
  /**
219
243
  * Persists the last known tunnel details for status reporting between sessions.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@woopsy/mcpanel",
3
- "version": "2.1.2",
3
+ "version": "2.1.4",
4
4
  "description": "MCPANEL — a terminal-based, single-server Minecraft server manager with an Arch/neofetch-style UI, live logs, backups, plugins and Playit.gg tunnels.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {