@napuketto/loader 0.4.1 → 0.4.3

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.
@@ -371,6 +371,8 @@ const env = {
371
371
  NAPUTO_SMOKE_PEER: process.env["NAPUTO_SMOKE_PEER"],
372
372
  /** 运行时探测开关(=1 触发 probeRuntime)。 */
373
373
  NAPUTO_PROBE: process.env["NAPUTO_PROBE"],
374
+ /** listener 录制器开关(=1 触发 startListenerRecording,先于探测挂起——批次三前置)。 */
375
+ NAPUTO_LISTENER_RECORD: process.env["NAPUTO_LISTENER_RECORD"],
374
376
  /** 全局 TOML 配置显式路径(优先级最高)。 */
375
377
  NAPKETTO_CONFIG: process.env["NAPKETTO_CONFIG"],
376
378
  /** 内联主配置 JSON 文本(嵌入式宿主注入;优先级高于 NAPKETTO_CONFIG 文件,2026-10-25)。 */
@@ -1149,6 +1151,8 @@ function attachIpcServices(actions, services) {
1149
1151
  forwardChannel(services.channel, stops);
1150
1152
  forwardChannel(services.groupChannel, stops);
1151
1153
  forwardChannel(services.friendChannel, stops);
1154
+ forwardChannel(services.recentContactChannel, stops);
1155
+ forwardChannel(services.loginChannel, stops);
1152
1156
  return () => {
1153
1157
  for (const stop of stops) stop();
1154
1158
  for (const name of full.keys()) actions.delete(name);
@@ -1693,6 +1697,8 @@ async function assembleOb11AndSatori(kernel, services, loginResult) {
1693
1697
  msgChannel: channel,
1694
1698
  groupChannel: services.groupChannel,
1695
1699
  buddyChannel: services.friendChannel,
1700
+ recentContactChannel: services.recentContactChannel,
1701
+ loginChannel: services.loginChannel,
1696
1702
  msgApi: services.msgApi,
1697
1703
  groupApi: services.groupApi,
1698
1704
  friendApi: services.friendApi,
@@ -1825,6 +1831,32 @@ function buildLoaderLoggerOptions(logCfg, consoleEnabled, logFile, account) {
1825
1831
  }
1826
1832
  };
1827
1833
  }
1834
+ /**
1835
+ * 批次三通道与桥(2026-11-01):RecentContactBridge(peer_pin_change 源)+
1836
+ * LoginBridge(bot_offline 源)。loginService 取自 wrapper 上下文(与
1837
+ * QrLoginSession 同源),缺失(老 kernel / 未 attach)时只跳过 Login 桥注册
1838
+ * ——通道保留,事件为空。
1839
+ */
1840
+ function createBatch3Channels(kernel, ctx, session, log) {
1841
+ const recentContactChannel = new kernel.NTEventChannel("RecentContact");
1842
+ const recentContactBridge = new kernel.RecentContactBridge(session, recentContactChannel);
1843
+ recentContactBridge.register();
1844
+ const loginChannel = new kernel.NTEventChannel("Login");
1845
+ const loginService = ctx.wrapper?.loginService;
1846
+ let loginBridge = null;
1847
+ if (loginService !== null && loginService !== void 0) {
1848
+ loginBridge = new kernel.LoginBridge(loginService, loginChannel);
1849
+ loginBridge.register();
1850
+ } else log("bootstrap: loginService 不可用,Login 桥未注册(bot_offline 事件不可用)");
1851
+ return {
1852
+ recentContactChannel,
1853
+ loginChannel,
1854
+ unregister: () => {
1855
+ recentContactBridge.unregister();
1856
+ loginBridge?.unregister();
1857
+ }
1858
+ };
1859
+ }
1828
1860
  /** 登录成功后创建 kernel 业务服务(channel/bridge/cache/apis)。失败返回 null。 */
1829
1861
  async function createKernelServices(kernel, ctx, loginResult, logCfg) {
1830
1862
  const ipcMode = env.NAPUTO_IPC === "1";
@@ -1867,6 +1899,7 @@ async function createKernelServices(kernel, ctx, loginResult, logCfg) {
1867
1899
  const friendChannel = new kernel.NTEventChannel("Buddy");
1868
1900
  const friendBridge = new kernel.FriendBridge(session, friendChannel);
1869
1901
  friendBridge.register();
1902
+ const batch3 = createBatch3Channels(kernel, ctx, session, log);
1870
1903
  const groupCache = new kernel.GroupCache({
1871
1904
  channel: groupChannel,
1872
1905
  groupApi
@@ -1879,6 +1912,11 @@ async function createKernelServices(kernel, ctx, loginResult, logCfg) {
1879
1912
  buddyCache.register();
1880
1913
  const groupNotifyApi = new kernel.GroupNotifyApi(session);
1881
1914
  const ticketApi = new kernel.TicketApi(session);
1915
+ const richMediaApi = new kernel.RichMediaApi(session);
1916
+ const recentContactApi = new kernel.RecentContactApi(session);
1917
+ const profileApi = new kernel.ProfileApi(session);
1918
+ const profileLikeApi = new kernel.ProfileLikeApi(session);
1919
+ const webApi = new kernel.WebApi({ getCookies: (domain) => ticketApi.getCookies(domain, loginResult.uin) });
1882
1920
  return {
1883
1921
  kernel,
1884
1922
  ctx,
@@ -1886,6 +1924,8 @@ async function createKernelServices(kernel, ctx, loginResult, logCfg) {
1886
1924
  channel,
1887
1925
  groupChannel,
1888
1926
  friendChannel,
1927
+ recentContactChannel: batch3.recentContactChannel,
1928
+ loginChannel: batch3.loginChannel,
1889
1929
  msgApi,
1890
1930
  groupApi,
1891
1931
  friendApi,
@@ -1893,11 +1933,11 @@ async function createKernelServices(kernel, ctx, loginResult, logCfg) {
1893
1933
  buddyCache,
1894
1934
  groupNotifyApi,
1895
1935
  ticketApi,
1896
- richMediaApi: new kernel.RichMediaApi(session),
1897
- recentContactApi: new kernel.RecentContactApi(session),
1898
- profileApi: new kernel.ProfileApi(session),
1899
- profileLikeApi: new kernel.ProfileLikeApi(session),
1900
- webApi: new kernel.WebApi({ getCookies: (domain) => ticketApi.getCookies(domain, loginResult.uin) }),
1936
+ richMediaApi,
1937
+ recentContactApi,
1938
+ profileApi,
1939
+ profileLikeApi,
1940
+ webApi,
1901
1941
  self: {
1902
1942
  uin: loginResult.uin,
1903
1943
  nickname: loginResult.nick ?? "",
@@ -1912,6 +1952,7 @@ async function createKernelServices(kernel, ctx, loginResult, logCfg) {
1912
1952
  bridge.unregister();
1913
1953
  groupBridge.unregister();
1914
1954
  friendBridge.unregister();
1955
+ batch3.unregister();
1915
1956
  groupCache.unregister();
1916
1957
  buddyCache.unregister();
1917
1958
  offMsgLogging();
@@ -2472,6 +2513,28 @@ function probeOnce(kernel, ctx) {
2472
2513
  log(`bootstrap: probe error: ${errMsg(e)}`);
2473
2514
  }
2474
2515
  }
2516
+ /**
2517
+ * listener 录制模式(NAPUTO_LISTENER_RECORD=1,批次三前置):万能监听器挂满
2518
+ * 候选服务,回调逐行落盘 napuketto-listener-record.jsonl。
2519
+ * ⚠️ 必须先于 runProbePhase——probe 的 getMainSession 写回副作用会毒化
2520
+ * ctx.session(空壳主 session),录制器要先取服务。
2521
+ */
2522
+ function runListenerRecordingPhase(kernel, ctx) {
2523
+ if (env.NAPUTO_LISTENER_RECORD !== "1") return;
2524
+ if (typeof kernel.startListenerRecording !== "function") {
2525
+ log("bootstrap: listener-record 请求但 kernel 缺 startListenerRecording(kernel 过旧)");
2526
+ return;
2527
+ }
2528
+ try {
2529
+ const rec = kernel.startListenerRecording(ctx);
2530
+ const ok = Object.values(rec.registered).filter((r) => r.ok).length;
2531
+ const total = Object.keys(rec.registered).length;
2532
+ log(`bootstrap: listener-record 挂起 ${ok}/${total} 服务 → ${rec.file}`);
2533
+ for (const [name, r] of Object.entries(rec.registered)) if (!r.ok) log(`bootstrap: listener-record ${name} 未挂: ${r.error ?? "unknown"}`);
2534
+ } catch (e) {
2535
+ log(`bootstrap: listener-record error: ${errMsg(e)}`);
2536
+ }
2537
+ }
2475
2538
  /** 探测模式(NAPUTO_PROBE=1):立即探测 + 35s 后晚探测(napuketto-probe-late.json)。 */
2476
2539
  function runProbePhase(kernel, ctx) {
2477
2540
  if (env.NAPUTO_PROBE !== "1") return;
@@ -2624,6 +2687,7 @@ async function bootstrapWithCore(kernel, state, bootEnv, Appid) {
2624
2687
  return false;
2625
2688
  }
2626
2689
  control.markReady();
2690
+ runListenerRecordingPhase(kernel, ctx);
2627
2691
  runProbePhase(kernel, ctx);
2628
2692
  return true;
2629
2693
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@napuketto/loader",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
4
  "description": "NapukettoQQ 引导组件:自建宿主(标准 Node + stub QQNT.dll)dlopen wrapper.node 并启动 kernel,不拉起 QQ / 不注入",
5
5
  "type": "module",
6
6
  "files": [