@mahidsec/nest 1.0.1 → 1.0.3

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/README.md CHANGED
@@ -43,15 +43,19 @@ The server starts at **http://localhost:6969**. Open it from any device on your
43
43
  ## Preview
44
44
 
45
45
  <p align="center">
46
- <img src="https://raw.githubusercontent.com/mahidsec/nest/main/screenshots/dashboard.png" alt="Nest Dashboard" width="640" />
46
+ <img src="https://raw.githubusercontent.com/mahidsec/nest/main/screenshots/home.png" alt="Home View" width="640" />
47
47
  </p>
48
48
 
49
49
  <p align="center">
50
- <img src="https://raw.githubusercontent.com/mahidsec/nest/main/screenshots/home.png" alt="Home View" width="640" />
50
+ <img src="https://raw.githubusercontent.com/mahidsec/nest/main/screenshots/course-adding.png" alt="Course Adding" width="640" />
51
51
  </p>
52
52
 
53
53
  <p align="center">
54
- <img src="https://raw.githubusercontent.com/mahidsec/nest/main/screenshots/course-adding.png" alt="Course Adding" width="640" />
54
+ <img src="https://raw.githubusercontent.com/mahidsec/nest/main/screenshots/dashboard.png" alt="Nest Dashboard" width="640" />
55
+ </p>
56
+
57
+ <p align="center">
58
+ <img src="https://raw.githubusercontent.com/mahidsec/nest/main/screenshots/navigation.png" alt="Navigation" width="640" />
55
59
  </p>
56
60
 
57
61
  ## Features
package/bin/nest.js CHANGED
@@ -314,7 +314,12 @@ async function handleSelect() {
314
314
  console.log(" \x1b[90mServer: http://localhost:" + PORT + "\x1b[0m");
315
315
  console.log();
316
316
 
317
- if (serverProcess) serverProcess.unref();
317
+ // Redirect server stdout/stderr so logs don't leak to terminal
318
+ if (serverProcess) {
319
+ serverProcess.stdout?.destroy();
320
+ serverProcess.stderr?.destroy();
321
+ serverProcess.unref();
322
+ }
318
323
 
319
324
  spawn("node", [__filename, "--tray"], {
320
325
  stdio: "ignore",
package/dist/server.js CHANGED
@@ -198,15 +198,12 @@ function findCloudflared() {
198
198
  } catch {
199
199
  }
200
200
  if (fs.existsSync(CLOUDFLARED_PATH)) return CLOUDFLARED_PATH;
201
- console.log("[Tunnel] cloudflared not found \u2014 downloading...");
202
201
  try {
203
202
  if (!fs.existsSync(NEST_BIN_DIR)) fs.mkdirSync(NEST_BIN_DIR, { recursive: true });
204
203
  execSync(`curl -fSL -o "${CLOUDFLARED_PATH}" "${getCloudflaredDownloadUrl()}"`, { stdio: "inherit" });
205
204
  fs.chmodSync(CLOUDFLARED_PATH, 493);
206
- console.log("[Tunnel] cloudflared installed");
207
205
  return CLOUDFLARED_PATH;
208
206
  } catch {
209
- console.error("[Tunnel] Failed to download cloudflared");
210
207
  return null;
211
208
  }
212
209
  }
@@ -286,8 +283,7 @@ app.get("/api/courses", async (_req, res) => {
286
283
  totalVideos: await getCachedVideoCount(c.localPath)
287
284
  })));
288
285
  res.json(enriched);
289
- } catch (err) {
290
- console.error("[Courses] List error:", err);
286
+ } catch {
291
287
  res.status(500).json({ error: "Failed to load courses" });
292
288
  }
293
289
  });
@@ -317,7 +313,6 @@ app.post("/api/courses", async (req, res) => {
317
313
  courses.push(course);
318
314
  await saveCourses(courses);
319
315
  invalidateVideoCount(resolved);
320
- console.log(`[Courses] Added "${name}" \u2192 ${resolved}`);
321
316
  res.json({ success: true, course });
322
317
  });
323
318
  app.delete("/api/courses/:id", async (req, res) => {
@@ -326,7 +321,6 @@ app.delete("/api/courses/:id", async (req, res) => {
326
321
  if (!target) return res.status(404).json({ error: "Course not found" });
327
322
  invalidateVideoCount(target.localPath);
328
323
  await saveCourses(courses.filter((c) => c.id !== req.params.id));
329
- console.log(`[Courses] Removed course ${req.params.id}`);
330
324
  res.json({ success: true });
331
325
  });
332
326
  app.get("/api/courses/:id/browse", async (req, res) => {
@@ -342,8 +336,7 @@ app.get("/api/courses/:id/browse", async (req, res) => {
342
336
  const result = await scanDirectory(course.localPath, course.localPath);
343
337
  invalidateVideoCount(course.localPath);
344
338
  res.json({ ...course, ...result });
345
- } catch (err) {
346
- console.error("[Courses] Browse error:", err);
339
+ } catch {
347
340
  res.status(500).json({ error: "Failed to scan directory" });
348
341
  }
349
342
  });
@@ -442,8 +435,7 @@ app.get("/api/courses/:id/file", async (req, res) => {
442
435
  "Cache-Control": "public, max-age=3600"
443
436
  });
444
437
  safePipe(fs.createReadStream(realResolved), res);
445
- } catch (err) {
446
- console.error("[Courses] File error:", err);
438
+ } catch {
447
439
  res.status(500).json({ error: "Failed to serve file" });
448
440
  }
449
441
  });
