@napuketto/loader 0.0.7 → 0.0.9
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/assets/7zip/7z.dll +0 -0
- package/assets/7zip/7z.exe +0 -0
- package/assets/7zip/License.txt +146 -0
- package/dist/host/self-host.cjs +213 -62
- package/dist/index.d.mts +208 -7
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +575 -43
- package/dist/index.mjs.map +1 -1
- package/package.json +31 -29
- package/qq-releases.json +13 -0
- package/LICENSE +0 -21
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
7-Zip
|
|
2
|
+
~~~~~
|
|
3
|
+
License for use and distribution
|
|
4
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
5
|
+
|
|
6
|
+
7-Zip Copyright (C) 1999-2026 Igor Pavlov.
|
|
7
|
+
|
|
8
|
+
The licenses for files are:
|
|
9
|
+
|
|
10
|
+
- 7z.dll:
|
|
11
|
+
- The "GNU LGPL" as main license for most of the code
|
|
12
|
+
- The "GNU LGPL" with "unRAR license restriction" for some code
|
|
13
|
+
- The "BSD 3-clause License" for some code
|
|
14
|
+
- The "BSD 2-clause License" for some code
|
|
15
|
+
- All other files: the "GNU LGPL".
|
|
16
|
+
|
|
17
|
+
Redistributions in binary form must reproduce related license information from this file.
|
|
18
|
+
|
|
19
|
+
Note:
|
|
20
|
+
You can use 7-Zip on any computer, including a computer in a commercial
|
|
21
|
+
organization. You don't need to register or pay for 7-Zip.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
GNU LGPL information
|
|
25
|
+
--------------------
|
|
26
|
+
|
|
27
|
+
This library is free software; you can redistribute it and/or
|
|
28
|
+
modify it under the terms of the GNU Lesser General Public
|
|
29
|
+
License as published by the Free Software Foundation; either
|
|
30
|
+
version 2.1 of the License, or (at your option) any later version.
|
|
31
|
+
|
|
32
|
+
This library is distributed in the hope that it will be useful,
|
|
33
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
34
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
35
|
+
Lesser General Public License for more details.
|
|
36
|
+
|
|
37
|
+
You can receive a copy of the GNU Lesser General Public License from
|
|
38
|
+
http://www.gnu.org/
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
BSD 3-clause License in 7-Zip code
|
|
44
|
+
----------------------------------
|
|
45
|
+
|
|
46
|
+
The "BSD 3-clause License" is used for the following code in 7z.dll
|
|
47
|
+
1) LZFSE data decompression.
|
|
48
|
+
That code was derived from the code in the "LZFSE compression library" developed by Apple Inc,
|
|
49
|
+
that also uses the "BSD 3-clause License".
|
|
50
|
+
2) ZSTD data decompression.
|
|
51
|
+
that code was developed using original zstd decoder code as reference code.
|
|
52
|
+
The original zstd decoder code was developed by Facebook Inc,
|
|
53
|
+
that also uses the "BSD 3-clause License".
|
|
54
|
+
|
|
55
|
+
Copyright (c) 2015-2016, Apple Inc. All rights reserved.
|
|
56
|
+
Copyright (c) Facebook, Inc. All rights reserved.
|
|
57
|
+
Copyright (c) 2023-2026 Igor Pavlov.
|
|
58
|
+
|
|
59
|
+
Text of the "BSD 3-clause License"
|
|
60
|
+
----------------------------------
|
|
61
|
+
|
|
62
|
+
Redistribution and use in source and binary forms, with or without modification,
|
|
63
|
+
are permitted provided that the following conditions are met:
|
|
64
|
+
|
|
65
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
66
|
+
list of conditions and the following disclaimer.
|
|
67
|
+
|
|
68
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
69
|
+
this list of conditions and the following disclaimer in the documentation
|
|
70
|
+
and/or other materials provided with the distribution.
|
|
71
|
+
|
|
72
|
+
3. Neither the name of the copyright holder nor the names of its contributors may
|
|
73
|
+
be used to endorse or promote products derived from this software without
|
|
74
|
+
specific prior written permission.
|
|
75
|
+
|
|
76
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
77
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
78
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
79
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
80
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
81
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
82
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
83
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
84
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
85
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
BSD 2-clause License in 7-Zip code
|
|
93
|
+
----------------------------------
|
|
94
|
+
|
|
95
|
+
The "BSD 2-clause License" is used for the XXH64 code in 7-Zip.
|
|
96
|
+
|
|
97
|
+
XXH64 code in 7-Zip was derived from the original XXH64 code developed by Yann Collet.
|
|
98
|
+
|
|
99
|
+
Copyright (c) 2012-2021 Yann Collet.
|
|
100
|
+
Copyright (c) 2023-2026 Igor Pavlov.
|
|
101
|
+
|
|
102
|
+
Text of the "BSD 2-clause License"
|
|
103
|
+
----------------------------------
|
|
104
|
+
|
|
105
|
+
Redistribution and use in source and binary forms, with or without modification,
|
|
106
|
+
are permitted provided that the following conditions are met:
|
|
107
|
+
|
|
108
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
109
|
+
list of conditions and the following disclaimer.
|
|
110
|
+
|
|
111
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
112
|
+
this list of conditions and the following disclaimer in the documentation
|
|
113
|
+
and/or other materials provided with the distribution.
|
|
114
|
+
|
|
115
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
116
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
117
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
118
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
119
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
120
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
121
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
122
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
123
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
124
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
unRAR license restriction
|
|
132
|
+
-------------------------
|
|
133
|
+
|
|
134
|
+
The decompression engine for RAR archives was developed using source
|
|
135
|
+
code of unRAR program.
|
|
136
|
+
All copyrights to original unRAR code are owned by Alexander Roshal.
|
|
137
|
+
|
|
138
|
+
The license for original unRAR code has the following restriction:
|
|
139
|
+
|
|
140
|
+
The unRAR sources cannot be used to re-create the RAR compression algorithm,
|
|
141
|
+
which is proprietary. Distribution of modified unRAR sources in separate form
|
|
142
|
+
or as a part of other software is permitted, provided that it is clearly
|
|
143
|
+
stated in the documentation and source comments that the code may
|
|
144
|
+
not be used to develop a RAR (WinRAR) compatible archiver.
|
|
145
|
+
|
|
146
|
+
--
|
package/dist/host/self-host.cjs
CHANGED
|
@@ -287,8 +287,135 @@ function createIpcActions(ctx) {
|
|
|
287
287
|
return ctx.groupCache.listGroupsRefreshed();
|
|
288
288
|
});
|
|
289
289
|
actions.set("friend.getFriendList", async () => ctx.friendApi.getFriendList());
|
|
290
|
+
actions.set("diag.richMediaTmpPaths", async () => runRichMediaDiag(ctx.session));
|
|
291
|
+
actions.set("diag.flashCall", async (params) => {
|
|
292
|
+
const sess = ctx.session;
|
|
293
|
+
if (sess === void 0) return { error: "session 未注入" };
|
|
294
|
+
const flash = typeof sess.getFlashTransferService === "function" ? sess.getFlashTransferService() : null;
|
|
295
|
+
if (flash === null || flash === void 0) return { error: "flash 服务为 null" };
|
|
296
|
+
return callDiagnosticMethod(flash, params);
|
|
297
|
+
});
|
|
298
|
+
actions.set("diag.sessionCall", async (params) => {
|
|
299
|
+
if (ctx.session === void 0) return { error: "session 未注入" };
|
|
300
|
+
return callDiagnosticMethod(ctx.session, params);
|
|
301
|
+
});
|
|
302
|
+
actions.set("diag.engineCall", async (params) => {
|
|
303
|
+
if (ctx.engine === void 0) return { error: "engine 未注入" };
|
|
304
|
+
return callDiagnosticMethod(ctx.engine, params);
|
|
305
|
+
});
|
|
306
|
+
actions.set("diag.richMediaCall", async (params) => {
|
|
307
|
+
const sess = ctx.session;
|
|
308
|
+
if (sess === void 0) return { error: "session 未注入" };
|
|
309
|
+
const svc = typeof sess.getRichMediaService === "function" ? sess.getRichMediaService() : null;
|
|
310
|
+
if (svc === null || svc === void 0) return { error: "richMedia 服务为 null" };
|
|
311
|
+
return callDiagnosticMethod(svc, params);
|
|
312
|
+
});
|
|
313
|
+
actions.set("diag.msgServiceCall", async (params) => {
|
|
314
|
+
const sess = ctx.session;
|
|
315
|
+
if (sess === void 0) return { error: "session 未注入" };
|
|
316
|
+
const svc = typeof sess.getMsgService === "function" ? sess.getMsgService() : null;
|
|
317
|
+
if (svc === null || svc === void 0) return { error: "msgService 为 null" };
|
|
318
|
+
return callDiagnosticMethod(svc, params);
|
|
319
|
+
});
|
|
320
|
+
actions.set("diag.utilCall", async (params) => {
|
|
321
|
+
const util = ctx.util;
|
|
322
|
+
if (util === void 0) return { error: "util 未注入" };
|
|
323
|
+
const instance = typeof util.get === "function" ? util.get() : util;
|
|
324
|
+
if (instance === null || instance === void 0) return { error: "util 实例为 null" };
|
|
325
|
+
return callDiagnosticMethod(instance, params);
|
|
326
|
+
});
|
|
290
327
|
return actions;
|
|
291
328
|
}
|
|
329
|
+
/** 诊断:按方法名 + 参数数组调用对象任意方法(返回结构化结果,不抛)。
|
|
330
|
+
* ⚠️ NAPI 对象方法挂在实例自身(非原型),__methods 须枚举实例 ownKeys。 */
|
|
331
|
+
async function callDiagnosticMethod(obj, params) {
|
|
332
|
+
const method = typeof params["method"] === "string" ? params["method"] : "";
|
|
333
|
+
const args = Array.isArray(params["args"]) ? params["args"] : [];
|
|
334
|
+
const target = obj;
|
|
335
|
+
if (method === "__methods") {
|
|
336
|
+
const own = Object.getOwnPropertyNames(obj);
|
|
337
|
+
const proto = Object.getOwnPropertyNames(Object.getPrototypeOf(obj) ?? {});
|
|
338
|
+
return { methods: [.../* @__PURE__ */ new Set([...own, ...proto])] };
|
|
339
|
+
}
|
|
340
|
+
const fn = target[method];
|
|
341
|
+
if (typeof fn !== "function") return { error: `方法不存在: ${method}` };
|
|
342
|
+
try {
|
|
343
|
+
return {
|
|
344
|
+
ok: true,
|
|
345
|
+
ret: await fn.apply(obj, args)
|
|
346
|
+
};
|
|
347
|
+
} catch (e) {
|
|
348
|
+
return {
|
|
349
|
+
ok: false,
|
|
350
|
+
err: e instanceof Error ? e.message : String(e)
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
/** 诊断:枚举富媒体临时路径(getPicTmpPath 等 0 参方法)。 */
|
|
355
|
+
async function enumerateTmpPaths(svc) {
|
|
356
|
+
const tmp = {};
|
|
357
|
+
for (const name of [
|
|
358
|
+
"getPicTmpPath",
|
|
359
|
+
"getRichMeidaTmpPath",
|
|
360
|
+
"getPttTmpPath",
|
|
361
|
+
"getVideoTmpPath",
|
|
362
|
+
"getFileTmpPath",
|
|
363
|
+
"getTransferingTmpPath"
|
|
364
|
+
]) {
|
|
365
|
+
const fn = svc[name];
|
|
366
|
+
if (typeof fn === "function") try {
|
|
367
|
+
tmp[name] = await fn.call(svc);
|
|
368
|
+
} catch (e) {
|
|
369
|
+
tmp[name] = `调用失败: ${e instanceof Error ? e.message : String(e)}`;
|
|
370
|
+
}
|
|
371
|
+
else tmp[name] = "方法缺失";
|
|
372
|
+
}
|
|
373
|
+
return tmp;
|
|
374
|
+
}
|
|
375
|
+
/** 诊断:闪传服务候选 side-effect 触发(§5.3 候选动作 1,参数宽松猜测)。 */
|
|
376
|
+
async function probeFlashSideEffects(flash) {
|
|
377
|
+
const flashObj = flash;
|
|
378
|
+
const sideEffects = {};
|
|
379
|
+
const candidates = [
|
|
380
|
+
["addFileSetSimpleStatusListener", [() => void 0]],
|
|
381
|
+
["setFlashTransferDir", [""]],
|
|
382
|
+
["setFileSetDownloadDir", [""]],
|
|
383
|
+
["getFileSetIdByCode", [""]]
|
|
384
|
+
];
|
|
385
|
+
for (const [name, args] of candidates) {
|
|
386
|
+
const fn = flashObj[name];
|
|
387
|
+
if (typeof fn === "function") try {
|
|
388
|
+
sideEffects[name] = {
|
|
389
|
+
ok: true,
|
|
390
|
+
ret: await fn.apply(flash, args)
|
|
391
|
+
};
|
|
392
|
+
} catch (e) {
|
|
393
|
+
sideEffects[name] = {
|
|
394
|
+
ok: false,
|
|
395
|
+
err: e instanceof Error ? e.message : String(e)
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
else sideEffects[name] = { missing: true };
|
|
399
|
+
}
|
|
400
|
+
return sideEffects;
|
|
401
|
+
}
|
|
402
|
+
/** 诊断主流程:session → 富媒体服务 + 闪传服务的方法面与触发结果。 */
|
|
403
|
+
async function runRichMediaDiag(session) {
|
|
404
|
+
const sess = session;
|
|
405
|
+
if (sess === void 0) return { error: "session 未注入(IPC 上下文缺 session)" };
|
|
406
|
+
const out = {};
|
|
407
|
+
const svc = typeof sess.getRichMediaService === "function" ? sess.getRichMediaService() : null;
|
|
408
|
+
if (svc !== null && svc !== void 0) {
|
|
409
|
+
out["richMediaTmpPaths"] = await enumerateTmpPaths(svc);
|
|
410
|
+
out["richMediaMethods"] = Object.getOwnPropertyNames(Object.getPrototypeOf(svc));
|
|
411
|
+
} else out["richMediaService"] = "null";
|
|
412
|
+
const flash = typeof sess.getFlashTransferService === "function" ? sess.getFlashTransferService() : null;
|
|
413
|
+
if (flash !== null && flash !== void 0) {
|
|
414
|
+
out["flashMethods"] = Object.getOwnPropertyNames(Object.getPrototypeOf(flash));
|
|
415
|
+
out["flashSideEffects"] = await probeFlashSideEffects(flash);
|
|
416
|
+
} else out["flashService"] = "null";
|
|
417
|
+
return out;
|
|
418
|
+
}
|
|
292
419
|
/** 统一动作调用:查找动作表 → 执行 → 返回结果或错误(不抛,调用方转 result)。 */
|
|
293
420
|
async function callIpcAction(actions, action, params) {
|
|
294
421
|
const handler = actions.get(action);
|
|
@@ -510,6 +637,9 @@ function startIpcMode(services) {
|
|
|
510
637
|
groupCache: services.groupCache,
|
|
511
638
|
friendApi: services.friendApi,
|
|
512
639
|
self: services.self,
|
|
640
|
+
session: services.session,
|
|
641
|
+
engine: services.engine,
|
|
642
|
+
util: services.util,
|
|
513
643
|
...groupApi.uinToUid !== void 0 ? { uinToUid: groupApi.uinToUid } : {}
|
|
514
644
|
}) });
|
|
515
645
|
const stops = [];
|
|
@@ -612,6 +742,10 @@ function loadProtocolSections(kernel, uin) {
|
|
|
612
742
|
* assemble-protocols.ts:OB11 / Satori 协议装配(非 IPC 模式,cli pnpm start)。
|
|
613
743
|
* 2026-08-08:从 protocols.ts 拆分——protocols.ts 只留入口 + IPC 分支。
|
|
614
744
|
*/
|
|
745
|
+
/** Windows 反斜杠(file:// URL 化时替换)。 */
|
|
746
|
+
const BACKSLASH_RE = /\\/g;
|
|
747
|
+
/** adapter 入口 index.mjs 后缀(子路径导出替换用)。 */
|
|
748
|
+
const INDEX_MJS_RE = /index\.mjs$/;
|
|
615
749
|
/** 装配 OB11 + Satori 适配器(登录成功后,非 IPC 模式)。 */
|
|
616
750
|
async function assembleOb11AndSatori(kernel, services, loginResult) {
|
|
617
751
|
const adapterEntry = env.NAPUTO_ADAPTER_ENTRY;
|
|
@@ -621,13 +755,13 @@ async function assembleOb11AndSatori(kernel, services, loginResult) {
|
|
|
621
755
|
return;
|
|
622
756
|
}
|
|
623
757
|
try {
|
|
624
|
-
const network = await import(`file://${networkEntry.replace(
|
|
625
|
-
const onebot11Entry = adapterEntry.replace(
|
|
626
|
-
const satoriEntry = adapterEntry.replace(
|
|
627
|
-
const coreEntry = adapterEntry.replace(
|
|
628
|
-
const adapter = await import(`file://${onebot11Entry.replace(
|
|
629
|
-
const satoriAdapter = await import(`file://${satoriEntry.replace(
|
|
630
|
-
const adapterCore = await import(`file://${coreEntry.replace(
|
|
758
|
+
const network = await import(`file://${networkEntry.replace(BACKSLASH_RE, "/")}`);
|
|
759
|
+
const onebot11Entry = adapterEntry.replace(INDEX_MJS_RE, "onebot11/index.mjs");
|
|
760
|
+
const satoriEntry = adapterEntry.replace(INDEX_MJS_RE, "satori/index.mjs");
|
|
761
|
+
const coreEntry = adapterEntry.replace(INDEX_MJS_RE, "core/index.mjs");
|
|
762
|
+
const adapter = await import(`file://${onebot11Entry.replace(BACKSLASH_RE, "/")}`);
|
|
763
|
+
const satoriAdapter = await import(`file://${satoriEntry.replace(BACKSLASH_RE, "/")}`);
|
|
764
|
+
const adapterCore = await import(`file://${coreEntry.replace(BACKSLASH_RE, "/")}`);
|
|
631
765
|
const { channel, groupCache } = services;
|
|
632
766
|
const broadcaster = new network.EventBroadcaster();
|
|
633
767
|
const { cfgFile, ob11Section, satoriSection } = loadProtocolSections(kernel, loginResult.uin);
|
|
@@ -772,7 +906,8 @@ async function createKernelServices(kernel, ctx, loginResult) {
|
|
|
772
906
|
new kernel.MsgBridge(session, channel).register();
|
|
773
907
|
setupMsgLogging(kernel, channel, logger);
|
|
774
908
|
const groupApi = new kernel.GroupApi(session);
|
|
775
|
-
const
|
|
909
|
+
const util = ctx.exports?.NodeQQNTWrapperUtil;
|
|
910
|
+
const msgApi = new kernel.MsgApi(session, channel, util);
|
|
776
911
|
const friendApi = new kernel.FriendApi(session, { uidToUin: (uids) => groupApi.uidToUin(uids) });
|
|
777
912
|
const groupChannel = new kernel.NTEventChannel("Group");
|
|
778
913
|
new kernel.GroupBridge(session, groupChannel).register();
|
|
@@ -802,7 +937,10 @@ async function createKernelServices(kernel, ctx, loginResult) {
|
|
|
802
937
|
self: {
|
|
803
938
|
uin: loginResult.uin,
|
|
804
939
|
nickname: loginResult.nick ?? ""
|
|
805
|
-
}
|
|
940
|
+
},
|
|
941
|
+
session,
|
|
942
|
+
engine: ctx.engine,
|
|
943
|
+
util: ctx.exports?.NodeQQNTWrapperUtil
|
|
806
944
|
};
|
|
807
945
|
}
|
|
808
946
|
//#endregion
|
|
@@ -855,32 +993,32 @@ function isSessionUsable(s) {
|
|
|
855
993
|
return false;
|
|
856
994
|
}
|
|
857
995
|
}
|
|
996
|
+
/** 描述单个 session 对象(探测日志用;无效对象返回带断言信息的占位)。 */
|
|
997
|
+
function describeSession(s) {
|
|
998
|
+
if (!s) return "null";
|
|
999
|
+
try {
|
|
1000
|
+
const sess = s;
|
|
1001
|
+
const id = typeof sess.getSessionId === "function" ? String(sess.getSessionId()) : "?";
|
|
1002
|
+
const svc = typeof sess.getMsgService === "function" ? sess.getMsgService() : null;
|
|
1003
|
+
return `id=${id} msgSvc=${svc !== null && svc !== void 0 ? "READY" : "null"}`;
|
|
1004
|
+
} catch (e) {
|
|
1005
|
+
return `id=? msgSvc=断言(${errMsg(e).slice(0, 60)})`;
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
/** 非空候选才追加探测描述。 */
|
|
1009
|
+
function pushProbe(out, label, candidate) {
|
|
1010
|
+
if (candidate) out.push(`${label}[${describeSession(candidate)}]`);
|
|
1011
|
+
}
|
|
858
1012
|
/** session 就绪探测(5s 间隔,60s 上限)——观察 qqSession / get() 状态。 */
|
|
859
1013
|
function startSessionProbe(state, _ctx, durationMs = 6e4) {
|
|
860
1014
|
const sessionProbe = setInterval(() => {
|
|
861
1015
|
try {
|
|
862
1016
|
const S2 = state.wrapperExports?.["NodeIQQNTWrapperSession"];
|
|
863
1017
|
const out = [];
|
|
864
|
-
const
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
const id = typeof sess.getSessionId === "function" ? String(sess.getSessionId()) : "?";
|
|
869
|
-
const svc = typeof sess.getMsgService === "function" ? sess.getMsgService() : null;
|
|
870
|
-
return `id=${id} msgSvc=${svc !== null && svc !== void 0 ? "READY" : "null"}`;
|
|
871
|
-
} catch (e) {
|
|
872
|
-
return `id=? msgSvc=断言(${errMsg(e).slice(0, 60)})`;
|
|
873
|
-
}
|
|
874
|
-
};
|
|
875
|
-
if (state.qqSession && typeof state.qqSession.getMsgService === "function") out.push(`qqSession[${describe(state.qqSession)}]`);
|
|
876
|
-
if (S2 && typeof S2.get === "function") {
|
|
877
|
-
const got = S2.get();
|
|
878
|
-
out.push(`get()[${describe(got)}]`);
|
|
879
|
-
}
|
|
880
|
-
if (S2 && typeof S2.getNTWrapperSession === "function") {
|
|
881
|
-
const gotNT = S2.getNTWrapperSession("Session");
|
|
882
|
-
if (gotNT) out.push(`getNT("Session")[${describe(gotNT)}]`);
|
|
883
|
-
}
|
|
1018
|
+
const qqSession = state.qqSession;
|
|
1019
|
+
if (qqSession && typeof qqSession.getMsgService === "function") pushProbe(out, "qqSession", qqSession);
|
|
1020
|
+
if (S2 && typeof S2.get === "function") pushProbe(out, "get()", S2.get());
|
|
1021
|
+
if (S2 && typeof S2.getNTWrapperSession === "function") pushProbe(out, "getNT(\"Session\")", S2.getNTWrapperSession("Session"));
|
|
884
1022
|
log(`BOOT: session 探测: ${out.join(" | ")}`);
|
|
885
1023
|
} catch (e) {
|
|
886
1024
|
log(`BOOT: session 探测失败: ${errMsg(e)}`);
|
|
@@ -1129,11 +1267,13 @@ function buildLoginOpts(Appid, forcedUin, ref) {
|
|
|
1129
1267
|
};
|
|
1130
1268
|
const ipcMode = env.NAPUTO_IPC === "1";
|
|
1131
1269
|
opts["onLoginProgress"] = (progress) => {
|
|
1132
|
-
if (progress.qr !== void 0)
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1270
|
+
if (progress.qr !== void 0) {
|
|
1271
|
+
if (ipcMode) sendQr(progress.qr.pngBase64, progress.qr.qrcodeUrl);
|
|
1272
|
+
else node_process.default.stdout.write(`${QR_LINE_PREFIX}${JSON.stringify({
|
|
1273
|
+
pngBase64: progress.qr.pngBase64,
|
|
1274
|
+
qrcodeUrl: progress.qr.qrcodeUrl
|
|
1275
|
+
})}\n`);
|
|
1276
|
+
}
|
|
1137
1277
|
if (ipcMode && isLoginState(progress.state)) sendLogin(progress.state, progress.selfInfo);
|
|
1138
1278
|
};
|
|
1139
1279
|
return opts;
|
|
@@ -1284,6 +1424,43 @@ async function bootstrapWithCore(kernel, state, bootEnv, Appid) {
|
|
|
1284
1424
|
function resolveAppid(kernel, bootEnv) {
|
|
1285
1425
|
return typeof kernel.parseAppidFromMajor === "function" && bootEnv.wrapperPath && kernel.parseAppidFromMajor((0, node_path.join)((0, node_path.dirname)(bootEnv.wrapperPath), "major.node")) || typeof kernel.resolveAppidQua === "function" && kernel.resolveAppidQua(bootEnv.qqVersion || "").appid || "537237765";
|
|
1286
1426
|
}
|
|
1427
|
+
/** 快速登录 + session 初始化(kernel lifecycle 路径;生命周期方法缺失则跳过)。 */
|
|
1428
|
+
async function quickLoginAndStartSession(kernel, ctx, Appid, bootEnv) {
|
|
1429
|
+
if (typeof kernel.quickLogin !== "function" || typeof kernel.initAndStartSession !== "function") {
|
|
1430
|
+
log("bootstrap: kernel missing lifecycle fns (quickLogin/initAndStartSession)");
|
|
1431
|
+
return;
|
|
1432
|
+
}
|
|
1433
|
+
if (typeof kernel.buildLoginConfig === "function" && ctx.loginService) {
|
|
1434
|
+
const loginCfg = kernel.buildLoginConfig(Appid, bootEnv.qqVersion || "", bootEnv.dataDir || ".");
|
|
1435
|
+
if (typeof ctx.loginService.initConfig === "function") {
|
|
1436
|
+
ctx.loginService.initConfig(loginCfg);
|
|
1437
|
+
log("bootstrap: loginService.initConfig OK");
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
const loginResult = await kernel.quickLogin(ctx, {});
|
|
1441
|
+
log(`bootstrap: quickLogin OK, uin=${loginResult.uin}, uid=${loginResult.uid}`);
|
|
1442
|
+
const sessionConfig = kernel.buildSessionConfig({
|
|
1443
|
+
appid: Appid,
|
|
1444
|
+
fullVersion: bootEnv.qqVersion || "",
|
|
1445
|
+
selfUin: loginResult.uin,
|
|
1446
|
+
selfUid: loginResult.uid,
|
|
1447
|
+
accountPath: bootEnv.dataDir || ".",
|
|
1448
|
+
downloadPath: (0, node_path.join)(bootEnv.dataDir || ".", "temp")
|
|
1449
|
+
});
|
|
1450
|
+
const listener = kernel.createLifecycleSessionListener();
|
|
1451
|
+
await kernel.initAndStartSession(ctx, sessionConfig, listener, { timeoutMs: 2e4 });
|
|
1452
|
+
log("bootstrap: session init + startNT OK!");
|
|
1453
|
+
}
|
|
1454
|
+
/** 冒烟探测(NAPUTO_PROBE=1 时运行)。 */
|
|
1455
|
+
async function probeRuntime(kernel, ctx) {
|
|
1456
|
+
if (env.NAPUTO_PROBE !== "1" || typeof kernel.probeRuntime !== "function") return;
|
|
1457
|
+
try {
|
|
1458
|
+
const probe = kernel.probeRuntime(ctx);
|
|
1459
|
+
log(`bootstrap: probe done, session=${probe.session ? "ok" : "null"}, services=${Object.keys(probe.services ?? {}).length}`);
|
|
1460
|
+
} catch (e) {
|
|
1461
|
+
log(`bootstrap: probe error: ${errMsg(e)}`);
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1287
1464
|
/** 回退:旧装配路径(startNapuketto + 手工 lifecycle)。 */
|
|
1288
1465
|
async function bootstrapFallback(kernel, state, bootEnv, Appid) {
|
|
1289
1466
|
log("bootstrap: kernel has no NapukettoCore, falling back");
|
|
@@ -1296,34 +1473,8 @@ async function bootstrapFallback(kernel, state, bootEnv, Appid) {
|
|
|
1296
1473
|
return;
|
|
1297
1474
|
}
|
|
1298
1475
|
log(`bootstrap: startNapuketto OK, engine=${typeof ctx.engine}, session=${ctx.session !== null}`);
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
const loginCfg = kernel.buildLoginConfig(Appid, bootEnv.qqVersion || "", bootEnv.dataDir || ".");
|
|
1302
|
-
if (typeof ctx.loginService.initConfig === "function") {
|
|
1303
|
-
ctx.loginService.initConfig(loginCfg);
|
|
1304
|
-
log("bootstrap: loginService.initConfig OK");
|
|
1305
|
-
}
|
|
1306
|
-
}
|
|
1307
|
-
const loginResult = await kernel.quickLogin(ctx, {});
|
|
1308
|
-
log(`bootstrap: quickLogin OK, uin=${loginResult.uin}, uid=${loginResult.uid}`);
|
|
1309
|
-
const sessionConfig = kernel.buildSessionConfig({
|
|
1310
|
-
appid: Appid,
|
|
1311
|
-
fullVersion: bootEnv.qqVersion || "",
|
|
1312
|
-
selfUin: loginResult.uin,
|
|
1313
|
-
selfUid: loginResult.uid,
|
|
1314
|
-
accountPath: bootEnv.dataDir || ".",
|
|
1315
|
-
downloadPath: (0, node_path.join)(bootEnv.dataDir || ".", "temp")
|
|
1316
|
-
});
|
|
1317
|
-
const listener = kernel.createLifecycleSessionListener();
|
|
1318
|
-
await kernel.initAndStartSession(ctx, sessionConfig, listener, { timeoutMs: 2e4 });
|
|
1319
|
-
log("bootstrap: session init + startNT OK!");
|
|
1320
|
-
} else log("bootstrap: kernel missing lifecycle fns (quickLogin/initAndStartSession)");
|
|
1321
|
-
if (env.NAPUTO_PROBE === "1" && typeof kernel.probeRuntime === "function") try {
|
|
1322
|
-
const probe = kernel.probeRuntime(ctx);
|
|
1323
|
-
log(`bootstrap: probe done, session=${probe.session ? "ok" : "null"}, services=${Object.keys(probe.services ?? {}).length}`);
|
|
1324
|
-
} catch (e) {
|
|
1325
|
-
log(`bootstrap: probe error: ${errMsg(e)}`);
|
|
1326
|
-
}
|
|
1476
|
+
await quickLoginAndStartSession(kernel, ctx, Appid, bootEnv);
|
|
1477
|
+
await probeRuntime(kernel, ctx);
|
|
1327
1478
|
}
|
|
1328
1479
|
/** 核心引导:import kernel → 装配 → 登录 → 替换 session → 等待就绪 → 协议装配。 */
|
|
1329
1480
|
async function bootstrap(state) {
|