@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 CHANGED
@@ -455,7 +455,7 @@ var FriendApi = class {
455
455
  if (raw.result !== 0) throw kernelError(`getBuddyListV2 失败: ${raw.errMsg}`, "UNKNOWN");
456
456
  categories = raw.data;
457
457
  }
458
- const uids = categories.flatMap((cat) => cat.buddyUids);
458
+ const uids = categories.flatMap((cat) => cat.buddyList?.map((b) => b.uid) ?? cat.buddyUids ?? []);
459
459
  let uinMap = /* @__PURE__ */ new Map();
460
460
  if (this.uidToUin !== void 0) uinMap = await this.uidToUin(uids);
461
461
  const out = [];
@@ -474,7 +474,7 @@ var FriendApi = class {
474
474
  for (const friend of await this.getFriendList()) friendMap.set(friend.uid, friend);
475
475
  return categories.map((cat) => {
476
476
  const buddies = [];
477
- for (const uid of cat.buddyUids) {
477
+ for (const uid of cat.buddyList?.map((b) => b.uid) ?? cat.buddyUids ?? []) {
478
478
  const friend = friendMap.get(uid);
479
479
  if (friend !== void 0) buddies.push(friend);
480
480
  }
@@ -1257,6 +1257,18 @@ const PTT_WAVE_AMPLITUDES = [
1257
1257
  15,
1258
1258
  17
1259
1259
  ];
1260
+ /** downloadRichMedia 契约值(2026-09-08 B1 实测:downloadType=2 可用 / thumbSize=0)。 */
1261
+ const DOWNLOAD_TYPE_COMMON = 2;
1262
+ const THUMB_SIZE_NONE = 0;
1263
+ /** 语音下载轮询参数(300ms × 34 ≈ 10s;返回 void 只能经重拉元素观察完成)。 */
1264
+ const PTT_POLL_INTERVAL_MS = 300;
1265
+ const PTT_POLL_TIMES = 34;
1266
+ /** sleep(下载轮询间隔)。 */
1267
+ function sleep$1(ms) {
1268
+ return new Promise((resolve) => {
1269
+ setTimeout(resolve, ms);
1270
+ });
1271
+ }
1260
1272
  /** 读文件 stat(富媒体发送预处理;文件不存在抛 INVALID_PARAM)。 */
1261
1273
  async function statFile(path) {
1262
1274
  try {
@@ -1517,6 +1529,35 @@ var MsgApi = class {
1517
1529
  async markRead(target) {
1518
1530
  unwrapResult("setMsgRead", await this.service.setMsgRead(target));
1519
1531
  }
1532
+ /**
1533
+ * 语音主动下载(get_record 本地未命中兜底,2026-09-08 B1)。
1534
+ * downloadRichMedia 返回 void(实测),完成信号 = 重拉消息元素:
1535
+ * 轮询(300ms × 34,约 10s)直到 filePath 非空且 transferStatus 进入
1536
+ * 已下载态(2/4);超时但 filePath 已有值则尽力返回(磁盘命中判断留给
1537
+ * 调用方),完全无路径抛 NOT_FOUND。
1538
+ */
1539
+ async downloadPtt(msgId, target) {
1540
+ const el = findPttElement(await this.fetchMsgsByMsgId(target, [msgId]));
1541
+ const ptt = el?.pttElement;
1542
+ if (el === null || ptt === void 0) throw kernelError("消息中不包含语音", "NOT_FOUND");
1543
+ const elemId = el.elementId ?? "";
1544
+ await this.service.downloadRichMedia({
1545
+ msgId,
1546
+ elemId,
1547
+ chatType: target.chatType,
1548
+ downloadType: DOWNLOAD_TYPE_COMMON,
1549
+ thumbSize: THUMB_SIZE_NONE
1550
+ });
1551
+ for (let i = 0; i < PTT_POLL_TIMES; i++) {
1552
+ await sleep$1(PTT_POLL_INTERVAL_MS);
1553
+ const latest = findPttElement(await this.fetchMsgsByMsgId(target, [msgId]))?.pttElement;
1554
+ if (latest === void 0) continue;
1555
+ const done = latest.transferStatus === 2 || latest.transferStatus === 4;
1556
+ if (latest.filePath !== void 0 && latest.filePath !== "" && done) return latest;
1557
+ if (i === 33 && latest.filePath !== void 0 && latest.filePath !== "") return latest;
1558
+ }
1559
+ throw kernelError("语音下载未完成(超时)", "TIMEOUT");
1560
+ }
1520
1561
  /** 发送输入状态(set_input_status;eventType=1 输入中,0 停止)。 */
1521
1562
  async setInputStatus(target, eventType) {
1522
1563
  await this.service.sendShowInputStatusReq(target.chatType, eventType, target.peerUid);
@@ -2117,7 +2158,8 @@ var GroupBridge = class {
2117
2158
  onMemberInfoChange: (groupCode, dataSource, members) => this.channel.emit("Group/onMemberInfoChange", groupCode, dataSource, members),
2118
2159
  onGroupNotifiesUpdated: (doubt, notifies) => this.channel.emit("Group/onGroupNotifiesUpdated", doubt, notifies),
2119
2160
  onGroupSingleScreenNotifies: (doubt, seq, notifies) => this.channel.emit("Group/onGroupSingleScreenNotifies", doubt, seq, notifies),
2120
- onShutUpMemberListChanged: (groupCode, members) => this.channel.emit("Group/onShutUpMemberListChanged", groupCode, members)
2161
+ onShutUpMemberListChanged: (groupCode, members) => this.channel.emit("Group/onShutUpMemberListChanged", groupCode, members),
2162
+ onGroupEssenceListChange: (arg) => this.channel.emit("Group/onGroupEssenceListChange", arg)
2121
2163
  };
2122
2164
  this.listenerId = this.service.addKernelGroupListener(listener);
2123
2165
  }
@@ -2151,7 +2193,10 @@ var MsgBridge = class {
2151
2193
  onRecvMsg: (msgs) => this.channel.emit("Msg/onRecvMsg", msgs),
2152
2194
  onRecvMsgReadReport: (reports) => this.channel.emit("Msg/onRecvMsgReadReport", reports),
2153
2195
  onRecvMsgReceipt: (receipts) => this.channel.emit("Msg/onRecvMsgReceipt", receipts),
2154
- onMsgInfoListUpdate: (msgs) => this.channel.emit("Msg/onMsgInfoListUpdate", msgs)
2196
+ onMsgInfoListUpdate: (msgs) => this.channel.emit("Msg/onMsgInfoListUpdate", msgs),
2197
+ onRecvOfflineFileMsg: (arg) => this.channel.emit("Msg/onRecvOfflineFileMsg", arg),
2198
+ onRecvOnlineFileMsg: (arg) => this.channel.emit("Msg/onRecvOnlineFileMsg", arg),
2199
+ onRecvSysMsg: (arg) => this.channel.emit("Msg/onRecvSysMsg", arg)
2155
2200
  };
2156
2201
  this.listenerId = this.service.addKernelMsgListener(listener);
2157
2202
  }
@@ -2163,6 +2208,193 @@ var MsgBridge = class {
2163
2208
  }
2164
2209
  };
2165
2210
  //#endregion
2211
+ //#region src/event-channel.ts
2212
+ /**
2213
+ * 类型化事件通道(ADR-003)
2214
+ *
2215
+ * - 事件名约定 `${Service}/${method}`(如 "Msg/onRecvMsg"),签名从 Listener 接口编译期推导
2216
+ * - 事件名写错 → 编译期报错(类型推导)
2217
+ * - `on` 返回 unsubscribe;`waitFor` 注册临时监听 → filter → 超时自动清理(替代魔法字符串方案)
2218
+ * - error 兜底:监听器抛异常不打断派发,统一经 `onError` 通知
2219
+ *
2220
+ * 组合实现而非 extends EventEmitter:EventEmitter.on 返回 `this`,与设计要求的
2221
+ * 返回 unsubscribe 冲突;组合更干净,且内核无全局单例(ADR-015 推论)。
2222
+ *
2223
+ * 类型推导说明:不直接 `ListenerEvents<L, Name>[E]` 索引(泛型下会扩宽到
2224
+ * string|number|symbol 索引,索引出 unknown),而是用 Extract 按事件名从
2225
+ * `{ name, fn }` 联合精确提取 handler / 参数类型,保证实例化后签名精确。
2226
+ */
2227
+ /** waitFor 默认超时(毫秒)。 */
2228
+ const DEFAULT_WAIT_TIMEOUT_MS = 3e4;
2229
+ /**
2230
+ * 类型化事件通道。
2231
+ *
2232
+ * @typeParam L - Listener 接口(探测产物,如 MsgListener)
2233
+ * @typeParam Name - Service 名(事件名前缀,如 "Msg")
2234
+ */
2235
+ var NTEventChannel = class {
2236
+ serviceName;
2237
+ emitter = new node_events.EventEmitter();
2238
+ errorHandlers = /* @__PURE__ */ new Set();
2239
+ anyHandlers = /* @__PURE__ */ new Set();
2240
+ constructor(serviceName) {
2241
+ this.serviceName = serviceName;
2242
+ this.emitter.setMaxListeners(0);
2243
+ }
2244
+ /**
2245
+ * 订阅事件:返回 unsubscribe(只注销该 handler,不影响其他订阅者)。
2246
+ * 每个 Service 只注册一次原生监听,缓存维护与协议翻译都订阅这里。
2247
+ */
2248
+ on(event, handler) {
2249
+ this.emitter.addListener(event, handler);
2250
+ return () => {
2251
+ this.emitter.removeListener(event, handler);
2252
+ };
2253
+ }
2254
+ /**
2255
+ * 请求-响应桥:注册临时监听 → filter 命中 → resolve;超时自动清理并 reject。
2256
+ * 替代魔法字符串事件名方案。
2257
+ */
2258
+ waitFor(event, opts = {}) {
2259
+ const timeoutMs = opts.timeout ?? DEFAULT_WAIT_TIMEOUT_MS;
2260
+ return new Promise((resolve, reject) => {
2261
+ const handler = (...args) => {
2262
+ if (opts.filter && !opts.filter(...args)) return;
2263
+ cleanup();
2264
+ resolve(args);
2265
+ };
2266
+ const timer = setTimeout(() => {
2267
+ cleanup();
2268
+ reject(new KernelError(`等待事件超时: ${event}`, "TIMEOUT"));
2269
+ }, timeoutMs);
2270
+ const cleanup = () => {
2271
+ clearTimeout(timer);
2272
+ this.emitter.removeListener(event, handler);
2273
+ };
2274
+ this.emitter.addListener(event, handler);
2275
+ });
2276
+ }
2277
+ /**
2278
+ * 类型化派发:wrapper-loader 的原生回调经此推入通道。
2279
+ * 2026-08-07 修复:原生 EventEmitter.emit 中一个 listener 抛异常会中断后续
2280
+ * listener 派发(Node 语义)——改为快照数组逐个 try/catch,保证「单个订阅者
2281
+ * 异常不打断派发」(协议翻译层异常不饿死缓存维护等其他订阅者)。
2282
+ */
2283
+ /**
2284
+ * 订阅所有事件(IPC 子进程模式整通道转发用:事件名 `"${service}/${method}"`
2285
+ * 经 handler 首参透出,args 原样透传)。返回退订函数。
2286
+ */
2287
+ onAny(handler) {
2288
+ this.anyHandlers.add(handler);
2289
+ return () => {
2290
+ this.anyHandlers.delete(handler);
2291
+ };
2292
+ }
2293
+ emit(event, ...args) {
2294
+ for (const anyHandler of this.anyHandlers) try {
2295
+ anyHandler(event, ...args);
2296
+ } catch (err) {
2297
+ this.notifyError(err);
2298
+ }
2299
+ const listeners = this.emitter.listeners(event);
2300
+ for (const listener of listeners) try {
2301
+ listener(...args);
2302
+ } catch (err) {
2303
+ this.notifyError(err);
2304
+ }
2305
+ }
2306
+ /** 通知所有错误处理器(单个异常不打断其他处理器)。 */
2307
+ notifyError(err) {
2308
+ for (const handler of this.errorHandlers) handler(err);
2309
+ }
2310
+ /** 订阅错误通知(监听器抛出的异常 / 其他内部错误)。 */
2311
+ onError(handler) {
2312
+ this.errorHandlers.add(handler);
2313
+ return () => {
2314
+ this.errorHandlers.delete(handler);
2315
+ };
2316
+ }
2317
+ };
2318
+ //#endregion
2319
+ //#region src/cache/buddy-cache.ts
2320
+ /**
2321
+ * 防御性收窄 onBuddyListChange 载荷 → BuddyCategory[](T10 实证形状;
2322
+ * 非数组返回 null,调用方打 raw 日志积累校准数据)。
2323
+ */
2324
+ function narrowBuddyCategories(arg) {
2325
+ if (!Array.isArray(arg)) return null;
2326
+ for (const item of arg) if (item === null || typeof item !== "object") return null;
2327
+ return arg;
2328
+ }
2329
+ /** 从快照分类拍平好友明细(buddyList 缺失的分类跳过)。 */
2330
+ function flattenEntries(categories) {
2331
+ const out = [];
2332
+ for (const cat of categories) for (const entry of cat.buddyList ?? []) if (typeof entry?.uid === "string" && entry.uid !== "") out.push(entry);
2333
+ return out;
2334
+ }
2335
+ /** 好友缓存:快照维护 + diff 归一化事件。 */
2336
+ var BuddyCache = class {
2337
+ channel;
2338
+ logger;
2339
+ /** diff 归一化事件通道(协议层订阅 friend_add / IPC 转发消费)。 */
2340
+ events = new NTEventChannel("BuddyCache");
2341
+ /** 好友快照(uid → entry,onBuddyListChange 全量维护)。 */
2342
+ buddies = /* @__PURE__ */ new Map();
2343
+ /** 首帧已建 baseline(此后快照才参与 diff)。 */
2344
+ bootstrapped = false;
2345
+ unsubscribes = null;
2346
+ constructor(opts) {
2347
+ this.channel = opts.channel;
2348
+ this.logger = opts.logger;
2349
+ }
2350
+ /** 订阅 Buddy 事件通道(幂等)。 */
2351
+ register() {
2352
+ if (this.unsubscribes !== null) return;
2353
+ const unsub = this.channel.on("Buddy/onBuddyListChange", (arg) => {
2354
+ const categories = narrowBuddyCategories(arg);
2355
+ if (categories === null) {
2356
+ this.logger?.warn({ raw: JSON.stringify(arg)?.slice(0, 2e3) }, "BuddyCache: onBuddyListChange 未知载荷形状");
2357
+ return;
2358
+ }
2359
+ this.applySnapshot(flattenEntries(categories));
2360
+ });
2361
+ this.unsubscribes = unsub;
2362
+ }
2363
+ /** 退订事件通道(幂等)。 */
2364
+ unregister() {
2365
+ this.unsubscribes?.();
2366
+ this.unsubscribes = null;
2367
+ this.buddies.clear();
2368
+ this.bootstrapped = false;
2369
+ }
2370
+ /** 应用全量快照:首帧建 baseline,之后 diff 发布归一化事件。 */
2371
+ applySnapshot(entries) {
2372
+ if (!this.bootstrapped) {
2373
+ for (const entry of entries) this.buddies.set(entry.uid, entry);
2374
+ this.bootstrapped = true;
2375
+ return;
2376
+ }
2377
+ const next = /* @__PURE__ */ new Map();
2378
+ for (const entry of entries) next.set(entry.uid, entry);
2379
+ for (const [uid, entry] of next) if (!this.buddies.has(uid)) this.events.emit("BuddyCache/onBuddyAdded", entry);
2380
+ for (const [uid, entry] of this.buddies) if (!next.has(uid)) this.events.emit("BuddyCache/onBuddyRemoved", entry);
2381
+ this.buddies.clear();
2382
+ for (const [uid, entry] of next) this.buddies.set(uid, entry);
2383
+ }
2384
+ /** 好友快照(只读拷贝)。 */
2385
+ listBuddies() {
2386
+ return [...this.buddies.values()];
2387
+ }
2388
+ /** 单个好友(快照;undefined = 不在缓存)。 */
2389
+ getBuddy(uid) {
2390
+ return this.buddies.get(uid);
2391
+ }
2392
+ /** 快照是否已建(测试/诊断用)。 */
2393
+ get baselineReady() {
2394
+ return this.bootstrapped;
2395
+ }
2396
+ };
2397
+ //#endregion
2166
2398
  //#region src/login/wait.ts
2167
2399
  /**
2168
2400
  * 等待/延迟工具(login 模块共享,2026-08-08 克隆合并)
@@ -3555,114 +3787,6 @@ function resolveCommonPath(ctx, wrapper) {
3555
3787
  return ctx.paths.accountDir;
3556
3788
  }
3557
3789
  //#endregion
3558
- //#region src/event-channel.ts
3559
- /**
3560
- * 类型化事件通道(ADR-003)
3561
- *
3562
- * - 事件名约定 `${Service}/${method}`(如 "Msg/onRecvMsg"),签名从 Listener 接口编译期推导
3563
- * - 事件名写错 → 编译期报错(类型推导)
3564
- * - `on` 返回 unsubscribe;`waitFor` 注册临时监听 → filter → 超时自动清理(替代魔法字符串方案)
3565
- * - error 兜底:监听器抛异常不打断派发,统一经 `onError` 通知
3566
- *
3567
- * 组合实现而非 extends EventEmitter:EventEmitter.on 返回 `this`,与设计要求的
3568
- * 返回 unsubscribe 冲突;组合更干净,且内核无全局单例(ADR-015 推论)。
3569
- *
3570
- * 类型推导说明:不直接 `ListenerEvents<L, Name>[E]` 索引(泛型下会扩宽到
3571
- * string|number|symbol 索引,索引出 unknown),而是用 Extract 按事件名从
3572
- * `{ name, fn }` 联合精确提取 handler / 参数类型,保证实例化后签名精确。
3573
- */
3574
- /** waitFor 默认超时(毫秒)。 */
3575
- const DEFAULT_WAIT_TIMEOUT_MS = 3e4;
3576
- /**
3577
- * 类型化事件通道。
3578
- *
3579
- * @typeParam L - Listener 接口(探测产物,如 MsgListener)
3580
- * @typeParam Name - Service 名(事件名前缀,如 "Msg")
3581
- */
3582
- var NTEventChannel = class {
3583
- serviceName;
3584
- emitter = new node_events.EventEmitter();
3585
- errorHandlers = /* @__PURE__ */ new Set();
3586
- anyHandlers = /* @__PURE__ */ new Set();
3587
- constructor(serviceName) {
3588
- this.serviceName = serviceName;
3589
- this.emitter.setMaxListeners(0);
3590
- }
3591
- /**
3592
- * 订阅事件:返回 unsubscribe(只注销该 handler,不影响其他订阅者)。
3593
- * 每个 Service 只注册一次原生监听,缓存维护与协议翻译都订阅这里。
3594
- */
3595
- on(event, handler) {
3596
- this.emitter.addListener(event, handler);
3597
- return () => {
3598
- this.emitter.removeListener(event, handler);
3599
- };
3600
- }
3601
- /**
3602
- * 请求-响应桥:注册临时监听 → filter 命中 → resolve;超时自动清理并 reject。
3603
- * 替代魔法字符串事件名方案。
3604
- */
3605
- waitFor(event, opts = {}) {
3606
- const timeoutMs = opts.timeout ?? DEFAULT_WAIT_TIMEOUT_MS;
3607
- return new Promise((resolve, reject) => {
3608
- const handler = (...args) => {
3609
- if (opts.filter && !opts.filter(...args)) return;
3610
- cleanup();
3611
- resolve(args);
3612
- };
3613
- const timer = setTimeout(() => {
3614
- cleanup();
3615
- reject(new KernelError(`等待事件超时: ${event}`, "TIMEOUT"));
3616
- }, timeoutMs);
3617
- const cleanup = () => {
3618
- clearTimeout(timer);
3619
- this.emitter.removeListener(event, handler);
3620
- };
3621
- this.emitter.addListener(event, handler);
3622
- });
3623
- }
3624
- /**
3625
- * 类型化派发:wrapper-loader 的原生回调经此推入通道。
3626
- * 2026-08-07 修复:原生 EventEmitter.emit 中一个 listener 抛异常会中断后续
3627
- * listener 派发(Node 语义)——改为快照数组逐个 try/catch,保证「单个订阅者
3628
- * 异常不打断派发」(协议翻译层异常不饿死缓存维护等其他订阅者)。
3629
- */
3630
- /**
3631
- * 订阅所有事件(IPC 子进程模式整通道转发用:事件名 `"${service}/${method}"`
3632
- * 经 handler 首参透出,args 原样透传)。返回退订函数。
3633
- */
3634
- onAny(handler) {
3635
- this.anyHandlers.add(handler);
3636
- return () => {
3637
- this.anyHandlers.delete(handler);
3638
- };
3639
- }
3640
- emit(event, ...args) {
3641
- for (const anyHandler of this.anyHandlers) try {
3642
- anyHandler(event, ...args);
3643
- } catch (err) {
3644
- this.notifyError(err);
3645
- }
3646
- const listeners = this.emitter.listeners(event);
3647
- for (const listener of listeners) try {
3648
- listener(...args);
3649
- } catch (err) {
3650
- this.notifyError(err);
3651
- }
3652
- }
3653
- /** 通知所有错误处理器(单个异常不打断其他处理器)。 */
3654
- notifyError(err) {
3655
- for (const handler of this.errorHandlers) handler(err);
3656
- }
3657
- /** 订阅错误通知(监听器抛出的异常 / 其他内部错误)。 */
3658
- onError(handler) {
3659
- this.errorHandlers.add(handler);
3660
- return () => {
3661
- this.errorHandlers.delete(handler);
3662
- };
3663
- }
3664
- };
3665
- //#endregion
3666
3790
  //#region src/wrapper/session-resolver.ts
3667
3791
  /** 从 getSessionIdList 的 Map 提取主 sessionId(nt_ 前缀优先)。 */
3668
3792
  function findMainSessionId(ids) {
@@ -4237,6 +4361,7 @@ function listQQVersions(installDir) {
4237
4361
  }).sort().reverse();
4238
4362
  }
4239
4363
  //#endregion
4364
+ exports.BuddyCache = BuddyCache;
4240
4365
  exports.ChatType = ChatType;
4241
4366
  exports.ConfigBase = ConfigBase;
4242
4367
  exports.DEFAULT_DATA_ROOT_NAME = DEFAULT_DATA_ROOT_NAME;
@@ -4289,6 +4414,7 @@ exports.isKernelError = isKernelError;
4289
4414
  exports.kernelError = kernelError;
4290
4415
  exports.listLoginAccounts = listLoginAccounts;
4291
4416
  exports.listQQVersions = listQQVersions;
4417
+ exports.narrowBuddyCategories = narrowBuddyCategories;
4292
4418
  exports.parseAppidFromMajor = parseAppidFromMajor;
4293
4419
  exports.parseToml = parseToml;
4294
4420
  exports.probeRuntime = probeRuntime;
package/dist/index.d.cts CHANGED
@@ -69,6 +69,16 @@ interface PttElement {
69
69
  otherBusinessInfo?: {
70
70
  aiVoiceType: number;
71
71
  };
72
+ fileId?: number;
73
+ fileUuid?: string;
74
+ translateStatus?: number;
75
+ /** 传输状态:实测 2=收到已下载(数据库态,此时挪走本地文件调 downloadRichMedia 不重下)、4=自己发送已上传。 */
76
+ transferStatus?: number;
77
+ progress?: number;
78
+ invalidState?: number;
79
+ fileBizId?: unknown;
80
+ import_rich_media_context?: unknown;
81
+ isInApplicationDataPath?: boolean | null;
72
82
  }
73
83
  /** 表情元素。 */
74
84
  interface FaceElement {
@@ -300,6 +310,18 @@ interface NodeIKernelMsgService {
300
310
  getMsgsByMsgId(peer: Peer, ids: string[]): Promise<GeneralCallResult & {
301
311
  msgList?: RawMessage[];
302
312
  }>;
313
+ /**
314
+ * 富媒体主动下载(get_record 语音下载,2026-09-08 B1 实测:单参数对象,
315
+ * resolve undefined——结果只能经重拉消息元素观察;参数残缺时静默 no-op 不抛错;
316
+ * transferStatus=2 已下载态调用为 no-op,详见 kernel design.md §5)。
317
+ */
318
+ downloadRichMedia(param: {
319
+ msgId: string;
320
+ elemId: string;
321
+ chatType: number;
322
+ downloadType: number;
323
+ thumbSize: number;
324
+ }): Promise<void>;
303
325
  setMsgRead(peer: Peer): Promise<GeneralCallResult>;
304
326
  /** 消息表情表态(set_msg_emoji_like;setOrCancel=true 点赞,false 取消)。 */
305
327
  setMsgEmojiLikes(peer: Peer, msgSeq: string, emojiId: string, emojiType: string, setOrCancel: boolean): Promise<GeneralCallResult>;
@@ -631,6 +653,14 @@ type GroupListener = {
631
653
  onGroupSingleScreenNotifies: (doubt: boolean, seq: string, notifies: GroupNotify[]) => void;
632
654
  /** 群禁言成员列表变化。 */
633
655
  onShutUpMemberListChanged: (groupCode: string, members: ShutUpGroupMember[]) => void;
656
+ /**
657
+ * 群精华列表变化(OB11 group_essence 候选源,2026-09-10 接线)。
658
+ * 证据:wrapper.node 9.9.33-52230 字符串——小写名位于 listener 反射字符串簇,
659
+ * 与已知 onMemberListChange/onBuddyReqChange 交错(同一字符串表页);
660
+ * API 族旁证 addGroupEssence/getGroupLatestEssenceList。
661
+ * ⚠️ 参数形状待真实事件校准(unknown 透传,订阅方 raw 日志观测)。
662
+ */
663
+ onGroupEssenceListChange: (arg: unknown) => void;
634
664
  };
635
665
  //#endregion
636
666
  //#region src/types/listeners/msg.d.ts
@@ -663,6 +693,28 @@ type MsgListener = {
663
693
  * 2026-08-11 补齐:sendMsg 发送结果以此事件为准(NapCat 同款),
664
694
  * sendMsg 返回值 result 可能非 0 但实际发送成功(异步确认)。 */
665
695
  onMsgInfoListUpdate: (msgs: RawMessage[]) => void;
696
+ /**
697
+ * 收到离线文件消息(OB11 offline_file 事件源,2026-09-10 接线)。
698
+ * 证据:wrapper.node 9.9.33-52230 字符串——小写名位于 listener 反射字符串簇
699
+ * (与 onRecvMsg 同页,offset 差 ~7KB)+ RTTI
700
+ * `OnRecvOfflineFileMsg@KernelMsgService@wrapper@nt`;API 族旁证
701
+ * getNewOfflineFileList。⚠️ 参数形状待真实事件校准(unknown 透传)。
702
+ */
703
+ onRecvOfflineFileMsg: (arg: unknown) => void;
704
+ /**
705
+ * 收到在线文件消息(onRecvOfflineFileMsg 同族,字符串簇相邻;
706
+ * OB11 无对应通知类型,仅作校准观测)。参数形状待校准。
707
+ */
708
+ onRecvOnlineFileMsg: (arg: unknown) => void;
709
+ /**
710
+ * 收到系统消息(sys msg 总闸,2026-09-10 接线):群名片/头衔/精华/荣誉等
711
+ * 系统事件的根载体(二进制 55 个 OnSysMsg* 处理器;另有请求式
712
+ * registerSysMsgNotification(type, subType, ids, callback) 需 3 参)。
713
+ * 证据:小写名与 onRecvMsg 相邻(offset 差 ~1.4KB)+ 日志
714
+ * `OnRecvSysMsg msg_type=0x{:x} sub_type=0x{:x} is_online={}`。
715
+ * ⚠️ 参数形状待真实事件校准(unknown 透传,订阅方 raw 日志观测)。
716
+ */
717
+ onRecvSysMsg: (arg: unknown) => void;
666
718
  };
667
719
  //#endregion
668
720
  //#region src/types/message-element.d.ts
@@ -721,14 +773,38 @@ type CanonicalElement = {
721
773
  };
722
774
  //#endregion
723
775
  //#region src/types/services/buddy-service.d.ts
724
- /** 好友列表分类(getBuddyListV2 返回,说明书参考)。 */
776
+ /** 好友核心信息(BuddyListEntry.coreInfo,2026-09-08 T10 实测)。 */
777
+ interface BuddyCoreInfo {
778
+ uid: string;
779
+ uin: string;
780
+ nick?: string;
781
+ remark?: string;
782
+ [key: string]: unknown;
783
+ }
784
+ /** 好友列表明细(BuddyCategory.buddyList 成员,2026-09-08 T10 实测快照)。 */
785
+ interface BuddyListEntry {
786
+ uid: string;
787
+ /** 顶层 uin(coreInfo.uin 同值;缺失时回退 coreInfo)。 */
788
+ uin?: string;
789
+ coreInfo?: BuddyCoreInfo;
790
+ baseInfo?: Record<string, unknown>;
791
+ [key: string]: unknown;
792
+ }
793
+ /**
794
+ * 好友列表分类(getBuddyListV2 返回 / onBuddyListChange 全量快照载荷)。
795
+ * ⚠️ 2026-09-08 T10 实测:onBuddyListChange 载荷 = BuddyCategory[],分类项
796
+ * 含 buddyList 明细(uid/uin/coreInfo/baseInfo);实测样本无 buddyUids——
797
+ * 两字段均按 optional 防御(旧描述的 buddyUids 保留兼容)。
798
+ */
725
799
  interface BuddyCategory {
726
800
  categoryId: number;
727
801
  categorySortId: number;
728
802
  categroyName: string;
729
803
  categroyMbCount: number;
730
804
  onlineCount: number;
731
- buddyUids: string[];
805
+ buddyUids?: string[];
806
+ /** 好友明细(onBuddyListChange 快照,T10 实证)。 */
807
+ buddyList?: BuddyListEntry[];
732
808
  }
733
809
  /** 好友申请(getBuddyReq 返回的 buddyReqs 成员,说明书参考,待探测校准)。 */
734
810
  interface BuddyReq {
@@ -1535,6 +1611,14 @@ declare class MsgApi {
1535
1611
  fetchPttText(msgId: string, target: Peer): Promise<string>;
1536
1612
  /** 标记会话已读。 */
1537
1613
  markRead(target: Peer): Promise<void>;
1614
+ /**
1615
+ * 语音主动下载(get_record 本地未命中兜底,2026-09-08 B1)。
1616
+ * downloadRichMedia 返回 void(实测),完成信号 = 重拉消息元素:
1617
+ * 轮询(300ms × 34,约 10s)直到 filePath 非空且 transferStatus 进入
1618
+ * 已下载态(2/4);超时但 filePath 已有值则尽力返回(磁盘命中判断留给
1619
+ * 调用方),完全无路径抛 NOT_FOUND。
1620
+ */
1621
+ downloadPtt(msgId: string, target: Peer): Promise<PttElement>;
1538
1622
  /** 发送输入状态(set_input_status;eventType=1 输入中,0 停止)。 */
1539
1623
  setInputStatus(target: Peer, eventType: number): Promise<void>;
1540
1624
  /**
@@ -1751,6 +1835,54 @@ declare class GroupBridge {
1751
1835
  unregister(): void;
1752
1836
  }
1753
1837
  //#endregion
1838
+ //#region src/cache/buddy-cache.d.ts
1839
+ /** BuddyCache diff 事件 listener(归一化「新增/删除」事件)。 */
1840
+ type BuddyCacheListener = {
1841
+ onBuddyAdded: (entry: BuddyListEntry) => void;
1842
+ onBuddyRemoved: (entry: BuddyListEntry) => void;
1843
+ };
1844
+ /** BuddyCache diff 事件通道(事件名 BuddyCache/onBuddyAdded 等)。 */
1845
+ type BuddyCacheEventChannel = NTEventChannel<BuddyCacheListener, "BuddyCache">;
1846
+ /** BuddyCache 构造参数。 */
1847
+ interface BuddyCacheOptions {
1848
+ /** Buddy 事件通道(FriendBridge 注册原生监听后 emit 到这里)。 */
1849
+ channel: BuddyEventChannel;
1850
+ /** 校准日志(可选:快照形状异常 raw 记录;缺省静默)。 */
1851
+ logger?: {
1852
+ warn(obj: unknown, msg?: string): void;
1853
+ };
1854
+ }
1855
+ /**
1856
+ * 防御性收窄 onBuddyListChange 载荷 → BuddyCategory[](T10 实证形状;
1857
+ * 非数组返回 null,调用方打 raw 日志积累校准数据)。
1858
+ */
1859
+ declare function narrowBuddyCategories(arg: unknown): BuddyCategory[] | null;
1860
+ /** 好友缓存:快照维护 + diff 归一化事件。 */
1861
+ declare class BuddyCache {
1862
+ private readonly channel;
1863
+ private readonly logger;
1864
+ /** diff 归一化事件通道(协议层订阅 friend_add / IPC 转发消费)。 */
1865
+ readonly events: BuddyCacheEventChannel;
1866
+ /** 好友快照(uid → entry,onBuddyListChange 全量维护)。 */
1867
+ private readonly buddies;
1868
+ /** 首帧已建 baseline(此后快照才参与 diff)。 */
1869
+ private bootstrapped;
1870
+ private unsubscribes;
1871
+ constructor(opts: BuddyCacheOptions);
1872
+ /** 订阅 Buddy 事件通道(幂等)。 */
1873
+ register(): void;
1874
+ /** 退订事件通道(幂等)。 */
1875
+ unregister(): void;
1876
+ /** 应用全量快照:首帧建 baseline,之后 diff 发布归一化事件。 */
1877
+ private applySnapshot;
1878
+ /** 好友快照(只读拷贝)。 */
1879
+ listBuddies(): BuddyListEntry[];
1880
+ /** 单个好友(快照;undefined = 不在缓存)。 */
1881
+ getBuddy(uid: string): BuddyListEntry | undefined;
1882
+ /** 快照是否已建(测试/诊断用)。 */
1883
+ get baselineReady(): boolean;
1884
+ }
1885
+ //#endregion
1754
1886
  //#region src/cache/group-cache.d.ts
1755
1887
  /** GroupCache 构造参数。 */
1756
1888
  interface GroupCacheOptions {
@@ -2480,5 +2612,5 @@ interface QQVersionInfo {
2480
2612
  qua: string;
2481
2613
  }
2482
2614
  //#endregion
2483
- export { type BootEnv, type BuddyCategory, type BuddyEventChannel, type BuddyListener, 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, FriendBridge, 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 };
2615
+ export { type BootEnv, BuddyCache, type BuddyCacheEventChannel, type BuddyCacheListener, type BuddyCacheOptions, type BuddyCategory, type BuddyCoreInfo, type BuddyEventChannel, type BuddyListEntry, type BuddyListener, 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, FriendBridge, 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, narrowBuddyCategories, parseAppidFromMajor, parseToml, probeRuntime, quickLogin, readMachineGuid, resolveAppidQua, resolveConfigPath, resolveDataRoot, resolveQQVersion, resolveQqGlobalPath, resolveQqUserDataRoot, resolveWrapperPath, startNapuketto, startSession, stringifyToml, toCanonicalElements, toSendElements, waitForNetworkConnection, waitSessionReady };
2484
2616
  //# sourceMappingURL=index.d.cts.map