server-studio 1.2.0 → 1.2.1

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/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  Notable changes to Server Studio. Dates are release dates.
4
4
 
5
+ ## 1.2.1 — 2026-08-30
6
+
7
+ - **Fixed:** an installed app reported its version as `0.0.0`, because the code looks for
8
+ `package.json` one level up and the app bundle does not contain one. The badge showed `v0.0.0`,
9
+ the update prompt appeared permanently even straight after updating, and telemetry recorded every
10
+ install as version 0.0.0. The installer now stamps the version beside the code.
11
+ - **Fixed:** if the local server was not responding, clicking **Update**, **Run** or **Stop** did
12
+ nothing at all. The failed request threw and was never caught, so there was no error either. Those
13
+ actions now say what went wrong.
14
+
5
15
  ## 1.2.0 — 2026-08-30
6
16
 
7
17
  ### Folders replace categories
package/bin/cli.js CHANGED
@@ -69,6 +69,14 @@ function install() {
69
69
  // cpSync does not preserve the exec bit on the launcher.
70
70
  // src/ is the single source of truth, copied into the bundle at install time.
71
71
  fs.cpSync(SRC, path.join(APP_DEST, 'Contents', 'Resources'), { recursive: true });
72
+ // The bundle has no package.json, so stamp the version beside the code. Without this
73
+ // an installed app reports 0.0.0 and therefore thinks an update is always available.
74
+ try {
75
+ fs.writeFileSync(
76
+ path.join(APP_DEST, 'Contents', 'Resources', 'version.json'),
77
+ JSON.stringify({ version: require(path.join(ROOT, 'package.json')).version }) + '\n'
78
+ );
79
+ } catch (e) {}
72
80
  fs.chmodSync(path.join(APP_DEST, 'Contents', 'MacOS', 'ServerStudio'), 0o755);
73
81
  } else skip('app skipped (--no-app)');
74
82
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "server-studio",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "A tiny dashboard for your local dev servers. One click to run, stop and open them, with one permanent port per project.",
5
5
  "author": "Md Mahdi Hasan",
6
6
  "license": "MIT",
package/src/index.html CHANGED
@@ -859,10 +859,13 @@ async function runUpdate() {
859
859
  'You are on ' + updateInfo.current + '. This runs npm install -g server-studio in a terminal window.\n\nYour saved servers and folders are not touched. Restart Server Studio when it finishes.',
860
860
  { okText: 'Update' });
861
861
  if (!ok) return;
862
- const r = await api('/api/run', { method: 'POST', headers: { 'Content-Type': 'application/json' },
863
- body: JSON.stringify({ cwd: '', command: 'npm install -g server-studio' }) });
862
+ let r = null;
863
+ try {
864
+ r = await api('/api/run', { method: 'POST', headers: { 'Content-Type': 'application/json' },
865
+ body: JSON.stringify({ cwd: '', command: 'npm install -g server-studio' }) });
866
+ } catch (e) { /* server gone: fall through to the error toast rather than doing nothing */ }
864
867
  if (r && r.ok) toast('Updating in ' + TERM_NAME + '. Restart Server Studio when it finishes.');
865
- else toast('Could not start the update. Run: npm install -g server-studio', true);
868
+ else toast('Could not start the update. Run this yourself: npm install -g server-studio', true);
866
869
  }
867
870
 
868
871
  function moveToFolder(serverId, folderId) {
@@ -988,8 +991,11 @@ async function runServer(id) {
988
991
  setTimeout(() => { const el = document.getElementById('f_cwd'); if (el) el.focus(); }, 120);
989
992
  return;
990
993
  }
991
- const r = await api('/api/run', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ cwd: s.cwd || '', command: s.command }) });
992
- if (r.ok) {
994
+ let r = null;
995
+ try {
996
+ r = await api('/api/run', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ cwd: s.cwd || '', command: s.command }) });
997
+ } catch (e) {}
998
+ if (r && r.ok) {
993
999
  toast('Running "' + (s.name || 'server') + '" in ' + TERM_NAME);
994
1000
  if (portOf(s)) { s._status = 'checking'; render(); }
995
1001
  setTimeout(() => refreshStatus(), 3500);
@@ -1000,8 +1006,10 @@ async function stopServer(id) {
1000
1006
  const port = portOf(s);
1001
1007
  if (!port) return;
1002
1008
  s._status = 'checking'; render();
1003
- await api('/api/stop', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ port }) });
1004
- toast('Stopped whatever was on port ' + port);
1009
+ try {
1010
+ await api('/api/stop', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ port }) });
1011
+ toast('Stopped whatever was on port ' + port);
1012
+ } catch (e) { toast('Could not stop it, the app is not responding.', true); }
1005
1013
  setTimeout(() => refreshStatus(), 700);
1006
1014
  }
1007
1015
  function copyUrl(url, btn) {
package/src/server.js CHANGED
@@ -88,7 +88,12 @@ function portFromUrl(url) {
88
88
 
89
89
  /* ---------- version check ---------- */
90
90
  function appVersion() {
91
- try { return require('../package.json').version || '0.0.0'; } catch (e) { return '0.0.0'; }
91
+ // Running from a checkout, package.json is one level up. Inside the installed app
92
+ // bundle there is no package.json, so the installer stamps version.json beside the
93
+ // code. Try both before giving up.
94
+ try { return require('./version.json').version || '0.0.0'; } catch (e) {}
95
+ try { return require('../package.json').version || '0.0.0'; } catch (e) {}
96
+ return '0.0.0';
92
97
  }
93
98
  function isNewer(a, b) {
94
99
  const pa = String(a).split('.').map(Number), pb = String(b).split('.').map(Number);
package/src/telemetry.js CHANGED
@@ -28,7 +28,12 @@ function optedOut() {
28
28
  }
29
29
 
30
30
  function appVersion() {
31
- try { return require('../package.json').version; } catch (e) { return '0.0.0'; }
31
+ // Running from a checkout, package.json is one level up. Inside the installed app
32
+ // bundle there is no package.json, so the installer stamps version.json beside the
33
+ // code. Try both before giving up.
34
+ try { return require('./version.json').version || '0.0.0'; } catch (e) {}
35
+ try { return require('../package.json').version || '0.0.0'; } catch (e) {}
36
+ return '0.0.0';
32
37
  }
33
38
 
34
39
  function dataDir() {