feat: fix repetitive update available prompt

Task #58 completed by ClaudeQueue

ClaudeQueue
This commit is contained in:
Claude Worker
2026-07-01 06:37:12 +00:00
parent 395af38246
commit 18ad8152bf

View File

@@ -25,15 +25,46 @@ import { logger } from 'hono/logger';
import { spawnSync } from 'node:child_process';
import { createServer } from 'node:http';
import { readFileSync } from 'node:fs';
import { createHash } from 'node:crypto';
import { initDb, upsertUser, recordVideoAccess, getUserData } from './db.js';
const PORT = parseInt(process.env.PORT || '3000', 10);
const APP_VERSION = process.env.APP_VERSION || '1.0.0';
const YTDLP = process.env.YTDLP_PATH || 'yt-dlp';
// Stable tag for this server process — changes on every deploy/restart.
// The frontend polls /api/version and reloads when the tag drifts.
const BUILD_TAG = process.env.BUILD_TAG || Date.now().toString(36);
// ----------------------------------------------------------------------------
// BUILD_TAG — must be DETERMINISTIC across restarts of identical code.
//
// Previously this was `Date.now().toString(36)`, which changes every time the
// process starts even if nothing was deployed (crash-loop, healthcheck
// restart, container reschedule). The frontend's checkBuildTag() polls
// /api/version and re-shows the "Update available" modal the instant the tag
// drifts — so a restarting-but-unchanged server kept re-announcing an update
// that never actually happened, and clicking "Refresh UI" (which itself
// reloads the page and re-polls) never made the prompt go away for good.
//
// Fix: hash the actual served frontend files. Identical code → identical
// hash → identical tag, no matter how many times the process restarts. A
// real deploy (changed files) still produces a new tag as intended.
// process.env.BUILD_TAG still wins if a CI pipeline already injects a git
// SHA — that's an even better source of truth than a content hash.
// ----------------------------------------------------------------------------
function computeBuildTag() {
try {
const hash = createHash('sha256');
for (const file of ['app.js', 'sw.js', 'index.html', 'styles.css']) {
hash.update(readFileSync(`./public/${file}`));
}
return hash.digest('hex').slice(0, 12);
} catch {
// Frontend files not readable (e.g. unit tests run outside ./public) —
// fall back to a fixed tag rather than Date.now(), so it still never
// drifts spuriously between restarts.
return 'dev-build';
}
}
const BUILD_TAG = process.env.BUILD_TAG || computeBuildTag();
const SEARCH_LIMIT = 25;
const CHANNEL_LIMIT = 60;