@napuketto/loader 0.0.34 → 0.0.36
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 +1 -1
- package/assets/7zip/7zz +0 -0
- package/assets/7zip/License-linux.txt +144 -144
- package/assets/7zip/License.txt +146 -146
- package/dist/index.cjs +98 -59
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +98 -59
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -2
- package/qq-releases.json +8 -0
- package/native/build/stub-test-env/QQNT.dll +0 -0
package/dist/index.cjs
CHANGED
|
@@ -479,6 +479,99 @@ function loaderVersion() {
|
|
|
479
479
|
return "0.0.0";
|
|
480
480
|
}
|
|
481
481
|
//#endregion
|
|
482
|
+
//#region src/qq-releases.ts
|
|
483
|
+
/**
|
|
484
|
+
* qq-releases.ts:版本清单读取(P1)。
|
|
485
|
+
*
|
|
486
|
+
* 运行时从包根 qq-releases.json 读取(发布时 files 含它,安装后位于
|
|
487
|
+
* node_modules/@napuketto/loader/qq-releases.json)。
|
|
488
|
+
*
|
|
489
|
+
* 维护机制(真实存在,非「声称」):清单由 CI 自动维护——
|
|
490
|
+
* .github/workflows/update-qq-releases.yml(每日 cron + 手动触发)调用
|
|
491
|
+
* tooling/qq-releases/update-qq-releases.ts(纯 Node,与本地共用),抓取 QQ 官方下载配置
|
|
492
|
+
* 解析最新版 + 下载安装包计算 sha256 + 解析安装包内部版本目录后更新本清单
|
|
493
|
+
* (保留历史条目、known 按版本递增)。社区 PR 仍可手动补充。NAPUTO_QQ_URL
|
|
494
|
+
* 可运行时覆盖下载地址(用户拿到新链接时用)。
|
|
495
|
+
*
|
|
496
|
+
* ⚠️ 下载 URL 必须经 normalizeDownloadUrl 归一化后再请求(2026-10-07 定位):
|
|
497
|
+
* 腾讯 CDN 边缘 WAF 对字面量 `/QQNTV2/` 路径段区分大小写地拦截,官方
|
|
498
|
+
* rainbow 配置给出的 URL 直接请求必得 403。详见该函数注释。
|
|
499
|
+
*/
|
|
500
|
+
/** 清单解析失败。 */
|
|
501
|
+
var QqReleasesError = class extends Error {
|
|
502
|
+
constructor(message) {
|
|
503
|
+
super(message);
|
|
504
|
+
this.name = "QqReleasesError";
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
/** 包根路径(dist 与包根同层:dist/index.mjs → ../qq-releases.json)。 */
|
|
508
|
+
function packageRoot() {
|
|
509
|
+
return (0, node_path.dirname)((0, node_path.dirname)((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href)));
|
|
510
|
+
}
|
|
511
|
+
/** 读版本清单(同步,启动期调用一次即可)。 */
|
|
512
|
+
function loadQqReleases() {
|
|
513
|
+
const file = (0, node_path.join)(packageRoot(), "qq-releases.json");
|
|
514
|
+
let raw;
|
|
515
|
+
try {
|
|
516
|
+
raw = (0, node_fs.readFileSync)(file, "utf8");
|
|
517
|
+
} catch {
|
|
518
|
+
throw new QqReleasesError(`版本清单缺失: ${file}(@napuketto/loader 包安装不完整?)`);
|
|
519
|
+
}
|
|
520
|
+
try {
|
|
521
|
+
const parsed = JSON.parse(raw);
|
|
522
|
+
if (parsed.schema !== 1 || !Array.isArray(parsed.known) || parsed.known.length === 0) throw new Error("结构不合法");
|
|
523
|
+
return parsed;
|
|
524
|
+
} catch {
|
|
525
|
+
throw new QqReleasesError(`版本清单解析失败: ${file}`);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
/** 取最新已知可用版本(known 数组按录入顺序,取最后一项 = 最新)。 */
|
|
529
|
+
function latestRelease(releases) {
|
|
530
|
+
const [latest] = [...releases.known].reverse();
|
|
531
|
+
if (latest === void 0) throw new QqReleasesError("版本清单为空");
|
|
532
|
+
return latest;
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* 解析实际下载 URL:NAPUTO_QQ_URL 环境变量覆盖 > 清单 URL。
|
|
536
|
+
* 供 downloadFile 使用(也支持按版本查询,当前固定取最新)。
|
|
537
|
+
*/
|
|
538
|
+
function resolveDownloadUrl(release) {
|
|
539
|
+
const override = node_process.default.env["NAPUTO_QQ_URL"];
|
|
540
|
+
return override !== void 0 && override !== "" ? override : release.url;
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* 被 CDN 边缘 WAF 大小写敏感拦截的路径段(全局匹配,仅用于 String.replace——
|
|
544
|
+
* replace 会复位 lastIndex,无跨调用状态残留)。语义见 normalizeDownloadUrl。
|
|
545
|
+
*/
|
|
546
|
+
const QQNTV2_SEGMENT_RE = /\/QQNTV2\//gi;
|
|
547
|
+
/**
|
|
548
|
+
* 归一化 QQ 官方安装包下载 URL:把 `/QQNTV2/` 路径段降为小写。
|
|
549
|
+
*
|
|
550
|
+
* **为什么需要**(2026-10-07 实测定位,issue #6 的真正根因):
|
|
551
|
+
* 腾讯 CDN 边缘 WAF 约 2026-08-25 起加了一条 **区分大小写** 的规则,匹配
|
|
552
|
+
* 字面量 `/QQNTV2/` 路径段。命中即由边缘直接拒绝,**不回源**:
|
|
553
|
+
*
|
|
554
|
+
* ```text
|
|
555
|
+
* HTTP/1.1 403 Forbidden
|
|
556
|
+
* Content-Length: 0
|
|
557
|
+
* Server: Lego Server
|
|
558
|
+
* X-Cache-Lookup: Return Directly
|
|
559
|
+
* ```
|
|
560
|
+
*
|
|
561
|
+
* 而 qqdl.gtimg.cn 的缓存/源站对路径大小写 **不敏感**:同一 URL 仅把路径段
|
|
562
|
+
* 写成 `/qqntv2/`(以及 `/Qqntv2/`)即正常返回(实测 x64 安装包
|
|
563
|
+
* `HTTP/1.1 200 OK` + `Content-Length: 330446512`,Range 请求返回 `206` 且首字节
|
|
564
|
+
* 为 PE 头 `MZ`)。同一出口 IP、同一时刻的两次请求只有路径大小写不同 → 403 的
|
|
565
|
+
* 成因是 **路径匹配规则**,不是「数据中心 IP 被封」。
|
|
566
|
+
*
|
|
567
|
+
* 归一化只改请求用的 URL,**清单里仍保留官方原样 URL**(可追溯、来源即官方
|
|
568
|
+
* 配置字段 `ntDownloadX64Url`);若腾讯哪天修掉这条规则,小写路径依旧等价可用
|
|
569
|
+
* (源站大小写不敏感),因此不必回改清单。
|
|
570
|
+
*/
|
|
571
|
+
function normalizeDownloadUrl(url) {
|
|
572
|
+
return url.replace(QQNTV2_SEGMENT_RE, "/qqntv2/");
|
|
573
|
+
}
|
|
574
|
+
//#endregion
|
|
482
575
|
//#region src/qq-download.ts
|
|
483
576
|
/**
|
|
484
577
|
* qq-download.ts:QQ 官方安装包下载器(P1)。
|
|
@@ -488,6 +581,8 @@ function loaderVersion() {
|
|
|
488
581
|
* - 下载同时流式累加 sha256,完成后与清单比对(防链接漂移劫持 / 下载不完整)
|
|
489
582
|
* - 支持 302 重定向(QQ CDN 可能跳转)
|
|
490
583
|
* - NAPUTO_QQ_URL 环境变量可覆盖下载地址(用户拿到新链接时用)
|
|
584
|
+
* - 出站 URL 统一经 normalizeDownloadUrl 归一化(绕过 CDN 边缘对 `/QQNTV2/`
|
|
585
|
+
* 路径段的大小写敏感拦截,见 qq-releases.ts;否则清单里的官方 URL 必 403)
|
|
491
586
|
*/
|
|
492
587
|
/** 下载请求 User-Agent(运行时读本包版本,失败兜底 0.0.0)。 */
|
|
493
588
|
const USER_AGENT = `napuketto-loader/${loaderVersion()}`;
|
|
@@ -535,8 +630,9 @@ function httpsGet(url, timeoutMs) {
|
|
|
535
630
|
* 返回实际 sha256(无论是否校验),便于调用方回填清单。
|
|
536
631
|
*/
|
|
537
632
|
async function downloadFile(options) {
|
|
538
|
-
const
|
|
539
|
-
if (
|
|
633
|
+
const requested = options.url ?? node_process.default.env["NAPUTO_QQ_URL"];
|
|
634
|
+
if (requested === void 0 || requested === "") throw new DownloadError("下载地址为空:请设置 NAPUTO_QQ_URL 或提供清单 URL");
|
|
635
|
+
const url = normalizeDownloadUrl(requested);
|
|
540
636
|
const timeoutMs = options.timeoutMs ?? 6e4;
|
|
541
637
|
(0, node_fs.mkdirSync)((0, node_path.dirname)(options.dest), { recursive: true });
|
|
542
638
|
const hash = (0, node_crypto.createHash)("sha256");
|
|
@@ -1057,63 +1153,6 @@ const ENV = {
|
|
|
1057
1153
|
IPC: "NAPUTO_IPC"
|
|
1058
1154
|
};
|
|
1059
1155
|
//#endregion
|
|
1060
|
-
//#region src/qq-releases.ts
|
|
1061
|
-
/**
|
|
1062
|
-
* qq-releases.ts:版本清单读取(P1)。
|
|
1063
|
-
*
|
|
1064
|
-
* 运行时从包根 qq-releases.json 读取(发布时 files 含它,安装后位于
|
|
1065
|
-
* node_modules/@napuketto/loader/qq-releases.json)。
|
|
1066
|
-
*
|
|
1067
|
-
* 维护机制(真实存在,非「声称」):清单由 CI 自动维护——
|
|
1068
|
-
* .github/workflows/update-qq-releases.yml(每日 cron + 手动触发)调用
|
|
1069
|
-
* scripts/qq-releases/update-qq-releases.ts(纯 Node,与本地共用),抓取 QQ 官方下载配置
|
|
1070
|
-
* 解析最新版 + 下载安装包计算 sha256 + 解析安装包内部版本目录后更新本清单
|
|
1071
|
-
* (保留历史条目、known 按版本递增)。社区 PR 仍可手动补充。NAPUTO_QQ_URL
|
|
1072
|
-
* 可运行时覆盖下载地址(用户拿到新链接时用)。
|
|
1073
|
-
*/
|
|
1074
|
-
/** 清单解析失败。 */
|
|
1075
|
-
var QqReleasesError = class extends Error {
|
|
1076
|
-
constructor(message) {
|
|
1077
|
-
super(message);
|
|
1078
|
-
this.name = "QqReleasesError";
|
|
1079
|
-
}
|
|
1080
|
-
};
|
|
1081
|
-
/** 包根路径(dist 与包根同层:dist/index.mjs → ../qq-releases.json)。 */
|
|
1082
|
-
function packageRoot() {
|
|
1083
|
-
return (0, node_path.dirname)((0, node_path.dirname)((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href)));
|
|
1084
|
-
}
|
|
1085
|
-
/** 读版本清单(同步,启动期调用一次即可)。 */
|
|
1086
|
-
function loadQqReleases() {
|
|
1087
|
-
const file = (0, node_path.join)(packageRoot(), "qq-releases.json");
|
|
1088
|
-
let raw;
|
|
1089
|
-
try {
|
|
1090
|
-
raw = (0, node_fs.readFileSync)(file, "utf8");
|
|
1091
|
-
} catch {
|
|
1092
|
-
throw new QqReleasesError(`版本清单缺失: ${file}(@napuketto/loader 包安装不完整?)`);
|
|
1093
|
-
}
|
|
1094
|
-
try {
|
|
1095
|
-
const parsed = JSON.parse(raw);
|
|
1096
|
-
if (parsed.schema !== 1 || !Array.isArray(parsed.known) || parsed.known.length === 0) throw new Error("结构不合法");
|
|
1097
|
-
return parsed;
|
|
1098
|
-
} catch {
|
|
1099
|
-
throw new QqReleasesError(`版本清单解析失败: ${file}`);
|
|
1100
|
-
}
|
|
1101
|
-
}
|
|
1102
|
-
/** 取最新已知可用版本(known 数组按录入顺序,取最后一项 = 最新)。 */
|
|
1103
|
-
function latestRelease(releases) {
|
|
1104
|
-
const [latest] = [...releases.known].reverse();
|
|
1105
|
-
if (latest === void 0) throw new QqReleasesError("版本清单为空");
|
|
1106
|
-
return latest;
|
|
1107
|
-
}
|
|
1108
|
-
/**
|
|
1109
|
-
* 解析实际下载 URL:NAPUTO_QQ_URL 环境变量覆盖 > 清单 URL。
|
|
1110
|
-
* 供 downloadFile 使用(也支持按版本查询,当前固定取最新)。
|
|
1111
|
-
*/
|
|
1112
|
-
function resolveDownloadUrl(release) {
|
|
1113
|
-
const override = node_process.default.env["NAPUTO_QQ_URL"];
|
|
1114
|
-
return override !== void 0 && override !== "" ? override : release.url;
|
|
1115
|
-
}
|
|
1116
|
-
//#endregion
|
|
1117
1156
|
//#region src/locate-qq.ts
|
|
1118
1157
|
/**
|
|
1119
1158
|
* 定位 QQ 原生文件(wrapper.node)来源(P0:多级来源纯定位,不下载)。
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/host/ipc/ipc-types.ts","../src/host/ipc/native-noise.ts","../src/instance-lock.ts","../src/locate-qq.ts","../src/win-node.ts","../src/launcher.ts","../src/pid-cmdline.ts","../src/qq-download.ts","../src/qq-extract.ts","../src/qq-releases.ts","../src/wine.ts"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/host/ipc/ipc-types.ts","../src/host/ipc/native-noise.ts","../src/instance-lock.ts","../src/locate-qq.ts","../src/win-node.ts","../src/launcher.ts","../src/pid-cmdline.ts","../src/qq-download.ts","../src/qq-extract.ts","../src/qq-releases.ts","../src/wine.ts"],"mappings":"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"}
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/host/ipc/ipc-types.ts","../src/host/ipc/native-noise.ts","../src/instance-lock.ts","../src/locate-qq.ts","../src/win-node.ts","../src/launcher.ts","../src/pid-cmdline.ts","../src/qq-download.ts","../src/qq-extract.ts","../src/qq-releases.ts","../src/wine.ts"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/host/ipc/ipc-types.ts","../src/host/ipc/native-noise.ts","../src/instance-lock.ts","../src/locate-qq.ts","../src/win-node.ts","../src/launcher.ts","../src/pid-cmdline.ts","../src/qq-download.ts","../src/qq-extract.ts","../src/qq-releases.ts","../src/wine.ts"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -455,6 +455,99 @@ function loaderVersion() {
|
|
|
455
455
|
return "0.0.0";
|
|
456
456
|
}
|
|
457
457
|
//#endregion
|
|
458
|
+
//#region src/qq-releases.ts
|
|
459
|
+
/**
|
|
460
|
+
* qq-releases.ts:版本清单读取(P1)。
|
|
461
|
+
*
|
|
462
|
+
* 运行时从包根 qq-releases.json 读取(发布时 files 含它,安装后位于
|
|
463
|
+
* node_modules/@napuketto/loader/qq-releases.json)。
|
|
464
|
+
*
|
|
465
|
+
* 维护机制(真实存在,非「声称」):清单由 CI 自动维护——
|
|
466
|
+
* .github/workflows/update-qq-releases.yml(每日 cron + 手动触发)调用
|
|
467
|
+
* tooling/qq-releases/update-qq-releases.ts(纯 Node,与本地共用),抓取 QQ 官方下载配置
|
|
468
|
+
* 解析最新版 + 下载安装包计算 sha256 + 解析安装包内部版本目录后更新本清单
|
|
469
|
+
* (保留历史条目、known 按版本递增)。社区 PR 仍可手动补充。NAPUTO_QQ_URL
|
|
470
|
+
* 可运行时覆盖下载地址(用户拿到新链接时用)。
|
|
471
|
+
*
|
|
472
|
+
* ⚠️ 下载 URL 必须经 normalizeDownloadUrl 归一化后再请求(2026-10-07 定位):
|
|
473
|
+
* 腾讯 CDN 边缘 WAF 对字面量 `/QQNTV2/` 路径段区分大小写地拦截,官方
|
|
474
|
+
* rainbow 配置给出的 URL 直接请求必得 403。详见该函数注释。
|
|
475
|
+
*/
|
|
476
|
+
/** 清单解析失败。 */
|
|
477
|
+
var QqReleasesError = class extends Error {
|
|
478
|
+
constructor(message) {
|
|
479
|
+
super(message);
|
|
480
|
+
this.name = "QqReleasesError";
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
/** 包根路径(dist 与包根同层:dist/index.mjs → ../qq-releases.json)。 */
|
|
484
|
+
function packageRoot() {
|
|
485
|
+
return dirname(dirname(fileURLToPath(import.meta.url)));
|
|
486
|
+
}
|
|
487
|
+
/** 读版本清单(同步,启动期调用一次即可)。 */
|
|
488
|
+
function loadQqReleases() {
|
|
489
|
+
const file = join(packageRoot(), "qq-releases.json");
|
|
490
|
+
let raw;
|
|
491
|
+
try {
|
|
492
|
+
raw = readFileSync(file, "utf8");
|
|
493
|
+
} catch {
|
|
494
|
+
throw new QqReleasesError(`版本清单缺失: ${file}(@napuketto/loader 包安装不完整?)`);
|
|
495
|
+
}
|
|
496
|
+
try {
|
|
497
|
+
const parsed = JSON.parse(raw);
|
|
498
|
+
if (parsed.schema !== 1 || !Array.isArray(parsed.known) || parsed.known.length === 0) throw new Error("结构不合法");
|
|
499
|
+
return parsed;
|
|
500
|
+
} catch {
|
|
501
|
+
throw new QqReleasesError(`版本清单解析失败: ${file}`);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
/** 取最新已知可用版本(known 数组按录入顺序,取最后一项 = 最新)。 */
|
|
505
|
+
function latestRelease(releases) {
|
|
506
|
+
const [latest] = [...releases.known].reverse();
|
|
507
|
+
if (latest === void 0) throw new QqReleasesError("版本清单为空");
|
|
508
|
+
return latest;
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* 解析实际下载 URL:NAPUTO_QQ_URL 环境变量覆盖 > 清单 URL。
|
|
512
|
+
* 供 downloadFile 使用(也支持按版本查询,当前固定取最新)。
|
|
513
|
+
*/
|
|
514
|
+
function resolveDownloadUrl(release) {
|
|
515
|
+
const override = process$1.env["NAPUTO_QQ_URL"];
|
|
516
|
+
return override !== void 0 && override !== "" ? override : release.url;
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* 被 CDN 边缘 WAF 大小写敏感拦截的路径段(全局匹配,仅用于 String.replace——
|
|
520
|
+
* replace 会复位 lastIndex,无跨调用状态残留)。语义见 normalizeDownloadUrl。
|
|
521
|
+
*/
|
|
522
|
+
const QQNTV2_SEGMENT_RE = /\/QQNTV2\//gi;
|
|
523
|
+
/**
|
|
524
|
+
* 归一化 QQ 官方安装包下载 URL:把 `/QQNTV2/` 路径段降为小写。
|
|
525
|
+
*
|
|
526
|
+
* **为什么需要**(2026-10-07 实测定位,issue #6 的真正根因):
|
|
527
|
+
* 腾讯 CDN 边缘 WAF 约 2026-08-25 起加了一条 **区分大小写** 的规则,匹配
|
|
528
|
+
* 字面量 `/QQNTV2/` 路径段。命中即由边缘直接拒绝,**不回源**:
|
|
529
|
+
*
|
|
530
|
+
* ```text
|
|
531
|
+
* HTTP/1.1 403 Forbidden
|
|
532
|
+
* Content-Length: 0
|
|
533
|
+
* Server: Lego Server
|
|
534
|
+
* X-Cache-Lookup: Return Directly
|
|
535
|
+
* ```
|
|
536
|
+
*
|
|
537
|
+
* 而 qqdl.gtimg.cn 的缓存/源站对路径大小写 **不敏感**:同一 URL 仅把路径段
|
|
538
|
+
* 写成 `/qqntv2/`(以及 `/Qqntv2/`)即正常返回(实测 x64 安装包
|
|
539
|
+
* `HTTP/1.1 200 OK` + `Content-Length: 330446512`,Range 请求返回 `206` 且首字节
|
|
540
|
+
* 为 PE 头 `MZ`)。同一出口 IP、同一时刻的两次请求只有路径大小写不同 → 403 的
|
|
541
|
+
* 成因是 **路径匹配规则**,不是「数据中心 IP 被封」。
|
|
542
|
+
*
|
|
543
|
+
* 归一化只改请求用的 URL,**清单里仍保留官方原样 URL**(可追溯、来源即官方
|
|
544
|
+
* 配置字段 `ntDownloadX64Url`);若腾讯哪天修掉这条规则,小写路径依旧等价可用
|
|
545
|
+
* (源站大小写不敏感),因此不必回改清单。
|
|
546
|
+
*/
|
|
547
|
+
function normalizeDownloadUrl(url) {
|
|
548
|
+
return url.replace(QQNTV2_SEGMENT_RE, "/qqntv2/");
|
|
549
|
+
}
|
|
550
|
+
//#endregion
|
|
458
551
|
//#region src/qq-download.ts
|
|
459
552
|
/**
|
|
460
553
|
* qq-download.ts:QQ 官方安装包下载器(P1)。
|
|
@@ -464,6 +557,8 @@ function loaderVersion() {
|
|
|
464
557
|
* - 下载同时流式累加 sha256,完成后与清单比对(防链接漂移劫持 / 下载不完整)
|
|
465
558
|
* - 支持 302 重定向(QQ CDN 可能跳转)
|
|
466
559
|
* - NAPUTO_QQ_URL 环境变量可覆盖下载地址(用户拿到新链接时用)
|
|
560
|
+
* - 出站 URL 统一经 normalizeDownloadUrl 归一化(绕过 CDN 边缘对 `/QQNTV2/`
|
|
561
|
+
* 路径段的大小写敏感拦截,见 qq-releases.ts;否则清单里的官方 URL 必 403)
|
|
467
562
|
*/
|
|
468
563
|
/** 下载请求 User-Agent(运行时读本包版本,失败兜底 0.0.0)。 */
|
|
469
564
|
const USER_AGENT = `napuketto-loader/${loaderVersion()}`;
|
|
@@ -511,8 +606,9 @@ function httpsGet(url, timeoutMs) {
|
|
|
511
606
|
* 返回实际 sha256(无论是否校验),便于调用方回填清单。
|
|
512
607
|
*/
|
|
513
608
|
async function downloadFile(options) {
|
|
514
|
-
const
|
|
515
|
-
if (
|
|
609
|
+
const requested = options.url ?? process$1.env["NAPUTO_QQ_URL"];
|
|
610
|
+
if (requested === void 0 || requested === "") throw new DownloadError("下载地址为空:请设置 NAPUTO_QQ_URL 或提供清单 URL");
|
|
611
|
+
const url = normalizeDownloadUrl(requested);
|
|
516
612
|
const timeoutMs = options.timeoutMs ?? 6e4;
|
|
517
613
|
mkdirSync(dirname(options.dest), { recursive: true });
|
|
518
614
|
const hash = createHash("sha256");
|
|
@@ -1033,63 +1129,6 @@ const ENV = {
|
|
|
1033
1129
|
IPC: "NAPUTO_IPC"
|
|
1034
1130
|
};
|
|
1035
1131
|
//#endregion
|
|
1036
|
-
//#region src/qq-releases.ts
|
|
1037
|
-
/**
|
|
1038
|
-
* qq-releases.ts:版本清单读取(P1)。
|
|
1039
|
-
*
|
|
1040
|
-
* 运行时从包根 qq-releases.json 读取(发布时 files 含它,安装后位于
|
|
1041
|
-
* node_modules/@napuketto/loader/qq-releases.json)。
|
|
1042
|
-
*
|
|
1043
|
-
* 维护机制(真实存在,非「声称」):清单由 CI 自动维护——
|
|
1044
|
-
* .github/workflows/update-qq-releases.yml(每日 cron + 手动触发)调用
|
|
1045
|
-
* scripts/qq-releases/update-qq-releases.ts(纯 Node,与本地共用),抓取 QQ 官方下载配置
|
|
1046
|
-
* 解析最新版 + 下载安装包计算 sha256 + 解析安装包内部版本目录后更新本清单
|
|
1047
|
-
* (保留历史条目、known 按版本递增)。社区 PR 仍可手动补充。NAPUTO_QQ_URL
|
|
1048
|
-
* 可运行时覆盖下载地址(用户拿到新链接时用)。
|
|
1049
|
-
*/
|
|
1050
|
-
/** 清单解析失败。 */
|
|
1051
|
-
var QqReleasesError = class extends Error {
|
|
1052
|
-
constructor(message) {
|
|
1053
|
-
super(message);
|
|
1054
|
-
this.name = "QqReleasesError";
|
|
1055
|
-
}
|
|
1056
|
-
};
|
|
1057
|
-
/** 包根路径(dist 与包根同层:dist/index.mjs → ../qq-releases.json)。 */
|
|
1058
|
-
function packageRoot() {
|
|
1059
|
-
return dirname(dirname(fileURLToPath(import.meta.url)));
|
|
1060
|
-
}
|
|
1061
|
-
/** 读版本清单(同步,启动期调用一次即可)。 */
|
|
1062
|
-
function loadQqReleases() {
|
|
1063
|
-
const file = join(packageRoot(), "qq-releases.json");
|
|
1064
|
-
let raw;
|
|
1065
|
-
try {
|
|
1066
|
-
raw = readFileSync(file, "utf8");
|
|
1067
|
-
} catch {
|
|
1068
|
-
throw new QqReleasesError(`版本清单缺失: ${file}(@napuketto/loader 包安装不完整?)`);
|
|
1069
|
-
}
|
|
1070
|
-
try {
|
|
1071
|
-
const parsed = JSON.parse(raw);
|
|
1072
|
-
if (parsed.schema !== 1 || !Array.isArray(parsed.known) || parsed.known.length === 0) throw new Error("结构不合法");
|
|
1073
|
-
return parsed;
|
|
1074
|
-
} catch {
|
|
1075
|
-
throw new QqReleasesError(`版本清单解析失败: ${file}`);
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
/** 取最新已知可用版本(known 数组按录入顺序,取最后一项 = 最新)。 */
|
|
1079
|
-
function latestRelease(releases) {
|
|
1080
|
-
const [latest] = [...releases.known].reverse();
|
|
1081
|
-
if (latest === void 0) throw new QqReleasesError("版本清单为空");
|
|
1082
|
-
return latest;
|
|
1083
|
-
}
|
|
1084
|
-
/**
|
|
1085
|
-
* 解析实际下载 URL:NAPUTO_QQ_URL 环境变量覆盖 > 清单 URL。
|
|
1086
|
-
* 供 downloadFile 使用(也支持按版本查询,当前固定取最新)。
|
|
1087
|
-
*/
|
|
1088
|
-
function resolveDownloadUrl(release) {
|
|
1089
|
-
const override = process$1.env["NAPUTO_QQ_URL"];
|
|
1090
|
-
return override !== void 0 && override !== "" ? override : release.url;
|
|
1091
|
-
}
|
|
1092
|
-
//#endregion
|
|
1093
1132
|
//#region src/locate-qq.ts
|
|
1094
1133
|
/**
|
|
1095
1134
|
* 定位 QQ 原生文件(wrapper.node)来源(P0:多级来源纯定位,不下载)。
|