liangzimixin 0.2.18 → 0.3.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.
package/dist/index.cjs CHANGED
@@ -3658,7 +3658,7 @@ __export(index_exports, {
3658
3658
  startPlugin: () => startPlugin
3659
3659
  });
3660
3660
  module.exports = __toCommonJS(index_exports);
3661
- var import_node_path3 = require("path");
3661
+ var import_node_path2 = require("path");
3662
3662
  var import_node_os = require("os");
3663
3663
 
3664
3664
  // node_modules/zod/v4/classic/external.js
@@ -17454,14 +17454,6 @@ var AccountConfigSchema = external_exports.object({
17454
17454
  "quantum-appId": external_exports.string().min(1, "quantum-appId \u4E0D\u80FD\u4E3A\u7A7A"),
17455
17455
  /** 🔴 量子服务密钥 — 用于量子密钥分发 */
17456
17456
  "quantum-appSecret": external_exports.string().min(1, "quantum-appSecret \u4E0D\u80FD\u4E3A\u7A7A"),
17457
- /** 🔴 PIN 口令 — 保护本地敏感数据 (切勿泄露, 修改后需删除旧密钥数据) */
17458
- pin: external_exports.string().min(1, "pin \u4E0D\u80FD\u4E3A\u7A7A"),
17459
- /**
17460
- * 🟡 量子密服地址 — 默认生产环境
17461
- * 测试环境: http://223.244.14.238:8552
17462
- * 生产环境: https://cmsp.zdxlz.com:8552
17463
- */
17464
- "quantum-url": external_exports.string().url().optional().default("https://cmsp.zdxlz.com:8552"),
17465
17457
  /**
17466
17458
  * 🟡 Bot 自己的用户 ID — 用于 anti-loop 检查
17467
17459
  * 如果不填,需要通过其他 API 在运行时获取。
@@ -17473,8 +17465,6 @@ var AccountConfigSchema = external_exports.object({
17473
17465
  quantumAccount: raw["quantum-account"],
17474
17466
  quantumAppId: raw["quantum-appId"],
17475
17467
  quantumAppSecret: raw["quantum-appSecret"],
17476
- pin: raw.pin,
17477
- quantumUrl: raw["quantum-url"],
17478
17468
  botUserId: raw.botUserId
17479
17469
  }));
17480
17470
  var DEFAULT_INTERNAL_CONFIG = {
@@ -17493,7 +17483,10 @@ var DEFAULT_INTERNAL_CONFIG = {
17493
17483
  }
17494
17484
  },
17495
17485
  auth: {
17496
- serverUrl: process.env.LZMX_AUTH_URL || "https://imtwo.zdxlz.com/open-apis/v1",
17486
+ serverUrl: process.env.LZMX_AUTH_URL || "https://seal.example.com",
17487
+ clientName: "liangzimixin",
17488
+ scopes: ["openid", "im_sdk", "data_operate", "offline_access"],
17489
+ autoRegister: true,
17497
17490
  refreshAheadMs: 3e5
17498
17491
  },
17499
17492
  crypto: {
@@ -17981,7 +17974,7 @@ async function resolveAndUploadMedia(params) {
17981
17974
  };
17982
17975
  }
17983
17976
  const msgType = fileType;
17984
- const contentPayload = fileType === "file" ? { fileId: uploadResult.fileKey, fileName, size: uploadResult.fileSize } : { fileId: uploadResult.fileKey };
17977
+ const contentPayload = fileType === "file" ? { fileKey: uploadResult.fileKey, filename: fileName, size: uploadResult.fileSize } : { fileKey: uploadResult.fileKey };
17985
17978
  await messagePipe.sendMessage({
17986
17979
  chatId,
17987
17980
  senderId: chatId,
@@ -17991,7 +17984,7 @@ async function resolveAndUploadMedia(params) {
17991
17984
  });
17992
17985
  log3.info("media:sent", {
17993
17986
  chatId,
17994
- fileId: uploadResult.fileKey,
17987
+ fileKey: uploadResult.fileKey,
17995
17988
  msgType
17996
17989
  });
17997
17990
  return {
@@ -18118,20 +18111,20 @@ ${body}` : body || raw.content;
18118
18111
  }
18119
18112
  case "image": {
18120
18113
  const c = parsed;
18121
- fileId = c?.fileId;
18114
+ fileId = c?.fileKey;
18122
18115
  text = c?.altText ?? (fileId ? `![image](${fileId})` : "[image]");
18123
18116
  break;
18124
18117
  }
18125
18118
  case "file": {
18126
18119
  const c = parsed;
18127
- fileId = c?.fileId;
18128
- fileName = c?.fileName;
18120
+ fileId = c?.fileKey;
18121
+ fileName = c?.filename;
18129
18122
  text = fileName ? `[File: ${fileName}]` : "[file]";
18130
18123
  break;
18131
18124
  }
18132
18125
  case "voice": {
18133
18126
  const c = parsed;
18134
- fileId = c?.fileId;
18127
+ fileId = c?.fileKey;
18135
18128
  const durationMs = c?.duration;
18136
18129
  const durationStr = durationMs != null ? ` ${(durationMs / 1e3).toFixed(1)}s` : "";
18137
18130
  text = `[Voice${durationStr}]`;
@@ -18139,7 +18132,7 @@ ${body}` : body || raw.content;
18139
18132
  }
18140
18133
  case "video": {
18141
18134
  const c = parsed;
18142
- fileId = c?.fileId;
18135
+ fileId = c?.fileKey;
18143
18136
  const durationMs = c?.duration;
18144
18137
  const durationStr = durationMs != null ? ` ${(durationMs / 1e3).toFixed(1)}s` : "";
18145
18138
  text = `[Video${durationStr}]`;
@@ -18461,7 +18454,7 @@ var QUANTUM_IM_CONFIG_JSON_SCHEMA = {
18461
18454
  title: "\u91CF\u5B50\u5BC6\u4FE1 IM \u63D2\u4EF6\u914D\u7F6E",
18462
18455
  description: "\u5BC6\u4FE1 IM Channel \u63D2\u4EF6\uFF0C\u652F\u6301\u91CF\u5B50\u52A0\u5BC6\u7684\u5B89\u5168\u5373\u65F6\u901A\u4FE1\u3002",
18463
18456
  type: "object",
18464
- required: ["appId", "appSecret", "quantum-account", "quantum-appId", "quantum-appSecret", "pin"],
18457
+ required: ["appId", "appSecret", "quantum-account", "quantum-appId", "quantum-appSecret"],
18465
18458
  properties: {
18466
18459
  appId: {
18467
18460
  type: "string",
@@ -18495,19 +18488,6 @@ var QUANTUM_IM_CONFIG_JSON_SCHEMA = {
18495
18488
  minLength: 1,
18496
18489
  format: "password"
18497
18490
  },
18498
- pin: {
18499
- type: "string",
18500
- title: "PIN \u53E3\u4EE4",
18501
- description: "\u4FDD\u62A4\u672C\u5730\u654F\u611F\u6570\u636E\u7684\u53E3\u4EE4\uFF0C\u7531\u7528\u6237\u81EA\u5B9A\u4E49\uFF08\u5207\u52FF\u6CC4\u9732\uFF0C\u4FEE\u6539\u540E\u8BF7\u5220\u9664\u65E7\u5BC6\u94A5\u6570\u636E\uFF09",
18502
- minLength: 1,
18503
- format: "password"
18504
- },
18505
- "quantum-url": {
18506
- type: "string",
18507
- title: "\u91CF\u5B50\u5BC6\u670D\u5730\u5740",
18508
- description: "\u91CF\u5B50\u5BC6\u94A5\u7BA1\u7406\u670D\u52A1\u5730\u5740\u3002\u6D4B\u8BD5\u73AF\u5883: http://223.244.14.238:8552\uFF0C\u751F\u4EA7\u73AF\u5883: https://cmsp.zdxlz.com:8552",
18509
- default: "https://cmsp.zdxlz.com:8552"
18510
- },
18511
18491
  botUserId: {
18512
18492
  type: "string",
18513
18493
  title: "Bot \u7528\u6237 ID",
@@ -18601,7 +18581,6 @@ var quantumImOnboarding = {
18601
18581
  "\u8BF7\u51C6\u5907\u4EE5\u4E0B\u4FE1\u606F:",
18602
18582
  " 1. \u5E73\u53F0\u7533\u8BF7\u7684 appId \u548C appSecret",
18603
18583
  " 2. \u91CF\u5B50\u52A0\u5BC6\u670D\u52A1\u7684\u8D26\u6237\u3001appId \u548C appSecret",
18604
- " 3. \u4FDD\u62A4\u672C\u5730\u5BC6\u94A5\u6570\u636E\u7684 PIN \u53E3\u4EE4",
18605
18584
  "",
18606
18585
  "\u5982\u6709\u7591\u95EE\u8BF7\u8054\u7CFB\u5E73\u53F0\u7BA1\u7406\u5458\u83B7\u53D6\u3002"
18607
18586
  ].join("\n"),
@@ -18633,36 +18612,6 @@ var quantumImOnboarding = {
18633
18612
  initialValue: existing["quantum-appSecret"] ?? void 0,
18634
18613
  validate: required2
18635
18614
  });
18636
- const pin = await prompter.text({
18637
- message: "PIN \u53E3\u4EE4 (\u4FDD\u62A4\u672C\u5730\u654F\u611F\u6570\u636E, \u5207\u52FF\u6CC4\u9732)",
18638
- initialValue: existing.pin ?? void 0,
18639
- validate: required2
18640
- });
18641
- const urlChoice = await prompter.select({
18642
- message: "\u91CF\u5B50\u5BC6\u670D\u73AF\u5883",
18643
- options: [
18644
- { value: "https://cmsp.zdxlz.com:8552", label: "\u751F\u4EA7\u73AF\u5883", hint: "https://cmsp.zdxlz.com:8552" },
18645
- { value: "http://223.244.14.238:8552", label: "\u6D4B\u8BD5\u73AF\u5883", hint: "http://223.244.14.238:8552" },
18646
- { value: "custom", label: "\u81EA\u5B9A\u4E49\u5730\u5740" }
18647
- ],
18648
- initialValue: existing["quantum-url"] ?? "https://cmsp.zdxlz.com:8552"
18649
- });
18650
- let quantumUrl = urlChoice;
18651
- if (urlChoice === "custom") {
18652
- quantumUrl = await prompter.text({
18653
- message: "\u8BF7\u8F93\u5165\u91CF\u5B50\u5BC6\u670D\u5730\u5740",
18654
- placeholder: "https://your-server:8552",
18655
- validate: (v) => {
18656
- if (!v.trim()) return "\u4E0D\u80FD\u4E3A\u7A7A";
18657
- try {
18658
- new URL(v);
18659
- } catch {
18660
- return "\u8BF7\u8F93\u5165\u5408\u6CD5\u7684 URL";
18661
- }
18662
- return void 0;
18663
- }
18664
- });
18665
- }
18666
18615
  const channels = cfg.channels ?? {};
18667
18616
  const channelCfg = channels[CHANNEL_ID] ?? {};
18668
18617
  const accounts = channelCfg.accounts ?? {};
@@ -18680,9 +18629,7 @@ var quantumImOnboarding = {
18680
18629
  appSecret: appSecret.trim(),
18681
18630
  "quantum-account": quantumAccount.trim(),
18682
18631
  "quantum-appId": quantumAppId.trim(),
18683
- "quantum-appSecret": quantumAppSecret.trim(),
18684
- pin: pin.trim(),
18685
- "quantum-url": quantumUrl.trim()
18632
+ "quantum-appSecret": quantumAppSecret.trim()
18686
18633
  }
18687
18634
  }
18688
18635
  }
@@ -18867,7 +18814,6 @@ var quantumImPlugin = {
18867
18814
 
18868
18815
  // src/crypto/quantun-plug-adapter.ts
18869
18816
  var import_node_module = require("module");
18870
- var import_node_url = require("url");
18871
18817
  var import_meta = {};
18872
18818
  var log14 = createLogger("crypto/quantun-plug-adapter");
18873
18819
  var SM4_MODE = {
@@ -18877,8 +18823,7 @@ var SM4_MODE = {
18877
18823
  CBC_PKCS7PADDING: 4
18878
18824
  };
18879
18825
  var DEFAULT_ENCRYPT_MODE = SM4_MODE.CBC_PKCS7PADDING;
18880
- var _currentUrl = typeof __filename !== "undefined" ? (0, import_node_url.pathToFileURL)(__filename).href : import_meta.url;
18881
- var require2 = (0, import_node_module.createRequire)(_currentUrl);
18826
+ var require2 = (0, import_node_module.createRequire)(import_meta.url);
18882
18827
  var quantunPlug = null;
18883
18828
  try {
18884
18829
  quantunPlug = require2("./sdk/index.min.cjs");
@@ -18889,32 +18834,8 @@ try {
18889
18834
  }
18890
18835
  var quantun_plug_adapter_default = quantunPlug;
18891
18836
 
18892
- // src/crypto/quantum-config-writer.ts
18893
- var import_node_fs = require("fs");
18894
- var import_node_path = require("path");
18895
- var import_node_url2 = require("url");
18896
- var import_meta2 = {};
18897
- var log15 = createLogger("crypto/quantum-config-writer");
18898
- var _currentDir = typeof __dirname !== "undefined" ? __dirname : (0, import_node_path.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url));
18899
- var QUANTUM_JSON_PATH = (0, import_node_path.join)(
18900
- _currentDir,
18901
- "sdk",
18902
- "quantum.json"
18903
- );
18904
- function writeQuantumConfig(credentials) {
18905
- const sdkConfig = {
18906
- account: credentials.quantumAccount,
18907
- appID: credentials.quantumAppId,
18908
- pin: credentials.pin,
18909
- authCode: credentials.quantumAppSecret,
18910
- url: credentials.quantumUrl
18911
- };
18912
- (0, import_node_fs.writeFileSync)(QUANTUM_JSON_PATH, JSON.stringify(sdkConfig, null, 2), "utf-8");
18913
- log15.info("quantum.json written to", QUANTUM_JSON_PATH);
18914
- }
18915
-
18916
18837
  // src/crypto/crypto-engine.ts
18917
- var log16 = createLogger("crypto/crypto-engine");
18838
+ var log15 = createLogger("crypto/crypto-engine");
18918
18839
  var PASSTHROUGH_KEY_ID = "passthrough";
18919
18840
  var FILE_CHUNK_SIZE = 10 * 1024 * 1024;
18920
18841
  var FILE_DECRYPT_CHUNK_SIZE = FILE_CHUNK_SIZE + 16;
@@ -18925,26 +18846,20 @@ var CryptoEngine = class _CryptoEngine {
18925
18846
  initialized;
18926
18847
  /** 是否为透传模式 (不加密, 明文直接透传) */
18927
18848
  passthrough;
18928
- /** 用户凭据 — 用于生成 quantum.json (透传模式下为 undefined) */
18929
- credentials;
18930
18849
  /**
18931
18850
  * 构造加密引擎
18932
18851
  *
18933
- * @param opts - 构造选项
18934
- * @param opts.passthrough - true 为透传模式 (不加密); false 为加密模式 (默认)
18935
- * @param opts.credentials - 用户凭据 (加密模式必需, 用于生成 quantum.json)
18852
+ * @param passthrough - true 为透传模式 (不加密); false 为加密模式 (默认)
18936
18853
  *
18937
18854
  * 请使用静态工厂方法:
18938
- * - new CryptoEngine({ credentials }) → 加密模式, 使用量子 SDK
18855
+ * - new CryptoEngine() → 加密模式, 使用量子 SDK
18939
18856
  * - CryptoEngine.createPassthrough() → 透传模式, 无需 init()
18940
18857
  */
18941
- constructor(opts = {}) {
18942
- const { passthrough = false, credentials } = opts;
18858
+ constructor(passthrough = false) {
18943
18859
  this.passthrough = passthrough;
18944
- this.credentials = credentials;
18945
18860
  this.plug = passthrough ? null : quantun_plug_adapter_default;
18946
18861
  this.initialized = passthrough;
18947
- log16.info(`CryptoEngine created (${passthrough ? "passthrough mode \u2014 crypto disabled" : "quantum SDK mode"})`);
18862
+ log15.info(`CryptoEngine created (${passthrough ? "passthrough mode \u2014 crypto disabled" : "quantum SDK mode"})`);
18948
18863
  }
18949
18864
  /**
18950
18865
  * 创建透传模式的加密引擎 (静态工厂方法)
@@ -18958,7 +18873,7 @@ var CryptoEngine = class _CryptoEngine {
18958
18873
  * 上层模块 (TokenStore, MessagePipe) 无需感知加密是否开启。
18959
18874
  */
18960
18875
  static createPassthrough() {
18961
- return new _CryptoEngine({ passthrough: true });
18876
+ return new _CryptoEngine(true);
18962
18877
  }
18963
18878
  /**
18964
18879
  * 初始化加密引擎
@@ -18974,19 +18889,11 @@ var CryptoEngine = class _CryptoEngine {
18974
18889
  return;
18975
18890
  }
18976
18891
  if (!this.plug) {
18977
- log16.warn(
18978
- "Quantum encryption SDK is missing \u2014 automatically falling back to passthrough mode. Messages will NOT be encrypted. Deploy sdk/index.min.cjs to enable encryption."
18979
- );
18980
- this.passthrough = true;
18981
- this.initialized = true;
18982
- return;
18983
- }
18984
- if (this.credentials) {
18985
- writeQuantumConfig(this.credentials);
18892
+ throw new Error("Quantum encryption SDK is missing. Cannot initialize in encryption mode (check dist/index.min.cjs).");
18986
18893
  }
18987
18894
  await this.plug.init();
18988
18895
  this.initialized = true;
18989
- log16.info("CryptoEngine initialized \u2713");
18896
+ log15.info("CryptoEngine initialized \u2713");
18990
18897
  }
18991
18898
  /**
18992
18899
  * 加密明文
@@ -19002,12 +18909,12 @@ var CryptoEngine = class _CryptoEngine {
19002
18909
  */
19003
18910
  async encrypt(plaintext) {
19004
18911
  if (this.passthrough) {
19005
- log16.debug("Encrypt (passthrough)", { length: plaintext.length });
18912
+ log15.debug("Encrypt (passthrough)", { length: plaintext.length });
19006
18913
  return { ciphertext: plaintext, keyId: PASSTHROUGH_KEY_ID };
19007
18914
  }
19008
18915
  const plug = this.requirePlug();
19009
18916
  const result = await plug.encrypt(plaintext, DEFAULT_ENCRYPT_MODE);
19010
- log16.debug("Encrypted", { length: plaintext.length, keyId: result.keyId });
18917
+ log15.debug("Encrypted", { length: plaintext.length, keyId: result.keyId });
19011
18918
  return { ciphertext: result.cipherText, keyId: result.keyId };
19012
18919
  }
19013
18920
  /**
@@ -19023,12 +18930,12 @@ var CryptoEngine = class _CryptoEngine {
19023
18930
  */
19024
18931
  async decrypt(ciphertext, keyId) {
19025
18932
  if (this.passthrough) {
19026
- log16.debug("Decrypt (passthrough)", { keyId });
18933
+ log15.debug("Decrypt (passthrough)", { keyId });
19027
18934
  return ciphertext;
19028
18935
  }
19029
18936
  const plug = this.requirePlug();
19030
18937
  const result = await plug.decrypt(ciphertext, keyId, DEFAULT_ENCRYPT_MODE);
19031
- log16.debug("Decrypted", { keyId });
18938
+ log15.debug("Decrypted", { keyId });
19032
18939
  return result.plainText;
19033
18940
  }
19034
18941
  /**
@@ -19045,7 +18952,7 @@ var CryptoEngine = class _CryptoEngine {
19045
18952
  */
19046
18953
  async encryptFile(fileData) {
19047
18954
  if (this.passthrough) {
19048
- log16.debug("EncryptFile (passthrough)", { size: fileData.length });
18955
+ log15.debug("EncryptFile (passthrough)", { size: fileData.length });
19049
18956
  return { fileBuffer: fileData, keyId: PASSTHROUGH_KEY_ID };
19050
18957
  }
19051
18958
  if (fileData.length === 0) {
@@ -19057,7 +18964,7 @@ var CryptoEngine = class _CryptoEngine {
19057
18964
  let sessionKey;
19058
18965
  let fillKey;
19059
18966
  const plug = this.requirePlug();
19060
- log16.debug("EncryptFile", { size: fileData.length, chunks: total });
18967
+ log15.debug("EncryptFile", { size: fileData.length, chunks: total });
19061
18968
  for (let i = 0; i < total; i++) {
19062
18969
  const start = i * FILE_CHUNK_SIZE;
19063
18970
  const end = Math.min(start + FILE_CHUNK_SIZE, fileData.length);
@@ -19072,7 +18979,7 @@ var CryptoEngine = class _CryptoEngine {
19072
18979
  sessionKey = result.sessionKey;
19073
18980
  fillKey = result.fillKey;
19074
18981
  }
19075
- log16.debug("EncryptFile done", { keyId, chunks: total });
18982
+ log15.debug("EncryptFile done", { keyId, chunks: total });
19076
18983
  return { fileBuffer: Buffer.concat(chunks), keyId: keyId ?? "" };
19077
18984
  }
19078
18985
  /**
@@ -19090,7 +18997,7 @@ var CryptoEngine = class _CryptoEngine {
19090
18997
  */
19091
18998
  async decryptFile(fileData, keyId) {
19092
18999
  if (this.passthrough) {
19093
- log16.debug("DecryptFile (passthrough)", { keyId });
19000
+ log15.debug("DecryptFile (passthrough)", { keyId });
19094
19001
  return fileData;
19095
19002
  }
19096
19003
  if (fileData.length === 0) {
@@ -19101,7 +19008,7 @@ var CryptoEngine = class _CryptoEngine {
19101
19008
  const total = Math.ceil(fileData.length / FILE_DECRYPT_CHUNK_SIZE);
19102
19009
  let sessionKey;
19103
19010
  let fillKey;
19104
- log16.debug("DecryptFile", { size: fileData.length, chunks: total, keyId });
19011
+ log15.debug("DecryptFile", { size: fileData.length, chunks: total, keyId });
19105
19012
  for (let i = 0; i < total; i++) {
19106
19013
  const start = i * FILE_DECRYPT_CHUNK_SIZE;
19107
19014
  const end = Math.min(start + FILE_DECRYPT_CHUNK_SIZE, fileData.length);
@@ -19114,7 +19021,7 @@ var CryptoEngine = class _CryptoEngine {
19114
19021
  sessionKey = result.sessionKey;
19115
19022
  fillKey = result.fillKey;
19116
19023
  }
19117
- log16.debug("DecryptFile done", { keyId, chunks: total });
19024
+ log15.debug("DecryptFile done", { keyId, chunks: total });
19118
19025
  return Buffer.concat(chunks);
19119
19026
  }
19120
19027
  /**
@@ -19137,14 +19044,14 @@ var CryptoEngine = class _CryptoEngine {
19137
19044
  };
19138
19045
 
19139
19046
  // src/auth/oauth-client.ts
19140
- var log17 = createLogger("auth/oauth-client");
19141
- var ApiError = class extends Error {
19047
+ var log16 = createLogger("auth/oauth-client");
19048
+ var SealApiError = class extends Error {
19142
19049
  constructor(status, body, endpoint) {
19143
- super(`API error: ${status} on ${endpoint}`);
19050
+ super(`Seal API error: ${status} on ${endpoint}`);
19144
19051
  this.status = status;
19145
19052
  this.body = body;
19146
19053
  this.endpoint = endpoint;
19147
- this.name = "ApiError";
19054
+ this.name = "SealApiError";
19148
19055
  }
19149
19056
  };
19150
19057
  var TokenAcquireError = class extends Error {
@@ -19161,21 +19068,28 @@ function sleep(ms) {
19161
19068
  return new Promise((resolve2) => setTimeout(resolve2, ms));
19162
19069
  }
19163
19070
  var DEFAULT_TIMEOUT_MS = 3e4;
19164
- var GRANT_TYPE = "client_credentials";
19165
- var SCOPE = "client_credentials refresh_token";
19166
- var OAuthClient = class {
19071
+ var SealClient = class {
19167
19072
  baseUrl;
19168
- appId;
19169
- appSecret;
19073
+ clientId;
19074
+ clientSecret;
19075
+ clientName;
19076
+ scopes;
19170
19077
  constructor(config2) {
19171
- this.baseUrl = config2.baseUrl.replace(/\/+$/, "");
19172
- this.appId = config2.appId;
19173
- this.appSecret = config2.appSecret;
19174
- log17.info("OAuthClient initialized", { baseUrl: this.baseUrl, appId: sanitize(this.appId) });
19078
+ this.baseUrl = config2.serverUrl.replace(/\/+$/, "");
19079
+ this.clientId = config2.clientId;
19080
+ this.clientSecret = config2.clientSecret;
19081
+ this.clientName = config2.clientName;
19082
+ this.scopes = config2.scopes;
19083
+ log16.info("SealClient initialized", { serverUrl: this.baseUrl, clientName: config2.clientName });
19175
19084
  }
19176
19085
  // ── 通用 HTTP 请求 ──
19177
19086
  /**
19178
19087
  * 统一 HTTP 请求封装 — 含超时、日志脱敏和错误处理
19088
+ * @param method - HTTP 方法
19089
+ * @param path - 请求路径 (如 '/seal/client/register')
19090
+ * @param options - 请求选项
19091
+ * @returns 解析后的 JSON 响应
19092
+ * @throws SealApiError — HTTP 非 2xx 响应
19179
19093
  */
19180
19094
  async request(method, path2, options = {}) {
19181
19095
  const url2 = `${this.baseUrl}${path2}`;
@@ -19191,7 +19105,7 @@ var OAuthClient = class {
19191
19105
  bodyStr = JSON.stringify(options.body);
19192
19106
  }
19193
19107
  }
19194
- log17.debug("HTTP request", { method, url: url2 });
19108
+ log16.debug("HTTP request", { method, url: url2 });
19195
19109
  const response = await fetch(url2, {
19196
19110
  method,
19197
19111
  headers,
@@ -19206,39 +19120,110 @@ var OAuthClient = class {
19206
19120
  } catch {
19207
19121
  parsedBody = responseBody;
19208
19122
  }
19209
- log17.error("HTTP error", { method, url: url2, status: response.status });
19210
- throw new ApiError(response.status, parsedBody, path2);
19123
+ log16.error("HTTP error", { method, url: url2, status: response.status });
19124
+ throw new SealApiError(response.status, parsedBody, path2);
19211
19125
  }
19212
- log17.debug("HTTP response", { method, url: url2, status: response.status });
19126
+ log16.debug("HTTP response", { method, url: url2, status: response.status });
19213
19127
  try {
19214
19128
  return JSON.parse(responseBody);
19215
19129
  } catch {
19216
- throw new ApiError(response.status, responseBody, path2);
19130
+ throw new SealApiError(response.status, responseBody, path2);
19217
19131
  }
19218
19132
  }
19219
19133
  // ── 公共方法 ──
19134
+ /** 判断是否已注册 (有 clientId + clientSecret) */
19135
+ isRegistered() {
19136
+ return !!(this.clientId && this.clientSecret);
19137
+ }
19138
+ /** 更新 clientId / clientSecret (注册成功后或从持久化加载后调用) */
19139
+ setCredentials(clientId, clientSecret) {
19140
+ this.clientId = clientId;
19141
+ this.clientSecret = clientSecret;
19142
+ log16.info("Credentials updated", { clientId: sanitize(clientId) });
19143
+ }
19220
19144
  /**
19221
- * 获取访问令牌 → POST /auth/token (client_credentials)
19145
+ * 动态注册客户端 → POST /seal/client/register
19222
19146
  *
19223
- * 请求参数 (x-www-form-urlencoded):
19224
- * - grant_type: client_credentials (写死)
19225
- * - client_id: appId
19226
- * - client_secret: appSecret
19227
- * - scope: client_credentials refresh_token (写死)
19147
+ * 首次运行时自动调用,获取 clientId 和 clientSecret。
19148
+ * 注册成功后自动更新内部凭据。
19149
+ */
19150
+ async register(params) {
19151
+ const body = {
19152
+ client_name: params.clientName,
19153
+ scopes: params.scopes,
19154
+ authentication_methods: params.authMethods ?? ["client_secret_post"],
19155
+ grant_types: params.grantTypes ?? ["authorization_code", "client_credentials", "refresh_token"],
19156
+ redirect_uris: params.redirectUris ?? ["https://placeholder.local"],
19157
+ logout_redirect_uris: [],
19158
+ client_settings: {
19159
+ "settings.client.require-authorization-consent": true
19160
+ }
19161
+ };
19162
+ if (params.tokenSettings) {
19163
+ const ts = {};
19164
+ if (params.tokenSettings.accessTokenTtl) {
19165
+ ts["settings.token.access-token-time-to-live"] = params.tokenSettings.accessTokenTtl;
19166
+ }
19167
+ if (params.tokenSettings.refreshTokenTtl) {
19168
+ ts["settings.token.refresh-token-time-to-live"] = params.tokenSettings.refreshTokenTtl;
19169
+ }
19170
+ if (params.tokenSettings.accessTokenFormat) {
19171
+ ts["settings.token.access-token-format"] = params.tokenSettings.accessTokenFormat;
19172
+ }
19173
+ if (params.tokenSettings.reuseRefreshTokens !== void 0) {
19174
+ ts["settings.token.reuse-refresh-tokens"] = params.tokenSettings.reuseRefreshTokens;
19175
+ }
19176
+ ts["settings.token.authorization-code-time-to-live"] = "300";
19177
+ body.token_settings = ts;
19178
+ }
19179
+ log16.info("Registering OAuth client", { clientName: params.clientName });
19180
+ const response = await this.request(
19181
+ "POST",
19182
+ "/seal/client/register",
19183
+ { body, contentType: "json" }
19184
+ );
19185
+ const registration = {
19186
+ clientId: response.client_id,
19187
+ clientSecret: response.client_secret,
19188
+ clientSecretExpiresAt: response.client_secret_expires_at ?? "",
19189
+ clientIdIssuedAt: response.client_id_issued_at ?? "",
19190
+ scopes: response.scopes ?? params.scopes
19191
+ };
19192
+ this.setCredentials(registration.clientId, registration.clientSecret);
19193
+ log16.info("OAuth client registered", {
19194
+ clientId: sanitize(registration.clientId),
19195
+ clientSecret: sanitize(registration.clientSecret),
19196
+ scopes: registration.scopes,
19197
+ expiresAt: registration.clientSecretExpiresAt
19198
+ });
19199
+ return registration;
19200
+ }
19201
+ /**
19202
+ * 获取访问令牌 → POST /seal/oauth2/token (client_credentials)
19228
19203
  *
19204
+ * 使用客户端凭证模式获取 Access Token。
19205
+ * 前置条件: clientId 和 clientSecret 必须存在 (通过 register 或 setCredentials 设置)
19206
+ *
19207
+ * @param scope - 请求的权限范围 (空格分隔),不传则使用注册时的全部 scope
19229
19208
  * @returns TokenData 包含 access_token、过期时间等
19230
- * @throws ApiErrorHTTP 错误
19209
+ * @throws ErrorclientId/clientSecret 未设置
19210
+ * @throws SealApiError — HTTP 错误
19231
19211
  */
19232
- async getToken() {
19212
+ async getToken(scope) {
19213
+ if (!this.clientId || !this.clientSecret) {
19214
+ throw new Error("Cannot get token: clientId and clientSecret are required. Call register() or setCredentials() first.");
19215
+ }
19233
19216
  const params = new URLSearchParams();
19234
- params.set("grant_type", GRANT_TYPE);
19235
- params.set("client_id", this.appId);
19236
- params.set("client_secret", this.appSecret);
19237
- params.set("scope", SCOPE);
19238
- log17.info("Requesting access token", { appId: sanitize(this.appId) });
19217
+ params.set("grant_type", "client_credentials");
19218
+ params.set("client_id", this.clientId);
19219
+ params.set("client_secret", this.clientSecret);
19220
+ if (scope) {
19221
+ params.set("scope", scope);
19222
+ }
19223
+ log16.info("Requesting access token", { clientId: sanitize(this.clientId) });
19239
19224
  const response = await this.request(
19240
19225
  "POST",
19241
- "/auth/token",
19226
+ "/seal/oauth2/token",
19242
19227
  { body: params, contentType: "form" }
19243
19228
  );
19244
19229
  const now = Date.now();
@@ -19249,28 +19234,32 @@ var OAuthClient = class {
19249
19234
  expiresIn,
19250
19235
  scope: response.scope ?? "",
19251
19236
  refreshToken: void 0,
19237
+ // Seal 不返回 refresh_token
19252
19238
  grantedAt: now,
19253
19239
  expiresAt: now + expiresIn * 1e3
19254
19240
  };
19255
- log17.info("Access token acquired", {
19241
+ log16.info("Access token acquired", {
19256
19242
  accessToken: sanitize(tokenData.accessToken),
19257
19243
  expiresIn: tokenData.expiresIn,
19258
19244
  scope: tokenData.scope
19259
19245
  });
19260
19246
  return tokenData;
19261
19247
  }
19262
- /** 获取 baseUrl (供其他模块复用) */
19263
- getBaseUrl() {
19264
- return this.baseUrl;
19248
+ /**
19249
+ * 令牌校验 → GET /seal/oauth2/introspect
19250
+ * 暂不实现 — 保留接口签名,后续需要时再补充
19251
+ */
19252
+ async introspect(_token) {
19253
+ throw new Error("introspect() not implemented yet \u2014 Seal introspect API \u6682\u4E0D\u4F7F\u7528");
19265
19254
  }
19266
19255
  };
19267
19256
 
19268
19257
  // src/auth/token-store.ts
19269
19258
  var import_promises = require("fs/promises");
19270
- var import_node_fs2 = require("fs");
19271
- var import_node_path2 = require("path");
19259
+ var import_node_fs = require("fs");
19260
+ var import_node_path = require("path");
19272
19261
  var import_node_crypto = require("crypto");
19273
- var log18 = createLogger("auth/token-store");
19262
+ var log17 = createLogger("auth/token-store");
19274
19263
  var TokenStore = class {
19275
19264
  /** 存储目录路径 */
19276
19265
  storageDir;
@@ -19285,7 +19274,7 @@ var TokenStore = class {
19285
19274
  constructor(storageDir, crypto) {
19286
19275
  this.storageDir = storageDir;
19287
19276
  this.crypto = crypto;
19288
- log18.info("TokenStore initialized", { storageDir });
19277
+ log17.info("TokenStore initialized", { storageDir });
19289
19278
  }
19290
19279
  /**
19291
19280
  * 确保存储目录存在并设置正确的权限。
@@ -19293,9 +19282,9 @@ var TokenStore = class {
19293
19282
  */
19294
19283
  async ensureDir() {
19295
19284
  if (this.dirEnsured) return;
19296
- if (!(0, import_node_fs2.existsSync)(this.storageDir)) {
19285
+ if (!(0, import_node_fs.existsSync)(this.storageDir)) {
19297
19286
  await (0, import_promises.mkdir)(this.storageDir, { recursive: true, mode: 448 });
19298
- log18.debug("Storage directory created", { dir: this.storageDir });
19287
+ log17.debug("Storage directory created", { dir: this.storageDir });
19299
19288
  }
19300
19289
  this.dirEnsured = true;
19301
19290
  }
@@ -19304,7 +19293,7 @@ var TokenStore = class {
19304
19293
  * @param key - 存储键名 (如 'token', 'credentials')
19305
19294
  */
19306
19295
  filePath(key) {
19307
- return (0, import_node_path2.join)(this.storageDir, `${key}.enc`);
19296
+ return (0, import_node_path.join)(this.storageDir, `${key}.enc`);
19308
19297
  }
19309
19298
  /**
19310
19299
  * 保存 Token — 加密写入文件
@@ -19330,7 +19319,7 @@ var TokenStore = class {
19330
19319
  try {
19331
19320
  await (0, import_promises.writeFile)(tmpPath, storageJson, { mode: 384 });
19332
19321
  await (0, import_promises.rename)(tmpPath, targetPath);
19333
- log18.debug("Token saved", { key, path: targetPath });
19322
+ log17.debug("Token saved", { key, path: targetPath });
19334
19323
  } catch (err) {
19335
19324
  try {
19336
19325
  await (0, import_promises.unlink)(tmpPath);
@@ -19352,8 +19341,8 @@ var TokenStore = class {
19352
19341
  */
19353
19342
  async load(key) {
19354
19343
  const filePath = this.filePath(key);
19355
- if (!(0, import_node_fs2.existsSync)(filePath)) {
19356
- log18.debug("Token file not found", { key, path: filePath });
19344
+ if (!(0, import_node_fs.existsSync)(filePath)) {
19345
+ log17.debug("Token file not found", { key, path: filePath });
19357
19346
  return null;
19358
19347
  }
19359
19348
  try {
@@ -19361,10 +19350,10 @@ var TokenStore = class {
19361
19350
  const storage = JSON.parse(raw);
19362
19351
  const json2 = await this.crypto.decrypt(storage.ciphertext, storage.keyId);
19363
19352
  const data = JSON.parse(json2);
19364
- log18.debug("Token loaded", { key, path: filePath });
19353
+ log17.debug("Token loaded", { key, path: filePath });
19365
19354
  return data;
19366
19355
  } catch (err) {
19367
- log18.warn("Failed to load token (corrupted or key mismatch), treating as empty", {
19356
+ log17.warn("Failed to load token (corrupted or key mismatch), treating as empty", {
19368
19357
  key,
19369
19358
  error: err instanceof Error ? err.message : String(err)
19370
19359
  });
@@ -19380,7 +19369,7 @@ var TokenStore = class {
19380
19369
  const filePath = this.filePath(key);
19381
19370
  try {
19382
19371
  await (0, import_promises.unlink)(filePath);
19383
- log18.debug("Token file cleared", { key, path: filePath });
19372
+ log17.debug("Token file cleared", { key, path: filePath });
19384
19373
  } catch (err) {
19385
19374
  if (err.code !== "ENOENT") {
19386
19375
  throw err;
@@ -19390,15 +19379,17 @@ var TokenStore = class {
19390
19379
  };
19391
19380
 
19392
19381
  // src/auth/token-manager.ts
19393
- var log19 = createLogger("auth/token-manager");
19382
+ var log18 = createLogger("auth/token-manager");
19394
19383
  var DEFAULT_REFRESH_AHEAD_MS = 5 * 60 * 1e3;
19395
19384
  var MAX_RETRIES = 3;
19396
19385
  var RETRY_BASE_MS = 1e3;
19397
19386
  var TokenManager = class {
19398
- oauthClient;
19387
+ sealClient;
19399
19388
  tokenStore;
19400
19389
  /** Token 过期前提前刷新的时间 (ms) */
19401
19390
  refreshAheadMs;
19391
+ /** 自动注册的参数 */
19392
+ autoRegisterParams;
19402
19393
  // ── 内存缓存 ──
19403
19394
  /** 内存中缓存的 access_token */
19404
19395
  cachedToken = null;
@@ -19412,10 +19403,11 @@ var TokenManager = class {
19412
19403
  /** 定时刷新器句柄 */
19413
19404
  refreshTimer = null;
19414
19405
  constructor(deps) {
19415
- this.oauthClient = deps.oauthClient;
19406
+ this.sealClient = deps.sealClient;
19416
19407
  this.tokenStore = deps.tokenStore;
19417
19408
  this.refreshAheadMs = deps.refreshAheadMs ?? DEFAULT_REFRESH_AHEAD_MS;
19418
- log19.info("TokenManager initialized", { refreshAheadMs: this.refreshAheadMs });
19409
+ this.autoRegisterParams = deps.autoRegisterParams;
19410
+ log18.info("TokenManager initialized", { refreshAheadMs: this.refreshAheadMs });
19419
19411
  }
19420
19412
  // ── 核心方法 ──
19421
19413
  /**
@@ -19433,7 +19425,7 @@ var TokenManager = class {
19433
19425
  return this.cachedToken;
19434
19426
  }
19435
19427
  if (this.refreshLock) {
19436
- log19.debug("Waiting for concurrent token acquisition");
19428
+ log18.debug("Waiting for concurrent token acquisition");
19437
19429
  return this.refreshLock;
19438
19430
  }
19439
19431
  this.refreshLock = this._acquireTokenWithRetry();
@@ -19443,6 +19435,13 @@ var TokenManager = class {
19443
19435
  this.refreshLock = null;
19444
19436
  }
19445
19437
  }
19438
+ /**
19439
+ * 令牌自省 — 暂不实现,后续补充。
19440
+ * 返回的 identity_id 用于 gate.ts 的 anti-loop 检查 (bot 自己的 ID)。
19441
+ */
19442
+ async introspect() {
19443
+ throw new Error("introspect() not implemented yet \u2014 Seal introspect API \u6682\u4E0D\u4F7F\u7528");
19444
+ }
19446
19445
  /** 检查当前令牌是否包含指定的 scope */
19447
19446
  hasScope(scope) {
19448
19447
  if (!this.cachedScope) return false;
@@ -19459,13 +19458,13 @@ var TokenManager = class {
19459
19458
  this.cachedToken = null;
19460
19459
  this.cachedScope = null;
19461
19460
  this.currentTokenData = null;
19462
- log19.info("Token revoked and cleared");
19461
+ log18.info("Token revoked and cleared");
19463
19462
  }
19464
19463
  /** 清理定时器和并发锁 — 优雅关闭时调用 */
19465
19464
  shutdown() {
19466
19465
  this.clearRefreshTimer();
19467
19466
  this.refreshLock = null;
19468
- log19.info("TokenManager shutdown");
19467
+ log18.info("TokenManager shutdown");
19469
19468
  }
19470
19469
  // ── 内部方法 ──
19471
19470
  /**
@@ -19473,26 +19472,26 @@ var TokenManager = class {
19473
19472
  *
19474
19473
  * 重试策略:
19475
19474
  * - 网络错误 / 5xx → 重试 (最多 3 次)
19476
- * - 401/403 → 不重试 (凭证可能无效)
19475
+ * - 401/403 → 不重试 (client_secret 可能无效)
19477
19476
  */
19478
19477
  async _acquireTokenWithRetry() {
19479
19478
  for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
19480
19479
  try {
19481
19480
  return await this._acquireToken();
19482
19481
  } catch (err) {
19483
- if (err instanceof ApiError && (err.status === 401 || err.status === 403)) {
19484
- log19.error("Token acquire failed with auth error, not retrying", { status: err.status });
19482
+ if (err instanceof SealApiError && (err.status === 401 || err.status === 403)) {
19483
+ log18.error("Token acquire failed with auth error, not retrying", { status: err.status });
19485
19484
  throw err;
19486
19485
  }
19487
19486
  if (attempt === MAX_RETRIES) {
19488
- log19.error("Token acquire failed after all retries", { attempts: attempt + 1 });
19487
+ log18.error("Token acquire failed after all retries", { attempts: attempt + 1 });
19489
19488
  throw new TokenAcquireError(
19490
19489
  `Token acquire failed after ${attempt + 1} attempts`,
19491
19490
  { cause: err instanceof Error ? err : void 0 }
19492
19491
  );
19493
19492
  }
19494
19493
  const delay = RETRY_BASE_MS * Math.pow(2, attempt);
19495
- log19.warn("Token acquire failed, retrying", {
19494
+ log18.warn("Token acquire failed, retrying", {
19496
19495
  attempt: attempt + 1,
19497
19496
  maxRetries: MAX_RETRIES,
19498
19497
  retryInMs: delay,
@@ -19508,27 +19507,63 @@ var TokenManager = class {
19508
19507
  *
19509
19508
  * 流程:
19510
19509
  * 1. 尝试从 TokenStore 加载缓存
19511
- * 2. 调用 OAuthClient.getToken() 获取新 Token
19512
- * 3. 保存到内存缓存 + TokenStore
19513
- * 4. 设置定时刷新器
19510
+ * 2. 检查是否需要注册客户端
19511
+ * 3. 调用 SealClient.getToken() 获取新 Token
19512
+ * 4. 保存到内存缓存 + TokenStore
19513
+ * 5. 设置定时刷新器
19514
19514
  */
19515
19515
  async _acquireToken() {
19516
19516
  try {
19517
19517
  const stored = await this.tokenStore.load("token");
19518
19518
  if (stored && !this.isTokenHardExpired(stored)) {
19519
- log19.info("Token loaded from store (still valid)");
19519
+ log18.info("Token loaded from store (still valid)");
19520
19520
  this.updateCache(stored);
19521
19521
  this.scheduleRefresh(stored);
19522
19522
  return stored.accessToken;
19523
19523
  }
19524
19524
  if (stored) {
19525
- log19.info("Stored token has expired, acquiring new one");
19525
+ log18.info("Stored token has expired, acquiring new one");
19526
19526
  }
19527
19527
  } catch {
19528
- log19.warn("Failed to load token from store, acquiring new one");
19528
+ log18.warn("Failed to load token from store, acquiring new one");
19529
+ }
19530
+ if (!this.sealClient.isRegistered()) {
19531
+ try {
19532
+ const savedCreds = await this.tokenStore.load("credentials");
19533
+ if (savedCreds?.clientId && savedCreds?.clientSecret) {
19534
+ this.sealClient.setCredentials(
19535
+ savedCreds.clientId,
19536
+ savedCreds.clientSecret
19537
+ );
19538
+ log18.info("Credentials loaded from store");
19539
+ }
19540
+ } catch {
19541
+ log18.debug("No saved credentials found");
19542
+ }
19543
+ }
19544
+ if (!this.sealClient.isRegistered()) {
19545
+ if (!this.autoRegisterParams) {
19546
+ throw new Error("SealClient not registered and autoRegisterParams not provided. Call setCredentials() or enable autoRegister.");
19547
+ }
19548
+ log18.info("Auto-registering OAuth client");
19549
+ const registration = await this.sealClient.register({
19550
+ clientName: this.autoRegisterParams.clientName,
19551
+ scopes: this.autoRegisterParams.scopes,
19552
+ tokenSettings: this.autoRegisterParams.tokenSettings ? {
19553
+ accessTokenTtl: this.autoRegisterParams.tokenSettings.accessTokenTtl,
19554
+ refreshTokenTtl: this.autoRegisterParams.tokenSettings.refreshTokenTtl,
19555
+ accessTokenFormat: this.autoRegisterParams.tokenSettings.accessTokenFormat
19556
+ } : void 0
19557
+ });
19558
+ await this.tokenStore.save("credentials", {
19559
+ clientId: registration.clientId,
19560
+ clientSecret: registration.clientSecret,
19561
+ clientSecretExpiresAt: registration.clientSecretExpiresAt
19562
+ });
19563
+ log18.info("OAuth client registered and credentials saved");
19529
19564
  }
19530
- log19.info("Acquiring new access token via POST /auth/token");
19531
- const tokenData = await this.oauthClient.getToken();
19565
+ log18.info("Acquiring new access token");
19566
+ const tokenData = await this.sealClient.getToken();
19532
19567
  this.updateCache(tokenData);
19533
19568
  await this.tokenStore.save("token", tokenData);
19534
19569
  this.scheduleRefresh(tokenData);
@@ -19558,22 +19593,22 @@ var TokenManager = class {
19558
19593
  this.clearRefreshTimer();
19559
19594
  const refreshInMs = tokenData.expiresAt - this.refreshAheadMs - Date.now();
19560
19595
  if (refreshInMs <= 0) {
19561
- log19.debug("Token already within refresh window, not scheduling timer");
19596
+ log18.debug("Token already within refresh window, not scheduling timer");
19562
19597
  return;
19563
19598
  }
19564
- log19.debug("Scheduling token refresh", {
19599
+ log18.debug("Scheduling token refresh", {
19565
19600
  refreshInMs,
19566
19601
  refreshAt: new Date(Date.now() + refreshInMs).toISOString()
19567
19602
  });
19568
19603
  this.refreshTimer = setTimeout(async () => {
19569
19604
  try {
19570
- log19.info("Scheduled token refresh triggered");
19605
+ log18.info("Scheduled token refresh triggered");
19571
19606
  this.cachedToken = null;
19572
19607
  this.currentTokenData = null;
19573
19608
  await this.getValidToken();
19574
- log19.info("Scheduled token refresh completed");
19609
+ log18.info("Scheduled token refresh completed");
19575
19610
  } catch (err) {
19576
- log19.error("Scheduled token refresh failed", {
19611
+ log18.error("Scheduled token refresh failed", {
19577
19612
  error: err instanceof Error ? err.message : String(err)
19578
19613
  });
19579
19614
  }
@@ -19601,13 +19636,13 @@ var wrapper_default = import_websocket.default;
19601
19636
 
19602
19637
  // src/transport/ws-client.ts
19603
19638
  var import_node_events = require("events");
19604
- var log20 = createLogger("transport/ws-client");
19639
+ var log19 = createLogger("transport/ws-client");
19605
19640
  var WSClient = class extends import_node_events.EventEmitter {
19606
19641
  /** 底层 WebSocket 实例 */
19607
19642
  ws = null;
19608
19643
  constructor() {
19609
19644
  super();
19610
- log20.info("WSClient initialized");
19645
+ log19.info("WSClient initialized");
19611
19646
  }
19612
19647
  /**
19613
19648
  * 连接到 WebSocket 服务器并绑定事件。
@@ -19623,11 +19658,11 @@ var WSClient = class extends import_node_events.EventEmitter {
19623
19658
  this.ws = null;
19624
19659
  }
19625
19660
  const { url: url2, protocols, headers } = options;
19626
- log20.info("ws:connecting", { url: url2 });
19661
+ log19.info("ws:connecting", { url: url2 });
19627
19662
  return new Promise((resolve2, reject) => {
19628
19663
  const ws = new wrapper_default(url2, protocols, { headers });
19629
19664
  ws.on("open", () => {
19630
- log20.info("ws:connected", { url: url2 });
19665
+ log19.info("ws:connected", { url: url2 });
19631
19666
  this.emit("open");
19632
19667
  resolve2();
19633
19668
  });
@@ -19635,11 +19670,11 @@ var WSClient = class extends import_node_events.EventEmitter {
19635
19670
  this.emit("message", data);
19636
19671
  });
19637
19672
  ws.on("close", (code, reason) => {
19638
- log20.info("ws:closed", { code, reason: reason.toString() });
19673
+ log19.info("ws:closed", { code, reason: reason.toString() });
19639
19674
  this.emit("close", code, reason.toString());
19640
19675
  });
19641
19676
  ws.on("error", (err) => {
19642
- log20.error("ws:error", { error: err.message });
19677
+ log19.error("ws:error", { error: err.message });
19643
19678
  this.emit("error", err);
19644
19679
  if (this.ws !== ws) {
19645
19680
  reject(err);
@@ -19651,7 +19686,7 @@ var WSClient = class extends import_node_events.EventEmitter {
19651
19686
  /** 发送数据到服务器 — 前置检查连接状态 */
19652
19687
  send(data) {
19653
19688
  if (!this.ws || this.ws.readyState !== wrapper_default.OPEN) {
19654
- log20.warn("ws:send skipped, not connected", { readyState: this.ws?.readyState });
19689
+ log19.warn("ws:send skipped, not connected", { readyState: this.ws?.readyState });
19655
19690
  return;
19656
19691
  }
19657
19692
  this.ws.send(data);
@@ -19662,7 +19697,7 @@ var WSClient = class extends import_node_events.EventEmitter {
19662
19697
  this.ws.removeAllListeners();
19663
19698
  this.ws.close(code, reason);
19664
19699
  this.ws = null;
19665
- log20.info("ws:close requested", { code, reason });
19700
+ log19.info("ws:close requested", { code, reason });
19666
19701
  }
19667
19702
  }
19668
19703
  /** 当前连接状态 (0=CONNECTING, 1=OPEN, 2=CLOSING, 3=CLOSED) */
@@ -19672,7 +19707,7 @@ var WSClient = class extends import_node_events.EventEmitter {
19672
19707
  };
19673
19708
 
19674
19709
  // src/transport/dedup.ts
19675
- var log21 = createLogger("transport/dedup");
19710
+ var log20 = createLogger("transport/dedup");
19676
19711
  var MessageDedup = class {
19677
19712
  /** 去重缓存生存时间 (ms) */
19678
19713
  ttlMs;
@@ -19683,7 +19718,7 @@ var MessageDedup = class {
19683
19718
  constructor(config2) {
19684
19719
  this.ttlMs = config2?.ttlMs ?? 3e5;
19685
19720
  this.maxEntries = config2?.maxEntries ?? 5e3;
19686
- log21.info("MessageDedup initialized", { ttlMs: this.ttlMs, maxEntries: this.maxEntries });
19721
+ log20.info("MessageDedup initialized", { ttlMs: this.ttlMs, maxEntries: this.maxEntries });
19687
19722
  }
19688
19723
  /**
19689
19724
  * 检查消息是否重复。
@@ -19719,7 +19754,7 @@ var MessageDedup = class {
19719
19754
 
19720
19755
  // src/transport/message-pipe.ts
19721
19756
  var import_node_crypto2 = require("crypto");
19722
- var log22 = createLogger("transport/message-pipe");
19757
+ var log21 = createLogger("transport/message-pipe");
19723
19758
  var MessagePipe = class {
19724
19759
  wsClient;
19725
19760
  dedup;
@@ -19738,15 +19773,15 @@ var MessagePipe = class {
19738
19773
  this.messageServiceBaseUrl = deps.messageServiceBaseUrl;
19739
19774
  this.wsClient.on("message", (rawData) => {
19740
19775
  this.handleInbound(rawData).catch((err) => {
19741
- log22.error("inbound:error", { step: "handleInbound", error: err.message });
19776
+ log21.error("inbound:error", { step: "handleInbound", error: err.message });
19742
19777
  });
19743
19778
  });
19744
- log22.info("MessagePipe initialized");
19779
+ log21.info("MessagePipe initialized");
19745
19780
  }
19746
19781
  /** 注册入站消息回调 — 解密后的消息会通过此回调传给 L4 层 */
19747
19782
  onMessage(callback) {
19748
19783
  this.messageCallback = callback;
19749
- log22.info("Inbound message callback registered");
19784
+ log21.info("Inbound message callback registered");
19750
19785
  }
19751
19786
  /**
19752
19787
  * 出站发送 — 通过 HTTP API 发送消息到 IM 服务器。
@@ -19766,7 +19801,7 @@ var MessagePipe = class {
19766
19801
  }
19767
19802
  const result = await this.callMessageApi("/messages/v1/send", body, "outbound");
19768
19803
  if (!result) return;
19769
- log22.info("outbound:sent", {
19804
+ log21.info("outbound:sent", {
19770
19805
  chatId: msg.chatId,
19771
19806
  senderId: msg.senderId,
19772
19807
  msgType: msg.msgType,
@@ -19790,7 +19825,7 @@ var MessagePipe = class {
19790
19825
  };
19791
19826
  const result = await this.callMessageApi("/messages/v1/recall", body, "recall");
19792
19827
  if (!result) return;
19793
- log22.info("recall:sent", {
19828
+ log21.info("recall:sent", {
19794
19829
  messageId: params.messageId,
19795
19830
  requestId: result.request_id
19796
19831
  });
@@ -19817,7 +19852,7 @@ var MessagePipe = class {
19817
19852
  body: JSON.stringify(body)
19818
19853
  });
19819
19854
  if (!resp.ok) {
19820
- log22.error(`${logTag}:http-error`, {
19855
+ log21.error(`${logTag}:http-error`, {
19821
19856
  status: resp.status,
19822
19857
  statusText: resp.statusText,
19823
19858
  url: url2
@@ -19826,7 +19861,7 @@ var MessagePipe = class {
19826
19861
  }
19827
19862
  const result = await resp.json();
19828
19863
  if (result.code !== 0) {
19829
- log22.error(`${logTag}:api-error`, {
19864
+ log21.error(`${logTag}:api-error`, {
19830
19865
  code: result.code,
19831
19866
  msg: result.msg,
19832
19867
  requestId: result.request_id
@@ -19835,7 +19870,7 @@ var MessagePipe = class {
19835
19870
  }
19836
19871
  return result;
19837
19872
  } catch (err) {
19838
- log22.error(`${logTag}:network-error`, {
19873
+ log21.error(`${logTag}:network-error`, {
19839
19874
  url: url2,
19840
19875
  error: err.message
19841
19876
  });
@@ -19857,7 +19892,7 @@ var MessagePipe = class {
19857
19892
  try {
19858
19893
  frame = JSON.parse(String(rawData));
19859
19894
  } catch (err) {
19860
- log22.warn("inbound:json-parse-error", { error: err.message });
19895
+ log21.warn("inbound:json-parse-error", { error: err.message });
19861
19896
  return;
19862
19897
  }
19863
19898
  const timestamp = frame["X-CTQ-Timestamp"];
@@ -19868,7 +19903,7 @@ var MessagePipe = class {
19868
19903
  const signatureInput = timestamp + nonce + frame.data;
19869
19904
  const expected = (0, import_node_crypto2.createHmac)("sha256", token).update(signatureInput).digest("hex");
19870
19905
  if (expected !== signature) {
19871
- log22.warn("inbound:signature-fail", { timestamp, nonce });
19906
+ log21.warn("inbound:signature-fail", { timestamp, nonce });
19872
19907
  return;
19873
19908
  }
19874
19909
  }
@@ -19882,37 +19917,30 @@ var MessagePipe = class {
19882
19917
  try {
19883
19918
  callbackData = JSON.parse(dataStr);
19884
19919
  } catch (err) {
19885
- log22.warn("inbound:data-parse-error", { error: err.message });
19920
+ log21.warn("inbound:data-parse-error", { error: err.message });
19886
19921
  return;
19887
19922
  }
19888
- if (callbackData.eventType !== "callback:direct") {
19889
- log22.debug("inbound:event-ignored", { eventType: callbackData.eventType });
19923
+ if (callbackData.eventType !== "MessageReceived") {
19924
+ log21.debug("inbound:event-ignored", { eventType: callbackData.eventType });
19890
19925
  return;
19891
19926
  }
19892
- const msg = {
19893
- messageId: callbackData.msgUid,
19894
- chatId: callbackData.groupId || callbackData.userId,
19895
- senderId: callbackData.userId,
19896
- msgType: callbackData.type,
19897
- content: JSON.stringify(callbackData.content),
19898
- timestamp: Date.now()
19899
- };
19900
- log22.debug("inbound:frame", { messageId: msg.messageId, eventType: callbackData.eventType });
19927
+ const msg = callbackData.content;
19928
+ log21.debug("inbound:frame", { messageId: msg.messageId, eventType: callbackData.eventType });
19901
19929
  if (this.dedup.isDuplicate(msg.messageId)) {
19902
- log22.debug("inbound:dedup-hit", { messageId: msg.messageId });
19930
+ log21.debug("inbound:dedup-hit", { messageId: msg.messageId });
19903
19931
  return;
19904
19932
  }
19905
- log22.info("inbound:verified", { messageId: msg.messageId, chatId: msg.chatId });
19933
+ log21.info("inbound:verified", { messageId: msg.messageId, chatId: msg.chatId });
19906
19934
  if (this.messageCallback) {
19907
19935
  this.messageCallback(msg);
19908
19936
  } else {
19909
- log22.warn("inbound:no-callback", { messageId: msg.messageId });
19937
+ log21.warn("inbound:no-callback", { messageId: msg.messageId });
19910
19938
  }
19911
19939
  }
19912
19940
  };
19913
19941
 
19914
19942
  // src/transport/connection-manager.ts
19915
- var log23 = createLogger("transport/connection-manager");
19943
+ var log22 = createLogger("transport/connection-manager");
19916
19944
  function sleep2(ms) {
19917
19945
  return new Promise((resolve2) => setTimeout(resolve2, ms));
19918
19946
  }
@@ -19942,7 +19970,7 @@ var ConnectionManager = class {
19942
19970
  reconnectMaxMs: options?.reconnectMaxMs ?? 6e4,
19943
19971
  maxReconnectAttempts: options?.maxReconnectAttempts ?? 10
19944
19972
  };
19945
- log23.info("ConnectionManager initialized", this.options);
19973
+ log22.info("ConnectionManager initialized", this.options);
19946
19974
  }
19947
19975
  /**
19948
19976
  * 启动连接 — 连接 WS + 开始心跳 + 注册重连逻辑
@@ -19957,33 +19985,29 @@ var ConnectionManager = class {
19957
19985
  this.running = true;
19958
19986
  this.reconnectAttempts = 0;
19959
19987
  const token = await tokenFn();
19960
- const wsUrl = url2.replace(/\/+$/, "") + "/events/stream";
19961
19988
  await this.client.connect({
19962
- url: wsUrl,
19989
+ url: url2,
19963
19990
  token,
19964
- headers: {
19965
- "Authorization": token,
19966
- ...this.appId ? { "X-App-ID": this.appId } : {}
19967
- }
19991
+ headers: this.appId ? { "X-App-ID": this.appId } : void 0
19968
19992
  });
19969
19993
  this.client.on("close", () => {
19970
19994
  if (this.running) {
19971
- log23.warn("ws:disconnected, scheduling reconnect");
19995
+ log22.warn("ws:disconnected, scheduling reconnect");
19972
19996
  this.scheduleReconnect();
19973
19997
  }
19974
19998
  });
19975
19999
  this.client.on("error", (err) => {
19976
- log23.error("ws:connection-error", { error: err.message });
20000
+ log22.error("ws:connection-error", { error: err.message });
19977
20001
  });
19978
20002
  this.startHeartbeat();
19979
- log23.info("ConnectionManager started \u2713", { url: url2 });
20003
+ log22.info("ConnectionManager started \u2713", { url: url2 });
19980
20004
  }
19981
20005
  /** 启动心跳保活 — 定时检查连接状态 */
19982
20006
  startHeartbeat() {
19983
20007
  this.stopHeartbeat();
19984
20008
  this.heartbeatTimer = setInterval(() => {
19985
20009
  if (this.client.readyState !== wrapper_default.OPEN) {
19986
- log23.warn("heartbeat: connection not open, scheduling reconnect");
20010
+ log22.warn("heartbeat: connection not open, scheduling reconnect");
19987
20011
  this.scheduleReconnect();
19988
20012
  }
19989
20013
  }, this.options.heartbeatIntervalMs);
@@ -20011,34 +20035,30 @@ var ConnectionManager = class {
20011
20035
  this.options.reconnectBaseMs * 2 ** this.reconnectAttempts,
20012
20036
  this.options.reconnectMaxMs
20013
20037
  );
20014
- log23.info("ws:reconnecting", { attempt: this.reconnectAttempts + 1, delayMs: delay });
20038
+ log22.info("ws:reconnecting", { attempt: this.reconnectAttempts + 1, delayMs: delay });
20015
20039
  await sleep2(delay);
20016
20040
  if (!this.running) return;
20017
20041
  this.reconnectAttempts++;
20018
20042
  try {
20019
20043
  const token = await this.tokenFn();
20020
- const wsUrl = this.url.replace(/\/+$/, "") + "/events/stream";
20021
20044
  await this.client.connect({
20022
- url: wsUrl,
20045
+ url: this.url,
20023
20046
  token,
20024
- headers: {
20025
- "Authorization": token,
20026
- ...this.appId ? { "X-App-ID": this.appId } : {}
20027
- }
20047
+ headers: this.appId ? { "X-App-ID": this.appId } : void 0
20028
20048
  });
20029
20049
  this.reconnectAttempts = 0;
20030
20050
  this.startHeartbeat();
20031
- log23.info("ws:reconnected", { attempt: this.reconnectAttempts, url: this.url });
20051
+ log22.info("ws:reconnected", { attempt: this.reconnectAttempts, url: this.url });
20032
20052
  return;
20033
20053
  } catch (err) {
20034
- log23.warn("ws:reconnect-failed", {
20054
+ log22.warn("ws:reconnect-failed", {
20035
20055
  attempt: this.reconnectAttempts,
20036
20056
  error: err.message
20037
20057
  });
20038
20058
  }
20039
20059
  }
20040
20060
  if (this.running) {
20041
- log23.error("ws:max-reconnect-reached", {
20061
+ log22.error("ws:max-reconnect-reached", {
20042
20062
  maxAttempts: this.options.maxReconnectAttempts
20043
20063
  });
20044
20064
  }
@@ -20048,7 +20068,7 @@ var ConnectionManager = class {
20048
20068
  this.running = false;
20049
20069
  this.stopHeartbeat();
20050
20070
  this.client.close(1e3, "shutdown");
20051
- log23.info("ConnectionManager stopped");
20071
+ log22.info("ConnectionManager stopped");
20052
20072
  }
20053
20073
  /** 当前是否已连接 (WebSocket readyState === OPEN) */
20054
20074
  get isConnected() {
@@ -20057,7 +20077,7 @@ var ConnectionManager = class {
20057
20077
  };
20058
20078
 
20059
20079
  // src/push/cockatoo-client.ts
20060
- var log24 = createLogger("push/cockatoo-client");
20080
+ var log23 = createLogger("push/cockatoo-client");
20061
20081
  var DEFAULT_TIMEOUT_MS2 = 3e4;
20062
20082
  var CockatooPushError = class extends Error {
20063
20083
  constructor(status, body, endpoint) {
@@ -20091,7 +20111,7 @@ var CockatooClient = class {
20091
20111
  const base = config2.endpoint.replace(/\/+$/, "");
20092
20112
  this.pushUrl = `${base}/api/v1/push`;
20093
20113
  this.healthUrl = `${base}/health`;
20094
- log24.info("CockatooClient initialized", { endpoint: config2.endpoint });
20114
+ log23.info("CockatooClient initialized", { endpoint: config2.endpoint });
20095
20115
  }
20096
20116
  /**
20097
20117
  * 推送消息到 Cockatoo 服务。
@@ -20122,7 +20142,7 @@ var CockatooClient = class {
20122
20142
  }
20123
20143
  throw new CockatooPushError(resp.status, body, this.pushUrl);
20124
20144
  }
20125
- log24.debug("push:sent", { type: payload.type });
20145
+ log23.debug("push:sent", { type: payload.type });
20126
20146
  }
20127
20147
  /**
20128
20148
  * 执行一次健康检查。
@@ -20140,11 +20160,11 @@ var CockatooClient = class {
20140
20160
  });
20141
20161
  const isHealthy = resp.ok;
20142
20162
  if (!isHealthy) {
20143
- log24.warn("health-check:unhealthy", { status: resp.status });
20163
+ log23.warn("health-check:unhealthy", { status: resp.status });
20144
20164
  }
20145
20165
  return isHealthy;
20146
20166
  } catch (err) {
20147
- log24.warn("health-check:error", { error: err.message });
20167
+ log23.warn("health-check:error", { error: err.message });
20148
20168
  return false;
20149
20169
  }
20150
20170
  }
@@ -20156,7 +20176,7 @@ var CockatooClient = class {
20156
20176
  this.healthy = await this.healthCheck();
20157
20177
  } catch {
20158
20178
  this.healthy = false;
20159
- log24.warn("Cockatoo health check failed");
20179
+ log23.warn("Cockatoo health check failed");
20160
20180
  }
20161
20181
  }, this.config.healthCheckIntervalMs ?? 6e4);
20162
20182
  if (typeof this.healthCheckTimer === "object" && "unref" in this.healthCheckTimer) {
@@ -20177,7 +20197,7 @@ var CockatooClient = class {
20177
20197
  };
20178
20198
 
20179
20199
  // src/push/push-queue.ts
20180
- var log25 = createLogger("push/push-queue");
20200
+ var log24 = createLogger("push/push-queue");
20181
20201
  var RETRY_BASE_MS2 = 1e3;
20182
20202
  var PushQueue = class {
20183
20203
  client;
@@ -20219,7 +20239,7 @@ var PushQueue = class {
20219
20239
  this.unhealthyRetryMs = config2?.unhealthyRetryMs ?? 5e3;
20220
20240
  this.drainOnStop = config2?.drainOnStop ?? false;
20221
20241
  this.drainTimeoutMs = config2?.drainTimeoutMs ?? 5e3;
20222
- log25.info("PushQueue initialized", {
20242
+ log24.info("PushQueue initialized", {
20223
20243
  maxSize: this.maxSize,
20224
20244
  retryAttempts: this.retryAttempts,
20225
20245
  processIntervalMs: this.processIntervalMs
@@ -20230,7 +20250,7 @@ var PushQueue = class {
20230
20250
  start() {
20231
20251
  if (this.running) return;
20232
20252
  this.running = true;
20233
- log25.info("PushQueue started");
20253
+ log24.info("PushQueue started");
20234
20254
  this.scheduleNext(0);
20235
20255
  }
20236
20256
  /**
@@ -20244,10 +20264,10 @@ var PushQueue = class {
20244
20264
  this.running = false;
20245
20265
  this.clearTimer();
20246
20266
  if (this.drainOnStop && this.queue.length > 0) {
20247
- log25.info("PushQueue draining", { remaining: this.queue.length });
20267
+ log24.info("PushQueue draining", { remaining: this.queue.length });
20248
20268
  await this.drain();
20249
20269
  }
20250
- log25.info("PushQueue stopped", {
20270
+ log24.info("PushQueue stopped", {
20251
20271
  remaining: this.queue.length,
20252
20272
  sent: this.sentCount,
20253
20273
  dropped: this.droppedCount,
@@ -20262,13 +20282,13 @@ var PushQueue = class {
20262
20282
  if (this.queue.length >= this.maxSize) {
20263
20283
  const dropped = this.queue.shift();
20264
20284
  this.droppedCount++;
20265
- log25.warn("queue:full, dropping oldest", {
20285
+ log24.warn("queue:full, dropping oldest", {
20266
20286
  droppedType: dropped?.payload.type,
20267
20287
  queueSize: this.queue.length
20268
20288
  });
20269
20289
  }
20270
20290
  this.queue.push({ payload, retries: 0, eligibleAt: 0 });
20271
- log25.debug("queue:enqueued", { type: payload.type, queueSize: this.queue.length });
20291
+ log24.debug("queue:enqueued", { type: payload.type, queueSize: this.queue.length });
20272
20292
  }
20273
20293
  /** 当前队列长度 */
20274
20294
  get size() {
@@ -20293,7 +20313,7 @@ var PushQueue = class {
20293
20313
  this.clearTimer();
20294
20314
  this.processTimer = setTimeout(() => {
20295
20315
  this.tick().catch((err) => {
20296
- log25.error("tick:unexpected-error", { error: err.message });
20316
+ log24.error("tick:unexpected-error", { error: err.message });
20297
20317
  if (this.running) {
20298
20318
  this.scheduleNext(this.idleIntervalMs);
20299
20319
  }
@@ -20315,7 +20335,7 @@ var PushQueue = class {
20315
20335
  async tick() {
20316
20336
  if (!this.running) return;
20317
20337
  if (!this.client.isHealthy) {
20318
- log25.debug("tick:service-unhealthy, pausing");
20338
+ log24.debug("tick:service-unhealthy, pausing");
20319
20339
  this.scheduleNext(this.unhealthyRetryMs);
20320
20340
  return;
20321
20341
  }
@@ -20335,7 +20355,7 @@ var PushQueue = class {
20335
20355
  try {
20336
20356
  await this.processItem(item);
20337
20357
  } catch (err) {
20338
- log25.error("tick:process-unexpected", { error: err.message });
20358
+ log24.error("tick:process-unexpected", { error: err.message });
20339
20359
  } finally {
20340
20360
  this.processing = false;
20341
20361
  }
@@ -20354,14 +20374,14 @@ var PushQueue = class {
20354
20374
  try {
20355
20375
  await this.client.push(item.payload);
20356
20376
  this.sentCount++;
20357
- log25.debug("push:success", {
20377
+ log24.debug("push:success", {
20358
20378
  type: item.payload.type,
20359
20379
  retries: item.retries
20360
20380
  });
20361
20381
  } catch (err) {
20362
20382
  if (err instanceof CockatooPushError && err.isClientError) {
20363
20383
  this.droppedCount++;
20364
- log25.warn("push:4xx-dropped", {
20384
+ log24.warn("push:4xx-dropped", {
20365
20385
  type: item.payload.type,
20366
20386
  status: err.status,
20367
20387
  retries: item.retries
@@ -20370,7 +20390,7 @@ var PushQueue = class {
20370
20390
  }
20371
20391
  if (item.retries >= this.retryAttempts) {
20372
20392
  this.droppedCount++;
20373
- log25.error("push:max-retries-dropped", {
20393
+ log24.error("push:max-retries-dropped", {
20374
20394
  type: item.payload.type,
20375
20395
  retries: item.retries,
20376
20396
  error: err.message
@@ -20383,7 +20403,7 @@ var PushQueue = class {
20383
20403
  item.eligibleAt = Date.now() + backoffMs;
20384
20404
  this.queue.push(item);
20385
20405
  const errorDetail = err instanceof CockatooPushError ? `HTTP ${err.status}` : err.message;
20386
- log25.warn("push:retry-enqueued", {
20406
+ log24.warn("push:retry-enqueued", {
20387
20407
  type: item.payload.type,
20388
20408
  retries: item.retries,
20389
20409
  backoffMs,
@@ -20407,22 +20427,22 @@ var PushQueue = class {
20407
20427
  try {
20408
20428
  await this.client.push(item.payload);
20409
20429
  this.sentCount++;
20410
- log25.debug("drain:sent", { type: item.payload.type });
20430
+ log24.debug("drain:sent", { type: item.payload.type });
20411
20431
  } catch (err) {
20412
20432
  this.droppedCount++;
20413
- log25.warn("drain:dropped", {
20433
+ log24.warn("drain:dropped", {
20414
20434
  type: item.payload.type,
20415
20435
  error: err.message
20416
20436
  });
20417
20437
  }
20418
20438
  }
20419
20439
  if (this.queue.length > 0) {
20420
- log25.warn("drain:timeout", {
20440
+ log24.warn("drain:timeout", {
20421
20441
  remaining: this.queue.length,
20422
20442
  timeoutMs: this.drainTimeoutMs
20423
20443
  });
20424
20444
  } else {
20425
- log25.info("drain:complete");
20445
+ log24.info("drain:complete");
20426
20446
  }
20427
20447
  }
20428
20448
  // ── 内部工具 ──
@@ -20436,32 +20456,43 @@ var PushQueue = class {
20436
20456
  };
20437
20457
 
20438
20458
  // src/index.ts
20439
- var log26 = createLogger("plugin");
20459
+ var log25 = createLogger("plugin");
20440
20460
  async function startPlugin(accountConfig, internalOverrides) {
20441
20461
  const config2 = buildPluginConfig(accountConfig, internalOverrides);
20442
- log26.info("Config built \u2713", { pluginId: config2.pluginId });
20462
+ log25.info("Config built \u2713", { pluginId: config2.pluginId });
20443
20463
  let cryptoEngine;
20444
20464
  if (config2.crypto.enabled) {
20445
- cryptoEngine = new CryptoEngine({ credentials: accountConfig });
20465
+ cryptoEngine = new CryptoEngine();
20446
20466
  await cryptoEngine.init();
20447
- log26.info("Crypto initialized \u2713");
20467
+ log25.info("Crypto initialized \u2713");
20448
20468
  } else {
20449
20469
  cryptoEngine = CryptoEngine.createPassthrough();
20450
- log26.info("Crypto passthrough mode \u2713 (disabled by config)");
20451
- }
20452
- const oauthClient = new OAuthClient({
20453
- baseUrl: config2.auth.serverUrl,
20454
- appId: accountConfig.appId,
20455
- appSecret: accountConfig.appSecret
20470
+ log25.info("Crypto passthrough mode \u2713 (disabled by config)");
20471
+ }
20472
+ const sealClient = new SealClient({
20473
+ serverUrl: config2.auth.serverUrl,
20474
+ clientName: config2.auth.clientName,
20475
+ clientId: config2.auth.clientId,
20476
+ clientSecret: config2.auth.clientSecret,
20477
+ scopes: config2.auth.scopes
20456
20478
  });
20457
- const tokenStorePath = (0, import_node_path3.join)((0, import_node_os.homedir)(), TOKEN_STORE_DIR, "tokens");
20479
+ const tokenStorePath = (0, import_node_path2.join)((0, import_node_os.homedir)(), TOKEN_STORE_DIR, "tokens");
20458
20480
  const tokenStore = new TokenStore(tokenStorePath, cryptoEngine);
20459
20481
  const tokenManager = new TokenManager({
20460
- oauthClient,
20482
+ sealClient,
20461
20483
  tokenStore,
20462
- refreshAheadMs: config2.auth.refreshAheadMs
20484
+ refreshAheadMs: config2.auth.refreshAheadMs,
20485
+ autoRegisterParams: config2.auth.autoRegister ? {
20486
+ clientName: config2.auth.clientName,
20487
+ scopes: config2.auth.scopes,
20488
+ tokenSettings: config2.auth.tokenSettings ? {
20489
+ accessTokenTtl: config2.auth.tokenSettings.accessTokenTtl,
20490
+ refreshTokenTtl: config2.auth.tokenSettings.refreshTokenTtl,
20491
+ accessTokenFormat: config2.auth.tokenSettings.accessTokenFormat
20492
+ } : void 0
20493
+ } : void 0
20463
20494
  });
20464
- log26.info("Auth initialized \u2713");
20495
+ log25.info("Auth initialized \u2713");
20465
20496
  let pushQueue = null;
20466
20497
  let cockatooClient = null;
20467
20498
  if (config2.push?.enabled) {
@@ -20476,7 +20507,7 @@ async function startPlugin(accountConfig, internalOverrides) {
20476
20507
  });
20477
20508
  cockatooClient.startHealthCheck();
20478
20509
  pushQueue.start();
20479
- log26.info("Push initialized \u2713");
20510
+ log25.info("Push initialized \u2713");
20480
20511
  }
20481
20512
  const wsClient = new WSClient();
20482
20513
  const dedup = new MessageDedup(config2.transport.dedup);
@@ -20494,8 +20525,8 @@ async function startPlugin(accountConfig, internalOverrides) {
20494
20525
  reconnectMaxMs: config2.transport.reconnectMaxMs,
20495
20526
  maxReconnectAttempts: config2.transport.maxReconnectAttempts
20496
20527
  });
20497
- log26.info("Transport initialized \u2713");
20498
- log26.info("Plugin started \u2713");
20528
+ log25.info("Transport initialized \u2713");
20529
+ log25.info("Plugin started \u2713");
20499
20530
  return {
20500
20531
  config: config2,
20501
20532
  messagePipe,
@@ -20503,22 +20534,22 @@ async function startPlugin(accountConfig, internalOverrides) {
20503
20534
  tokenManager,
20504
20535
  pushQueue,
20505
20536
  shutdown: async () => {
20506
- log26.info("Shutting down...");
20537
+ log25.info("Shutting down...");
20507
20538
  await connectionManager.stop();
20508
20539
  if (pushQueue) await pushQueue.stop();
20509
20540
  if (cockatooClient) cockatooClient.stopHealthCheck();
20510
20541
  tokenManager.shutdown();
20511
- log26.info("Shutdown complete \u2713");
20542
+ log25.info("Shutdown complete \u2713");
20512
20543
  }
20513
20544
  };
20514
20545
  }
20515
20546
  var plugin = {
20516
- id: CHANNEL_ID,
20547
+ id: PLUGIN_ID,
20517
20548
  name: "\u91CF\u5B50\u5BC6\u4FE1",
20518
20549
  description: "Quantum-encrypted IM channel plugin",
20519
20550
  register(api) {
20520
20551
  api.registerChannel({ plugin: quantumImPlugin });
20521
- log26.info("plugin registered \u2713");
20552
+ log25.info("plugin registered \u2713");
20522
20553
  }
20523
20554
  };
20524
20555
  var index_default = plugin;