seo-intel 1.2.2 → 1.2.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.
- package/CHANGELOG.md +9 -2
- package/package.json +1 -1
- package/reports/generate-html.js +2 -2
- package/server.js +27 -16
package/CHANGELOG.md
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 1.2.
|
|
3
|
+
## 1.2.4 (2026-03-31)
|
|
4
|
+
|
|
5
|
+
### Fixes
|
|
6
|
+
- Fix favicon serving — explicit `Content-Type: image/png` header prevents browser showing cached favicon from crawled sites
|
|
7
|
+
- Favicon link tag now cache-busts on dashboard regeneration
|
|
8
|
+
|
|
9
|
+
## 1.2.3 (2026-03-28)
|
|
4
10
|
|
|
5
11
|
### Dashboard
|
|
6
12
|
- Remove redundant Crawl/Extract buttons from status bar — terminal already has them
|
|
7
13
|
- Status bar now shows only Stop, Restart, and Stealth toggle (cleaner UI)
|
|
8
|
-
-
|
|
14
|
+
- Fix stealth toggle scoping in multi-project dashboard — each project panel reads its own toggle
|
|
15
|
+
- Stop button now clears crashed processes (dead PIDs) instead of showing stale "running" state
|
|
9
16
|
|
|
10
17
|
## 1.2.0 (2026-03-28)
|
|
11
18
|
|
package/package.json
CHANGED
package/reports/generate-html.js
CHANGED
|
@@ -208,7 +208,7 @@ function buildHtmlTemplate(data, opts = {}) {
|
|
|
208
208
|
<meta charset="UTF-8">
|
|
209
209
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
210
210
|
<title>SEO Intel ${pro ? 'Dashboard' : 'Preview'} — ${project.toUpperCase()}</title>
|
|
211
|
-
<link rel="icon" type="image/png" href="/favicon.png">
|
|
211
|
+
<link rel="icon" type="image/png" href="/favicon.png?v=${Date.now()}">
|
|
212
212
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
213
213
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
214
214
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=Syne:wght@600;700;800&display=swap" rel="stylesheet">
|
|
@@ -2162,7 +2162,7 @@ function buildHtmlTemplate(data, opts = {}) {
|
|
|
2162
2162
|
var extra = scope ? { scope: scope } : {};
|
|
2163
2163
|
// Crawl/extract: read stealth toggle + update status bar
|
|
2164
2164
|
if (cmd === 'crawl' || cmd === 'extract') {
|
|
2165
|
-
var stealthEl =
|
|
2165
|
+
var stealthEl = btn.closest('.project-panel')?.querySelector('[id^="stealthToggle"]') || document.getElementById('stealthToggle' + suffix);
|
|
2166
2166
|
if (stealthEl?.checked) extra.stealth = true;
|
|
2167
2167
|
if (window._setButtonsState) window._setButtonsState(true, cmd);
|
|
2168
2168
|
if (window._startPolling) window._startPolling();
|
package/server.js
CHANGED
|
@@ -339,32 +339,39 @@ async function handleRequest(req, res) {
|
|
|
339
339
|
if (req.method === 'POST' && path === '/api/stop') {
|
|
340
340
|
try {
|
|
341
341
|
const progress = readProgress();
|
|
342
|
-
if (!progress ||
|
|
342
|
+
if (!progress || !progress.pid) {
|
|
343
343
|
json(res, 404, { error: 'No running job to stop' });
|
|
344
344
|
return;
|
|
345
345
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
346
|
+
|
|
347
|
+
// Check if process is actually alive
|
|
348
|
+
let isAlive = false;
|
|
349
|
+
try { process.kill(progress.pid, 0); isAlive = true; } catch { isAlive = false; }
|
|
350
|
+
|
|
351
|
+
if (isAlive) {
|
|
352
|
+
try {
|
|
353
|
+
// Graceful: SIGTERM lets the CLI close browsers / write progress
|
|
354
|
+
process.kill(progress.pid, 'SIGTERM');
|
|
355
|
+
// Escalate: SIGKILL after 5s if still alive (stealth browser cleanup needs time)
|
|
356
|
+
setTimeout(() => {
|
|
357
|
+
try { process.kill(progress.pid, 0); } catch { return; } // already dead
|
|
358
|
+
try { process.kill(progress.pid, 'SIGKILL'); } catch {}
|
|
359
|
+
}, 5000);
|
|
360
|
+
} catch (e) {
|
|
361
|
+
if (e.code !== 'ESRCH') throw e;
|
|
362
|
+
}
|
|
357
363
|
}
|
|
358
|
-
|
|
364
|
+
|
|
365
|
+
// Update progress file — clears both running and crashed states
|
|
359
366
|
try {
|
|
360
367
|
writeFileSync(PROGRESS_FILE, JSON.stringify({
|
|
361
368
|
...progress,
|
|
362
|
-
status: 'stopped',
|
|
369
|
+
status: isAlive ? 'stopped' : 'crashed_cleared',
|
|
363
370
|
stopped_at: Date.now(),
|
|
364
371
|
updated_at: Date.now(),
|
|
365
372
|
}, null, 2));
|
|
366
373
|
} catch { /* best-effort */ }
|
|
367
|
-
json(res, 200, { stopped: true, pid: progress.pid, command: progress.command });
|
|
374
|
+
json(res, 200, { stopped: true, pid: progress.pid, command: progress.command, wasAlive: isAlive });
|
|
368
375
|
} catch (e) {
|
|
369
376
|
json(res, 500, { error: e.message });
|
|
370
377
|
}
|
|
@@ -671,7 +678,11 @@ async function handleRequest(req, res) {
|
|
|
671
678
|
if (req.method === 'GET' && (path === '/favicon.ico' || path === '/favicon.png')) {
|
|
672
679
|
const faviconPath = join(__dirname, 'seo-intel.png');
|
|
673
680
|
if (existsSync(faviconPath)) {
|
|
674
|
-
|
|
681
|
+
res.writeHead(200, {
|
|
682
|
+
'Content-Type': 'image/png',
|
|
683
|
+
'Cache-Control': 'public, max-age=3600',
|
|
684
|
+
});
|
|
685
|
+
res.end(readFileSync(faviconPath));
|
|
675
686
|
} else {
|
|
676
687
|
res.writeHead(204); res.end();
|
|
677
688
|
}
|