@napuketto/kernel 0.0.16 → 0.1.0
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 +238 -112
- package/dist/index.d.cts +135 -3
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +135 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +237 -113
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -429,7 +429,7 @@ var FriendApi = class {
|
|
|
429
429
|
if (raw.result !== 0) throw kernelError(`getBuddyListV2 失败: ${raw.errMsg}`, "UNKNOWN");
|
|
430
430
|
categories = raw.data;
|
|
431
431
|
}
|
|
432
|
-
const uids = categories.flatMap((cat) => cat.buddyUids);
|
|
432
|
+
const uids = categories.flatMap((cat) => cat.buddyList?.map((b) => b.uid) ?? cat.buddyUids ?? []);
|
|
433
433
|
let uinMap = /* @__PURE__ */ new Map();
|
|
434
434
|
if (this.uidToUin !== void 0) uinMap = await this.uidToUin(uids);
|
|
435
435
|
const out = [];
|
|
@@ -448,7 +448,7 @@ var FriendApi = class {
|
|
|
448
448
|
for (const friend of await this.getFriendList()) friendMap.set(friend.uid, friend);
|
|
449
449
|
return categories.map((cat) => {
|
|
450
450
|
const buddies = [];
|
|
451
|
-
for (const uid of cat.buddyUids) {
|
|
451
|
+
for (const uid of cat.buddyList?.map((b) => b.uid) ?? cat.buddyUids ?? []) {
|
|
452
452
|
const friend = friendMap.get(uid);
|
|
453
453
|
if (friend !== void 0) buddies.push(friend);
|
|
454
454
|
}
|
|
@@ -1231,6 +1231,18 @@ const PTT_WAVE_AMPLITUDES = [
|
|
|
1231
1231
|
15,
|
|
1232
1232
|
17
|
|
1233
1233
|
];
|
|
1234
|
+
/** downloadRichMedia 契约值(2026-09-08 B1 实测:downloadType=2 可用 / thumbSize=0)。 */
|
|
1235
|
+
const DOWNLOAD_TYPE_COMMON = 2;
|
|
1236
|
+
const THUMB_SIZE_NONE = 0;
|
|
1237
|
+
/** 语音下载轮询参数(300ms × 34 ≈ 10s;返回 void 只能经重拉元素观察完成)。 */
|
|
1238
|
+
const PTT_POLL_INTERVAL_MS = 300;
|
|
1239
|
+
const PTT_POLL_TIMES = 34;
|
|
1240
|
+
/** sleep(下载轮询间隔)。 */
|
|
1241
|
+
function sleep$1(ms) {
|
|
1242
|
+
return new Promise((resolve) => {
|
|
1243
|
+
setTimeout(resolve, ms);
|
|
1244
|
+
});
|
|
1245
|
+
}
|
|
1234
1246
|
/** 读文件 stat(富媒体发送预处理;文件不存在抛 INVALID_PARAM)。 */
|
|
1235
1247
|
async function statFile(path) {
|
|
1236
1248
|
try {
|
|
@@ -1491,6 +1503,35 @@ var MsgApi = class {
|
|
|
1491
1503
|
async markRead(target) {
|
|
1492
1504
|
unwrapResult("setMsgRead", await this.service.setMsgRead(target));
|
|
1493
1505
|
}
|
|
1506
|
+
/**
|
|
1507
|
+
* 语音主动下载(get_record 本地未命中兜底,2026-09-08 B1)。
|
|
1508
|
+
* downloadRichMedia 返回 void(实测),完成信号 = 重拉消息元素:
|
|
1509
|
+
* 轮询(300ms × 34,约 10s)直到 filePath 非空且 transferStatus 进入
|
|
1510
|
+
* 已下载态(2/4);超时但 filePath 已有值则尽力返回(磁盘命中判断留给
|
|
1511
|
+
* 调用方),完全无路径抛 NOT_FOUND。
|
|
1512
|
+
*/
|
|
1513
|
+
async downloadPtt(msgId, target) {
|
|
1514
|
+
const el = findPttElement(await this.fetchMsgsByMsgId(target, [msgId]));
|
|
1515
|
+
const ptt = el?.pttElement;
|
|
1516
|
+
if (el === null || ptt === void 0) throw kernelError("消息中不包含语音", "NOT_FOUND");
|
|
1517
|
+
const elemId = el.elementId ?? "";
|
|
1518
|
+
await this.service.downloadRichMedia({
|
|
1519
|
+
msgId,
|
|
1520
|
+
elemId,
|
|
1521
|
+
chatType: target.chatType,
|
|
1522
|
+
downloadType: DOWNLOAD_TYPE_COMMON,
|
|
1523
|
+
thumbSize: THUMB_SIZE_NONE
|
|
1524
|
+
});
|
|
1525
|
+
for (let i = 0; i < PTT_POLL_TIMES; i++) {
|
|
1526
|
+
await sleep$1(PTT_POLL_INTERVAL_MS);
|
|
1527
|
+
const latest = findPttElement(await this.fetchMsgsByMsgId(target, [msgId]))?.pttElement;
|
|
1528
|
+
if (latest === void 0) continue;
|
|
1529
|
+
const done = latest.transferStatus === 2 || latest.transferStatus === 4;
|
|
1530
|
+
if (latest.filePath !== void 0 && latest.filePath !== "" && done) return latest;
|
|
1531
|
+
if (i === 33 && latest.filePath !== void 0 && latest.filePath !== "") return latest;
|
|
1532
|
+
}
|
|
1533
|
+
throw kernelError("语音下载未完成(超时)", "TIMEOUT");
|
|
1534
|
+
}
|
|
1494
1535
|
/** 发送输入状态(set_input_status;eventType=1 输入中,0 停止)。 */
|
|
1495
1536
|
async setInputStatus(target, eventType) {
|
|
1496
1537
|
await this.service.sendShowInputStatusReq(target.chatType, eventType, target.peerUid);
|
|
@@ -2091,7 +2132,8 @@ var GroupBridge = class {
|
|
|
2091
2132
|
onMemberInfoChange: (groupCode, dataSource, members) => this.channel.emit("Group/onMemberInfoChange", groupCode, dataSource, members),
|
|
2092
2133
|
onGroupNotifiesUpdated: (doubt, notifies) => this.channel.emit("Group/onGroupNotifiesUpdated", doubt, notifies),
|
|
2093
2134
|
onGroupSingleScreenNotifies: (doubt, seq, notifies) => this.channel.emit("Group/onGroupSingleScreenNotifies", doubt, seq, notifies),
|
|
2094
|
-
onShutUpMemberListChanged: (groupCode, members) => this.channel.emit("Group/onShutUpMemberListChanged", groupCode, members)
|
|
2135
|
+
onShutUpMemberListChanged: (groupCode, members) => this.channel.emit("Group/onShutUpMemberListChanged", groupCode, members),
|
|
2136
|
+
onGroupEssenceListChange: (arg) => this.channel.emit("Group/onGroupEssenceListChange", arg)
|
|
2095
2137
|
};
|
|
2096
2138
|
this.listenerId = this.service.addKernelGroupListener(listener);
|
|
2097
2139
|
}
|
|
@@ -2125,7 +2167,10 @@ var MsgBridge = class {
|
|
|
2125
2167
|
onRecvMsg: (msgs) => this.channel.emit("Msg/onRecvMsg", msgs),
|
|
2126
2168
|
onRecvMsgReadReport: (reports) => this.channel.emit("Msg/onRecvMsgReadReport", reports),
|
|
2127
2169
|
onRecvMsgReceipt: (receipts) => this.channel.emit("Msg/onRecvMsgReceipt", receipts),
|
|
2128
|
-
onMsgInfoListUpdate: (msgs) => this.channel.emit("Msg/onMsgInfoListUpdate", msgs)
|
|
2170
|
+
onMsgInfoListUpdate: (msgs) => this.channel.emit("Msg/onMsgInfoListUpdate", msgs),
|
|
2171
|
+
onRecvOfflineFileMsg: (arg) => this.channel.emit("Msg/onRecvOfflineFileMsg", arg),
|
|
2172
|
+
onRecvOnlineFileMsg: (arg) => this.channel.emit("Msg/onRecvOnlineFileMsg", arg),
|
|
2173
|
+
onRecvSysMsg: (arg) => this.channel.emit("Msg/onRecvSysMsg", arg)
|
|
2129
2174
|
};
|
|
2130
2175
|
this.listenerId = this.service.addKernelMsgListener(listener);
|
|
2131
2176
|
}
|
|
@@ -2137,6 +2182,193 @@ var MsgBridge = class {
|
|
|
2137
2182
|
}
|
|
2138
2183
|
};
|
|
2139
2184
|
//#endregion
|
|
2185
|
+
//#region src/event-channel.ts
|
|
2186
|
+
/**
|
|
2187
|
+
* 类型化事件通道(ADR-003)
|
|
2188
|
+
*
|
|
2189
|
+
* - 事件名约定 `${Service}/${method}`(如 "Msg/onRecvMsg"),签名从 Listener 接口编译期推导
|
|
2190
|
+
* - 事件名写错 → 编译期报错(类型推导)
|
|
2191
|
+
* - `on` 返回 unsubscribe;`waitFor` 注册临时监听 → filter → 超时自动清理(替代魔法字符串方案)
|
|
2192
|
+
* - error 兜底:监听器抛异常不打断派发,统一经 `onError` 通知
|
|
2193
|
+
*
|
|
2194
|
+
* 组合实现而非 extends EventEmitter:EventEmitter.on 返回 `this`,与设计要求的
|
|
2195
|
+
* 返回 unsubscribe 冲突;组合更干净,且内核无全局单例(ADR-015 推论)。
|
|
2196
|
+
*
|
|
2197
|
+
* 类型推导说明:不直接 `ListenerEvents<L, Name>[E]` 索引(泛型下会扩宽到
|
|
2198
|
+
* string|number|symbol 索引,索引出 unknown),而是用 Extract 按事件名从
|
|
2199
|
+
* `{ name, fn }` 联合精确提取 handler / 参数类型,保证实例化后签名精确。
|
|
2200
|
+
*/
|
|
2201
|
+
/** waitFor 默认超时(毫秒)。 */
|
|
2202
|
+
const DEFAULT_WAIT_TIMEOUT_MS = 3e4;
|
|
2203
|
+
/**
|
|
2204
|
+
* 类型化事件通道。
|
|
2205
|
+
*
|
|
2206
|
+
* @typeParam L - Listener 接口(探测产物,如 MsgListener)
|
|
2207
|
+
* @typeParam Name - Service 名(事件名前缀,如 "Msg")
|
|
2208
|
+
*/
|
|
2209
|
+
var NTEventChannel = class {
|
|
2210
|
+
serviceName;
|
|
2211
|
+
emitter = new EventEmitter();
|
|
2212
|
+
errorHandlers = /* @__PURE__ */ new Set();
|
|
2213
|
+
anyHandlers = /* @__PURE__ */ new Set();
|
|
2214
|
+
constructor(serviceName) {
|
|
2215
|
+
this.serviceName = serviceName;
|
|
2216
|
+
this.emitter.setMaxListeners(0);
|
|
2217
|
+
}
|
|
2218
|
+
/**
|
|
2219
|
+
* 订阅事件:返回 unsubscribe(只注销该 handler,不影响其他订阅者)。
|
|
2220
|
+
* 每个 Service 只注册一次原生监听,缓存维护与协议翻译都订阅这里。
|
|
2221
|
+
*/
|
|
2222
|
+
on(event, handler) {
|
|
2223
|
+
this.emitter.addListener(event, handler);
|
|
2224
|
+
return () => {
|
|
2225
|
+
this.emitter.removeListener(event, handler);
|
|
2226
|
+
};
|
|
2227
|
+
}
|
|
2228
|
+
/**
|
|
2229
|
+
* 请求-响应桥:注册临时监听 → filter 命中 → resolve;超时自动清理并 reject。
|
|
2230
|
+
* 替代魔法字符串事件名方案。
|
|
2231
|
+
*/
|
|
2232
|
+
waitFor(event, opts = {}) {
|
|
2233
|
+
const timeoutMs = opts.timeout ?? DEFAULT_WAIT_TIMEOUT_MS;
|
|
2234
|
+
return new Promise((resolve, reject) => {
|
|
2235
|
+
const handler = (...args) => {
|
|
2236
|
+
if (opts.filter && !opts.filter(...args)) return;
|
|
2237
|
+
cleanup();
|
|
2238
|
+
resolve(args);
|
|
2239
|
+
};
|
|
2240
|
+
const timer = setTimeout(() => {
|
|
2241
|
+
cleanup();
|
|
2242
|
+
reject(new KernelError(`等待事件超时: ${event}`, "TIMEOUT"));
|
|
2243
|
+
}, timeoutMs);
|
|
2244
|
+
const cleanup = () => {
|
|
2245
|
+
clearTimeout(timer);
|
|
2246
|
+
this.emitter.removeListener(event, handler);
|
|
2247
|
+
};
|
|
2248
|
+
this.emitter.addListener(event, handler);
|
|
2249
|
+
});
|
|
2250
|
+
}
|
|
2251
|
+
/**
|
|
2252
|
+
* 类型化派发:wrapper-loader 的原生回调经此推入通道。
|
|
2253
|
+
* 2026-08-07 修复:原生 EventEmitter.emit 中一个 listener 抛异常会中断后续
|
|
2254
|
+
* listener 派发(Node 语义)——改为快照数组逐个 try/catch,保证「单个订阅者
|
|
2255
|
+
* 异常不打断派发」(协议翻译层异常不饿死缓存维护等其他订阅者)。
|
|
2256
|
+
*/
|
|
2257
|
+
/**
|
|
2258
|
+
* 订阅所有事件(IPC 子进程模式整通道转发用:事件名 `"${service}/${method}"`
|
|
2259
|
+
* 经 handler 首参透出,args 原样透传)。返回退订函数。
|
|
2260
|
+
*/
|
|
2261
|
+
onAny(handler) {
|
|
2262
|
+
this.anyHandlers.add(handler);
|
|
2263
|
+
return () => {
|
|
2264
|
+
this.anyHandlers.delete(handler);
|
|
2265
|
+
};
|
|
2266
|
+
}
|
|
2267
|
+
emit(event, ...args) {
|
|
2268
|
+
for (const anyHandler of this.anyHandlers) try {
|
|
2269
|
+
anyHandler(event, ...args);
|
|
2270
|
+
} catch (err) {
|
|
2271
|
+
this.notifyError(err);
|
|
2272
|
+
}
|
|
2273
|
+
const listeners = this.emitter.listeners(event);
|
|
2274
|
+
for (const listener of listeners) try {
|
|
2275
|
+
listener(...args);
|
|
2276
|
+
} catch (err) {
|
|
2277
|
+
this.notifyError(err);
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
/** 通知所有错误处理器(单个异常不打断其他处理器)。 */
|
|
2281
|
+
notifyError(err) {
|
|
2282
|
+
for (const handler of this.errorHandlers) handler(err);
|
|
2283
|
+
}
|
|
2284
|
+
/** 订阅错误通知(监听器抛出的异常 / 其他内部错误)。 */
|
|
2285
|
+
onError(handler) {
|
|
2286
|
+
this.errorHandlers.add(handler);
|
|
2287
|
+
return () => {
|
|
2288
|
+
this.errorHandlers.delete(handler);
|
|
2289
|
+
};
|
|
2290
|
+
}
|
|
2291
|
+
};
|
|
2292
|
+
//#endregion
|
|
2293
|
+
//#region src/cache/buddy-cache.ts
|
|
2294
|
+
/**
|
|
2295
|
+
* 防御性收窄 onBuddyListChange 载荷 → BuddyCategory[](T10 实证形状;
|
|
2296
|
+
* 非数组返回 null,调用方打 raw 日志积累校准数据)。
|
|
2297
|
+
*/
|
|
2298
|
+
function narrowBuddyCategories(arg) {
|
|
2299
|
+
if (!Array.isArray(arg)) return null;
|
|
2300
|
+
for (const item of arg) if (item === null || typeof item !== "object") return null;
|
|
2301
|
+
return arg;
|
|
2302
|
+
}
|
|
2303
|
+
/** 从快照分类拍平好友明细(buddyList 缺失的分类跳过)。 */
|
|
2304
|
+
function flattenEntries(categories) {
|
|
2305
|
+
const out = [];
|
|
2306
|
+
for (const cat of categories) for (const entry of cat.buddyList ?? []) if (typeof entry?.uid === "string" && entry.uid !== "") out.push(entry);
|
|
2307
|
+
return out;
|
|
2308
|
+
}
|
|
2309
|
+
/** 好友缓存:快照维护 + diff 归一化事件。 */
|
|
2310
|
+
var BuddyCache = class {
|
|
2311
|
+
channel;
|
|
2312
|
+
logger;
|
|
2313
|
+
/** diff 归一化事件通道(协议层订阅 friend_add / IPC 转发消费)。 */
|
|
2314
|
+
events = new NTEventChannel("BuddyCache");
|
|
2315
|
+
/** 好友快照(uid → entry,onBuddyListChange 全量维护)。 */
|
|
2316
|
+
buddies = /* @__PURE__ */ new Map();
|
|
2317
|
+
/** 首帧已建 baseline(此后快照才参与 diff)。 */
|
|
2318
|
+
bootstrapped = false;
|
|
2319
|
+
unsubscribes = null;
|
|
2320
|
+
constructor(opts) {
|
|
2321
|
+
this.channel = opts.channel;
|
|
2322
|
+
this.logger = opts.logger;
|
|
2323
|
+
}
|
|
2324
|
+
/** 订阅 Buddy 事件通道(幂等)。 */
|
|
2325
|
+
register() {
|
|
2326
|
+
if (this.unsubscribes !== null) return;
|
|
2327
|
+
const unsub = this.channel.on("Buddy/onBuddyListChange", (arg) => {
|
|
2328
|
+
const categories = narrowBuddyCategories(arg);
|
|
2329
|
+
if (categories === null) {
|
|
2330
|
+
this.logger?.warn({ raw: JSON.stringify(arg)?.slice(0, 2e3) }, "BuddyCache: onBuddyListChange 未知载荷形状");
|
|
2331
|
+
return;
|
|
2332
|
+
}
|
|
2333
|
+
this.applySnapshot(flattenEntries(categories));
|
|
2334
|
+
});
|
|
2335
|
+
this.unsubscribes = unsub;
|
|
2336
|
+
}
|
|
2337
|
+
/** 退订事件通道(幂等)。 */
|
|
2338
|
+
unregister() {
|
|
2339
|
+
this.unsubscribes?.();
|
|
2340
|
+
this.unsubscribes = null;
|
|
2341
|
+
this.buddies.clear();
|
|
2342
|
+
this.bootstrapped = false;
|
|
2343
|
+
}
|
|
2344
|
+
/** 应用全量快照:首帧建 baseline,之后 diff 发布归一化事件。 */
|
|
2345
|
+
applySnapshot(entries) {
|
|
2346
|
+
if (!this.bootstrapped) {
|
|
2347
|
+
for (const entry of entries) this.buddies.set(entry.uid, entry);
|
|
2348
|
+
this.bootstrapped = true;
|
|
2349
|
+
return;
|
|
2350
|
+
}
|
|
2351
|
+
const next = /* @__PURE__ */ new Map();
|
|
2352
|
+
for (const entry of entries) next.set(entry.uid, entry);
|
|
2353
|
+
for (const [uid, entry] of next) if (!this.buddies.has(uid)) this.events.emit("BuddyCache/onBuddyAdded", entry);
|
|
2354
|
+
for (const [uid, entry] of this.buddies) if (!next.has(uid)) this.events.emit("BuddyCache/onBuddyRemoved", entry);
|
|
2355
|
+
this.buddies.clear();
|
|
2356
|
+
for (const [uid, entry] of next) this.buddies.set(uid, entry);
|
|
2357
|
+
}
|
|
2358
|
+
/** 好友快照(只读拷贝)。 */
|
|
2359
|
+
listBuddies() {
|
|
2360
|
+
return [...this.buddies.values()];
|
|
2361
|
+
}
|
|
2362
|
+
/** 单个好友(快照;undefined = 不在缓存)。 */
|
|
2363
|
+
getBuddy(uid) {
|
|
2364
|
+
return this.buddies.get(uid);
|
|
2365
|
+
}
|
|
2366
|
+
/** 快照是否已建(测试/诊断用)。 */
|
|
2367
|
+
get baselineReady() {
|
|
2368
|
+
return this.bootstrapped;
|
|
2369
|
+
}
|
|
2370
|
+
};
|
|
2371
|
+
//#endregion
|
|
2140
2372
|
//#region src/login/wait.ts
|
|
2141
2373
|
/**
|
|
2142
2374
|
* 等待/延迟工具(login 模块共享,2026-08-08 克隆合并)
|
|
@@ -3529,114 +3761,6 @@ function resolveCommonPath(ctx, wrapper) {
|
|
|
3529
3761
|
return ctx.paths.accountDir;
|
|
3530
3762
|
}
|
|
3531
3763
|
//#endregion
|
|
3532
|
-
//#region src/event-channel.ts
|
|
3533
|
-
/**
|
|
3534
|
-
* 类型化事件通道(ADR-003)
|
|
3535
|
-
*
|
|
3536
|
-
* - 事件名约定 `${Service}/${method}`(如 "Msg/onRecvMsg"),签名从 Listener 接口编译期推导
|
|
3537
|
-
* - 事件名写错 → 编译期报错(类型推导)
|
|
3538
|
-
* - `on` 返回 unsubscribe;`waitFor` 注册临时监听 → filter → 超时自动清理(替代魔法字符串方案)
|
|
3539
|
-
* - error 兜底:监听器抛异常不打断派发,统一经 `onError` 通知
|
|
3540
|
-
*
|
|
3541
|
-
* 组合实现而非 extends EventEmitter:EventEmitter.on 返回 `this`,与设计要求的
|
|
3542
|
-
* 返回 unsubscribe 冲突;组合更干净,且内核无全局单例(ADR-015 推论)。
|
|
3543
|
-
*
|
|
3544
|
-
* 类型推导说明:不直接 `ListenerEvents<L, Name>[E]` 索引(泛型下会扩宽到
|
|
3545
|
-
* string|number|symbol 索引,索引出 unknown),而是用 Extract 按事件名从
|
|
3546
|
-
* `{ name, fn }` 联合精确提取 handler / 参数类型,保证实例化后签名精确。
|
|
3547
|
-
*/
|
|
3548
|
-
/** waitFor 默认超时(毫秒)。 */
|
|
3549
|
-
const DEFAULT_WAIT_TIMEOUT_MS = 3e4;
|
|
3550
|
-
/**
|
|
3551
|
-
* 类型化事件通道。
|
|
3552
|
-
*
|
|
3553
|
-
* @typeParam L - Listener 接口(探测产物,如 MsgListener)
|
|
3554
|
-
* @typeParam Name - Service 名(事件名前缀,如 "Msg")
|
|
3555
|
-
*/
|
|
3556
|
-
var NTEventChannel = class {
|
|
3557
|
-
serviceName;
|
|
3558
|
-
emitter = new EventEmitter();
|
|
3559
|
-
errorHandlers = /* @__PURE__ */ new Set();
|
|
3560
|
-
anyHandlers = /* @__PURE__ */ new Set();
|
|
3561
|
-
constructor(serviceName) {
|
|
3562
|
-
this.serviceName = serviceName;
|
|
3563
|
-
this.emitter.setMaxListeners(0);
|
|
3564
|
-
}
|
|
3565
|
-
/**
|
|
3566
|
-
* 订阅事件:返回 unsubscribe(只注销该 handler,不影响其他订阅者)。
|
|
3567
|
-
* 每个 Service 只注册一次原生监听,缓存维护与协议翻译都订阅这里。
|
|
3568
|
-
*/
|
|
3569
|
-
on(event, handler) {
|
|
3570
|
-
this.emitter.addListener(event, handler);
|
|
3571
|
-
return () => {
|
|
3572
|
-
this.emitter.removeListener(event, handler);
|
|
3573
|
-
};
|
|
3574
|
-
}
|
|
3575
|
-
/**
|
|
3576
|
-
* 请求-响应桥:注册临时监听 → filter 命中 → resolve;超时自动清理并 reject。
|
|
3577
|
-
* 替代魔法字符串事件名方案。
|
|
3578
|
-
*/
|
|
3579
|
-
waitFor(event, opts = {}) {
|
|
3580
|
-
const timeoutMs = opts.timeout ?? DEFAULT_WAIT_TIMEOUT_MS;
|
|
3581
|
-
return new Promise((resolve, reject) => {
|
|
3582
|
-
const handler = (...args) => {
|
|
3583
|
-
if (opts.filter && !opts.filter(...args)) return;
|
|
3584
|
-
cleanup();
|
|
3585
|
-
resolve(args);
|
|
3586
|
-
};
|
|
3587
|
-
const timer = setTimeout(() => {
|
|
3588
|
-
cleanup();
|
|
3589
|
-
reject(new KernelError(`等待事件超时: ${event}`, "TIMEOUT"));
|
|
3590
|
-
}, timeoutMs);
|
|
3591
|
-
const cleanup = () => {
|
|
3592
|
-
clearTimeout(timer);
|
|
3593
|
-
this.emitter.removeListener(event, handler);
|
|
3594
|
-
};
|
|
3595
|
-
this.emitter.addListener(event, handler);
|
|
3596
|
-
});
|
|
3597
|
-
}
|
|
3598
|
-
/**
|
|
3599
|
-
* 类型化派发:wrapper-loader 的原生回调经此推入通道。
|
|
3600
|
-
* 2026-08-07 修复:原生 EventEmitter.emit 中一个 listener 抛异常会中断后续
|
|
3601
|
-
* listener 派发(Node 语义)——改为快照数组逐个 try/catch,保证「单个订阅者
|
|
3602
|
-
* 异常不打断派发」(协议翻译层异常不饿死缓存维护等其他订阅者)。
|
|
3603
|
-
*/
|
|
3604
|
-
/**
|
|
3605
|
-
* 订阅所有事件(IPC 子进程模式整通道转发用:事件名 `"${service}/${method}"`
|
|
3606
|
-
* 经 handler 首参透出,args 原样透传)。返回退订函数。
|
|
3607
|
-
*/
|
|
3608
|
-
onAny(handler) {
|
|
3609
|
-
this.anyHandlers.add(handler);
|
|
3610
|
-
return () => {
|
|
3611
|
-
this.anyHandlers.delete(handler);
|
|
3612
|
-
};
|
|
3613
|
-
}
|
|
3614
|
-
emit(event, ...args) {
|
|
3615
|
-
for (const anyHandler of this.anyHandlers) try {
|
|
3616
|
-
anyHandler(event, ...args);
|
|
3617
|
-
} catch (err) {
|
|
3618
|
-
this.notifyError(err);
|
|
3619
|
-
}
|
|
3620
|
-
const listeners = this.emitter.listeners(event);
|
|
3621
|
-
for (const listener of listeners) try {
|
|
3622
|
-
listener(...args);
|
|
3623
|
-
} catch (err) {
|
|
3624
|
-
this.notifyError(err);
|
|
3625
|
-
}
|
|
3626
|
-
}
|
|
3627
|
-
/** 通知所有错误处理器(单个异常不打断其他处理器)。 */
|
|
3628
|
-
notifyError(err) {
|
|
3629
|
-
for (const handler of this.errorHandlers) handler(err);
|
|
3630
|
-
}
|
|
3631
|
-
/** 订阅错误通知(监听器抛出的异常 / 其他内部错误)。 */
|
|
3632
|
-
onError(handler) {
|
|
3633
|
-
this.errorHandlers.add(handler);
|
|
3634
|
-
return () => {
|
|
3635
|
-
this.errorHandlers.delete(handler);
|
|
3636
|
-
};
|
|
3637
|
-
}
|
|
3638
|
-
};
|
|
3639
|
-
//#endregion
|
|
3640
3764
|
//#region src/wrapper/session-resolver.ts
|
|
3641
3765
|
/** 从 getSessionIdList 的 Map 提取主 sessionId(nt_ 前缀优先)。 */
|
|
3642
3766
|
function findMainSessionId(ids) {
|
|
@@ -4211,6 +4335,6 @@ function listQQVersions(installDir) {
|
|
|
4211
4335
|
}).sort().reverse();
|
|
4212
4336
|
}
|
|
4213
4337
|
//#endregion
|
|
4214
|
-
export { ChatType, ConfigBase, DEFAULT_DATA_ROOT_NAME, ElementType, FriendApi, FriendBridge, GrayTipSubType, GroupApi, GroupBridge, GroupCache, GroupListUpdateType, GroupNotifyApi, GroupNotifyMsgStatus, GroupNotifyMsgType, KERNEL_ERROR_CODES, KernelError, MAIN_CONFIG_FILE, MsgApi, MsgBridge, NTEventChannel, NTGroupMemberRole, NTGroupRequestOperateTypes, NapukettoCore, PathWrapper, ProfileApi, ProfileLikeApi, QrLoginSession, RichMediaApi, TicketApi, TipGroupElementType, WebApi, WebHonorType, 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 };
|
|
4338
|
+
export { BuddyCache, ChatType, ConfigBase, DEFAULT_DATA_ROOT_NAME, ElementType, FriendApi, FriendBridge, GrayTipSubType, GroupApi, GroupBridge, GroupCache, GroupListUpdateType, GroupNotifyApi, GroupNotifyMsgStatus, GroupNotifyMsgType, KERNEL_ERROR_CODES, KernelError, MAIN_CONFIG_FILE, MsgApi, MsgBridge, NTEventChannel, NTGroupMemberRole, NTGroupRequestOperateTypes, NapukettoCore, PathWrapper, ProfileApi, ProfileLikeApi, QrLoginSession, RichMediaApi, TicketApi, TipGroupElementType, WebApi, WebHonorType, buildEngineConfig, buildLoginConfig, buildSessionConfig, createCoreContext, createSessionListener as createLifecycleSessionListener, createSessionListener, createLogger, createLoginListener, createSession, createWrapper, electronProcessType, getExistingSession, getMainSession, initAndStartSession, initEngine, initSession, isKernelError, kernelError, listLoginAccounts, listQQVersions, narrowBuddyCategories, parseAppidFromMajor, parseToml, probeRuntime, quickLogin, readMachineGuid, resolveAppidQua, resolveConfigPath, resolveDataRoot, resolveQQVersion, resolveQqGlobalPath, resolveQqUserDataRoot, resolveWrapperPath, startNapuketto, startSession, stringifyToml, toCanonicalElements, toSendElements, waitForNetworkConnection, waitSessionReady };
|
|
4215
4339
|
|
|
4216
4340
|
//# sourceMappingURL=index.mjs.map
|