@balaji003/lantransfer 1.0.9 → 1.0.10

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": "@balaji003/lantransfer",
3
- "version": "1.0.9",
3
+ "version": "1.0.10",
4
4
  "description": "LAN File Transfer — peer-to-peer file sharing over local network. Zero dependencies.",
5
5
  "main": "server.js",
6
6
  "bin": {
package/public/index.html CHANGED
@@ -186,6 +186,28 @@
186
186
  }
187
187
  .btn-change-dir:hover { background: var(--surface-hover); border-color: var(--accent); }
188
188
 
189
+ /* ── Update banner ── */
190
+ .update-banner {
191
+ display: none; align-items: center; justify-content: center; gap: 12px;
192
+ padding: 8px 24px; background: rgba(74, 158, 255, 0.1);
193
+ border-bottom: 1px solid var(--accent); font-size: 13px; flex-shrink: 0;
194
+ }
195
+ .update-banner.show { display: flex; }
196
+ .update-banner span { color: var(--text); }
197
+ .update-banner .version-new { color: var(--green); font-weight: 600; }
198
+ .update-banner .version-old { color: var(--text-dim); }
199
+ .btn-update {
200
+ background: var(--accent); color: #fff; border: none; border-radius: 4px;
201
+ padding: 3px 12px; font-size: 12px; font-weight: 500; cursor: pointer;
202
+ transition: background 0.12s;
203
+ }
204
+ .btn-update:hover { background: var(--accent-dim); }
205
+ .btn-dismiss {
206
+ background: none; border: none; color: var(--text-dim); cursor: pointer;
207
+ font-size: 16px; padding: 0 4px; line-height: 1;
208
+ }
209
+ .btn-dismiss:hover { color: var(--text); }
210
+
189
211
  /* ── Transfers ── */
190
212
  .transfers-section { flex: 1; overflow-y: auto; padding: 16px 24px; }
191
213
  .transfer {
@@ -284,6 +306,13 @@
284
306
  </div>
285
307
  </div>
286
308
 
309
+ <!-- Update banner -->
310
+ <div class="update-banner" id="update-banner">
311
+ <span>Update available: <span class="version-old" id="ver-current"></span> → <span class="version-new" id="ver-latest"></span></span>
312
+ <button class="btn-update" id="update-btn" onclick="doUpdate()">Update Now</button>
313
+ <button class="btn-dismiss" onclick="dismissUpdate()" title="Dismiss">&times;</button>
314
+ </div>
315
+
287
316
  <!-- Download location -->
288
317
  <div class="download-dir">
289
318
  <span>Save to:</span>
@@ -419,6 +448,28 @@
419
448
  api('open-folder', { transferId: transferId });
420
449
  }
421
450
 
