安全与权限: - 站点访问权限改为 optional_host_permissions,保存配置时逐域名授权;移除 host_permissions 与 tabs,安装提示不再出现全站数据访问与浏览记录 - 主口令不再写入 storage.session,改用 IndexedDB 中不可导出的 CryptoKey 句柄恢复解锁,锁定即丢弃 - content script 注入范围只注册已授权域名,并随权限变化即时收敛 自动登录: - 支持 iframe 内的登录表单:脚本注入所有帧,逐帧按自身地址匹配配置 - 手动填充改为逐帧探测,定向发送到真正含密码框的帧 - 限流修正:只在真正触发提交后计数;判定登录成功后立即清零;达到上限时页面给出可见提示;重置判断只看启用中的配置 - SPA 重试改为 DOM 变更门控 + 退避,并单独监听已发现的 Shadow Root 工程化与文档: - 引入 ESLint(扁平配置)与 Prettier,CI 增加 lint 与 format:check - 信息类日志改为 debugLog(默认静默,chrome.storage.local.debugLog 开关) - 测试 123 → 128 用例(新增权限、iframe、限流相关用例) - README / PRIVACY / CHANGELOG 同步
90 lines
3.6 KiB
JavaScript
90 lines
3.6 KiB
JavaScript
#!/usr/bin/env node
|
||
/**
|
||
* 版本化发布:递增版本号 → 同步 manifest.json / package.json / updates.xml →
|
||
* 发布构建 → 打出 zip,并打印后续 git 操作命令(不自动提交/打 tag)。
|
||
*
|
||
* 用法:
|
||
* npm run release -- patch 1.0.0 → 1.0.1
|
||
* npm run release -- minor 1.0.0 → 1.1.0
|
||
* npm run release -- major 1.0.0 → 2.0.0
|
||
* npm run release -- 1.4.0 指定版本
|
||
* npm run release -- patch --codebase http://host/auto-login.crx 同步自托管更新地址
|
||
*/
|
||
import { readFile, writeFile } from "node:fs/promises";
|
||
import path from "node:path";
|
||
import { fileURLToPath } from "node:url";
|
||
import { packageExtension } from "./package.mjs";
|
||
|
||
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
||
const MANIFEST = path.join(ROOT, "manifest.json");
|
||
const PKG = path.join(ROOT, "package.json");
|
||
const UPDATES = path.join(ROOT, "updates.xml");
|
||
|
||
function bump(current, kind) {
|
||
const parts = current.split(".").map((n) => parseInt(n, 10));
|
||
while (parts.length < 3) parts.push(0);
|
||
if (kind === "major") return [parts[0] + 1, 0, 0].join(".");
|
||
if (kind === "minor") return [parts[0], parts[1] + 1, 0].join(".");
|
||
if (kind === "patch") return [parts[0], parts[1], parts[2] + 1].join(".");
|
||
if (/^\d+(\.\d+){0,3}$/.test(kind)) return kind;
|
||
throw new Error(`无法识别的版本参数:${kind}(支持 patch / minor / major / x.y.z)`);
|
||
}
|
||
|
||
/** 只替换 version 字段,保留文件原有格式(避免整份 JSON 被重排产生无意义 diff) */
|
||
async function setJsonVersion(file, version) {
|
||
const raw = await readFile(file, "utf8");
|
||
const next = raw.replace(/("version"\s*:\s*")[^"]*(")/, `$1${version}$2`);
|
||
if (next === raw) throw new Error(`未能在 ${path.basename(file)} 中找到 version 字段`);
|
||
await writeFile(file, next);
|
||
}
|
||
|
||
/** 同步自托管更新清单里的 version 与 codebase */
|
||
async function syncUpdatesXml(version, codebase) {
|
||
let xml;
|
||
try {
|
||
xml = await readFile(UPDATES, "utf8");
|
||
} catch {
|
||
return false;
|
||
}
|
||
let next = xml.replace(/(<updatecheck\b[^>]*?version=')[^']*(')/, `$1${version}$2`);
|
||
if (codebase) {
|
||
next = next.replace(/(<updatecheck\b[^>]*?codebase=')[^']*(')/, `$1${codebase}$2`);
|
||
}
|
||
await writeFile(UPDATES, next);
|
||
return true;
|
||
}
|
||
|
||
async function main() {
|
||
const args = process.argv.slice(2);
|
||
const codebaseIdx = args.indexOf("--codebase");
|
||
const codebase = codebaseIdx !== -1 ? args[codebaseIdx + 1] : null;
|
||
const kind = args.find((a) => !a.startsWith("--") && a !== codebase) || "patch";
|
||
|
||
const manifest = JSON.parse(await readFile(MANIFEST, "utf8"));
|
||
const pkg = JSON.parse(await readFile(PKG, "utf8"));
|
||
const nextVersion = bump(manifest.version, kind);
|
||
const prevVersion = manifest.version;
|
||
|
||
await setJsonVersion(MANIFEST, nextVersion);
|
||
if (pkg.version !== nextVersion) await setJsonVersion(PKG, nextVersion);
|
||
|
||
const updatesSynced = await syncUpdatesXml(nextVersion, codebase);
|
||
|
||
console.log(`[release] ${prevVersion} → ${nextVersion}`);
|
||
|
||
const { zipPath } = await packageExtension();
|
||
|
||
console.log("\n[release] 完成。后续操作:");
|
||
console.log(
|
||
` git add manifest.json package.json${updatesSynced ? " updates.xml" : ""} && git commit -m "release: v${nextVersion}"`,
|
||
);
|
||
console.log(` git tag v${nextVersion}`);
|
||
console.log(" git push && git push --tags");
|
||
console.log(`\n产物:${path.relative(ROOT, zipPath)}`);
|
||
console.log(
|
||
"上传 Chrome Web Store 用该 zip;自托管自更新需用同一份内容打成 .crx 并放到 updates.xml 的 codebase 地址。",
|
||
);
|
||
}
|
||
|
||
await main();
|