llonebot-dist 7.7.0 → 7.7.1

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.
@@ -1,4 +1,5 @@
1
- import { A, M, a, N, O } from "../llbot.js";
1
+ import { M as Msg } from "../llbot.js";
2
+ import { A, a, N, O } from "../llbot.js";
2
3
  import "node:path";
3
4
  import "node:url";
4
5
  import "cosmokit";
@@ -43,9 +44,9 @@ import "dns";
43
44
  import "tls";
44
45
  export {
45
46
  A as Action,
46
- M as Media,
47
- a as Msg,
47
+ a as Media,
48
+ Msg,
48
49
  N as Notify,
49
50
  O as Oidb
50
51
  };
51
- //# sourceMappingURL=index-B1KgxRHW.js.map
52
+ //# sourceMappingURL=index-BvqM9dZ0.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-BvqM9dZ0.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/llbot.js CHANGED
@@ -2127,6 +2127,11 @@ class PMHQBase {
2127
2127
  wsUrl = "ws://127.0.0.1:13000/ws";
2128
2128
  ws;
2129
2129
  resListeners = /* @__PURE__ */ new Map();
2130
+ disconnectCallbacks = /* @__PURE__ */ new Map();
2131
+ lastConnectedTime = Date.now();
2132
+ disconnectCheckTimer;
2133
+ hasConnectedOnce = false;
2134
+ hasLoggedConnectionError = false;
2130
2135
  constructor() {
2131
2136
  console.log(process.argv);
2132
2137
  const { pmhqHost, pmhqPort } = this.getPMHQHostPort();
@@ -2137,6 +2142,41 @@ class PMHQBase {
2137
2142
  get_is_connected() {
2138
2143
  return this.ws && this.ws.readyState === WebSocket.OPEN;
2139
2144
  }
2145
+ onDisconnect(timeout2, callback) {
2146
+ const id2 = randomUUID();
2147
+ this.disconnectCallbacks.set(id2, { timeout: timeout2, callback, triggered: false });
2148
+ console.info(`[PMHQ] Registered disconnect callback ${id2} with timeout ${timeout2}ms`);
2149
+ return id2;
2150
+ }
2151
+ offDisconnect(id2) {
2152
+ this.disconnectCallbacks.delete(id2);
2153
+ }
2154
+ startDisconnectMonitoring() {
2155
+ if (this.disconnectCheckTimer) return;
2156
+ console.info("[PMHQ] Starting disconnect monitoring");
2157
+ this.disconnectCheckTimer = setInterval(() => {
2158
+ const isConnected = this.get_is_connected();
2159
+ if (isConnected) {
2160
+ this.lastConnectedTime = Date.now();
2161
+ for (const info of this.disconnectCallbacks.values()) {
2162
+ info.triggered = false;
2163
+ }
2164
+ } else {
2165
+ const disconnectedDuration = Date.now() - this.lastConnectedTime;
2166
+ for (const info of this.disconnectCallbacks.values()) {
2167
+ if (!info.triggered && disconnectedDuration >= info.timeout) {
2168
+ info.triggered = true;
2169
+ console.warn(`[PMHQ] Triggering disconnect callback, duration: ${disconnectedDuration}ms, timeout: ${info.timeout}ms`);
2170
+ try {
2171
+ info.callback(disconnectedDuration);
2172
+ } catch (e) {
2173
+ console.error("PMHQ disconnect callback error", e);
2174
+ }
2175
+ }
2176
+ }
2177
+ }
2178
+ }, 5e3);
2179
+ }
2140
2180
  getPMHQHostPort() {
2141
2181
  let pmhqPort = "13000";
2142
2182
  let pmhqHost = "127.0.0.1";
@@ -2194,16 +2234,27 @@ class PMHQBase {
2194
2234
  };
2195
2235
  this.ws.onerror = () => {
2196
2236
  selfInfo.online = false;
2197
- console.error("PMHQ WebSocket 连接错误,可能 QQ 未启动", "正在等待 QQ 启动进行重连...");
2237
+ if (!this.hasLoggedConnectionError) {
2238
+ console.error("PMHQ WebSocket 连接错误,可能 QQ 未启动,正在等待 QQ 启动进行重连...");
2239
+ this.hasLoggedConnectionError = true;
2240
+ }
2198
2241
  reconnect();
2199
2242
  };
2200
2243
  this.ws.onclose = () => {
2201
2244
  selfInfo.online = false;
2202
- console.info("PMHQ WebSocket 连接关闭,准备重连...");
2245
+ if (!this.hasLoggedConnectionError) {
2246
+ console.info("PMHQ WebSocket 连接关闭,准备重连...");
2247
+ this.hasLoggedConnectionError = true;
2248
+ }
2203
2249
  reconnect();
2204
2250
  };
2205
2251
  this.ws.onopen = () => {
2206
2252
  console.info("PMHQ WebSocket 连接成功");
2253
+ this.hasLoggedConnectionError = false;
2254
+ if (!this.hasConnectedOnce) {
2255
+ this.hasConnectedOnce = true;
2256
+ this.startDisconnectMonitoring();
2257
+ }
2207
2258
  };
2208
2259
  }
2209
2260
  async call(func, args, timeout2 = 1e4) {
@@ -10613,7 +10664,7 @@ class OB11HeartbeatEvent extends OB11BaseMetaEvent {
10613
10664
  };
10614
10665
  }
10615
10666
  }
10616
- const version$3 = "7.7.0";
10667
+ const version$3 = "7.7.1";
10617
10668
  class OB11WebSocket {
10618
10669
  constructor(ctx, config2) {
10619
10670
  this.ctx = ctx;
@@ -70059,11 +70110,11 @@ function createEmailRoutes(ctx) {
70059
70110
  const router2 = expressExports.Router();
70060
70111
  router2.get("/config", async (_req, res) => {
70061
70112
  try {
70062
- const emailService = ctx.emailNotification;
70063
- if (!emailService) {
70064
- res.status(500).json({ success: false, message: "邮件服务未初始化" });
70113
+ if (!ctx.emailNotification) {
70114
+ res.status(503).json({ success: false, message: "邮件服务未初始化,请等待登录完成" });
70065
70115
  return;
70066
70116
  }
70117
+ const emailService = ctx.emailNotification;
70067
70118
  const config2 = emailService.getConfigManager().getConfig();
70068
70119
  const maskedConfig = {
70069
70120
  ...config2,
@@ -70089,11 +70140,11 @@ function createEmailRoutes(ctx) {
70089
70140
  });
70090
70141
  router2.post("/config", async (req, res) => {
70091
70142
  try {
70092
- const emailService = ctx.emailNotification;
70093
- if (!emailService) {
70094
- res.status(500).json({ success: false, message: "邮件服务未初始化" });
70143
+ if (!ctx.emailNotification) {
70144
+ res.status(503).json({ success: false, message: "邮件服务未初始化,请等待登录完成" });
70095
70145
  return;
70096
70146
  }
70147
+ const emailService = ctx.emailNotification;
70097
70148
  const emailConfig = req.body;
70098
70149
  if (!emailConfig) {
70099
70150
  res.status(400).json({
@@ -70131,15 +70182,19 @@ function createEmailRoutes(ctx) {
70131
70182
  });
70132
70183
  router2.post("/test", async (req, res) => {
70133
70184
  try {
70134
- const emailService = ctx.emailNotification;
70135
- if (!emailService) {
70136
- res.status(500).json({ success: false, message: "邮件服务未初始化" });
70185
+ if (!ctx.emailNotification) {
70186
+ res.status(503).json({ success: false, message: "邮件服务未初始化,请等待登录完成" });
70137
70187
  return;
70138
70188
  }
70189
+ const emailService = ctx.emailNotification;
70139
70190
  const { config: testConfig } = req.body;
70140
70191
  let emailConfig;
70141
70192
  if (testConfig) {
70142
70193
  emailConfig = testConfig;
70194
+ const currentConfig = emailService.getConfigManager().getConfig();
70195
+ if (emailConfig.smtp.auth.pass === "********" || emailConfig.smtp.auth.pass === "") {
70196
+ emailConfig.smtp.auth.pass = currentConfig.smtp.auth.pass;
70197
+ }
70143
70198
  } else {
70144
70199
  emailConfig = emailService.getConfigManager().getConfig();
70145
70200
  }
@@ -70211,7 +70266,10 @@ class WebUIServer extends Service2 {
70211
70266
  upload;
70212
70267
  fileUpload;
70213
70268
  uploadDir;
70214
- static inject = ["ntLoginApi", "ntFriendApi", "ntGroupApi", "ntSystemApi", "ntMsgApi", "ntUserApi", "ntFileApi"];
70269
+ static inject = {
70270
+ required: ["ntLoginApi", "ntFriendApi", "ntGroupApi", "ntSystemApi", "ntMsgApi", "ntUserApi", "ntFileApi"],
70271
+ optional: ["emailNotification"]
70272
+ };
70215
70273
  createImageUpload() {
70216
70274
  return multer({
70217
70275
  storage: multer.diskStorage({
@@ -70340,7 +70398,7 @@ data: ${JSON.stringify(serializedData)}
70340
70398
  if (data.type !== "recv" || data.data.cmd !== "trpc.msg.olpush.OlPushService.MsgPush") return;
70341
70399
  try {
70342
70400
  const { Msg: Msg2 } = await __vitePreload(async () => {
70343
- const { Msg: Msg3 } = await import("./assets/index-B1KgxRHW.js");
70401
+ const { Msg: Msg3 } = await import("./assets/index-BvqM9dZ0.js");
70344
70402
  return { Msg: Msg3 };
70345
70403
  }, true ? [] : void 0);
70346
70404
  const pushMsg = Msg2.PushMsg.decode(Buffer.from(data.data.pb, "hex"));
@@ -81639,305 +81697,91 @@ class EmailService {
81639
81697
  }
81640
81698
  formatOfflineEmail(botInfo, reason) {
81641
81699
  const timestamp = botInfo.timestamp.toLocaleString("zh-CN", { timeZone: "Asia/Shanghai" });
81642
- const reasonText = reason || "未知原因";
81643
- const subject = `【LLBot 告警】机器人 ${botInfo.uin} 已离线`;
81700
+ const displayName = botInfo.nick ? `${botInfo.nick} (${botInfo.uin})` : botInfo.uin;
81701
+ const subject = "LLBot 掉线通知";
81702
+ const reasonSection = reason ? `<div class="info">
81703
+ <p><strong>掉线原因:</strong> ${reason}</p>
81704
+ </div>` : `<p>可能的原因:</p>
81705
+ <ul>
81706
+ <li>网络连接中断</li>
81707
+ <li>QQ 被强制下线</li>
81708
+ <li>程序异常退出</li>
81709
+ </ul>`;
81644
81710
  const html = `
81645
81711
  <!DOCTYPE html>
81646
81712
  <html>
81647
81713
  <head>
81648
- <meta charset="UTF-8">
81649
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
81650
- <style>
81651
- * { margin: 0; padding: 0; box-sizing: border-box; }
81652
- body {
81653
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Microsoft YaHei", Arial, sans-serif;
81654
- background: linear-gradient(135deg, #8b5cf6 0%, #ec4899 100%);
81655
- padding: 40px 20px;
81656
- line-height: 1.6;
81657
- }
81658
- .container {
81659
- max-width: 600px;
81660
- margin: 0 auto;
81661
- background: white;
81662
- border-radius: 20px;
81663
- overflow: hidden;
81664
- box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
81665
- }
81666
- .header {
81667
- background: linear-gradient(135deg, #ef4444 0%, #ec4899 100%);
81668
- color: white;
81669
- padding: 40px 32px;
81670
- text-align: center;
81671
- position: relative;
81672
- }
81673
- .header::before {
81674
- content: '';
81675
- position: absolute;
81676
- top: 0;
81677
- left: 0;
81678
- right: 0;
81679
- bottom: 0;
81680
- background: radial-gradient(circle at 30% 50%, rgba(255,255,255,0.1) 0%, transparent 50%);
81681
- }
81682
- .header-content {
81683
- position: relative;
81684
- z-index: 1;
81685
- }
81686
- .icon {
81687
- font-size: 56px;
81688
- margin-bottom: 16px;
81689
- filter: drop-shadow(0 4px 6px rgba(0,0,0,0.1));
81690
- }
81691
- .header h2 {
81692
- font-size: 28px;
81693
- font-weight: 700;
81694
- margin-bottom: 8px;
81695
- letter-spacing: -0.5px;
81696
- }
81697
- .header p {
81698
- font-size: 15px;
81699
- opacity: 0.95;
81700
- font-weight: 500;
81701
- }
81702
- .content {
81703
- padding: 36px 32px;
81704
- }
81705
- .info-card {
81706
- background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%);
81707
- border-radius: 16px;
81708
- padding: 24px;
81709
- margin-bottom: 24px;
81710
- border: 1px solid rgba(0,0,0,0.05);
81711
- }
81712
- .info-item {
81713
- margin: 14px 0;
81714
- display: flex;
81715
- align-items: flex-start;
81716
- padding: 8px 0;
81717
- }
81718
- .info-item:not(:last-child) {
81719
- border-bottom: 1px solid rgba(0,0,0,0.06);
81720
- }
81721
- .label {
81722
- font-weight: 600;
81723
- color: #374151;
81724
- min-width: 90px;
81725
- flex-shrink: 0;
81726
- font-size: 14px;
81727
- }
81728
- .value {
81729
- color: #6b7280;
81730
- flex: 1;
81731
- font-size: 14px;
81732
- word-break: break-word;
81733
- }
81734
- .alert-message {
81735
- background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
81736
- border-left: 4px solid #f59e0b;
81737
- padding: 18px 20px;
81738
- border-radius: 12px;
81739
- color: #92400e;
81740
- font-size: 14px;
81741
- line-height: 1.6;
81742
- box-shadow: 0 1px 3px rgba(0,0,0,0.1);
81743
- }
81744
- .footer {
81745
- text-align: center;
81746
- padding: 28px 24px;
81747
- background: linear-gradient(135deg, #f9fafb 0%, #f3f4f6 100%);
81748
- color: #9ca3af;
81749
- font-size: 13px;
81750
- border-top: 1px solid rgba(0,0,0,0.05);
81751
- }
81752
- .footer strong {
81753
- background: linear-gradient(135deg, #8b5cf6 0%, #ec4899 100%);
81754
- -webkit-background-clip: text;
81755
- -webkit-text-fill-color: transparent;
81756
- background-clip: text;
81757
- font-weight: 600;
81758
- }
81759
- </style>
81714
+ <meta charset="utf-8">
81715
+ <style>
81716
+ body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
81717
+ .container { max-width: 600px; margin: 0 auto; padding: 20px; }
81718
+ .header { background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); color: white; padding: 20px; border-radius: 8px 8px 0 0; }
81719
+ .content { background: #f9f9f9; padding: 20px; border-radius: 0 0 8px 8px; }
81720
+ .alert { background: #fff3cd; border-left: 4px solid #ffc107; padding: 15px; margin: 10px 0; }
81721
+ .info { background: white; padding: 15px; margin: 10px 0; }
81722
+ .footer { text-align: center; margin-top: 20px; color: #666; font-size: 12px; }
81723
+ </style>
81760
81724
  </head>
81761
81725
  <body>
81762
- <div class="container">
81763
- <div class="header">
81764
- <div class="header-content">
81765
- <div class="icon">⚠️</div>
81766
- <h2>机器人离线告警</h2>
81767
- <p>您的 LLBot 实例已离线</p>
81768
- </div>
81769
- </div>
81770
- <div class="content">
81771
- <div class="info-card">
81772
- <div class="info-item">
81773
- <span class="label">机器人账号</span>
81774
- <span class="value">${botInfo.uin} (${botInfo.nick})</span>
81726
+ <div class="container">
81727
+ <div class="header">
81728
+ <h2>⚠️ LLBot 掉线通知</h2>
81775
81729
  </div>
81776
- <div class="info-item">
81777
- <span class="label">离线时间</span>
81778
- <span class="value">${timestamp}</span>
81730
+ <div class="content">
81731
+ <div class="alert">
81732
+ <p><strong>⚠️ QQ 已掉线</strong></p>
81733
+ </div>
81734
+ <div class="info">
81735
+ <p><strong>账号信息:</strong> ${displayName}</p>
81736
+ <p><strong>掉线时间:</strong> ${timestamp}</p>
81737
+ </div>
81738
+ <p>您的 QQ 机器人已掉线,请及时检查并重新登录。</p>
81739
+ ${reasonSection}
81779
81740
  </div>
81780
- <div class="info-item">
81781
- <span class="label">离线原因</span>
81782
- <span class="value">${reasonText}</span>
81741
+ <div class="footer">
81742
+ <p>此邮件由 LLBot 自动发送,请勿回复</p>
81783
81743
  </div>
81784
- </div>
81785
- <div class="alert-message">
81786
- 💡 请检查机器人状态和日志以获取更多信息,确保服务正常运行。
81787
- </div>
81788
- </div>
81789
- <div class="footer">
81790
- Powered by <strong>LLBot</strong> · Lucky Lillia Bot
81791
81744
  </div>
81792
- </div>
81793
81745
  </body>
81794
81746
  </html>
81795
81747
  `.trim();
81796
81748
  return { subject, html };
81797
81749
  }
81798
81750
  formatTestEmail(timestamp) {
81799
- const subject = "LLBot】测试邮件";
81751
+ const subject = "LLBot 邮件通知测试";
81800
81752
  const html = `
81801
81753
  <!DOCTYPE html>
81802
81754
  <html>
81803
81755
  <head>
81804
- <meta charset="UTF-8">
81805
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
81806
- <style>
81807
- * { margin: 0; padding: 0; box-sizing: border-box; }
81808
- body {
81809
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Microsoft YaHei", Arial, sans-serif;
81810
- background: linear-gradient(135deg, #8b5cf6 0%, #ec4899 100%);
81811
- padding: 40px 20px;
81812
- line-height: 1.6;
81813
- }
81814
- .container {
81815
- max-width: 600px;
81816
- margin: 0 auto;
81817
- background: white;
81818
- border-radius: 20px;
81819
- overflow: hidden;
81820
- box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
81821
- }
81822
- .header {
81823
- background: linear-gradient(135deg, #10b981 0%, #14b8a6 100%);
81824
- color: white;
81825
- padding: 40px 32px;
81826
- text-align: center;
81827
- position: relative;
81828
- }
81829
- .header::before {
81830
- content: '';
81831
- position: absolute;
81832
- top: 0;
81833
- left: 0;
81834
- right: 0;
81835
- bottom: 0;
81836
- background: radial-gradient(circle at 30% 50%, rgba(255,255,255,0.1) 0%, transparent 50%);
81837
- }
81838
- .header-content {
81839
- position: relative;
81840
- z-index: 1;
81841
- }
81842
- .icon {
81843
- font-size: 56px;
81844
- margin-bottom: 16px;
81845
- filter: drop-shadow(0 4px 6px rgba(0,0,0,0.1));
81846
- }
81847
- .header h2 {
81848
- font-size: 28px;
81849
- font-weight: 700;
81850
- margin-bottom: 8px;
81851
- letter-spacing: -0.5px;
81852
- }
81853
- .header p {
81854
- font-size: 15px;
81855
- opacity: 0.95;
81856
- font-weight: 500;
81857
- }
81858
- .content {
81859
- padding: 36px 32px;
81860
- }
81861
- .success-card {
81862
- background: linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%);
81863
- border-radius: 16px;
81864
- padding: 28px;
81865
- margin-bottom: 24px;
81866
- text-align: center;
81867
- border: 1px solid rgba(16, 185, 129, 0.2);
81868
- box-shadow: 0 1px 3px rgba(0,0,0,0.1);
81869
- }
81870
- .success-card p {
81871
- color: #065f46;
81872
- font-size: 17px;
81873
- margin: 10px 0;
81874
- font-weight: 500;
81875
- }
81876
- .success-card .subtitle {
81877
- font-size: 14px;
81878
- margin-top: 12px;
81879
- opacity: 0.8;
81880
- font-weight: 400;
81881
- }
81882
- .info-box {
81883
- background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%);
81884
- border-radius: 12px;
81885
- padding: 20px;
81886
- margin-top: 24px;
81887
- border: 1px solid rgba(0,0,0,0.05);
81888
- }
81889
- .info-box .label {
81890
- font-weight: 600;
81891
- color: #374151;
81892
- margin-bottom: 6px;
81893
- font-size: 13px;
81894
- text-transform: uppercase;
81895
- letter-spacing: 0.5px;
81896
- }
81897
- .info-box .value {
81898
- color: #6b7280;
81899
- font-size: 15px;
81900
- }
81901
- .footer {
81902
- text-align: center;
81903
- padding: 28px 24px;
81904
- background: linear-gradient(135deg, #f9fafb 0%, #f3f4f6 100%);
81905
- color: #9ca3af;
81906
- font-size: 13px;
81907
- border-top: 1px solid rgba(0,0,0,0.05);
81908
- }
81909
- .footer strong {
81910
- background: linear-gradient(135deg, #8b5cf6 0%, #ec4899 100%);
81911
- -webkit-background-clip: text;
81912
- -webkit-text-fill-color: transparent;
81913
- background-clip: text;
81914
- font-weight: 600;
81915
- }
81916
- </style>
81756
+ <meta charset="utf-8">
81757
+ <style>
81758
+ body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
81759
+ .container { max-width: 600px; margin: 0 auto; padding: 20px; }
81760
+ .header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; border-radius: 8px 8px 0 0; }
81761
+ .content { background: #f9f9f9; padding: 20px; border-radius: 0 0 8px 8px; }
81762
+ .info { background: white; padding: 15px; border-left: 4px solid #667eea; margin: 10px 0; }
81763
+ .footer { text-align: center; margin-top: 20px; color: #666; font-size: 12px; }
81764
+ </style>
81917
81765
  </head>
81918
81766
  <body>
81919
- <div class="container">
81920
- <div class="header">
81921
- <div class="header-content">
81922
- <div class="icon">✅</div>
81923
- <h2>测试邮件</h2>
81924
- <p>LLBot 邮件通知系统</p>
81925
- </div>
81926
- </div>
81927
- <div class="content">
81928
- <div class="success-card">
81929
- <p>🎉 恭喜!邮件配置测试成功</p>
81930
- <p class="subtitle">如果您收到此邮件,说明您的邮件配置已正确设置。</p>
81931
- </div>
81932
- <div class="info-box">
81933
- <div class="label">发送时间</div>
81934
- <div class="value">${timestamp}</div>
81935
- </div>
81936
- </div>
81937
- <div class="footer">
81938
- Powered by <strong>LLBot</strong> · Lucky Lillia Bot
81767
+ <div class="container">
81768
+ <div class="header">
81769
+ <h2>🎉 LLBot 邮件通知测试</h2>
81770
+ </div>
81771
+ <div class="content">
81772
+ <p>您好!</p>
81773
+ <p>这是一封来自 <strong>LLBot</strong> 的测试邮件。</p>
81774
+ <div class="info">
81775
+ <p><strong>📧 邮件配置测试成功</strong></p>
81776
+ <p>发送时间: ${timestamp}</p>
81777
+ </div>
81778
+ <p>如果您收到这封邮件,说明邮件通知功能已正常工作。</p>
81779
+ <p>当 QQ 掉线时,系统将自动向您发送通知邮件。</p>
81780
+ </div>
81781
+ <div class="footer">
81782
+ <p>此邮件由 LLBot 自动发送,请勿回复</p>
81783
+ </div>
81939
81784
  </div>
81940
- </div>
81941
81785
  </body>
81942
81786
  </html>
81943
81787
  `.trim();
@@ -82043,12 +81887,14 @@ class EmailConfigManager {
82043
81887
  }
82044
81888
  }
82045
81889
  class EmailNotificationService extends Service2 {
81890
+ static inject = ["logger"];
82046
81891
  emailService;
82047
81892
  configManager;
82048
81893
  notificationSent = false;
82049
81894
  hasLoggedIn = false;
82050
81895
  configPath;
82051
81896
  fileWatcher = null;
81897
+ pmhqDisconnectId = null;
82052
81898
  constructor(ctx) {
82053
81899
  super(ctx, "emailNotification", true);
82054
81900
  this.configPath = path__default.join(DATA_DIR, "email_config.json");
@@ -82057,6 +81903,7 @@ class EmailNotificationService extends Service2 {
82057
81903
  this.initializeConfig();
82058
81904
  this.registerEventListeners();
82059
81905
  this.watchConfigFile();
81906
+ this.registerPmhqDisconnectCallback();
82060
81907
  }
82061
81908
  async initializeConfig() {
82062
81909
  try {
@@ -82072,7 +81919,7 @@ class EmailNotificationService extends Service2 {
82072
81919
  let wasOffline = false;
82073
81920
  this.ctx.on("nt/kicked-offLine", (info) => {
82074
81921
  wasOffline = true;
82075
- this.onOffline(info);
81922
+ this.onOffline(info.tipsDesc || info.tipsTitle);
82076
81923
  });
82077
81924
  const checkLoginStatus = setInterval(() => {
82078
81925
  if (wasOffline && selfInfo.online) {
@@ -82086,6 +81933,9 @@ class EmailNotificationService extends Service2 {
82086
81933
  if (this.fileWatcher) {
82087
81934
  this.fileWatcher.close();
82088
81935
  }
81936
+ if (this.pmhqDisconnectId) {
81937
+ pmhq.offDisconnect(this.pmhqDisconnectId);
81938
+ }
82089
81939
  });
82090
81940
  }
82091
81941
  watchConfigFile() {
@@ -82102,7 +81952,16 @@ class EmailNotificationService extends Service2 {
82102
81952
  this.ctx.logger.error("[EmailNotification] Failed to watch config file:", error2);
82103
81953
  }
82104
81954
  }
82105
- onOffline(info) {
81955
+ registerPmhqDisconnectCallback() {
81956
+ this.pmhqDisconnectId = pmhq.onDisconnect(6e4, (duration2) => {
81957
+ if (!this.notificationSent && this.hasLoggedIn) {
81958
+ this.ctx.logger.warn(`[EmailNotification] PMHQ disconnected for ${duration2}ms`);
81959
+ this.onOffline("可能 QQ 已经有点死了");
81960
+ }
81961
+ });
81962
+ this.ctx.logger.info(`[EmailNotification] Registered PMHQ disconnect callback with ID: ${this.pmhqDisconnectId}`);
81963
+ }
81964
+ onOffline(reason) {
82106
81965
  if (!this.hasLoggedIn) {
82107
81966
  this.ctx.logger.debug("[EmailNotification] Offline event before login, ignoring");
82108
81967
  return;
@@ -82112,7 +81971,7 @@ class EmailNotificationService extends Service2 {
82112
81971
  return;
82113
81972
  }
82114
81973
  this.ctx.logger.info("[EmailNotification] Bot went offline, sending notification");
82115
- this.sendOfflineNotification(info.tipsDesc || info.tipsTitle);
81974
+ this.sendOfflineNotification(reason);
82116
81975
  }
82117
81976
  async sendOfflineNotification(reason) {
82118
81977
  try {
@@ -82257,9 +82116,9 @@ try {
82257
82116
  }
82258
82117
  export {
82259
82118
  Action as A,
82260
- Media as M,
82119
+ Msg as M,
82261
82120
  Notify as N,
82262
82121
  Oidb as O,
82263
- Msg as a
82122
+ Media as a
82264
82123
  };
82265
82124
  //# sourceMappingURL=llbot.js.map