451
+ let updateDismissed = false;
452
+
453
+ function doUpdate() {
454
+ const btn = document.getElementById('update-btn');
455
+ btn.textContent = 'Updating...';
456
+ btn.disabled = true;
457
+ api('do-update');
458
+ // Server will restart — poll until it's back
459
+ setTimeout(function poll() {
460
+ fetch('/api/ping').then(() => {
461
+ window.location.reload();
462
+ }).catch(() => {
463
+ setTimeout(poll, 1000);
464
+ });
465
+ }, 3000);
466
+ }
467
+
468
+ function dismissUpdate() {
469
+ updateDismissed = true;
470
+ document.getElementById('update-banner').classList.remove('show');
471
+ }
472
+
422
473
  function doShutdown() {
423
474
  if (confirm('Stop the server? This will close LAN Transfer.')) {
424
475
  api('shutdown');
@@ -450,6 +501,16 @@
450
501
  }
451
502
  document.getElementById('local-ip').textContent = state.localIP || '';
452
503
 
504
+ // Update banner
505
+ const banner = document.getElementById('update-banner');
506
+ if (!updateDismissed && state.latestVersion && state.currentVersion && state.latestVersion !== state.currentVersion) {
507
+ document.getElementById('ver-current').textContent = 'v' + state.currentVersion;
508
+ document.getElementById('ver-latest').textContent = 'v' + state.latestVersion;
509
+ banner.classList.add('show');
510
+ } else {
511
+ banner.classList.remove('show');
512
+ }
513
+
453
514
  // Download dir
454
515
  const dirEl = document.getElementById('download-dir');
455
516
  dirEl.textContent = state.downloadDir || '';
package/server.js CHANGED
@@ -13,6 +13,7 @@
13
13
  */
14
14
 
15
15
  const http = require('http');
16
+ const https = require('https');
16
17
  const fs = require('fs');
17
18
  const path = require('path');
18
19
  const crypto = require('crypto');
@@ -30,6 +31,10 @@ const HTTP_PORT = 3000;
30
31
  const PEER_TIMEOUT = 10_000; // ms
31
32
  const BROADCAST_INTERVAL = 3_000; // ms
32
33
  const ECDH_CURVE = 'prime256v1'; // NIST P-256
34
+ const PKG = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf-8'));
35
+ const CURRENT_VERSION = PKG.version;
36
+ const PKG_NAME = PKG.name;
37
+ let latestVersion = null; // filled by update check
33
38
 
34
39
  // ──────────────────────────────────────────────────────────────────────────────
35
40
  // Persistent config (device name)
@@ -101,6 +106,8 @@ function serializeState() {
101
106
  isDiscoverable,
102
107
  deviceName,
103
108
  downloadDir,
109
+ currentVersion: CURRENT_VERSION,
110
+ latestVersion,
104
111
  localIP: getLocalIP(),
105
112
  peers: [...peers.entries()].map(([id, p]) => ({
106
113
  id, name: p.device_name, ip: p.ip,
@@ -354,6 +361,34 @@ const server = http.createServer(async (req, res) => {
354
361
  console.log(` [open] Failed — transferId: ${transferId}, found: ${!!t}, savePath: ${t ? t.savePath : 'N/A'}`);
355
362
  }
356
363
  }
364
+ else if (req.url === '/api/check-update') {
365
+ checkForUpdate();
366
+ }
367
+ else if (req.url === '/api/do-update') {
368
+ res.writeHead(200, { 'Content-Type': 'text/plain' });
369
+ res.end('ok');
370
+ console.log(` [update] Running: npm install -g ${PKG_NAME}`);
371
+ exec(`npm install -g ${PKG_NAME}`, { timeout: 120_000 }, (err, stdout, stderr) => {
372
+ if (err) {
373
+ console.error(` [update] Failed: ${err.message}`);
374
+ console.error(stderr);
375
+ } else {
376
+ console.log(` [update] Success! Restarting...`);
377
+ console.log(stdout);
378
+ // Restart the process
379
+ setTimeout(() => {
380
+ const args = process.argv.slice(1);
381
+ const child = require('child_process').spawn(process.execPath, args, {
382
+ detached: true,
383
+ stdio: 'ignore',
384
+ });
385
+ child.unref();
386
+ process.exit(0);
387
+ }, 500);
388
+ }
389
+ });
390
+ return;
391
+ }
357
392
  else if (req.url === '/api/shutdown') {
358
393
  res.writeHead(200, { 'Content-Type': 'text/plain' });
359
394
  res.end('ok');
@@ -717,6 +752,33 @@ async function sendFile(peer, file) {
717
752
  }
718
753
  }
719
754
 
755
+ // ──────────────────────────────────────────────────────────────────────────────
756
+ // Update checker
757
+ // ──────────────────────────────────────────────────────────────────────────────
758
+ function checkForUpdate() {
759
+ const url = `https://registry.npmjs.org/${PKG_NAME}/latest`;
760
+ console.log(` [update] Checking ${url}`);
761
+ https.get(url, { timeout: 5000 }, res => {
762
+ let body = '';
763
+ res.on('data', c => body += c);
764
+ res.on('end', () => {
765
+ try {
766
+ const data = JSON.parse(body);
767
+ latestVersion = data.version || null;
768
+ console.log(` [update] Current: ${CURRENT_VERSION}, Latest: ${latestVersion}`);
769
+ if (latestVersion && latestVersion !== CURRENT_VERSION) {
770
+ console.log(` [update] Update available! Run: npm install -g ${PKG_NAME}`);
771
+ }
772
+ broadcast();
773
+ } catch (e) {
774
+ console.error(` [update] Parse error: ${e.message}`);
775
+ }
776
+ });
777
+ }).on('error', e => {
778
+ console.error(` [update] Check failed: ${e.message}`);
779
+ });
780
+ }
781
+
720
782
  // ──────────────────────────────────────────────────────────────────────────────
721
783
  // Utility
722
784
  // ──────────────────────────────────────────────────────────────────────────────
@@ -826,9 +888,13 @@ server.listen(HTTP_PORT, () => {
826
888
  console.log(` Discovery UDP :${DISCOVERY_PORT} (fallback)`);
827
889
  console.log(` Transfer TCP :${TRANSFER_PORT}`);
828
890
  console.log(` Encryption ECDH + AES-256-CTR (E2E)`);
891
+ console.log(` Version ${CURRENT_VERSION}`);
829
892
  console.log(` UI: http://localhost:${HTTP_PORT}`);
830
893
  console.log('');
831
894
 
895
+ // Check for updates on startup
896
+ checkForUpdate();
897
+
832
898
  // Auto-open browser
833
899
  const url = `http://localhost:${HTTP_PORT}`;
834
900
  if (process.platform === 'win32') exec(`start "" "${url}"`);