@@ -472,9 +464,6 @@ app.get("*", (_req, res) => {
472
464
  }
473
465
  });
474
466
  httpServer.listen(PORT, "0.0.0.0", () => {
475
- console.log(`[Nest] Server running on http://localhost:${PORT}`);
476
- console.log(`[Nest] Data dir: ${DATA_DIR}`);
477
- if (IS_TUNNEL) console.log(`[Nest] Tunnel mode: enabled`);
478
467
  });
479
468
  var shuttingDown = false;
480
469
  var shutdown = (signal) => {
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@mahidsec/nest",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Standalone local course viewer with Moonlight themes",
5
5
  "type": "module",
6
6
  "bin": {
7
- "nest": "./bin/nest.js"
7
+ "nestviewer": "./bin/nest.js"
8
8
  },
9
9
  "scripts": {
10
10
  "build": "cd frontend && npm run build && cd .. && node esbuild.config.mjs",
package/src/server.ts CHANGED
@@ -199,16 +199,12 @@ function findCloudflared(): string | null {
199
199
  } catch {}
200
200
  // 2. Check ~/.nest/bin/cloudflared
201
201
  if (fs.existsSync(CLOUDFLARED_PATH)) return CLOUDFLARED_PATH;
202
- // 3. Auto-download
203
- console.log('[Tunnel] cloudflared not found — downloading...');
204
202
  try {
205
203
  if (!fs.existsSync(NEST_BIN_DIR)) fs.mkdirSync(NEST_BIN_DIR, { recursive: true });
206
204
  execSync(`curl -fSL -o "${CLOUDFLARED_PATH}" "${getCloudflaredDownloadUrl()}"`, { stdio: 'inherit' });
207
205
  fs.chmodSync(CLOUDFLARED_PATH, 0o755);
208
- console.log('[Tunnel] cloudflared installed');
209
206
  return CLOUDFLARED_PATH;
210
207
  } catch {
211
- console.error('[Tunnel] Failed to download cloudflared');
212
208
  return null;
213
209
  }
214
210
  }
@@ -295,8 +291,7 @@ app.get('/api/courses', async (_req, res) => {
295
291
  totalVideos: await getCachedVideoCount(c.localPath),
296
292
  })));
297
293
  res.json(enriched);
298
- } catch (err) {
299
- console.error('[Courses] List error:', err);
294
+ } catch {
300
295
  res.status(500).json({ error: 'Failed to load courses' });
301
296
  }
302
297
  });
@@ -333,7 +328,6 @@ app.post('/api/courses', async (req, res) => {
333
328
  courses.push(course);
334
329
  await saveCourses(courses);
335
330
  invalidateVideoCount(resolved);
336
- console.log(`[Courses] Added "${name}" → ${resolved}`);
337
331
  res.json({ success: true, course });
338
332
  });
339
333
 
@@ -343,7 +337,6 @@ app.delete('/api/courses/:id', async (req, res) => {
343
337
  if (!target) return res.status(404).json({ error: 'Course not found' });
344
338
  invalidateVideoCount(target.localPath);
345
339
  await saveCourses(courses.filter((c) => c.id !== req.params.id));
346
- console.log(`[Courses] Removed course ${req.params.id}`);
347
340
  res.json({ success: true });
348
341
  });
349
342
 
@@ -362,8 +355,7 @@ app.get('/api/courses/:id/browse', async (req, res) => {
362
355
  const result = await scanDirectory(course.localPath, course.localPath);
363
356
  invalidateVideoCount(course.localPath);
364
357
  res.json({ ...course, ...result });
365
- } catch (err: unknown) {
366
- console.error('[Courses] Browse error:', err);
358
+ } catch {
367
359
  res.status(500).json({ error: 'Failed to scan directory' });
368
360
  }
369
361
  });
@@ -463,8 +455,7 @@ app.get('/api/courses/:id/file', async (req, res) => {
463
455
  'Cache-Control': 'public, max-age=3600',
464
456
  });
465
457
  safePipe(fs.createReadStream(realResolved), res);
466
- } catch (err) {
467
- console.error('[Courses] File error:', err);
458
+ } catch {
468
459
  res.status(500).json({ error: 'Failed to serve file' });
469
460
  }
470
461
  });
@@ -500,11 +491,7 @@ app.get('*', (_req, res) => {
500
491
  });
501
492
 
502
493
  // ─── Start ───
503
- httpServer.listen(PORT, '0.0.0.0', () => {
504
- console.log(`[Nest] Server running on http://localhost:${PORT}`);
505
- console.log(`[Nest] Data dir: ${DATA_DIR}`);
506
- if (IS_TUNNEL) console.log(`[Nest] Tunnel mode: enabled`);
507
- });
494
+ httpServer.listen(PORT, '0.0.0.0', () => {});
508
495
 
509
496
  // ─── Graceful Shutdown ───
510
497
  let shuttingDown = false;