bookworm-smart-assistant/scripts/patches/patch-w7-safe-age.js
Bookworm Admin b7a8e29d21 release: v6.7.0 - OTA E2E test release
- VERSION file as authoritative version source
- export.mjs reads VERSION with package.json fallback
- bw-ota.ps1 DryRun mode for safe testing
- auto-setup.ps1 bumped to v3.2.0 (Phase 8 OTA)
2026-04-27 17:59:44 +08:00

75 lines
2.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
/**
* Patch W7: health-check.js 时间回拨防护
* 注入 safeAge(t) 统一处理 Date.now() - mtimemax(0, diff) 防负值
* 幂等: sentinel W7_SAFE_AGE_v1
*/
const fs = require('fs');
const path = require('path');
const TARGET = path.join(__dirname, '..', 'health-check.js');
const SENTINEL = 'W7_SAFE_AGE_v1';
function main() {
if (!fs.existsSync(TARGET)) { console.error('[patch-w7] missing target'); process.exit(2); }
const src = fs.readFileSync(TARGET, 'utf8');
if (src.includes(SENTINEL)) { console.error('[patch-w7] already applied, skip'); process.exit(0); }
// 1) 注入 safeAge helper (在 JSON_MODE 声明后)
const anchor1 = "const JSON_MODE = process.argv.includes('--json');";
if (!src.includes(anchor1)) { console.error('[patch-w7] anchor1 missing'); process.exit(3); }
const helperBlock =
anchor1 + "\n\n" +
"// " + SENTINEL + ": 时间回拨防护 (NTP 回跳/跨时区/休眠恢复)\n" +
"function safeAge(t) {\n" +
" const ts = typeof t === 'number' ? t : (t && t.getTime ? t.getTime() : 0);\n" +
" const d = Date.now() - ts;\n" +
" return d < 0 ? 0 : d;\n" +
"}\n";
let patched = src.replace(anchor1, helperBlock);
// 2) 替换 4 处 Date.now() - X 调用点
const replacements = [
{
from: "const lockAge = (Date.now() - fs.statSync(lockFile).mtimeMs) / 3600000;",
to: "const lockAge = safeAge(fs.statSync(lockFile).mtimeMs) / 3600000;"
},
{
from: "const daysSince = genDate ? Math.floor((Date.now() - genDate.getTime()) / 86400000) : -1;",
to: "const daysSince = genDate ? Math.floor(safeAge(genDate) / 86400000) : -1;",
all: true
},
{
from: "return (Date.now() - created) > 30 * 60 * 1000;",
to: "return safeAge(created) > 30 * 60 * 1000;"
}
];
let hitCount = 0;
for (const r of replacements) {
if (r.all) {
while (patched.includes(r.from)) {
patched = patched.replace(r.from, r.to);
hitCount++;
}
} else {
if (!patched.includes(r.from)) { console.error('[patch-w7] miss:', r.from.slice(0,60)); process.exit(4); }
patched = patched.replace(r.from, r.to);
hitCount++;
}
}
if (hitCount < 4) { console.error('[patch-w7] expected 4 hits, got', hitCount); process.exit(5); }
if (patched === src) { console.error('[patch-w7] nothing changed'); process.exit(6); }
const bakDir = path.join(path.dirname(TARGET), 'patches', 'bak');
if (!fs.existsSync(bakDir)) fs.mkdirSync(bakDir, { recursive: true });
const bak = path.join(bakDir, 'health-check.js.bak.w7.' + Date.now());
fs.writeFileSync(bak, src);
const tmp = TARGET + '.tmp.' + process.pid;
fs.writeFileSync(tmp, patched);
fs.renameSync(tmp, TARGET);
console.error('[patch-w7] applied, hits=' + hitCount + ', bak=' + bak);
}
main();