@napuketto/kernel 0.0.9 → 0.0.12
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/dist/index.cjs +165 -53
- package/dist/index.d.cts +54 -13
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +54 -13
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +166 -55
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1341,9 +1341,9 @@ var MsgApi = class {
|
|
|
1341
1341
|
* 且发送后进程崩溃重启(supervisor 自动拉起)。完整字段(NapCat 同款,
|
|
1342
1342
|
* formatType/voiceType/canConvert2Text/waveAmplitudes 等)消除该错误。
|
|
1343
1343
|
*
|
|
1344
|
-
* ⚠️ silk 格式:QQ 语音协议为 silk v3
|
|
1345
|
-
*
|
|
1346
|
-
*
|
|
1344
|
+
* ⚠️ silk 格式:QQ 语音协议为 silk v3。非 silk → silk 的转码在协议层
|
|
1345
|
+
* (adapter,@napuketto/media 的 encodePcmToSilk,2026-08-12 接线)完成,
|
|
1346
|
+
* 此处接收的已是 silk 路径,仅做放置。kernel 不 import media(解耦红线)。
|
|
1347
1347
|
*/
|
|
1348
1348
|
async preparePttElement(path) {
|
|
1349
1349
|
const file = await statFile(path);
|
|
@@ -2616,6 +2616,8 @@ function startupSessionStart(ctx) {
|
|
|
2616
2616
|
/** 二维码过期错误码(errType=1 errCode=3,实测)。 */
|
|
2617
2617
|
const QR_EXPIRED_ERR_TYPE = 1;
|
|
2618
2618
|
const QR_EXPIRED_ERR_CODE = 3;
|
|
2619
|
+
/** 登录超时提示(参考项目文案,前端 failed 态展示)。 */
|
|
2620
|
+
const QR_LOGIN_TIMEOUT_MESSAGE = "登录超时,请刷新页面重试";
|
|
2619
2621
|
/** 二维码过期判定。 */
|
|
2620
2622
|
function isQrCodeExpired(errType, errCode) {
|
|
2621
2623
|
return errType === QR_EXPIRED_ERR_TYPE && errCode === QR_EXPIRED_ERR_CODE;
|
|
@@ -2630,10 +2632,17 @@ var QrLoginSession = class {
|
|
|
2630
2632
|
self = null;
|
|
2631
2633
|
qrCodeHandlers = /* @__PURE__ */ new Set();
|
|
2632
2634
|
stateHandlers = /* @__PURE__ */ new Set();
|
|
2633
|
-
|
|
2635
|
+
/** 超时定时器(refresh 后启动,登录成功/失败/stop 清理)。 */
|
|
2636
|
+
timeoutTimer = null;
|
|
2637
|
+
/** 失败原因(超时等,failed 态透出给上层提示文案)。 */
|
|
2638
|
+
failureReasonValue = null;
|
|
2639
|
+
/** 超时上限(毫秒,默认 QR_LOGIN_TIMEOUT_MS)。 */
|
|
2640
|
+
timeoutMs;
|
|
2641
|
+
constructor(loginService, options = {}) {
|
|
2634
2642
|
const svc = loginService;
|
|
2635
2643
|
if (svc === null || typeof svc.addKernelLoginListener !== "function") throw kernelError("loginService 无效(缺 addKernelLoginListener)", "INVALID_STATE");
|
|
2636
2644
|
this.loginService = svc;
|
|
2645
|
+
this.timeoutMs = options.timeoutMs ?? 12e4;
|
|
2637
2646
|
}
|
|
2638
2647
|
/** 当前状态。 */
|
|
2639
2648
|
get currentState() {
|
|
@@ -2643,6 +2652,10 @@ var QrLoginSession = class {
|
|
|
2643
2652
|
get selfInfo() {
|
|
2644
2653
|
return this.self;
|
|
2645
2654
|
}
|
|
2655
|
+
/** 失败原因(超时等;failed 态透出给上层提示文案)。 */
|
|
2656
|
+
get failureReason() {
|
|
2657
|
+
return this.failureReasonValue;
|
|
2658
|
+
}
|
|
2646
2659
|
/** 订阅二维码(png base64 + url)。返回退订函数。 */
|
|
2647
2660
|
onQrCode(cb) {
|
|
2648
2661
|
this.qrCodeHandlers.add(cb);
|
|
@@ -2665,10 +2678,12 @@ var QrLoginSession = class {
|
|
|
2665
2678
|
});
|
|
2666
2679
|
else this.refresh();
|
|
2667
2680
|
}
|
|
2668
|
-
/** 刷新二维码(手动 /
|
|
2681
|
+
/** 刷新二维码(手动 / 过期自动)。每次出码重启超时计时。 */
|
|
2669
2682
|
refresh() {
|
|
2683
|
+
this.failureReasonValue = null;
|
|
2670
2684
|
this.setState("waiting_scan");
|
|
2671
2685
|
this.loginService.getQRCodePicture();
|
|
2686
|
+
this.restartTimeout();
|
|
2672
2687
|
}
|
|
2673
2688
|
/** 构建登录监听(普通 JS 对象,NAPI 反射)。 */
|
|
2674
2689
|
buildListener() {
|
|
@@ -2687,6 +2702,7 @@ var QrLoginSession = class {
|
|
|
2687
2702
|
this.setState("scanned");
|
|
2688
2703
|
};
|
|
2689
2704
|
listener.onQRCodeLoginSucceed = (result) => {
|
|
2705
|
+
this.clearTimeoutTimer();
|
|
2690
2706
|
this.self = {
|
|
2691
2707
|
uin: result.uin,
|
|
2692
2708
|
uid: result.uid,
|
|
@@ -2699,20 +2715,41 @@ var QrLoginSession = class {
|
|
|
2699
2715
|
this.refresh();
|
|
2700
2716
|
return;
|
|
2701
2717
|
}
|
|
2718
|
+
this.clearTimeoutTimer();
|
|
2719
|
+
this.failureReasonValue = null;
|
|
2702
2720
|
this.setState("failed");
|
|
2703
2721
|
};
|
|
2704
2722
|
listener.onLoginFailed = () => {
|
|
2723
|
+
this.clearTimeoutTimer();
|
|
2724
|
+
this.failureReasonValue = null;
|
|
2705
2725
|
this.setState("failed");
|
|
2706
2726
|
};
|
|
2707
2727
|
return listener;
|
|
2708
2728
|
}
|
|
2709
2729
|
/** 停止:注销监听(登录成功后调用,防重复回调)。 */
|
|
2710
2730
|
stop() {
|
|
2731
|
+
this.clearTimeoutTimer();
|
|
2711
2732
|
if (this.listenerId !== null) {
|
|
2712
2733
|
this.loginService.removeKernelLoginListener(this.listenerId);
|
|
2713
2734
|
this.listenerId = null;
|
|
2714
2735
|
}
|
|
2715
2736
|
}
|
|
2737
|
+
/** 重启超时计时器:超时未登录 → failed + 超时提示。 */
|
|
2738
|
+
restartTimeout() {
|
|
2739
|
+
this.clearTimeoutTimer();
|
|
2740
|
+
this.timeoutTimer = setTimeout(() => {
|
|
2741
|
+
this.timeoutTimer = null;
|
|
2742
|
+
this.failureReasonValue = QR_LOGIN_TIMEOUT_MESSAGE;
|
|
2743
|
+
this.setState("failed");
|
|
2744
|
+
}, this.timeoutMs);
|
|
2745
|
+
}
|
|
2746
|
+
/** 清理超时计时器(幂等)。 */
|
|
2747
|
+
clearTimeoutTimer() {
|
|
2748
|
+
if (this.timeoutTimer !== null) {
|
|
2749
|
+
clearTimeout(this.timeoutTimer);
|
|
2750
|
+
this.timeoutTimer = null;
|
|
2751
|
+
}
|
|
2752
|
+
}
|
|
2716
2753
|
setState(next) {
|
|
2717
2754
|
this.state = next;
|
|
2718
2755
|
for (const cb of this.stateHandlers) cb(next);
|
|
@@ -2794,13 +2831,59 @@ function findInObject(value) {
|
|
|
2794
2831
|
*
|
|
2795
2832
|
* 与 lifecycle.ts(流程编排)解耦:本模块只回答「配置长什么样」,不管流程怎么走。
|
|
2796
2833
|
* 字段为 wrapper.node 外部契约(appid/qua/版本),运行时实测确认,自研描述。
|
|
2834
|
+
* appid 唯一来源是 major.node 动态解析(每版本不同);解析失败显式抛 KernelError,
|
|
2835
|
+
* 不再静默回退过期 appid(2026-08 硬编码审计:537237765 是 9.9.31 的 appid,该版本
|
|
2836
|
+
* 登录服务已被腾讯下线,静默用它会导致扫码「请下载最新版」且极难排查)。
|
|
2837
|
+
*/
|
|
2838
|
+
/** app_type=4:桌面端应用类型(engine.initWithDeskTopConfig 契约;移动端为其它值)。 */
|
|
2839
|
+
const APP_TYPE_DESKTOP = 4;
|
|
2840
|
+
/**
|
|
2841
|
+
* 缩略图生成参数(thumb_config,engine 契约):
|
|
2842
|
+
* maxSide 最长边像素上限 / minSide 最短边像素下限 / longLimit 长图最长短边比例上限 /
|
|
2843
|
+
* density 像素密度倍数。
|
|
2844
|
+
*/
|
|
2845
|
+
const THUMB_CONFIG = {
|
|
2846
|
+
maxSide: 324,
|
|
2847
|
+
minSide: 48,
|
|
2848
|
+
longLimit: 6,
|
|
2849
|
+
density: 2
|
|
2850
|
+
};
|
|
2851
|
+
/**
|
|
2852
|
+
* session.init 的 deviceConfig(wrapper 契约,JSON 字符串字面量):
|
|
2853
|
+
* appearance.isSplitViewMode 分屏模式开关,msg 空对象为占位。自建宿主无 UI,保持最小可用。
|
|
2854
|
+
*/
|
|
2855
|
+
const DEVICE_CONFIG_JSON = "{\"appearance\":{\"isSplitViewMode\":true},\"msg\":{}}";
|
|
2856
|
+
/** localId=2052:zh-CN(简体中文)locale 码(Windows LCID,deviceInfo.localId 契约)。 */
|
|
2857
|
+
const ZH_CN_LOCALE_ID = 2052;
|
|
2858
|
+
/** 平台名映射:os.platform() → wrapper devType 契约值(不写死具体构建号)。 */
|
|
2859
|
+
const DEV_TYPE_BY_PLATFORM = {
|
|
2860
|
+
win32: "Windows",
|
|
2861
|
+
darwin: "Mac",
|
|
2862
|
+
linux: "Linux",
|
|
2863
|
+
android: "Android",
|
|
2864
|
+
freebsd: "FreeBSD",
|
|
2865
|
+
openbsd: "OpenBSD",
|
|
2866
|
+
sunos: "SunOS",
|
|
2867
|
+
aix: "AIX"
|
|
2868
|
+
};
|
|
2869
|
+
/**
|
|
2870
|
+
* 系统信息运行时探测(wrapper 契约:platVer / osVersion / devType)。
|
|
2871
|
+
* 旧实现写死 "Windows 10.0.22631"/"Windows 10 Pro"——换机即失真(2026-08 硬编码审计整改)。
|
|
2872
|
+
* 探测失败时给通用值兜底,但不写死具体 Windows 构建号。
|
|
2797
2873
|
*/
|
|
2798
|
-
/** 系统信息(先用 fixed 值,真实环境探测后补)。 */
|
|
2799
2874
|
function systemInfo() {
|
|
2875
|
+
let devType = "Unknown";
|
|
2876
|
+
let platVer = "Unknown";
|
|
2877
|
+
let osVersion = "Unknown";
|
|
2878
|
+
try {
|
|
2879
|
+
devType = DEV_TYPE_BY_PLATFORM[(0, node_os.platform)()] ?? (0, node_os.platform)();
|
|
2880
|
+
platVer = `${devType} ${(0, node_os.release)()}`;
|
|
2881
|
+
osVersion = (0, node_os.version)() || (0, node_os.type)();
|
|
2882
|
+
} catch {}
|
|
2800
2883
|
return {
|
|
2801
|
-
platVer
|
|
2802
|
-
osVersion
|
|
2803
|
-
devType
|
|
2884
|
+
platVer,
|
|
2885
|
+
osVersion,
|
|
2886
|
+
devType
|
|
2804
2887
|
};
|
|
2805
2888
|
}
|
|
2806
2889
|
/** 纯数字串(major.node 提取的 appid 判定)。 */
|
|
@@ -2808,7 +2891,7 @@ const DIGITS_ONLY_RE = /^\d+$/;
|
|
|
2808
2891
|
/**
|
|
2809
2892
|
* 从 major.node 提取 appid(NapCat parseAppidFromMajorV2 的自研等价实现)。
|
|
2810
2893
|
* major.node 含 `QQAppId/` 标记后跟数字(腾讯工具链产物,实测确认)。
|
|
2811
|
-
* 返回 null
|
|
2894
|
+
* 返回 null 表示解析失败(调用方应显式报错,不再回退硬编码 appid)。
|
|
2812
2895
|
*/
|
|
2813
2896
|
function parseAppidFromMajor(majorPath) {
|
|
2814
2897
|
if (!(0, node_fs.existsSync)(majorPath)) return null;
|
|
@@ -2839,48 +2922,34 @@ function readMarkerValue(buf, start) {
|
|
|
2839
2922
|
while (end < buf.length && buf[end] !== 0) end += 1;
|
|
2840
2923
|
return buf.subarray(start, end).toString("utf-8");
|
|
2841
2924
|
}
|
|
2842
|
-
/** Windows 兜底 appid / qua(major.node 解析失败时)。 */
|
|
2843
|
-
function fallbackAppidQua(fullVersion) {
|
|
2844
|
-
return {
|
|
2845
|
-
appid: "537237765",
|
|
2846
|
-
qua: `V1_WIN_NQ_${fullVersion}_${fullVersion.split("-")[1] ?? ""}_GW_B`
|
|
2847
|
-
};
|
|
2848
|
-
}
|
|
2849
2925
|
/**
|
|
2850
2926
|
* 解析 appid / qua(自研,参考 NapCat QQBasicInfoWrapper 思路但独立实现):
|
|
2851
|
-
*
|
|
2852
|
-
*
|
|
2853
|
-
* majorPath 传 wrapper.node 同目录 major.node
|
|
2927
|
+
* appid 唯一来源 = major.node 提取(实测 9.9.33-51802 = 537376818)。
|
|
2928
|
+
* majorPath 缺省或解析失败时抛 KernelError——不再静默回退过期 appid。
|
|
2929
|
+
* majorPath 传 wrapper.node 同目录 major.node。
|
|
2854
2930
|
*/
|
|
2855
2931
|
function resolveAppidQua(fullVersion, majorPath) {
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
}
|
|
2863
|
-
return fallbackAppidQua(fullVersion);
|
|
2932
|
+
const appid = majorPath !== void 0 ? parseAppidFromMajor(majorPath) : null;
|
|
2933
|
+
if (appid === null) throw kernelError("无法从 major.node 解析 appid,请确认 wrapper.node/major.node 完整,或更新 qq-releases.json", "INVALID_STATE");
|
|
2934
|
+
return {
|
|
2935
|
+
appid,
|
|
2936
|
+
qua: `V1_WIN_NQ_${fullVersion}_${fullVersion.split("-")[1] ?? ""}_GW_B`
|
|
2937
|
+
};
|
|
2864
2938
|
}
|
|
2865
|
-
/** 生成 engine 桌面配置(wrapper 契约字段)。majorPath
|
|
2939
|
+
/** 生成 engine 桌面配置(wrapper 契约字段)。majorPath 可选(缺失/解析失败会抛错)。 */
|
|
2866
2940
|
function buildEngineConfig(fullVersion, dataPathGlobal, majorPath) {
|
|
2867
2941
|
const { osVersion } = systemInfo();
|
|
2868
2942
|
const { qua } = resolveAppidQua(fullVersion, majorPath);
|
|
2869
2943
|
return {
|
|
2870
2944
|
base_path_prefix: "",
|
|
2871
2945
|
platform_type: PlatformType.KWINDOWS,
|
|
2872
|
-
app_type:
|
|
2946
|
+
app_type: APP_TYPE_DESKTOP,
|
|
2873
2947
|
app_version: fullVersion,
|
|
2874
2948
|
os_version: osVersion,
|
|
2875
2949
|
use_xlog: true,
|
|
2876
2950
|
qua,
|
|
2877
2951
|
global_path_config: { desktopGlobalPath: dataPathGlobal },
|
|
2878
|
-
thumb_config:
|
|
2879
|
-
maxSide: 324,
|
|
2880
|
-
minSide: 48,
|
|
2881
|
-
longLimit: 6,
|
|
2882
|
-
density: 2
|
|
2883
|
-
}
|
|
2952
|
+
thumb_config: THUMB_CONFIG
|
|
2884
2953
|
};
|
|
2885
2954
|
}
|
|
2886
2955
|
/** 生成登录初始化配置(externalVersion: false 与 NapCat 同款,扫码兼容关键)。 */
|
|
@@ -2898,12 +2967,12 @@ function buildLoginConfig(appid, fullVersion, commonPath) {
|
|
|
2898
2967
|
}
|
|
2899
2968
|
/** 生成 session 初始化配置(登录成功后调用)。 */
|
|
2900
2969
|
function buildSessionConfig(options) {
|
|
2901
|
-
const { appid, fullVersion, selfUin, selfUid, accountPath, downloadPath } = options;
|
|
2970
|
+
const { appid, fullVersion, selfUin, selfUid, accountPath, downloadPath, machineGuid } = options;
|
|
2902
2971
|
const { platVer, osVersion, devType } = systemInfo();
|
|
2903
2972
|
const deviceInfo = {
|
|
2904
|
-
guid: "",
|
|
2973
|
+
guid: machineGuid ?? "",
|
|
2905
2974
|
buildVer: fullVersion,
|
|
2906
|
-
localId:
|
|
2975
|
+
localId: ZH_CN_LOCALE_ID,
|
|
2907
2976
|
devName: (0, node_os.hostname)(),
|
|
2908
2977
|
devType,
|
|
2909
2978
|
vendorName: "",
|
|
@@ -2941,9 +3010,25 @@ function buildSessionConfig(options) {
|
|
|
2941
3010
|
},
|
|
2942
3011
|
defaultFileDownloadPath: downloadPath,
|
|
2943
3012
|
deviceInfo,
|
|
2944
|
-
deviceConfig:
|
|
3013
|
+
deviceConfig: DEVICE_CONFIG_JSON
|
|
2945
3014
|
};
|
|
2946
3015
|
}
|
|
3016
|
+
/**
|
|
3017
|
+
* 读取设备指纹 guid(wrapper.node 字符串分析实证,2026-08-12):
|
|
3018
|
+
* NodeIKernelLoginService::getMachineGuid(0 参,返回机器 GUID 字符串)。
|
|
3019
|
+
* 无 getMachineId 方法——TODO 里的方法名不存在,等价方法是 getMachineGuid。
|
|
3020
|
+
* 失败(无该方法 / 调用抛错 / 返回值非字符串)兜底空串。
|
|
3021
|
+
*/
|
|
3022
|
+
function readMachineGuid(loginService) {
|
|
3023
|
+
try {
|
|
3024
|
+
const fn = loginService?.["getMachineGuid"];
|
|
3025
|
+
if (typeof fn !== "function") return "";
|
|
3026
|
+
const value = fn.call(loginService);
|
|
3027
|
+
return typeof value === "string" ? value : "";
|
|
3028
|
+
} catch {
|
|
3029
|
+
return "";
|
|
3030
|
+
}
|
|
3031
|
+
}
|
|
2947
3032
|
//#endregion
|
|
2948
3033
|
//#region src/wrapper/wrapper-loader.ts
|
|
2949
3034
|
/**
|
|
@@ -3099,7 +3184,7 @@ function startSession(ctx) {
|
|
|
3099
3184
|
* 2. createSession(`new NodeIQQNTWrapperSession()`)——实测可用,默认路径
|
|
3100
3185
|
* (getMainSession 实测为空壳:service 全 null + 缺 startNT,仅 probe 探测参考)
|
|
3101
3186
|
*
|
|
3102
|
-
* 由
|
|
3187
|
+
* 由 kernel NapukettoCore(core.ts)装配调用;loader 自建宿主 bootstrap 也直接调用作回退。
|
|
3103
3188
|
* 返回 WrapperContext;失败抛 KernelError。
|
|
3104
3189
|
*/
|
|
3105
3190
|
function startNapuketto(options) {
|
|
@@ -3185,7 +3270,8 @@ function getOrCreateLoginService(exports) {
|
|
|
3185
3270
|
* 典型用法(boot.cjs 截获 exports 后):
|
|
3186
3271
|
* const core = await NapukettoCore.create({ dataRoot, account });
|
|
3187
3272
|
* core.attachWrapper(wrapperExports, { qqVersion, dataDir });
|
|
3188
|
-
*
|
|
3273
|
+
* // appid 由 resolveAppidQua 从 major.node 动态解析(版本绑定,不写死)
|
|
3274
|
+
* await core.login({ appid });
|
|
3189
3275
|
*
|
|
3190
3276
|
* 与手动拼 startNapuketto/quickLogin/initAndStartSession 等价,但把装配状态
|
|
3191
3277
|
* (ctx)集中管理,协议层直接消费 core.ctx。
|
|
@@ -3197,6 +3283,8 @@ function getOrCreateLoginService(exports) {
|
|
|
3197
3283
|
var NapukettoCore = class NapukettoCore {
|
|
3198
3284
|
/** 装配根(协议层 / apis / cache 的消费入口)。 */
|
|
3199
3285
|
ctx;
|
|
3286
|
+
/** QR 登录会话句柄(登录期间非空;登录终态后清空)。refreshQr() 据此可达。 */
|
|
3287
|
+
qrSession = null;
|
|
3200
3288
|
/** 由 create() 装配,不直接 new。 */
|
|
3201
3289
|
constructor(ctx) {
|
|
3202
3290
|
this.ctx = ctx;
|
|
@@ -3252,6 +3340,11 @@ var NapukettoCore = class NapukettoCore {
|
|
|
3252
3340
|
const { wrapper } = this.ctx;
|
|
3253
3341
|
if (wrapper === null) throw kernelError("wrapper 未装配,无法登录", "INVALID_STATE");
|
|
3254
3342
|
this.initLoginConfig(wrapper, opts.appid);
|
|
3343
|
+
if (opts.qrOnly === true) {
|
|
3344
|
+
const loginResult = await this.loginByQr(opts);
|
|
3345
|
+
this.ctx.login = loginResult;
|
|
3346
|
+
return loginResult;
|
|
3347
|
+
}
|
|
3255
3348
|
let loginResult;
|
|
3256
3349
|
try {
|
|
3257
3350
|
const quickOpts = {};
|
|
@@ -3295,23 +3388,37 @@ var NapukettoCore = class NapukettoCore {
|
|
|
3295
3388
|
if (this.ctx.wrapper === null) throw kernelError("wrapper 未装配,无法设置 session", "INVALID_STATE");
|
|
3296
3389
|
this.ctx.wrapper.session = session;
|
|
3297
3390
|
}
|
|
3391
|
+
/**
|
|
3392
|
+
* 手动刷新二维码(QR 登录期间可用)。返回是否成功触发(false = 当前不在扫码态)。
|
|
3393
|
+
* koishi 前端「刷新二维码」按钮经 loader IPC `login.refreshQr` 动作直达。
|
|
3394
|
+
*/
|
|
3395
|
+
refreshQr() {
|
|
3396
|
+
if (this.qrSession === null) return false;
|
|
3397
|
+
this.qrSession.refresh();
|
|
3398
|
+
return true;
|
|
3399
|
+
}
|
|
3298
3400
|
/** QR 登录:QrLoginSession 状态机 + 二维码写缓存目录(无 UI,cli 可打印路径)。 */
|
|
3299
3401
|
async loginByQr(opts) {
|
|
3300
3402
|
const { wrapper } = this.ctx;
|
|
3301
3403
|
if (wrapper === null || wrapper.loginService === null) throw kernelError("wrapper/loginService 不可用,无法 QR 登录", "INVALID_STATE");
|
|
3302
3404
|
const session = new QrLoginSession(wrapper.loginService);
|
|
3405
|
+
this.qrSession = session;
|
|
3303
3406
|
const qrPath = opts.qrCodePath ?? this.ctx.paths.file("cache", "qrcode.png");
|
|
3304
3407
|
this.subscribeQrProgress(session, opts, qrPath);
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3408
|
+
try {
|
|
3409
|
+
session.start();
|
|
3410
|
+
await waitQrLoggedIn(session);
|
|
3411
|
+
const self = session.selfInfo;
|
|
3412
|
+
if (self === null) throw kernelError("QR 登录成功但 selfInfo 为空", "INVALID_STATE");
|
|
3413
|
+
return {
|
|
3414
|
+
uin: self.uin,
|
|
3415
|
+
uid: self.uid,
|
|
3416
|
+
nick: self.nick
|
|
3417
|
+
};
|
|
3418
|
+
} finally {
|
|
3419
|
+
session.stop();
|
|
3420
|
+
this.qrSession = null;
|
|
3421
|
+
}
|
|
3315
3422
|
}
|
|
3316
3423
|
/** 订阅 QR 进度:二维码写盘 + 状态机经 onLoginProgress 转发。 */
|
|
3317
3424
|
subscribeQrProgress(session, opts, qrPath) {
|
|
@@ -3325,7 +3432,11 @@ var NapukettoCore = class NapukettoCore {
|
|
|
3325
3432
|
});
|
|
3326
3433
|
session.onStateChange((state) => {
|
|
3327
3434
|
this.ctx.logger.info({ state }, "QR 登录状态");
|
|
3328
|
-
|
|
3435
|
+
const message = state === "failed" ? session.failureReason ?? void 0 : void 0;
|
|
3436
|
+
opts.onLoginProgress?.({
|
|
3437
|
+
state,
|
|
3438
|
+
...message !== void 0 ? { message } : {}
|
|
3439
|
+
});
|
|
3329
3440
|
});
|
|
3330
3441
|
}
|
|
3331
3442
|
/** 停止:日志收尾(资源清理留给 P2 常驻管理)。 */
|
|
@@ -4104,6 +4215,7 @@ exports.parseAppidFromMajor = parseAppidFromMajor;
|
|
|
4104
4215
|
exports.parseToml = parseToml;
|
|
4105
4216
|
exports.probeRuntime = probeRuntime;
|
|
4106
4217
|
exports.quickLogin = quickLogin;
|
|
4218
|
+
exports.readMachineGuid = readMachineGuid;
|
|
4107
4219
|
exports.resolveAppidQua = resolveAppidQua;
|
|
4108
4220
|
exports.resolveConfigPath = resolveConfigPath;
|
|
4109
4221
|
exports.resolveDataRoot = resolveDataRoot;
|
package/dist/index.d.cts
CHANGED
|
@@ -977,6 +977,7 @@ interface NodeQQNTWrapperUtil {
|
|
|
977
977
|
interface EnginInitDesktopConfig {
|
|
978
978
|
base_path_prefix: string;
|
|
979
979
|
platform_type: PlatformType;
|
|
980
|
+
/** 桌面端应用类型(engine.initWithDeskTopConfig 契约,桌面端固定 4;移动端为其它值)。 */
|
|
980
981
|
app_type: 4;
|
|
981
982
|
app_version: string;
|
|
982
983
|
os_version: string;
|
|
@@ -985,6 +986,10 @@ interface EnginInitDesktopConfig {
|
|
|
985
986
|
global_path_config: {
|
|
986
987
|
desktopGlobalPath: string;
|
|
987
988
|
};
|
|
989
|
+
/**
|
|
990
|
+
* 缩略图生成参数(wrapper 契约):maxSide 最长边上限 / minSide 最短边下限 /
|
|
991
|
+
* longLimit 长图最长短边比例上限 / density 像素密度倍数。
|
|
992
|
+
*/
|
|
988
993
|
thumb_config: {
|
|
989
994
|
maxSide: 324;
|
|
990
995
|
minSide: 48;
|
|
@@ -1107,6 +1112,8 @@ interface NodeIKernelLoginService {
|
|
|
1107
1112
|
quickLoginWithUin(uin: string): Promise<unknown>;
|
|
1108
1113
|
getQRCodePicture(): boolean;
|
|
1109
1114
|
getMsfStatus(): number;
|
|
1115
|
+
/** 设备指纹 guid(wrapper.node 字符串分析实证,2026-08-12;无 getMachineId)。 */
|
|
1116
|
+
getMachineGuid(): string;
|
|
1110
1117
|
}
|
|
1111
1118
|
/** NodeIKernelLoginService 构造器(含静态 get)。 */
|
|
1112
1119
|
type NodeIKernelLoginServiceCtor = new () => NodeIKernelLoginService & {
|
|
@@ -1468,9 +1475,9 @@ declare class MsgApi {
|
|
|
1468
1475
|
* 且发送后进程崩溃重启(supervisor 自动拉起)。完整字段(NapCat 同款,
|
|
1469
1476
|
* formatType/voiceType/canConvert2Text/waveAmplitudes 等)消除该错误。
|
|
1470
1477
|
*
|
|
1471
|
-
* ⚠️ silk 格式:QQ 语音协议为 silk v3
|
|
1472
|
-
*
|
|
1473
|
-
*
|
|
1478
|
+
* ⚠️ silk 格式:QQ 语音协议为 silk v3。非 silk → silk 的转码在协议层
|
|
1479
|
+
* (adapter,@napuketto/media 的 encodePcmToSilk,2026-08-12 接线)完成,
|
|
1480
|
+
* 此处接收的已是 silk 路径,仅做放置。kernel 不 import media(解耦红线)。
|
|
1474
1481
|
*/
|
|
1475
1482
|
private preparePttElement;
|
|
1476
1483
|
/**
|
|
@@ -2026,7 +2033,7 @@ declare function startSession(ctx: WrapperContext): void;
|
|
|
2026
2033
|
* 2. createSession(`new NodeIQQNTWrapperSession()`)——实测可用,默认路径
|
|
2027
2034
|
* (getMainSession 实测为空壳:service 全 null + 缺 startNT,仅 probe 探测参考)
|
|
2028
2035
|
*
|
|
2029
|
-
* 由
|
|
2036
|
+
* 由 kernel NapukettoCore(core.ts)装配调用;loader 自建宿主 bootstrap 也直接调用作回退。
|
|
2030
2037
|
* 返回 WrapperContext;失败抛 KernelError。
|
|
2031
2038
|
*/
|
|
2032
2039
|
declare function startNapuketto(options: StartNapukettoOptions): WrapperContext;
|
|
@@ -2138,11 +2145,21 @@ declare class QrLoginSession {
|
|
|
2138
2145
|
private self;
|
|
2139
2146
|
private readonly qrCodeHandlers;
|
|
2140
2147
|
private readonly stateHandlers;
|
|
2141
|
-
|
|
2148
|
+
/** 超时定时器(refresh 后启动,登录成功/失败/stop 清理)。 */
|
|
2149
|
+
private timeoutTimer;
|
|
2150
|
+
/** 失败原因(超时等,failed 态透出给上层提示文案)。 */
|
|
2151
|
+
private failureReasonValue;
|
|
2152
|
+
/** 超时上限(毫秒,默认 QR_LOGIN_TIMEOUT_MS)。 */
|
|
2153
|
+
private readonly timeoutMs;
|
|
2154
|
+
constructor(loginService: unknown, options?: {
|
|
2155
|
+
timeoutMs?: number;
|
|
2156
|
+
});
|
|
2142
2157
|
/** 当前状态。 */
|
|
2143
2158
|
get currentState(): LoginState;
|
|
2144
2159
|
/** selfInfo(登录成功后有值)。 */
|
|
2145
2160
|
get selfInfo(): SelfInfo | null;
|
|
2161
|
+
/** 失败原因(超时等;failed 态透出给上层提示文案)。 */
|
|
2162
|
+
get failureReason(): string | null;
|
|
2146
2163
|
/** 订阅二维码(png base64 + url)。返回退订函数。 */
|
|
2147
2164
|
onQrCode(cb: (qr: QrCodeData) => void): () => void;
|
|
2148
2165
|
/** 订阅状态变化。返回退订函数。 */
|
|
@@ -2151,12 +2168,16 @@ declare class QrLoginSession {
|
|
|
2151
2168
|
start(opts?: {
|
|
2152
2169
|
quickUin?: string;
|
|
2153
2170
|
}): void;
|
|
2154
|
-
/** 刷新二维码(手动 /
|
|
2171
|
+
/** 刷新二维码(手动 / 过期自动)。每次出码重启超时计时。 */
|
|
2155
2172
|
refresh(): void;
|
|
2156
2173
|
/** 构建登录监听(普通 JS 对象,NAPI 反射)。 */
|
|
2157
2174
|
private buildListener;
|
|
2158
2175
|
/** 停止:注销监听(登录成功后调用,防重复回调)。 */
|
|
2159
2176
|
stop(): void;
|
|
2177
|
+
/** 重启超时计时器:超时未登录 → failed + 超时提示。 */
|
|
2178
|
+
private restartTimeout;
|
|
2179
|
+
/** 清理超时计时器(幂等)。 */
|
|
2180
|
+
private clearTimeoutTimer;
|
|
2160
2181
|
private setState;
|
|
2161
2182
|
private emitQrCode;
|
|
2162
2183
|
}
|
|
@@ -2202,10 +2223,12 @@ interface LoginProgress {
|
|
|
2202
2223
|
qr?: QrCodeData;
|
|
2203
2224
|
/** 登录成功 selfInfo(state=logged_in 时有)。 */
|
|
2204
2225
|
selfInfo?: SelfInfo;
|
|
2226
|
+
/** 失败原因(state=failed 时有;如「登录超时,请刷新页面重试」)。 */
|
|
2227
|
+
message?: string;
|
|
2205
2228
|
}
|
|
2206
2229
|
/** login 参数。 */
|
|
2207
2230
|
interface CoreLoginOptions {
|
|
2208
|
-
/** appid
|
|
2231
|
+
/** appid(登录握手,由 resolveAppidQua 从 major.node 动态解析,不写死)。 */
|
|
2209
2232
|
appid: string;
|
|
2210
2233
|
/** session.init 超时(毫秒),默认 15s。 */
|
|
2211
2234
|
initTimeoutMs?: number;
|
|
@@ -2213,6 +2236,8 @@ interface CoreLoginOptions {
|
|
|
2213
2236
|
quickUin?: string;
|
|
2214
2237
|
/** 快速登录失败时回退 QR 登录(二维码写缓存目录),默认 false。 */
|
|
2215
2238
|
qrFallback?: boolean;
|
|
2239
|
+
/** 强制扫码:跳过快速登录,直接走 QR 登录(koishi 强制扫码 / 切账号)。默认 false。 */
|
|
2240
|
+
qrOnly?: boolean;
|
|
2216
2241
|
/** QR 二维码图片保存路径(默认缓存目录 qrcode.png)。 */
|
|
2217
2242
|
qrCodePath?: string;
|
|
2218
2243
|
/** 登录进度回调(QR 阶段:二维码数据 + 状态变化)。子进程 IPC 模式转发用。 */
|
|
@@ -2225,6 +2250,8 @@ interface CoreLoginOptions {
|
|
|
2225
2250
|
declare class NapukettoCore {
|
|
2226
2251
|
/** 装配根(协议层 / apis / cache 的消费入口)。 */
|
|
2227
2252
|
readonly ctx: CoreContext;
|
|
2253
|
+
/** QR 登录会话句柄(登录期间非空;登录终态后清空)。refreshQr() 据此可达。 */
|
|
2254
|
+
private qrSession;
|
|
2228
2255
|
/** 由 create() 装配,不直接 new。 */
|
|
2229
2256
|
private constructor();
|
|
2230
2257
|
/**
|
|
@@ -2265,6 +2292,11 @@ declare class NapukettoCore {
|
|
|
2265
2292
|
* 在 QQ 主进程内由 boot.cjs 调用(登录成功后)。
|
|
2266
2293
|
*/
|
|
2267
2294
|
setSession(session: NodeIQQNTWrapperSession): void;
|
|
2295
|
+
/**
|
|
2296
|
+
* 手动刷新二维码(QR 登录期间可用)。返回是否成功触发(false = 当前不在扫码态)。
|
|
2297
|
+
* koishi 前端「刷新二维码」按钮经 loader IPC `login.refreshQr` 动作直达。
|
|
2298
|
+
*/
|
|
2299
|
+
refreshQr(): boolean;
|
|
2268
2300
|
/** QR 登录:QrLoginSession 状态机 + 二维码写缓存目录(无 UI,cli 可打印路径)。 */
|
|
2269
2301
|
private loginByQr;
|
|
2270
2302
|
/** 订阅 QR 进度:二维码写盘 + 状态机经 onLoginProgress 转发。 */
|
|
@@ -2333,20 +2365,20 @@ declare function createLoginListener(): IKernelLoginListener;
|
|
|
2333
2365
|
/**
|
|
2334
2366
|
* 从 major.node 提取 appid(NapCat parseAppidFromMajorV2 的自研等价实现)。
|
|
2335
2367
|
* major.node 含 `QQAppId/` 标记后跟数字(腾讯工具链产物,实测确认)。
|
|
2336
|
-
* 返回 null
|
|
2368
|
+
* 返回 null 表示解析失败(调用方应显式报错,不再回退硬编码 appid)。
|
|
2337
2369
|
*/
|
|
2338
2370
|
declare function parseAppidFromMajor(majorPath: string): string | null;
|
|
2339
2371
|
/**
|
|
2340
2372
|
* 解析 appid / qua(自研,参考 NapCat QQBasicInfoWrapper 思路但独立实现):
|
|
2341
|
-
*
|
|
2342
|
-
*
|
|
2343
|
-
* majorPath 传 wrapper.node 同目录 major.node
|
|
2373
|
+
* appid 唯一来源 = major.node 提取(实测 9.9.33-51802 = 537376818)。
|
|
2374
|
+
* majorPath 缺省或解析失败时抛 KernelError——不再静默回退过期 appid。
|
|
2375
|
+
* majorPath 传 wrapper.node 同目录 major.node。
|
|
2344
2376
|
*/
|
|
2345
2377
|
declare function resolveAppidQua(fullVersion: string, majorPath?: string): {
|
|
2346
2378
|
appid: string;
|
|
2347
2379
|
qua: string;
|
|
2348
2380
|
};
|
|
2349
|
-
/** 生成 engine 桌面配置(wrapper 契约字段)。majorPath
|
|
2381
|
+
/** 生成 engine 桌面配置(wrapper 契约字段)。majorPath 可选(缺失/解析失败会抛错)。 */
|
|
2350
2382
|
declare function buildEngineConfig(fullVersion: string, dataPathGlobal: string, majorPath?: string): EnginInitDesktopConfig;
|
|
2351
2383
|
/** 生成登录初始化配置(externalVersion: false 与 NapCat 同款,扫码兼容关键)。 */
|
|
2352
2384
|
declare function buildLoginConfig(appid: string, fullVersion: string, commonPath: string): Record<string, unknown>;
|
|
@@ -2358,9 +2390,18 @@ interface SessionConfigOptions {
|
|
|
2358
2390
|
selfUid: string;
|
|
2359
2391
|
accountPath: string;
|
|
2360
2392
|
downloadPath: string;
|
|
2393
|
+
/** 设备指纹 guid(来自 loginService.getMachineGuid();缺省空串)。 */
|
|
2394
|
+
machineGuid?: string;
|
|
2361
2395
|
}
|
|
2362
2396
|
/** 生成 session 初始化配置(登录成功后调用)。 */
|
|
2363
2397
|
declare function buildSessionConfig(options: SessionConfigOptions): WrapperSessionInitConfig;
|
|
2398
|
+
/**
|
|
2399
|
+
* 读取设备指纹 guid(wrapper.node 字符串分析实证,2026-08-12):
|
|
2400
|
+
* NodeIKernelLoginService::getMachineGuid(0 参,返回机器 GUID 字符串)。
|
|
2401
|
+
* 无 getMachineId 方法——TODO 里的方法名不存在,等价方法是 getMachineGuid。
|
|
2402
|
+
* 失败(无该方法 / 调用抛错 / 返回值非字符串)兜底空串。
|
|
2403
|
+
*/
|
|
2404
|
+
declare function readMachineGuid(loginService: unknown): string;
|
|
2364
2405
|
//#endregion
|
|
2365
2406
|
//#region src/wrapper/wrapper-version.d.ts
|
|
2366
2407
|
/**
|
|
@@ -2397,5 +2438,5 @@ interface QQVersionInfo {
|
|
|
2397
2438
|
qua: string;
|
|
2398
2439
|
}
|
|
2399
2440
|
//#endregion
|
|
2400
|
-
export { type BootEnv, type BuddyCategory, type BuddyReq, type CanonicalElement, ChatType, ConfigBase, type ConfigFormat, type ConfigOptions, type ConfigSchema, type CoreContext, type CoreContextOptions, type CoreLoginOptions, DEFAULT_DATA_ROOT_NAME, type DesktopPathConfig, type DeviceInfo, type DoubtBuddyReq, type DoubtFriendRequestInfo, ElementType, type EnginInitDesktopConfig, type EssenceMsgItem, type ForceFetchClientKeyRetType, type Friend, FriendApi, type FriendCategory, type GeneralCallResult, type GetFileListParam, type GrayTipElement, type GrayTipRevokeElement, GrayTipSubType, type Group, GroupApi, GroupBridge, GroupCache, type GroupCacheOptions, type GroupDetailInfo, type GroupEventChannel, type GroupFileItemInfo, type GroupFolderInfo, type GroupHonorWebInfo, GroupListUpdateType, type GroupListener, type GroupMember, type GroupMemberDataSource, type GroupMemberListChange, type GroupNotify, GroupNotifyApi, GroupNotifyMsgStatus, GroupNotifyMsgType, type GroupSpaceInfo, type HonorListItem, KERNEL_ERROR_CODES, KernelError, type KernelErrorCode, type ListenerEvents, type LogLevel, type LoggerOptions, type LoginAccountInfo, type LoginListItem, type LoginProgress, type LoginResult, type LoginState, MAIN_CONFIG_FILE, MsgApi, MsgBridge, type MsgEventChannel, type MsgListener, NTEventChannel, NTGroupMemberRole, NTGroupRequestOperateTypes, NapukettoCore, type NapukettoCoreOptions, type NodeIDependsAdapter, type NodeIDispatcherAdapter, type NodeIGlobalAdapter, type NodeIKernelBuddyService, type NodeIKernelGroupService, type NodeIKernelLoginService, type NodeIKernelMsgService, type NodeIKernelProfileLikeService, type NodeIKernelProfileService, type NodeIKernelRichMediaService, type NodeIKernelSessionListener, type NodeIKernelTicketService, type NodeIQQNTStartupSessionWrapper, type NodeIQQNTWrapperEngine, type NodeIQQNTWrapperSession, type NodeQQNTWrapperUtil, type PathOptions, PathWrapper, type Peer, type PlatformType, ProfileApi, ProfileLikeApi, type QQVersionContext, type QQVersionInfo, type QrCodeData, QrLoginSession, type RDeliveryConfig, type RawElement, type RawMessage, RichMediaApi, type SelfInfo, type SendMessageElement, type SessionConfigOptions, type ShutUpGroupMember, type StartNapukettoOptions, type StrangerInfo, TicketApi, type TipAioOpGrayTipElement, type TipGroupElement, TipGroupElementType, type UserDetailInfoByUin, type VendorType, WebApi, WebHonorType, type WrapperContext, type WrapperNodeApi, type WrapperSessionInitConfig, buildEngineConfig, buildLoginConfig, buildSessionConfig, createCoreContext, createSessionListener as createLifecycleSessionListener, createSessionListener, createLogger, createLoginListener, createSession, createWrapper, electronProcessType, getExistingSession, getMainSession, initAndStartSession, initEngine, initSession, isKernelError, kernelError, listLoginAccounts, listQQVersions, parseAppidFromMajor, parseToml, probeRuntime, quickLogin, resolveAppidQua, resolveConfigPath, resolveDataRoot, resolveQQVersion, resolveQqGlobalPath, resolveQqUserDataRoot, resolveWrapperPath, startNapuketto, startSession, stringifyToml, toCanonicalElements, toSendElements, waitForNetworkConnection, waitSessionReady };
|
|
2441
|
+
export { type BootEnv, type BuddyCategory, type BuddyReq, type CanonicalElement, ChatType, ConfigBase, type ConfigFormat, type ConfigOptions, type ConfigSchema, type CoreContext, type CoreContextOptions, type CoreLoginOptions, DEFAULT_DATA_ROOT_NAME, type DesktopPathConfig, type DeviceInfo, type DoubtBuddyReq, type DoubtFriendRequestInfo, ElementType, type EnginInitDesktopConfig, type EssenceMsgItem, type ForceFetchClientKeyRetType, type Friend, FriendApi, type FriendCategory, type GeneralCallResult, type GetFileListParam, type GrayTipElement, type GrayTipRevokeElement, GrayTipSubType, type Group, GroupApi, GroupBridge, GroupCache, type GroupCacheOptions, type GroupDetailInfo, type GroupEventChannel, type GroupFileItemInfo, type GroupFolderInfo, type GroupHonorWebInfo, GroupListUpdateType, type GroupListener, type GroupMember, type GroupMemberDataSource, type GroupMemberListChange, type GroupNotify, GroupNotifyApi, GroupNotifyMsgStatus, GroupNotifyMsgType, type GroupSpaceInfo, type HonorListItem, KERNEL_ERROR_CODES, KernelError, type KernelErrorCode, type ListenerEvents, type LogLevel, type LoggerOptions, type LoginAccountInfo, type LoginListItem, type LoginProgress, type LoginResult, type LoginState, MAIN_CONFIG_FILE, MsgApi, MsgBridge, type MsgEventChannel, type MsgListener, NTEventChannel, NTGroupMemberRole, NTGroupRequestOperateTypes, NapukettoCore, type NapukettoCoreOptions, type NodeIDependsAdapter, type NodeIDispatcherAdapter, type NodeIGlobalAdapter, type NodeIKernelBuddyService, type NodeIKernelGroupService, type NodeIKernelLoginService, type NodeIKernelMsgService, type NodeIKernelProfileLikeService, type NodeIKernelProfileService, type NodeIKernelRichMediaService, type NodeIKernelSessionListener, type NodeIKernelTicketService, type NodeIQQNTStartupSessionWrapper, type NodeIQQNTWrapperEngine, type NodeIQQNTWrapperSession, type NodeQQNTWrapperUtil, type PathOptions, PathWrapper, type Peer, type PlatformType, ProfileApi, ProfileLikeApi, type QQVersionContext, type QQVersionInfo, type QrCodeData, QrLoginSession, type RDeliveryConfig, type RawElement, type RawMessage, RichMediaApi, type SelfInfo, type SendMessageElement, type SessionConfigOptions, type ShutUpGroupMember, type StartNapukettoOptions, type StrangerInfo, TicketApi, type TipAioOpGrayTipElement, type TipGroupElement, TipGroupElementType, type UserDetailInfoByUin, type VendorType, WebApi, WebHonorType, type WrapperContext, type WrapperNodeApi, type WrapperSessionInitConfig, buildEngineConfig, buildLoginConfig, buildSessionConfig, createCoreContext, createSessionListener as createLifecycleSessionListener, createSessionListener, createLogger, createLoginListener, createSession, createWrapper, electronProcessType, getExistingSession, getMainSession, initAndStartSession, initEngine, initSession, isKernelError, kernelError, listLoginAccounts, listQQVersions, parseAppidFromMajor, parseToml, probeRuntime, quickLogin, readMachineGuid, resolveAppidQua, resolveConfigPath, resolveDataRoot, resolveQQVersion, resolveQqGlobalPath, resolveQqUserDataRoot, resolveWrapperPath, startNapuketto, startSession, stringifyToml, toCanonicalElements, toSendElements, waitForNetworkConnection, waitSessionReady };
|
|
2401
2442
|
//# sourceMappingURL=index.d.cts.map
|