liangzimixin 0.3.104 → 0.3.105
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 +558 -376
- package/dist/index.d.cts +7 -6
- package/dist/package.json +1 -1
- package/dist/setup-entry.cjs +451 -269
- package/package.json +1 -1
- package/scripts/liangzimixin_install.bat +18 -14
- package/scripts/liangzimixin_install.sh +13 -7
- package/scripts/liangzimixin_install_test.bat +20 -16
- package/scripts/liangzimixin_install_test.sh +14 -8
package/dist/index.cjs
CHANGED
|
@@ -8502,9 +8502,9 @@ var require_file = __commonJS({
|
|
|
8502
8502
|
});
|
|
8503
8503
|
function add(buff2, attempt) {
|
|
8504
8504
|
try {
|
|
8505
|
-
const
|
|
8506
|
-
if (check2(
|
|
8507
|
-
push(
|
|
8505
|
+
const log33 = JSON.parse(buff2);
|
|
8506
|
+
if (check2(log33)) {
|
|
8507
|
+
push(log33);
|
|
8508
8508
|
}
|
|
8509
8509
|
} catch (e) {
|
|
8510
8510
|
if (!attempt) {
|
|
@@ -8512,7 +8512,7 @@ var require_file = __commonJS({
|
|
|
8512
8512
|
}
|
|
8513
8513
|
}
|
|
8514
8514
|
}
|
|
8515
|
-
function push(
|
|
8515
|
+
function push(log33) {
|
|
8516
8516
|
if (options.rows && results.length >= options.rows && options.order !== "desc") {
|
|
8517
8517
|
if (stream.readable) {
|
|
8518
8518
|
stream.destroy();
|
|
@@ -8520,8 +8520,8 @@ var require_file = __commonJS({
|
|
|
8520
8520
|
return;
|
|
8521
8521
|
}
|
|
8522
8522
|
if (options.fields) {
|
|
8523
|
-
|
|
8524
|
-
obj[key] =
|
|
8523
|
+
log33 = options.fields.reduce((obj, key) => {
|
|
8524
|
+
obj[key] = log33[key];
|
|
8525
8525
|
return obj;
|
|
8526
8526
|
}, {});
|
|
8527
8527
|
}
|
|
@@ -8530,17 +8530,17 @@ var require_file = __commonJS({
|
|
|
8530
8530
|
results.shift();
|
|
8531
8531
|
}
|
|
8532
8532
|
}
|
|
8533
|
-
results.push(
|
|
8533
|
+
results.push(log33);
|
|
8534
8534
|
}
|
|
8535
|
-
function check2(
|
|
8536
|
-
if (!
|
|
8535
|
+
function check2(log33) {
|
|
8536
|
+
if (!log33) {
|
|
8537
8537
|
return;
|
|
8538
8538
|
}
|
|
8539
|
-
if (typeof
|
|
8539
|
+
if (typeof log33 !== "object") {
|
|
8540
8540
|
return;
|
|
8541
8541
|
}
|
|
8542
|
-
const time3 = new Date(
|
|
8543
|
-
if (options.from && time3 < options.from || options.until && time3 > options.until || options.level && options.level !==
|
|
8542
|
+
const time3 = new Date(log33.timestamp);
|
|
8543
|
+
if (options.from && time3 < options.from || options.until && time3 > options.until || options.level && options.level !== log33.level) {
|
|
8544
8544
|
return;
|
|
8545
8545
|
}
|
|
8546
8546
|
return true;
|
|
@@ -10395,10 +10395,10 @@ var require_logger = __commonJS({
|
|
|
10395
10395
|
return;
|
|
10396
10396
|
}
|
|
10397
10397
|
streams.push(str);
|
|
10398
|
-
str.on("log", (
|
|
10399
|
-
|
|
10400
|
-
|
|
10401
|
-
out.emit("log",
|
|
10398
|
+
str.on("log", (log33) => {
|
|
10399
|
+
log33.transport = log33.transport || [];
|
|
10400
|
+
log33.transport.push(transport.name);
|
|
10401
|
+
out.emit("log", log33);
|
|
10402
10402
|
});
|
|
10403
10403
|
str.on("error", (err) => {
|
|
10404
10404
|
err.transport = err.transport || [];
|
|
@@ -18678,10 +18678,10 @@ var require_daily_rotate_file = __commonJS({
|
|
|
18678
18678
|
const limit = options.limit || results.length;
|
|
18679
18679
|
results = results.slice(start, start + limit);
|
|
18680
18680
|
if (options.fields) {
|
|
18681
|
-
results = results.map((
|
|
18681
|
+
results = results.map((log33) => {
|
|
18682
18682
|
const obj = {};
|
|
18683
18683
|
options.fields.forEach((key) => {
|
|
18684
|
-
obj[key] =
|
|
18684
|
+
obj[key] = log33[key];
|
|
18685
18685
|
});
|
|
18686
18686
|
return obj;
|
|
18687
18687
|
});
|
|
@@ -18691,15 +18691,15 @@ var require_daily_rotate_file = __commonJS({
|
|
|
18691
18691
|
});
|
|
18692
18692
|
function add(buff2, attempt) {
|
|
18693
18693
|
try {
|
|
18694
|
-
const
|
|
18695
|
-
if (!
|
|
18694
|
+
const log33 = JSON.parse(buff2);
|
|
18695
|
+
if (!log33 || typeof log33 !== "object") {
|
|
18696
18696
|
return;
|
|
18697
18697
|
}
|
|
18698
|
-
const time3 = new Date(
|
|
18699
|
-
if (options.from && time3 < options.from || options.until && time3 > options.until || options.level && options.level !==
|
|
18698
|
+
const time3 = new Date(log33.timestamp);
|
|
18699
|
+
if (options.from && time3 < options.from || options.until && time3 > options.until || options.level && options.level !== log33.level) {
|
|
18700
18700
|
return;
|
|
18701
18701
|
}
|
|
18702
|
-
results.push(
|
|
18702
|
+
results.push(log33);
|
|
18703
18703
|
} catch (e) {
|
|
18704
18704
|
if (!attempt) {
|
|
18705
18705
|
stream.emit("error", e);
|
|
@@ -22352,7 +22352,7 @@ __export(index_exports, {
|
|
|
22352
22352
|
});
|
|
22353
22353
|
module.exports = __toCommonJS(index_exports);
|
|
22354
22354
|
var import_node_path5 = require("path");
|
|
22355
|
-
var
|
|
22355
|
+
var import_node_os5 = require("os");
|
|
22356
22356
|
var import_node_crypto4 = require("crypto");
|
|
22357
22357
|
|
|
22358
22358
|
// src/config.ts
|
|
@@ -36918,7 +36918,7 @@ var AccountConfigSchema = external_exports.object({
|
|
|
36918
36918
|
*/
|
|
36919
36919
|
botUserId: external_exports.string().optional(),
|
|
36920
36920
|
/** 🟡 部署环境 — test=测试, staging=联调, production=线上 */
|
|
36921
|
-
env: external_exports.enum(["test", "staging", "production"]).optional(),
|
|
36921
|
+
env: external_exports.enum(["test", "new-test", "staging", "production"]).optional(),
|
|
36922
36922
|
/** 🟡 消息加密模式 — quantum_only=仅加密, quantum_and_plain=加密+普通(默认) */
|
|
36923
36923
|
encryptionMode: external_exports.enum(["quantum_only", "quantum_and_plain"]).default("quantum_and_plain")
|
|
36924
36924
|
}).transform((raw) => ({
|
|
@@ -36933,32 +36933,44 @@ var AccountConfigSchema = external_exports.object({
|
|
|
36933
36933
|
encryptionMode: raw.encryptionMode
|
|
36934
36934
|
}));
|
|
36935
36935
|
var ENV_PRESETS = {
|
|
36936
|
-
/**
|
|
36937
|
-
test: {
|
|
36936
|
+
/** 新测试环境 */
|
|
36937
|
+
"new-test": {
|
|
36938
36938
|
apiBaseUrl: "https://test-mx.zdxlz.com:1443/open-apis/v1",
|
|
36939
36939
|
wsBaseUrl: "wss://test-mx.zdxlz.com:1443/open-apis/v1",
|
|
36940
36940
|
msgBaseUrl: "https://test-mx.zdxlz.com:1443/open-apis/v1",
|
|
36941
|
-
fileBaseUrl: "https://test-mx.zdxlz.com:1443/open-apis/v1"
|
|
36941
|
+
fileBaseUrl: "https://test-mx.zdxlz.com:1443/open-apis/v1",
|
|
36942
|
+
eventGatewayBaseUrl: "https://test-mx.zdxlz.com:1443"
|
|
36943
|
+
},
|
|
36944
|
+
/** 测试环境 */
|
|
36945
|
+
test: {
|
|
36946
|
+
apiBaseUrl: "https://impre.zdxlz.com:1443/open-apis/v1",
|
|
36947
|
+
wsBaseUrl: "wss://impre.zdxlz.com:1443/open-apis/v1",
|
|
36948
|
+
msgBaseUrl: "https://impre.zdxlz.com:1443/open-apis/v1",
|
|
36949
|
+
fileBaseUrl: "https://impre.zdxlz.com:1443/open-apis/v1",
|
|
36950
|
+
eventGatewayBaseUrl: "https://impre.zdxlz.com:1443"
|
|
36942
36951
|
},
|
|
36943
36952
|
/** 联调环境 */
|
|
36944
36953
|
staging: {
|
|
36945
36954
|
apiBaseUrl: "https://mxpre.zdxlz.com:1443/open-apis/v1",
|
|
36946
36955
|
wsBaseUrl: "wss://mxpre.zdxlz.com:1443/open-apis/v1",
|
|
36947
36956
|
msgBaseUrl: "https://mxpre.zdxlz.com:1443/open-apis/v1",
|
|
36948
|
-
fileBaseUrl: "https://mxpre.zdxlz.com:1443/open-apis/v1"
|
|
36957
|
+
fileBaseUrl: "https://mxpre.zdxlz.com:1443/open-apis/v1",
|
|
36958
|
+
eventGatewayBaseUrl: "https://mxpre.zdxlz.com:1443"
|
|
36949
36959
|
},
|
|
36950
36960
|
/** 线上环境 */
|
|
36951
36961
|
production: {
|
|
36952
36962
|
apiBaseUrl: "https://imtwo.zdxlz.com/open-apis/v1",
|
|
36953
36963
|
wsBaseUrl: "wss://imtwo.zdxlz.com/open-apis/v1",
|
|
36954
36964
|
msgBaseUrl: "https://imtwo.zdxlz.com/open-apis/v1",
|
|
36955
|
-
fileBaseUrl: "https://imtwo.zdxlz.com/open-apis/v1"
|
|
36965
|
+
fileBaseUrl: "https://imtwo.zdxlz.com/open-apis/v1",
|
|
36966
|
+
eventGatewayBaseUrl: "https://imtwo.zdxlz.com"
|
|
36956
36967
|
}
|
|
36957
36968
|
};
|
|
36958
36969
|
function resolveEnv(accountEnv) {
|
|
36959
36970
|
if (accountEnv) return accountEnv;
|
|
36960
36971
|
const raw = (getEnv("LZMX_ENV") || "").trim().toLowerCase();
|
|
36961
36972
|
if (raw === "test") return "test";
|
|
36973
|
+
if (raw === "new-test" || raw === "new_test") return "new-test";
|
|
36962
36974
|
if (raw === "staging" || raw === "dev") return "staging";
|
|
36963
36975
|
return "production";
|
|
36964
36976
|
}
|
|
@@ -39050,9 +39062,15 @@ function isRemoteMediaUrl(mediaUrl) {
|
|
|
39050
39062
|
}
|
|
39051
39063
|
|
|
39052
39064
|
// src/runtime.ts
|
|
39065
|
+
var log15 = createLogger("runtime", "info");
|
|
39053
39066
|
var runtime = null;
|
|
39067
|
+
var cachedOpenClawVersion = "unknown";
|
|
39054
39068
|
function setPluginRuntime(next) {
|
|
39055
39069
|
runtime = next;
|
|
39070
|
+
log15.info("plugin runtime initialized", runtime);
|
|
39071
|
+
if (next?.version && typeof next.version === "string" && next.version.trim()) {
|
|
39072
|
+
cachedOpenClawVersion = next.version.trim();
|
|
39073
|
+
}
|
|
39056
39074
|
}
|
|
39057
39075
|
function getPluginRuntime() {
|
|
39058
39076
|
if (!runtime) {
|
|
@@ -39062,12 +39080,12 @@ function getPluginRuntime() {
|
|
|
39062
39080
|
}
|
|
39063
39081
|
|
|
39064
39082
|
// src/message-handler/handler.ts
|
|
39065
|
-
var
|
|
39083
|
+
var log16 = createLogger("message-handler/handler");
|
|
39066
39084
|
var InboundPipeline = class {
|
|
39067
39085
|
deps;
|
|
39068
39086
|
constructor(deps) {
|
|
39069
39087
|
this.deps = deps;
|
|
39070
|
-
|
|
39088
|
+
log16.info("InboundPipeline initialized");
|
|
39071
39089
|
}
|
|
39072
39090
|
/** 处理单条入站消息 — 获取 Semaphore slot 后执行完整的处理流水线 */
|
|
39073
39091
|
async handle(msg) {
|
|
@@ -39078,7 +39096,7 @@ var InboundPipeline = class {
|
|
|
39078
39096
|
metrics.recordLatency("inbound.semaphore_wait", Date.now() - semaphoreStartMs);
|
|
39079
39097
|
if (acquireResult === "rejected") {
|
|
39080
39098
|
metrics.increment("inbound.semaphore_rejected");
|
|
39081
|
-
|
|
39099
|
+
log16.warn("\u{1F6AB} \u6D88\u606F\u88AB\u62D2\u7EDD (Semaphore \u6EA2\u51FA)", {
|
|
39082
39100
|
messageId: msg.messageId,
|
|
39083
39101
|
active: semaphore.activeCount,
|
|
39084
39102
|
waiting: semaphore.waitingCount
|
|
@@ -39089,7 +39107,7 @@ var InboundPipeline = class {
|
|
|
39089
39107
|
const context = parseMessage(msg);
|
|
39090
39108
|
const gateResult = checkMessageGate(msg, this.deps.gateConfig);
|
|
39091
39109
|
if (!gateResult.pass) {
|
|
39092
|
-
|
|
39110
|
+
log16.info("\u{1F6AB} \u6D88\u606F\u88AB\u62E6\u622A (gate)", {
|
|
39093
39111
|
messageId: msg.messageId,
|
|
39094
39112
|
reason: gateResult.reason
|
|
39095
39113
|
});
|
|
@@ -39097,7 +39115,7 @@ var InboundPipeline = class {
|
|
|
39097
39115
|
}
|
|
39098
39116
|
setInboundEncryptionStatus(msg.chatId, msg.messageId, msg.isEncrypted ?? false);
|
|
39099
39117
|
if (detectAbort(context.text)) {
|
|
39100
|
-
|
|
39118
|
+
log16.info("\u26D4 \u68C0\u6D4B\u5230\u4E2D\u6B62\u6307\u4EE4", {
|
|
39101
39119
|
messageId: msg.messageId,
|
|
39102
39120
|
chatId: msg.chatId
|
|
39103
39121
|
});
|
|
@@ -39106,12 +39124,12 @@ var InboundPipeline = class {
|
|
|
39106
39124
|
const core = getPluginRuntime();
|
|
39107
39125
|
const isCommand = core.channel.commands?.isControlCommandMessage?.(context.text, this.deps.sdkConfig);
|
|
39108
39126
|
if (isCommand) {
|
|
39109
|
-
|
|
39127
|
+
log16.info("\u{1F527} \u68C0\u6D4B\u5230\u7CFB\u7EDF\u547D\u4EE4", {
|
|
39110
39128
|
messageId: msg.messageId,
|
|
39111
39129
|
command: context.text.trim()
|
|
39112
39130
|
});
|
|
39113
39131
|
const cmdPayload = buildInboundPayload(msg, { text: context.text }, this.deps.pluginConfig);
|
|
39114
|
-
|
|
39132
|
+
log16.info("\u{1F50D} [DEBUG] cmdPayload \u5173\u952E\u5B57\u6BB5", {
|
|
39115
39133
|
messageId: msg.messageId,
|
|
39116
39134
|
CommandAuthorized: cmdPayload.CommandAuthorized ?? "\u26A0\uFE0F \u672A\u8BBE\u7F6E",
|
|
39117
39135
|
CommandBody: String(cmdPayload.CommandBody ?? "").slice(0, 100),
|
|
@@ -39126,7 +39144,7 @@ var InboundPipeline = class {
|
|
|
39126
39144
|
payloadKeys: Object.keys(cmdPayload)
|
|
39127
39145
|
});
|
|
39128
39146
|
const cmdCtx = core.channel.reply.finalizeInboundContext(cmdPayload);
|
|
39129
|
-
|
|
39147
|
+
log16.info("\u{1F50D} [DEBUG] cmdCtx (finalizeInboundContext \u4E4B\u540E)", {
|
|
39130
39148
|
messageId: msg.messageId,
|
|
39131
39149
|
CommandAuthorized: cmdCtx.CommandAuthorized ?? "\u26A0\uFE0F \u672A\u8BBE\u7F6E",
|
|
39132
39150
|
CommandBody: String(cmdCtx.CommandBody ?? "").slice(0, 100),
|
|
@@ -39136,7 +39154,7 @@ var InboundPipeline = class {
|
|
|
39136
39154
|
const cmdSkipEncrypt = this.deps.pluginConfig.credentials.encryptionMode === "quantum_only" ? false : true;
|
|
39137
39155
|
let deliverCalled = false;
|
|
39138
39156
|
let deliverCallCount = 0;
|
|
39139
|
-
|
|
39157
|
+
log16.info("\u{1F680} [DEBUG] \u5F00\u59CB dispatchReplyWithBufferedBlockDispatcher", {
|
|
39140
39158
|
messageId: msg.messageId,
|
|
39141
39159
|
command: context.text.trim()
|
|
39142
39160
|
});
|
|
@@ -39147,7 +39165,7 @@ var InboundPipeline = class {
|
|
|
39147
39165
|
deliver: async (payload2) => {
|
|
39148
39166
|
deliverCallCount++;
|
|
39149
39167
|
deliverCalled = true;
|
|
39150
|
-
|
|
39168
|
+
log16.info("\u{1F527} \u547D\u4EE4 deliver \u56DE\u8C03\u6536\u5230", {
|
|
39151
39169
|
messageId: msg.messageId,
|
|
39152
39170
|
callIndex: deliverCallCount,
|
|
39153
39171
|
hasText: Boolean(payload2.text),
|
|
@@ -39158,7 +39176,7 @@ var InboundPipeline = class {
|
|
|
39158
39176
|
});
|
|
39159
39177
|
const text = (payload2.text ?? "").trim();
|
|
39160
39178
|
if (!text) {
|
|
39161
|
-
|
|
39179
|
+
log16.warn("\u26A0\uFE0F deliver \u6536\u5230\u7A7A\u6587\u672C\uFF0C\u8DF3\u8FC7\u53D1\u9001", { messageId: msg.messageId });
|
|
39162
39180
|
return;
|
|
39163
39181
|
}
|
|
39164
39182
|
await this.deps.messagePipe.sendMessage({
|
|
@@ -39170,14 +39188,14 @@ var InboundPipeline = class {
|
|
|
39170
39188
|
});
|
|
39171
39189
|
},
|
|
39172
39190
|
onSkip: (payload2, info) => {
|
|
39173
|
-
|
|
39191
|
+
log16.warn("\u23ED\uFE0F [DEBUG] dispatcher onSkip", {
|
|
39174
39192
|
messageId: msg.messageId,
|
|
39175
39193
|
reason: info?.reason,
|
|
39176
39194
|
payload: JSON.stringify(payload2).slice(0, 300)
|
|
39177
39195
|
});
|
|
39178
39196
|
},
|
|
39179
39197
|
onError: (err, info) => {
|
|
39180
|
-
|
|
39198
|
+
log16.error("\u274C \u547D\u4EE4\u56DE\u590D\u9519\u8BEF", {
|
|
39181
39199
|
messageId: msg.messageId,
|
|
39182
39200
|
error: String(err),
|
|
39183
39201
|
errorStack: err?.stack?.slice(0, 500),
|
|
@@ -39187,7 +39205,7 @@ var InboundPipeline = class {
|
|
|
39187
39205
|
},
|
|
39188
39206
|
replyOptions: {}
|
|
39189
39207
|
});
|
|
39190
|
-
|
|
39208
|
+
log16.info("\u{1F3C1} [DEBUG] dispatchReplyWithBufferedBlockDispatcher \u5B8C\u6210", {
|
|
39191
39209
|
messageId: msg.messageId,
|
|
39192
39210
|
command: context.text.trim(),
|
|
39193
39211
|
deliverCalled,
|
|
@@ -39201,7 +39219,7 @@ var InboundPipeline = class {
|
|
|
39201
39219
|
"/reset": "\u2705 \u4F1A\u8BDD\u5DF2\u91CD\u7F6E\uFF0C\u53EF\u4EE5\u5F00\u59CB\u65B0\u7684\u5BF9\u8BDD\u4E86\u3002"
|
|
39202
39220
|
};
|
|
39203
39221
|
const fallbackText = fallbackMessages[command] ?? `\u2705 \u547D\u4EE4 \`${command}\` \u5DF2\u6267\u884C\u3002`;
|
|
39204
|
-
|
|
39222
|
+
log16.info("\u{1F4E8} SDK \u672A\u56DE\u8C03 deliver\uFF0C\u53D1\u9001\u56DE\u9000\u786E\u8BA4\u6D88\u606F", {
|
|
39205
39223
|
messageId: msg.messageId,
|
|
39206
39224
|
command
|
|
39207
39225
|
});
|
|
@@ -39212,12 +39230,12 @@ var InboundPipeline = class {
|
|
|
39212
39230
|
content: JSON.stringify({ content: fallbackText }),
|
|
39213
39231
|
skipEncrypt: true
|
|
39214
39232
|
}).catch((err) => {
|
|
39215
|
-
|
|
39233
|
+
log16.warn("\u26A0\uFE0F \u56DE\u9000\u786E\u8BA4\u6D88\u606F\u53D1\u9001\u5931\u8D25", { error: err.message });
|
|
39216
39234
|
});
|
|
39217
39235
|
}
|
|
39218
39236
|
clearInboundEncryptionStatus(msg.chatId, msg.messageId);
|
|
39219
39237
|
const durationMs2 = Date.now() - startMs;
|
|
39220
|
-
|
|
39238
|
+
log16.info("\u2705 \u7CFB\u7EDF\u547D\u4EE4\u5904\u7406\u5B8C\u6210", {
|
|
39221
39239
|
messageId: msg.messageId,
|
|
39222
39240
|
command: context.text.trim(),
|
|
39223
39241
|
deliverCalled,
|
|
@@ -39233,7 +39251,7 @@ var InboundPipeline = class {
|
|
|
39233
39251
|
content: JSON.stringify({ content: "\u4EFB\u52A1\u5DF2\u6536\u5230\u{1F44C}\uFF0C\u6B63\u5728\u5904\u7406\u4E2D..." }),
|
|
39234
39252
|
skipEncrypt: feedbackSkipEncrypt
|
|
39235
39253
|
}).catch((err) => {
|
|
39236
|
-
|
|
39254
|
+
log16.warn("\u26A0\uFE0F \u5373\u65F6\u53CD\u9988\u53D1\u9001\u5931\u8D25", { error: err.message });
|
|
39237
39255
|
});
|
|
39238
39256
|
const contentResolveStartMs = Date.now();
|
|
39239
39257
|
const resolvedContent = await resolveContent(context, {
|
|
@@ -39269,7 +39287,7 @@ var InboundPipeline = class {
|
|
|
39269
39287
|
deliver
|
|
39270
39288
|
// TODO: 可选 typingCallbacks (打字指示器)
|
|
39271
39289
|
});
|
|
39272
|
-
|
|
39290
|
+
log16.info("\u{1F4E5} \u6536\u5230\u6D88\u606F \u2192 \u53D1\u7ED9 AI", {
|
|
39273
39291
|
messageId: msg.messageId,
|
|
39274
39292
|
chatId: msg.chatId,
|
|
39275
39293
|
\u5185\u5BB9\u9884\u89C8: String(payload.Body ?? "").slice(0, 200)
|
|
@@ -39293,16 +39311,16 @@ var InboundPipeline = class {
|
|
|
39293
39311
|
const replyCount = (counts?.final ?? 0) + (counts?.block ?? 0) + (counts?.tool ?? 0);
|
|
39294
39312
|
const durationMs = Date.now() - startMs;
|
|
39295
39313
|
if (queuedFinal) {
|
|
39296
|
-
|
|
39314
|
+
log16.info("\u23F3 \u6D88\u606F\u6682\u5FD9\u5DF2\u8FDB\u5165\u5E76\u53D1\u63A7\u5236\u961F\u5217\uFF0C\u7A0D\u540E SDK \u5C06\u81EA\u52A8\u72EC\u7ACB\u5904\u7406", { messageId: msg.messageId, chatId: msg.chatId });
|
|
39297
39315
|
} else if (replyCount === 0) {
|
|
39298
|
-
|
|
39316
|
+
log16.warn("\u26A0\uFE0F AI \u8FD4\u56DE\u7A7A\u56DE\u590D (\u56DE\u590D\u6570=0)\uFF0C\u4EC5\u8BB0\u5F55\u4E0D\u53D1\u9001\u515C\u5E95\u63D0\u793A", {
|
|
39299
39317
|
messageId: msg.messageId,
|
|
39300
39318
|
chatId: msg.chatId,
|
|
39301
39319
|
AI\u56DE\u590Dms: aiDurationMs
|
|
39302
39320
|
});
|
|
39303
39321
|
metrics.increment("inbound.empty_reply");
|
|
39304
39322
|
}
|
|
39305
|
-
|
|
39323
|
+
log16.info("\u2705 \u6D88\u606F\u5904\u7406\u5B8C\u6210", {
|
|
39306
39324
|
messageId: msg.messageId,
|
|
39307
39325
|
chatId: msg.chatId,
|
|
39308
39326
|
\u56DE\u590D\u6570: replyCount,
|
|
@@ -39313,7 +39331,7 @@ var InboundPipeline = class {
|
|
|
39313
39331
|
clearInboundEncryptionStatus(msg.chatId, msg.messageId);
|
|
39314
39332
|
} catch (err) {
|
|
39315
39333
|
const durationMs = Date.now() - startMs;
|
|
39316
|
-
|
|
39334
|
+
log16.error("\u274C \u6D88\u606F\u5904\u7406\u5931\u8D25", {
|
|
39317
39335
|
messageId: msg.messageId,
|
|
39318
39336
|
chatId: msg.chatId,
|
|
39319
39337
|
step: "handle",
|
|
@@ -39332,7 +39350,7 @@ var InboundPipeline = class {
|
|
|
39332
39350
|
// 系统提示消息不加密,避免加密失败导致的死循环
|
|
39333
39351
|
});
|
|
39334
39352
|
} catch (tipErr) {
|
|
39335
|
-
|
|
39353
|
+
log16.warn("\u26A0\uFE0F \u9519\u8BEF\u63D0\u793A\u6D88\u606F\u53D1\u9001\u5931\u8D25\uFF08\u907F\u514D\u6B7B\u5FAA\u73AF\uFF0C\u4E0D\u518D\u91CD\u8BD5\uFF09", {
|
|
39336
39354
|
error: tipErr.message
|
|
39337
39355
|
});
|
|
39338
39356
|
}
|
|
@@ -39399,8 +39417,8 @@ var QUANTUM_IM_CONFIG_JSON_SCHEMA = {
|
|
|
39399
39417
|
env: {
|
|
39400
39418
|
type: "string",
|
|
39401
39419
|
title: "\u90E8\u7F72\u73AF\u5883",
|
|
39402
|
-
description: "\u9009\u62E9\u5BF9\u63A5\u7684\u670D\u52A1\u5668\u73AF\u5883\u3002test = \u6D4B\u8BD5\u73AF\u5883\uFF0Cstaging = \u8054\u8C03\u73AF\u5883\uFF0Cproduction = \u7EBF\u4E0A\u73AF\u5883",
|
|
39403
|
-
enum: ["test", "staging", "production"],
|
|
39420
|
+
description: "\u9009\u62E9\u5BF9\u63A5\u7684\u670D\u52A1\u5668\u73AF\u5883\u3002test = \u6D4B\u8BD5\u73AF\u5883\uFF0Cnew-test = \u65B0\u6D4B\u8BD5\u73AF\u5883\uFF0Cstaging = \u8054\u8C03\u73AF\u5883\uFF0Cproduction = \u7EBF\u4E0A\u73AF\u5883",
|
|
39421
|
+
enum: ["test", "new-test", "staging", "production"],
|
|
39404
39422
|
default: "production"
|
|
39405
39423
|
},
|
|
39406
39424
|
encryptionMode: {
|
|
@@ -39646,8 +39664,288 @@ var quantumImOnboarding = {
|
|
|
39646
39664
|
})
|
|
39647
39665
|
};
|
|
39648
39666
|
|
|
39667
|
+
// src/channel/version-reporter.ts
|
|
39668
|
+
var import_node_os4 = require("os");
|
|
39669
|
+
|
|
39670
|
+
// package.json
|
|
39671
|
+
var package_default = {
|
|
39672
|
+
name: "liangzimixin",
|
|
39673
|
+
version: "0.3.105",
|
|
39674
|
+
description: "Quantum-encrypted IM channel plugin for OpenClaw",
|
|
39675
|
+
type: "module",
|
|
39676
|
+
main: "dist/index.cjs",
|
|
39677
|
+
types: "dist/index.d.ts",
|
|
39678
|
+
files: [
|
|
39679
|
+
"dist/",
|
|
39680
|
+
"dist/quantum-sdk/",
|
|
39681
|
+
"scripts/liangzimixin_install.sh",
|
|
39682
|
+
"scripts/liangzimixin_install.bat",
|
|
39683
|
+
"scripts/liangzimixin_install_test.sh",
|
|
39684
|
+
"scripts/liangzimixin_install_test.bat",
|
|
39685
|
+
"scripts/liangzimixin_install_test_beta.bat",
|
|
39686
|
+
"openclaw.plugin.json",
|
|
39687
|
+
"README.md",
|
|
39688
|
+
"LICENSE"
|
|
39689
|
+
],
|
|
39690
|
+
scripts: {
|
|
39691
|
+
build: "tsup",
|
|
39692
|
+
dev: "tsup --watch",
|
|
39693
|
+
lint: "eslint src/",
|
|
39694
|
+
"lint:fix": "eslint src/ --fix",
|
|
39695
|
+
typecheck: "tsc --noEmit",
|
|
39696
|
+
format: "prettier --write src/**/*.ts",
|
|
39697
|
+
"format:check": "prettier --check src/**/*.ts"
|
|
39698
|
+
},
|
|
39699
|
+
peerDependencies: {
|
|
39700
|
+
openclaw: ">=2026.2.0"
|
|
39701
|
+
},
|
|
39702
|
+
engines: {
|
|
39703
|
+
node: ">=20"
|
|
39704
|
+
},
|
|
39705
|
+
devDependencies: {
|
|
39706
|
+
"@types/node": "^20.0.0",
|
|
39707
|
+
"@types/ws": "^8.18.1",
|
|
39708
|
+
"@typescript-eslint/eslint-plugin": "^8.56.1",
|
|
39709
|
+
"@typescript-eslint/parser": "^8.56.1",
|
|
39710
|
+
eslint: "^9.39.3",
|
|
39711
|
+
openclaw: "^2026.4.14",
|
|
39712
|
+
prettier: "^3.5.3",
|
|
39713
|
+
tsup: "^8.5.1",
|
|
39714
|
+
typescript: "^5.8.3",
|
|
39715
|
+
winston: "^3.19.0",
|
|
39716
|
+
"winston-daily-rotate-file": "^5.0.0",
|
|
39717
|
+
ws: "^8.19.0",
|
|
39718
|
+
zod: "^4.3.6"
|
|
39719
|
+
},
|
|
39720
|
+
keywords: [
|
|
39721
|
+
"openclaw",
|
|
39722
|
+
"liangzimixin",
|
|
39723
|
+
"channel-plugin",
|
|
39724
|
+
"instant-messaging",
|
|
39725
|
+
"encryption"
|
|
39726
|
+
],
|
|
39727
|
+
openclaw: {
|
|
39728
|
+
compat: {
|
|
39729
|
+
pluginApi: ">=2026.3.8"
|
|
39730
|
+
},
|
|
39731
|
+
build: {
|
|
39732
|
+
openclawVersion: ">=2026.3.8"
|
|
39733
|
+
},
|
|
39734
|
+
extensions: [
|
|
39735
|
+
"./dist/index.cjs"
|
|
39736
|
+
],
|
|
39737
|
+
setupEntry: "./dist/setup-entry.cjs",
|
|
39738
|
+
channel: {
|
|
39739
|
+
id: "liangzimixin",
|
|
39740
|
+
label: "QuantumIM",
|
|
39741
|
+
selectionLabel: "\u5BC6\u4FE1 IM (\u91CF\u5B50\u5BC6\u4FE1)",
|
|
39742
|
+
docsPath: "/channels/liangzimixin",
|
|
39743
|
+
docsLabel: "liangzimixin",
|
|
39744
|
+
blurb: "\u5BC6\u4FE1 IM Channel\uFF0C\u652F\u6301\u91CF\u5B50\u52A0\u5BC6\u7684\u5B89\u5168\u5373\u65F6\u901A\u4FE1\u3002",
|
|
39745
|
+
aliases: [
|
|
39746
|
+
"qim"
|
|
39747
|
+
],
|
|
39748
|
+
order: 80
|
|
39749
|
+
},
|
|
39750
|
+
install: {
|
|
39751
|
+
npmSpec: "liangzimixin",
|
|
39752
|
+
clawhubSpec: "liangzimixin",
|
|
39753
|
+
localPath: "extensions/liangzimixin",
|
|
39754
|
+
defaultChoice: "npm"
|
|
39755
|
+
}
|
|
39756
|
+
},
|
|
39757
|
+
license: "MIT"
|
|
39758
|
+
};
|
|
39759
|
+
|
|
39760
|
+
// src/runtime-info.ts
|
|
39761
|
+
var import_node_child_process = require("child_process");
|
|
39762
|
+
var import_node_os3 = require("os");
|
|
39763
|
+
var log17 = createLogger("runtime-info");
|
|
39764
|
+
var PACKAGE_VERSION = normalizeVersion(package_default.version);
|
|
39765
|
+
function normalizeVersion(value) {
|
|
39766
|
+
return typeof value === "string" && value.trim() ? value.trim() : "unknown";
|
|
39767
|
+
}
|
|
39768
|
+
function resolveHostOpenClawVersion(runtime2) {
|
|
39769
|
+
if (runtime2 && typeof runtime2 === "object") {
|
|
39770
|
+
const fromRuntime = normalizeVersion(runtime2.version);
|
|
39771
|
+
if (fromRuntime !== "unknown") return fromRuntime;
|
|
39772
|
+
}
|
|
39773
|
+
try {
|
|
39774
|
+
const versionString = (0, import_node_child_process.execSync)("openclaw --version", { encoding: "utf-8" }).trim();
|
|
39775
|
+
return normalizeVersion(versionString);
|
|
39776
|
+
} catch {
|
|
39777
|
+
log17.error("get openclaw version failed via openclaw --version");
|
|
39778
|
+
return "unknown";
|
|
39779
|
+
}
|
|
39780
|
+
}
|
|
39781
|
+
function resolveOsType(nodePlatform = (0, import_node_os3.platform)()) {
|
|
39782
|
+
const normalized = nodePlatform.trim();
|
|
39783
|
+
if (!normalized) return "unknown";
|
|
39784
|
+
switch (normalized) {
|
|
39785
|
+
case "win32":
|
|
39786
|
+
return "windows";
|
|
39787
|
+
case "darwin":
|
|
39788
|
+
return "macOS";
|
|
39789
|
+
case "linux":
|
|
39790
|
+
return "linux";
|
|
39791
|
+
default:
|
|
39792
|
+
return normalized;
|
|
39793
|
+
}
|
|
39794
|
+
}
|
|
39795
|
+
function buildRuntimeInfoLogMeta(runtime2, options = {}) {
|
|
39796
|
+
const nodePlatform = options.platform?.trim() || (0, import_node_os3.platform)();
|
|
39797
|
+
return {
|
|
39798
|
+
openclawVersion: resolveHostOpenClawVersion(runtime2),
|
|
39799
|
+
pluginVersion: normalizeVersion(options.pluginVersion ?? PACKAGE_VERSION),
|
|
39800
|
+
os: resolveOsType(nodePlatform),
|
|
39801
|
+
nodePlatform
|
|
39802
|
+
};
|
|
39803
|
+
}
|
|
39804
|
+
|
|
39805
|
+
// src/channel/version-reporter.ts
|
|
39806
|
+
var log18 = createLogger("channel/version-reporter");
|
|
39807
|
+
var REPORT_PATH = "/event-gateway/api/v1/personal-agent/openclaw-version";
|
|
39808
|
+
function resolveReportUrl(accountEnv) {
|
|
39809
|
+
const explicitUrl = getEnv("LZMX_EVENT_GATEWAY_URL");
|
|
39810
|
+
if (explicitUrl?.trim()) {
|
|
39811
|
+
const base = explicitUrl.trim().replace(/\/+$/, "");
|
|
39812
|
+
return `${base}${REPORT_PATH}`;
|
|
39813
|
+
}
|
|
39814
|
+
const env = resolveEnv(accountEnv);
|
|
39815
|
+
const preset = ENV_PRESETS[env];
|
|
39816
|
+
return `${preset.eventGatewayBaseUrl}${REPORT_PATH}`;
|
|
39817
|
+
}
|
|
39818
|
+
var MAX_RETRIES = 3;
|
|
39819
|
+
var RETRY_BASE_MS = 2e3;
|
|
39820
|
+
var DAILY_REPORT_HOUR = 2;
|
|
39821
|
+
var DAILY_REPORT_RANDOM_MINUTES_MAX = 59;
|
|
39822
|
+
function retryDelay(attempt) {
|
|
39823
|
+
return RETRY_BASE_MS * Math.pow(2, attempt);
|
|
39824
|
+
}
|
|
39825
|
+
function getPluginVersion() {
|
|
39826
|
+
const version2 = package_default?.version;
|
|
39827
|
+
return typeof version2 === "string" && version2.trim() ? version2.trim() : "unknown";
|
|
39828
|
+
}
|
|
39829
|
+
var dailyTimer = null;
|
|
39830
|
+
function msUntilNextReportWindow() {
|
|
39831
|
+
const now = /* @__PURE__ */ new Date();
|
|
39832
|
+
const randomMinute = Math.floor(Math.random() * (DAILY_REPORT_RANDOM_MINUTES_MAX + 1));
|
|
39833
|
+
const reportTime = new Date(now);
|
|
39834
|
+
reportTime.setHours(DAILY_REPORT_HOUR, randomMinute, 0, 0);
|
|
39835
|
+
if (reportTime.getTime() <= now.getTime()) {
|
|
39836
|
+
reportTime.setDate(reportTime.getDate() + 1);
|
|
39837
|
+
}
|
|
39838
|
+
return reportTime.getTime() - now.getTime();
|
|
39839
|
+
}
|
|
39840
|
+
async function reportVersion(deps, reportSource = "startup") {
|
|
39841
|
+
const osType = resolveOsType(deps.nodePlatform ?? (0, import_node_os4.platform)());
|
|
39842
|
+
const openclawVersion = resolveHostOpenClawVersion(getPluginRuntime());
|
|
39843
|
+
log18.info("Version reporter \u2014 resolved openclaw version", { source: reportSource, openclawVersion });
|
|
39844
|
+
const payload = {
|
|
39845
|
+
openclaw_version: openclawVersion,
|
|
39846
|
+
plugin_version: getPluginVersion(),
|
|
39847
|
+
os_type: osType
|
|
39848
|
+
};
|
|
39849
|
+
log18.info(`Version report triggered (source=${reportSource})`, payload);
|
|
39850
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
39851
|
+
try {
|
|
39852
|
+
const token2 = await deps.getToken();
|
|
39853
|
+
const reportUrl = resolveReportUrl(deps.accountEnv);
|
|
39854
|
+
log18.info(`Version report URL: ${reportUrl}`);
|
|
39855
|
+
const response = await fetch(reportUrl, {
|
|
39856
|
+
method: "POST",
|
|
39857
|
+
headers: {
|
|
39858
|
+
"Authorization": `Bearer ${token2}`,
|
|
39859
|
+
"Content-Type": "application/json"
|
|
39860
|
+
},
|
|
39861
|
+
body: JSON.stringify(payload)
|
|
39862
|
+
});
|
|
39863
|
+
if (response.ok) {
|
|
39864
|
+
log18.info(`Version report succeeded (source=${reportSource}, attempt=${attempt + 1})`);
|
|
39865
|
+
return true;
|
|
39866
|
+
}
|
|
39867
|
+
if (response.status >= 400 && response.status < 500) {
|
|
39868
|
+
log18.warn("Version report failed with client error, not retrying", {
|
|
39869
|
+
source: reportSource,
|
|
39870
|
+
status: response.status,
|
|
39871
|
+
statusText: response.statusText
|
|
39872
|
+
});
|
|
39873
|
+
return false;
|
|
39874
|
+
}
|
|
39875
|
+
if (attempt < MAX_RETRIES) {
|
|
39876
|
+
const delay = retryDelay(attempt);
|
|
39877
|
+
log18.warn("Version report failed with server error, retrying", {
|
|
39878
|
+
source: reportSource,
|
|
39879
|
+
attempt: attempt + 1,
|
|
39880
|
+
status: response.status,
|
|
39881
|
+
retryInMs: delay
|
|
39882
|
+
});
|
|
39883
|
+
await new Promise((resolve3) => setTimeout(resolve3, delay));
|
|
39884
|
+
} else {
|
|
39885
|
+
log18.error("Version report failed after all retries", {
|
|
39886
|
+
source: reportSource,
|
|
39887
|
+
status: response.status,
|
|
39888
|
+
attempts: attempt + 1
|
|
39889
|
+
});
|
|
39890
|
+
return false;
|
|
39891
|
+
}
|
|
39892
|
+
} catch (err) {
|
|
39893
|
+
if (attempt < MAX_RETRIES) {
|
|
39894
|
+
const delay = retryDelay(attempt);
|
|
39895
|
+
log18.warn("Version report network error, retrying", {
|
|
39896
|
+
source: reportSource,
|
|
39897
|
+
attempt: attempt + 1,
|
|
39898
|
+
error: err.message,
|
|
39899
|
+
retryInMs: delay
|
|
39900
|
+
});
|
|
39901
|
+
await new Promise((resolve3) => setTimeout(resolve3, delay));
|
|
39902
|
+
} else {
|
|
39903
|
+
log18.error("Version report failed after all retries (network)", {
|
|
39904
|
+
source: reportSource,
|
|
39905
|
+
error: err.message,
|
|
39906
|
+
attempts: attempt + 1
|
|
39907
|
+
});
|
|
39908
|
+
return false;
|
|
39909
|
+
}
|
|
39910
|
+
}
|
|
39911
|
+
}
|
|
39912
|
+
return false;
|
|
39913
|
+
}
|
|
39914
|
+
function startDailyReport(deps) {
|
|
39915
|
+
stopDailyReport();
|
|
39916
|
+
const scheduleNext = () => {
|
|
39917
|
+
const delay = msUntilNextReportWindow();
|
|
39918
|
+
log18.info("Daily version report scheduled", {
|
|
39919
|
+
nextAt: new Date(Date.now() + delay).toISOString(),
|
|
39920
|
+
delayMs: delay
|
|
39921
|
+
});
|
|
39922
|
+
dailyTimer = setTimeout(async () => {
|
|
39923
|
+
try {
|
|
39924
|
+
await reportVersion(deps, "daily");
|
|
39925
|
+
} catch (err) {
|
|
39926
|
+
log18.error("Daily version report threw unexpected error", {
|
|
39927
|
+
error: err.message
|
|
39928
|
+
});
|
|
39929
|
+
}
|
|
39930
|
+
scheduleNext();
|
|
39931
|
+
}, delay);
|
|
39932
|
+
if (dailyTimer && typeof dailyTimer === "object" && "unref" in dailyTimer) {
|
|
39933
|
+
dailyTimer.unref();
|
|
39934
|
+
}
|
|
39935
|
+
};
|
|
39936
|
+
scheduleNext();
|
|
39937
|
+
log18.info("Daily version reporter started");
|
|
39938
|
+
}
|
|
39939
|
+
function stopDailyReport() {
|
|
39940
|
+
if (dailyTimer) {
|
|
39941
|
+
clearTimeout(dailyTimer);
|
|
39942
|
+
dailyTimer = null;
|
|
39943
|
+
log18.info("Daily version reporter stopped");
|
|
39944
|
+
}
|
|
39945
|
+
}
|
|
39946
|
+
|
|
39649
39947
|
// src/channel/plugin.ts
|
|
39650
|
-
var
|
|
39948
|
+
var log19 = createLogger("channel/plugin");
|
|
39651
39949
|
var VALID_CLI_QUANTUM_MODE_CHOICES = /* @__PURE__ */ new Set(["quantum_only", "quantum_and_plain", "not_enabled"]);
|
|
39652
39950
|
var meta3 = {
|
|
39653
39951
|
id: CHANNEL_ID,
|
|
@@ -39835,7 +40133,7 @@ var quantumImPlugin = {
|
|
|
39835
40133
|
credentials: [],
|
|
39836
40134
|
textInputs: [
|
|
39837
40135
|
{
|
|
39838
|
-
inputKey: "
|
|
40136
|
+
inputKey: "appId",
|
|
39839
40137
|
message: APP_ID_INPUT_PROMPT,
|
|
39840
40138
|
shouldPrompt: ({ credentialValues }) => credentialValues[SETUP_WIZARD_RETURN_FLAG] !== "1",
|
|
39841
40139
|
confirmCurrentValue: false,
|
|
@@ -39866,7 +40164,7 @@ var quantumImPlugin = {
|
|
|
39866
40164
|
}
|
|
39867
40165
|
},
|
|
39868
40166
|
{
|
|
39869
|
-
inputKey: "
|
|
40167
|
+
inputKey: "appSecret",
|
|
39870
40168
|
message: APP_SECRET_INPUT_PROMPT,
|
|
39871
40169
|
shouldPrompt: ({ credentialValues }) => credentialValues[SETUP_WIZARD_RETURN_FLAG] !== "1",
|
|
39872
40170
|
confirmCurrentValue: false,
|
|
@@ -40044,7 +40342,7 @@ var quantumImPlugin = {
|
|
|
40044
40342
|
gateway: {
|
|
40045
40343
|
/** 启动账户 — 初始化所有模块并开始接收消息 */
|
|
40046
40344
|
startAccount: async (ctx) => {
|
|
40047
|
-
|
|
40345
|
+
log19.info(`starting liangzimixin[${ctx.accountId}]`);
|
|
40048
40346
|
try {
|
|
40049
40347
|
const resolved = resolveAccount(ctx.cfg, ctx.accountId);
|
|
40050
40348
|
if (!resolved.credentials) {
|
|
@@ -40075,17 +40373,26 @@ var quantumImPlugin = {
|
|
|
40075
40373
|
instance.messagePipe.onMessage((msg) => {
|
|
40076
40374
|
pipeline.handle(msg);
|
|
40077
40375
|
});
|
|
40078
|
-
|
|
40079
|
-
|
|
40376
|
+
log19.info(`liangzimixin[${ctx.accountId}] started \u2713`);
|
|
40377
|
+
log19.info("\u{1F389} \u6B22\u8FCE\u4F7F\u7528\u91CF\u5B50\u5BC6\u4FE1\u9F99\u867E\uFF0C\u60A8\u5DF2\u6210\u529F\u8FDE\u63A5\u667A\u80FD\u52A9\u7406");
|
|
40378
|
+
const versionReportDeps = {
|
|
40379
|
+
getToken: () => instance.tokenManager.getValidToken(),
|
|
40380
|
+
accountEnv: config2.credentials.env
|
|
40381
|
+
};
|
|
40382
|
+
reportVersion(versionReportDeps, "startup").catch((err) => {
|
|
40383
|
+
log19.error("Startup version report failed", { error: err.message });
|
|
40384
|
+
});
|
|
40385
|
+
startDailyReport(versionReportDeps);
|
|
40080
40386
|
await new Promise((resolve3) => {
|
|
40081
40387
|
if (ctx.abortSignal?.aborted) {
|
|
40082
40388
|
resolve3();
|
|
40083
40389
|
return;
|
|
40084
40390
|
}
|
|
40085
40391
|
const onAbort = () => {
|
|
40086
|
-
|
|
40392
|
+
log19.info(`liangzimixin[${ctx.accountId}] received abort signal, shutting down`);
|
|
40087
40393
|
ctx.abortSignal?.removeEventListener("abort", onAbort);
|
|
40088
|
-
|
|
40394
|
+
stopDailyReport();
|
|
40395
|
+
instance.shutdown().catch((err) => log19.error("Shutdown error", { error: err.message })).finally(() => {
|
|
40089
40396
|
activeInstance = null;
|
|
40090
40397
|
resolve3();
|
|
40091
40398
|
});
|
|
@@ -40093,7 +40400,7 @@ var quantumImPlugin = {
|
|
|
40093
40400
|
ctx.abortSignal?.addEventListener("abort", onAbort);
|
|
40094
40401
|
});
|
|
40095
40402
|
} catch (err) {
|
|
40096
|
-
|
|
40403
|
+
log19.error(`liangzimixin[${ctx.accountId}] start failed`, {
|
|
40097
40404
|
error: err.message
|
|
40098
40405
|
});
|
|
40099
40406
|
throw err;
|
|
@@ -40101,148 +40408,23 @@ var quantumImPlugin = {
|
|
|
40101
40408
|
},
|
|
40102
40409
|
/** 停止账户 — 优雅关闭所有模块 */
|
|
40103
40410
|
stopAccount: async (ctx) => {
|
|
40104
|
-
|
|
40411
|
+
log19.info(`stopping liangzimixin[${ctx.accountId}]`);
|
|
40105
40412
|
if (activeInstance) {
|
|
40106
40413
|
await activeInstance.shutdown();
|
|
40107
40414
|
activeInstance = null;
|
|
40108
40415
|
}
|
|
40109
|
-
|
|
40416
|
+
log19.info(`stopped liangzimixin[${ctx.accountId}]`);
|
|
40110
40417
|
}
|
|
40111
40418
|
}
|
|
40112
40419
|
};
|
|
40113
40420
|
|
|
40114
|
-
// src/runtime-info.ts
|
|
40115
|
-
var import_node_os3 = require("os");
|
|
40116
|
-
|
|
40117
|
-
// package.json
|
|
40118
|
-
var package_default = {
|
|
40119
|
-
name: "liangzimixin",
|
|
40120
|
-
version: "0.3.104",
|
|
40121
|
-
description: "Quantum-encrypted IM channel plugin for OpenClaw",
|
|
40122
|
-
type: "module",
|
|
40123
|
-
main: "dist/index.cjs",
|
|
40124
|
-
types: "dist/index.d.ts",
|
|
40125
|
-
files: [
|
|
40126
|
-
"dist/",
|
|
40127
|
-
"dist/quantum-sdk/",
|
|
40128
|
-
"scripts/liangzimixin_install.sh",
|
|
40129
|
-
"scripts/liangzimixin_install.bat",
|
|
40130
|
-
"scripts/liangzimixin_install_test.sh",
|
|
40131
|
-
"scripts/liangzimixin_install_test.bat",
|
|
40132
|
-
"scripts/liangzimixin_install_test_beta.bat",
|
|
40133
|
-
"openclaw.plugin.json",
|
|
40134
|
-
"README.md",
|
|
40135
|
-
"LICENSE"
|
|
40136
|
-
],
|
|
40137
|
-
scripts: {
|
|
40138
|
-
build: "tsup",
|
|
40139
|
-
dev: "tsup --watch",
|
|
40140
|
-
lint: "eslint src/",
|
|
40141
|
-
"lint:fix": "eslint src/ --fix",
|
|
40142
|
-
typecheck: "tsc --noEmit",
|
|
40143
|
-
format: "prettier --write src/**/*.ts",
|
|
40144
|
-
"format:check": "prettier --check src/**/*.ts"
|
|
40145
|
-
},
|
|
40146
|
-
peerDependencies: {
|
|
40147
|
-
openclaw: ">=2026.2.0"
|
|
40148
|
-
},
|
|
40149
|
-
engines: {
|
|
40150
|
-
node: ">=20"
|
|
40151
|
-
},
|
|
40152
|
-
devDependencies: {
|
|
40153
|
-
"@types/node": "^20.0.0",
|
|
40154
|
-
"@types/ws": "^8.18.1",
|
|
40155
|
-
"@typescript-eslint/eslint-plugin": "^8.56.1",
|
|
40156
|
-
"@typescript-eslint/parser": "^8.56.1",
|
|
40157
|
-
eslint: "^9.39.3",
|
|
40158
|
-
openclaw: "^2026.4.14",
|
|
40159
|
-
prettier: "^3.5.3",
|
|
40160
|
-
tsup: "^8.5.1",
|
|
40161
|
-
typescript: "^5.8.3",
|
|
40162
|
-
winston: "^3.19.0",
|
|
40163
|
-
"winston-daily-rotate-file": "^5.0.0",
|
|
40164
|
-
ws: "^8.19.0",
|
|
40165
|
-
zod: "^4.3.6"
|
|
40166
|
-
},
|
|
40167
|
-
keywords: [
|
|
40168
|
-
"openclaw",
|
|
40169
|
-
"liangzimixin",
|
|
40170
|
-
"channel-plugin",
|
|
40171
|
-
"instant-messaging",
|
|
40172
|
-
"encryption"
|
|
40173
|
-
],
|
|
40174
|
-
openclaw: {
|
|
40175
|
-
compat: {
|
|
40176
|
-
pluginApi: ">=2026.3.8"
|
|
40177
|
-
},
|
|
40178
|
-
build: {
|
|
40179
|
-
openclawVersion: ">=2026.3.8"
|
|
40180
|
-
},
|
|
40181
|
-
extensions: [
|
|
40182
|
-
"./dist/index.cjs"
|
|
40183
|
-
],
|
|
40184
|
-
setupEntry: "./dist/setup-entry.cjs",
|
|
40185
|
-
channel: {
|
|
40186
|
-
id: "liangzimixin",
|
|
40187
|
-
label: "QuantumIM",
|
|
40188
|
-
selectionLabel: "\u5BC6\u4FE1 IM (\u91CF\u5B50\u5BC6\u4FE1)",
|
|
40189
|
-
docsPath: "/channels/liangzimixin",
|
|
40190
|
-
docsLabel: "liangzimixin",
|
|
40191
|
-
blurb: "\u5BC6\u4FE1 IM Channel\uFF0C\u652F\u6301\u91CF\u5B50\u52A0\u5BC6\u7684\u5B89\u5168\u5373\u65F6\u901A\u4FE1\u3002",
|
|
40192
|
-
aliases: [
|
|
40193
|
-
"qim"
|
|
40194
|
-
],
|
|
40195
|
-
order: 80
|
|
40196
|
-
},
|
|
40197
|
-
install: {
|
|
40198
|
-
npmSpec: "liangzimixin",
|
|
40199
|
-
clawhubSpec: "liangzimixin",
|
|
40200
|
-
localPath: "extensions/liangzimixin",
|
|
40201
|
-
defaultChoice: "npm"
|
|
40202
|
-
}
|
|
40203
|
-
},
|
|
40204
|
-
license: "MIT"
|
|
40205
|
-
};
|
|
40206
|
-
|
|
40207
|
-
// src/runtime-info.ts
|
|
40208
|
-
var PACKAGE_VERSION = normalizeVersion(package_default.version);
|
|
40209
|
-
function normalizeVersion(value) {
|
|
40210
|
-
return typeof value === "string" && value.trim() ? value.trim() : "unknown";
|
|
40211
|
-
}
|
|
40212
|
-
function resolveHostOpenClawVersion(runtime2) {
|
|
40213
|
-
if (!runtime2 || typeof runtime2 !== "object") return "unknown";
|
|
40214
|
-
return normalizeVersion(runtime2.version);
|
|
40215
|
-
}
|
|
40216
|
-
function resolveOsType(nodePlatform = (0, import_node_os3.platform)()) {
|
|
40217
|
-
const normalized = nodePlatform.trim();
|
|
40218
|
-
if (!normalized) return "unknown";
|
|
40219
|
-
switch (normalized) {
|
|
40220
|
-
case "win32":
|
|
40221
|
-
return "windows";
|
|
40222
|
-
case "darwin":
|
|
40223
|
-
return "macOS";
|
|
40224
|
-
case "linux":
|
|
40225
|
-
return "linux";
|
|
40226
|
-
default:
|
|
40227
|
-
return normalized;
|
|
40228
|
-
}
|
|
40229
|
-
}
|
|
40230
|
-
function buildRuntimeInfoLogMeta(runtime2, options = {}) {
|
|
40231
|
-
const nodePlatform = options.platform?.trim() || (0, import_node_os3.platform)();
|
|
40232
|
-
return {
|
|
40233
|
-
openclawVersion: resolveHostOpenClawVersion(runtime2),
|
|
40234
|
-
pluginVersion: normalizeVersion(options.pluginVersion ?? PACKAGE_VERSION),
|
|
40235
|
-
os: resolveOsType(nodePlatform),
|
|
40236
|
-
nodePlatform
|
|
40237
|
-
};
|
|
40238
|
-
}
|
|
40239
|
-
|
|
40240
40421
|
// src/crypto/quantum-plug.ts
|
|
40241
40422
|
var import_node_fs3 = require("fs");
|
|
40242
40423
|
var import_node_path3 = require("path");
|
|
40243
|
-
var
|
|
40424
|
+
var log20 = createLogger("crypto/quantum-plug");
|
|
40244
40425
|
var KMS_URLS = {
|
|
40245
40426
|
test: "https://cmsp.zdxlz.com:8552",
|
|
40427
|
+
"new-test": "https://cmsp.zdxlz.com:8552",
|
|
40246
40428
|
staging: "http://223.244.14.238:8552",
|
|
40247
40429
|
production: "https://cmsp.zdxlz.com:8552"
|
|
40248
40430
|
};
|
|
@@ -40260,7 +40442,7 @@ function writeQuantumConfig(config2) {
|
|
|
40260
40442
|
const configPath = (0, import_node_path3.join)(sdkDir, "quantum.json");
|
|
40261
40443
|
(0, import_node_fs3.mkdirSync)(sdkDir, { recursive: true });
|
|
40262
40444
|
(0, import_node_fs3.writeFileSync)(configPath, JSON.stringify(config2, null, 2), "utf-8");
|
|
40263
|
-
|
|
40445
|
+
log20.info("quantum.json written", { path: configPath });
|
|
40264
40446
|
}
|
|
40265
40447
|
function createQuantumPlug() {
|
|
40266
40448
|
let sdk = null;
|
|
@@ -40269,11 +40451,11 @@ function createQuantumPlug() {
|
|
|
40269
40451
|
try {
|
|
40270
40452
|
const sdkPath = (0, import_node_path3.resolve)(__dirname, "quantum-sdk", "index.cjs");
|
|
40271
40453
|
sdk = require(sdkPath);
|
|
40272
|
-
|
|
40454
|
+
log20.info("Quantum SDK loaded \u2713");
|
|
40273
40455
|
return sdk;
|
|
40274
40456
|
} catch (err) {
|
|
40275
40457
|
const msg = err instanceof Error ? err.message : String(err);
|
|
40276
|
-
|
|
40458
|
+
log20.error("Failed to load quantum SDK", { error: msg });
|
|
40277
40459
|
throw new Error(`Quantum SDK load failed: ${msg}`);
|
|
40278
40460
|
}
|
|
40279
40461
|
}
|
|
@@ -40282,7 +40464,7 @@ function createQuantumPlug() {
|
|
|
40282
40464
|
const s = loadSdk();
|
|
40283
40465
|
ensureSdkLogReady();
|
|
40284
40466
|
await s.init();
|
|
40285
|
-
|
|
40467
|
+
log20.info("Quantum SDK initialized \u2713");
|
|
40286
40468
|
},
|
|
40287
40469
|
async encrypt(plaintext, iv, mode) {
|
|
40288
40470
|
const s = loadSdk();
|
|
@@ -40321,7 +40503,7 @@ function getKmsUrl(env) {
|
|
|
40321
40503
|
|
|
40322
40504
|
// src/crypto/crypto-engine.ts
|
|
40323
40505
|
var import_node_crypto = require("crypto");
|
|
40324
|
-
var
|
|
40506
|
+
var log21 = createLogger("crypto/crypto-engine");
|
|
40325
40507
|
var SM4_MODE = 4;
|
|
40326
40508
|
var PASSTHROUGH_KEY_ID = "passthrough";
|
|
40327
40509
|
var IV_LENGTH = 8;
|
|
@@ -40373,7 +40555,7 @@ var CryptoEngine = class _CryptoEngine {
|
|
|
40373
40555
|
* 构造加密引擎 (加密模式)
|
|
40374
40556
|
*
|
|
40375
40557
|
* @param credentials - 量子 SDK 所需的凭据
|
|
40376
|
-
* @param env - 部署环境 ('test' | 'staging' | 'production')
|
|
40558
|
+
* @param env - 部署环境 ('test' | 'new-test' | 'staging' | 'production')
|
|
40377
40559
|
*/
|
|
40378
40560
|
constructor(credentials, env = "production", operationTimeoutMs) {
|
|
40379
40561
|
this.plug = quantum_plug_default;
|
|
@@ -40381,7 +40563,7 @@ var CryptoEngine = class _CryptoEngine {
|
|
|
40381
40563
|
this.credentials = credentials;
|
|
40382
40564
|
this.env = env;
|
|
40383
40565
|
this.operationTimeoutMs = operationTimeoutMs ?? DEFAULT_OPERATION_TIMEOUT_MS;
|
|
40384
|
-
|
|
40566
|
+
log21.info("CryptoEngine created (quantum SDK mode)", { operationTimeoutMs: this.operationTimeoutMs });
|
|
40385
40567
|
}
|
|
40386
40568
|
/**
|
|
40387
40569
|
* 创建透传模式的加密引擎 (静态工厂方法)
|
|
@@ -40402,7 +40584,7 @@ var CryptoEngine = class _CryptoEngine {
|
|
|
40402
40584
|
instance.credentials = null;
|
|
40403
40585
|
instance.env = "production";
|
|
40404
40586
|
instance.operationTimeoutMs = DEFAULT_OPERATION_TIMEOUT_MS;
|
|
40405
|
-
|
|
40587
|
+
log21.info("CryptoEngine created (passthrough mode \u2014 crypto disabled)");
|
|
40406
40588
|
return instance;
|
|
40407
40589
|
}
|
|
40408
40590
|
/**
|
|
@@ -40432,7 +40614,7 @@ var CryptoEngine = class _CryptoEngine {
|
|
|
40432
40614
|
}
|
|
40433
40615
|
await this.plug.init();
|
|
40434
40616
|
this.initialized = true;
|
|
40435
|
-
|
|
40617
|
+
log21.info("CryptoEngine initialized \u2713");
|
|
40436
40618
|
}
|
|
40437
40619
|
/**
|
|
40438
40620
|
* 加密明文
|
|
@@ -40446,7 +40628,7 @@ var CryptoEngine = class _CryptoEngine {
|
|
|
40446
40628
|
async encrypt(plaintext) {
|
|
40447
40629
|
this.ensureInitialized();
|
|
40448
40630
|
if (this.passthrough) {
|
|
40449
|
-
|
|
40631
|
+
log21.debug("Encrypt (passthrough)", { length: plaintext.length });
|
|
40450
40632
|
return { ciphertext: plaintext, keyId: PASSTHROUGH_KEY_ID, iv: "" };
|
|
40451
40633
|
}
|
|
40452
40634
|
const iv = generateIv();
|
|
@@ -40457,7 +40639,7 @@ var CryptoEngine = class _CryptoEngine {
|
|
|
40457
40639
|
"encrypt"
|
|
40458
40640
|
);
|
|
40459
40641
|
metrics.recordLatency("crypto.encrypt", Date.now() - startMs);
|
|
40460
|
-
|
|
40642
|
+
log21.debug("Encrypted", { length: plaintext.length, keyId: result.keyId });
|
|
40461
40643
|
return { ...result, iv };
|
|
40462
40644
|
}
|
|
40463
40645
|
/**
|
|
@@ -40474,7 +40656,7 @@ var CryptoEngine = class _CryptoEngine {
|
|
|
40474
40656
|
async decrypt(ciphertext, keyId, iv = "") {
|
|
40475
40657
|
this.ensureInitialized();
|
|
40476
40658
|
if (this.passthrough) {
|
|
40477
|
-
|
|
40659
|
+
log21.debug("Decrypt (passthrough)", { keyId });
|
|
40478
40660
|
return ciphertext;
|
|
40479
40661
|
}
|
|
40480
40662
|
const startMs = Date.now();
|
|
@@ -40484,7 +40666,7 @@ var CryptoEngine = class _CryptoEngine {
|
|
|
40484
40666
|
"decrypt"
|
|
40485
40667
|
);
|
|
40486
40668
|
metrics.recordLatency("crypto.decrypt", Date.now() - startMs);
|
|
40487
|
-
|
|
40669
|
+
log21.debug("Decrypted", { keyId });
|
|
40488
40670
|
return result.plaintext;
|
|
40489
40671
|
}
|
|
40490
40672
|
/**
|
|
@@ -40564,7 +40746,7 @@ var CryptoEngine = class _CryptoEngine {
|
|
|
40564
40746
|
};
|
|
40565
40747
|
|
|
40566
40748
|
// src/auth/oauth-client.ts
|
|
40567
|
-
var
|
|
40749
|
+
var log22 = createLogger("auth/oauth-client");
|
|
40568
40750
|
var ApiError = class extends Error {
|
|
40569
40751
|
constructor(status, body, endpoint) {
|
|
40570
40752
|
super(`API error: ${status} on ${endpoint}`);
|
|
@@ -40601,7 +40783,7 @@ var OAuthClient = class {
|
|
|
40601
40783
|
this.baseUrl = config2.baseUrl.replace(/\/+$/, "");
|
|
40602
40784
|
this.appId = config2.appId;
|
|
40603
40785
|
this.appSecret = config2.appSecret;
|
|
40604
|
-
|
|
40786
|
+
log22.info("OAuthClient initialized", { baseUrl: this.baseUrl, appId: sanitize(this.appId) });
|
|
40605
40787
|
}
|
|
40606
40788
|
// ── 通用 HTTP 请求 ──
|
|
40607
40789
|
/**
|
|
@@ -40621,7 +40803,7 @@ var OAuthClient = class {
|
|
|
40621
40803
|
bodyStr = JSON.stringify(options.body);
|
|
40622
40804
|
}
|
|
40623
40805
|
}
|
|
40624
|
-
|
|
40806
|
+
log22.debug("HTTP request", { method, url: url2 });
|
|
40625
40807
|
const response = await fetch(url2, {
|
|
40626
40808
|
method,
|
|
40627
40809
|
headers,
|
|
@@ -40630,10 +40812,10 @@ var OAuthClient = class {
|
|
|
40630
40812
|
});
|
|
40631
40813
|
const responseBody = await response.text();
|
|
40632
40814
|
if (!response.ok) {
|
|
40633
|
-
|
|
40815
|
+
log22.error("HTTP error", { method, url: url2, status: response.status });
|
|
40634
40816
|
throw new ApiError(response.status, void 0, path4);
|
|
40635
40817
|
}
|
|
40636
|
-
|
|
40818
|
+
log22.debug("HTTP response", { method, url: url2, status: response.status });
|
|
40637
40819
|
try {
|
|
40638
40820
|
return JSON.parse(responseBody);
|
|
40639
40821
|
} catch {
|
|
@@ -40659,7 +40841,7 @@ var OAuthClient = class {
|
|
|
40659
40841
|
params.set("client_id", this.appId);
|
|
40660
40842
|
params.set("client_secret", this.appSecret);
|
|
40661
40843
|
params.set("scope", SCOPE);
|
|
40662
|
-
|
|
40844
|
+
log22.info("Requesting access token", { appId: sanitize(this.appId) });
|
|
40663
40845
|
const response = await this.request(
|
|
40664
40846
|
"POST",
|
|
40665
40847
|
"/auth/token",
|
|
@@ -40676,7 +40858,7 @@ var OAuthClient = class {
|
|
|
40676
40858
|
grantedAt: now,
|
|
40677
40859
|
expiresAt: now + expiresIn * 1e3
|
|
40678
40860
|
};
|
|
40679
|
-
|
|
40861
|
+
log22.info("Access token acquired", {
|
|
40680
40862
|
accessToken: sanitize(tokenData.accessToken),
|
|
40681
40863
|
expiresIn: tokenData.expiresIn,
|
|
40682
40864
|
scope: tokenData.scope
|
|
@@ -40694,7 +40876,7 @@ var import_promises = require("fs/promises");
|
|
|
40694
40876
|
var import_node_fs4 = require("fs");
|
|
40695
40877
|
var import_node_path4 = require("path");
|
|
40696
40878
|
var import_node_crypto2 = require("crypto");
|
|
40697
|
-
var
|
|
40879
|
+
var log23 = createLogger("auth/token-store");
|
|
40698
40880
|
var TokenStore = class {
|
|
40699
40881
|
/** 存储目录路径 */
|
|
40700
40882
|
storageDir;
|
|
@@ -40709,7 +40891,7 @@ var TokenStore = class {
|
|
|
40709
40891
|
constructor(storageDir, crypto) {
|
|
40710
40892
|
this.storageDir = storageDir;
|
|
40711
40893
|
this.crypto = crypto;
|
|
40712
|
-
|
|
40894
|
+
log23.info("TokenStore initialized", { storageDir });
|
|
40713
40895
|
}
|
|
40714
40896
|
/**
|
|
40715
40897
|
* 确保存储目录存在并设置正确的权限。
|
|
@@ -40719,7 +40901,7 @@ var TokenStore = class {
|
|
|
40719
40901
|
if (this.dirEnsured) return;
|
|
40720
40902
|
if (!(0, import_node_fs4.existsSync)(this.storageDir)) {
|
|
40721
40903
|
await (0, import_promises.mkdir)(this.storageDir, { recursive: true, mode: 448 });
|
|
40722
|
-
|
|
40904
|
+
log23.debug("Storage directory created", { dir: this.storageDir });
|
|
40723
40905
|
}
|
|
40724
40906
|
this.dirEnsured = true;
|
|
40725
40907
|
}
|
|
@@ -40755,7 +40937,7 @@ var TokenStore = class {
|
|
|
40755
40937
|
try {
|
|
40756
40938
|
await (0, import_promises.writeFile)(tmpPath, storageJson, { mode: 384 });
|
|
40757
40939
|
await (0, import_promises.rename)(tmpPath, targetPath);
|
|
40758
|
-
|
|
40940
|
+
log23.debug("Token saved", { key, path: targetPath });
|
|
40759
40941
|
} catch (err) {
|
|
40760
40942
|
try {
|
|
40761
40943
|
await (0, import_promises.unlink)(tmpPath);
|
|
@@ -40778,7 +40960,7 @@ var TokenStore = class {
|
|
|
40778
40960
|
async load(key) {
|
|
40779
40961
|
const filePath = this.filePath(key);
|
|
40780
40962
|
if (!(0, import_node_fs4.existsSync)(filePath)) {
|
|
40781
|
-
|
|
40963
|
+
log23.debug("Token file not found", { key, path: filePath });
|
|
40782
40964
|
return null;
|
|
40783
40965
|
}
|
|
40784
40966
|
try {
|
|
@@ -40787,24 +40969,24 @@ var TokenStore = class {
|
|
|
40787
40969
|
if (storage.hmac) {
|
|
40788
40970
|
const expectedHmac = (0, import_node_crypto2.createHmac)("sha256", storage.keyId).update(storage.ciphertext).digest("hex");
|
|
40789
40971
|
if (expectedHmac !== storage.hmac) {
|
|
40790
|
-
|
|
40972
|
+
log23.warn("SECURITY_AUDIT: token file integrity check failed", {
|
|
40791
40973
|
key,
|
|
40792
40974
|
path: filePath
|
|
40793
40975
|
});
|
|
40794
40976
|
return null;
|
|
40795
40977
|
}
|
|
40796
40978
|
} else {
|
|
40797
|
-
|
|
40979
|
+
log23.debug("Token file missing HMAC (legacy format), skipping integrity check", {
|
|
40798
40980
|
key,
|
|
40799
40981
|
path: filePath
|
|
40800
40982
|
});
|
|
40801
40983
|
}
|
|
40802
40984
|
const json2 = await this.crypto.decrypt(storage.ciphertext, storage.keyId, storage.iv ?? "");
|
|
40803
40985
|
const data = JSON.parse(json2);
|
|
40804
|
-
|
|
40986
|
+
log23.debug("Token loaded", { key, path: filePath });
|
|
40805
40987
|
return data;
|
|
40806
40988
|
} catch (err) {
|
|
40807
|
-
|
|
40989
|
+
log23.warn("Failed to load token (corrupted or key mismatch), treating as empty", {
|
|
40808
40990
|
key,
|
|
40809
40991
|
error: err instanceof Error ? err.message : String(err)
|
|
40810
40992
|
});
|
|
@@ -40820,7 +41002,7 @@ var TokenStore = class {
|
|
|
40820
41002
|
const filePath = this.filePath(key);
|
|
40821
41003
|
try {
|
|
40822
41004
|
await (0, import_promises.unlink)(filePath);
|
|
40823
|
-
|
|
41005
|
+
log23.debug("Token file cleared", { key, path: filePath });
|
|
40824
41006
|
} catch (err) {
|
|
40825
41007
|
if (err.code !== "ENOENT") {
|
|
40826
41008
|
throw err;
|
|
@@ -40830,10 +41012,10 @@ var TokenStore = class {
|
|
|
40830
41012
|
};
|
|
40831
41013
|
|
|
40832
41014
|
// src/auth/token-manager.ts
|
|
40833
|
-
var
|
|
41015
|
+
var log24 = createLogger("auth/token-manager");
|
|
40834
41016
|
var DEFAULT_REFRESH_AHEAD_MS = 5 * 60 * 1e3;
|
|
40835
|
-
var
|
|
40836
|
-
var
|
|
41017
|
+
var MAX_RETRIES2 = 3;
|
|
41018
|
+
var RETRY_BASE_MS2 = 1e3;
|
|
40837
41019
|
var TokenManager = class {
|
|
40838
41020
|
oauthClient;
|
|
40839
41021
|
tokenStore;
|
|
@@ -40858,7 +41040,7 @@ var TokenManager = class {
|
|
|
40858
41040
|
this.tokenStore = deps.tokenStore;
|
|
40859
41041
|
this.refreshAheadMs = deps.refreshAheadMs ?? DEFAULT_REFRESH_AHEAD_MS;
|
|
40860
41042
|
this.credentialHash = deps.credentialHash;
|
|
40861
|
-
|
|
41043
|
+
log24.info("TokenManager initialized", { refreshAheadMs: this.refreshAheadMs });
|
|
40862
41044
|
}
|
|
40863
41045
|
// ── 核心方法 ──
|
|
40864
41046
|
/**
|
|
@@ -40876,7 +41058,7 @@ var TokenManager = class {
|
|
|
40876
41058
|
return this.cachedToken;
|
|
40877
41059
|
}
|
|
40878
41060
|
if (this.refreshLock) {
|
|
40879
|
-
|
|
41061
|
+
log24.debug("Waiting for concurrent token acquisition");
|
|
40880
41062
|
return this.refreshLock;
|
|
40881
41063
|
}
|
|
40882
41064
|
this.refreshLock = this._acquireTokenWithRetry();
|
|
@@ -40903,7 +41085,7 @@ var TokenManager = class {
|
|
|
40903
41085
|
invalidate() {
|
|
40904
41086
|
this.cachedToken = null;
|
|
40905
41087
|
this.currentTokenData = null;
|
|
40906
|
-
|
|
41088
|
+
log24.info("Token invalidated (will re-acquire on next call)");
|
|
40907
41089
|
}
|
|
40908
41090
|
/** 废置并清除所有令牌 (包括文件存储和内存缓存) */
|
|
40909
41091
|
async revokeAndClear() {
|
|
@@ -40912,13 +41094,13 @@ var TokenManager = class {
|
|
|
40912
41094
|
this.cachedToken = null;
|
|
40913
41095
|
this.cachedScope = null;
|
|
40914
41096
|
this.currentTokenData = null;
|
|
40915
|
-
|
|
41097
|
+
log24.info("Token revoked and cleared");
|
|
40916
41098
|
}
|
|
40917
41099
|
/** 清理定时器和并发锁 — 优雅关闭时调用 */
|
|
40918
41100
|
shutdown() {
|
|
40919
41101
|
this.clearRefreshTimer();
|
|
40920
41102
|
this.refreshLock = null;
|
|
40921
|
-
|
|
41103
|
+
log24.info("TokenManager shutdown");
|
|
40922
41104
|
}
|
|
40923
41105
|
// ── 内部方法 ──
|
|
40924
41106
|
/**
|
|
@@ -40929,25 +41111,25 @@ var TokenManager = class {
|
|
|
40929
41111
|
* - 401/403 → 不重试 (凭证可能无效)
|
|
40930
41112
|
*/
|
|
40931
41113
|
async _acquireTokenWithRetry() {
|
|
40932
|
-
for (let attempt = 0; attempt <=
|
|
41114
|
+
for (let attempt = 0; attempt <= MAX_RETRIES2; attempt++) {
|
|
40933
41115
|
try {
|
|
40934
41116
|
return await this._acquireToken();
|
|
40935
41117
|
} catch (err) {
|
|
40936
41118
|
if (err instanceof ApiError && (err.status === 401 || err.status === 403)) {
|
|
40937
|
-
|
|
41119
|
+
log24.error("Token acquire failed with auth error, not retrying", { status: err.status });
|
|
40938
41120
|
throw err;
|
|
40939
41121
|
}
|
|
40940
|
-
if (attempt ===
|
|
40941
|
-
|
|
41122
|
+
if (attempt === MAX_RETRIES2) {
|
|
41123
|
+
log24.error("Token acquire failed after all retries", { attempts: attempt + 1 });
|
|
40942
41124
|
throw new TokenAcquireError(
|
|
40943
41125
|
`Token acquire failed after ${attempt + 1} attempts`,
|
|
40944
41126
|
{ cause: err instanceof Error ? err : void 0 }
|
|
40945
41127
|
);
|
|
40946
41128
|
}
|
|
40947
|
-
const delay =
|
|
40948
|
-
|
|
41129
|
+
const delay = RETRY_BASE_MS2 * Math.pow(2, attempt);
|
|
41130
|
+
log24.warn("Token acquire failed, retrying", {
|
|
40949
41131
|
attempt: attempt + 1,
|
|
40950
|
-
maxRetries:
|
|
41132
|
+
maxRetries: MAX_RETRIES2,
|
|
40951
41133
|
retryInMs: delay,
|
|
40952
41134
|
error: err instanceof Error ? err.message : String(err)
|
|
40953
41135
|
});
|
|
@@ -40970,23 +41152,23 @@ var TokenManager = class {
|
|
|
40970
41152
|
const stored = await this.tokenStore.load("token");
|
|
40971
41153
|
if (stored) {
|
|
40972
41154
|
if (this.credentialHash && stored.credentialHash !== this.credentialHash) {
|
|
40973
|
-
|
|
41155
|
+
log24.info("Credential hash mismatch \u2014 credentials have changed, discarding cached token", {
|
|
40974
41156
|
hasStoredHash: stored.credentialHash !== void 0
|
|
40975
41157
|
});
|
|
40976
41158
|
await this.tokenStore.clear("token");
|
|
40977
41159
|
} else if (!this.isTokenHardExpired(stored)) {
|
|
40978
|
-
|
|
41160
|
+
log24.info("Token loaded from store (still valid)");
|
|
40979
41161
|
this.updateCache(stored);
|
|
40980
41162
|
this.scheduleRefresh(stored);
|
|
40981
41163
|
return stored.accessToken;
|
|
40982
41164
|
} else {
|
|
40983
|
-
|
|
41165
|
+
log24.info("Stored token has expired, acquiring new one");
|
|
40984
41166
|
}
|
|
40985
41167
|
}
|
|
40986
41168
|
} catch {
|
|
40987
|
-
|
|
41169
|
+
log24.warn("Failed to load token from store, acquiring new one");
|
|
40988
41170
|
}
|
|
40989
|
-
|
|
41171
|
+
log24.info("Acquiring new access token via POST /auth/token");
|
|
40990
41172
|
const tokenData = await this.oauthClient.getToken();
|
|
40991
41173
|
if (this.credentialHash) {
|
|
40992
41174
|
tokenData.credentialHash = this.credentialHash;
|
|
@@ -41020,22 +41202,22 @@ var TokenManager = class {
|
|
|
41020
41202
|
this.clearRefreshTimer();
|
|
41021
41203
|
const refreshInMs = tokenData.expiresAt - this.refreshAheadMs - Date.now();
|
|
41022
41204
|
if (refreshInMs <= 0) {
|
|
41023
|
-
|
|
41205
|
+
log24.debug("Token already within refresh window, not scheduling timer");
|
|
41024
41206
|
return;
|
|
41025
41207
|
}
|
|
41026
|
-
|
|
41208
|
+
log24.debug("Scheduling token refresh", {
|
|
41027
41209
|
refreshInMs,
|
|
41028
41210
|
refreshAt: new Date(Date.now() + refreshInMs).toISOString()
|
|
41029
41211
|
});
|
|
41030
41212
|
this.refreshTimer = setTimeout(async () => {
|
|
41031
41213
|
try {
|
|
41032
|
-
|
|
41214
|
+
log24.info("Scheduled token refresh triggered");
|
|
41033
41215
|
this.cachedToken = null;
|
|
41034
41216
|
this.currentTokenData = null;
|
|
41035
41217
|
await this.getValidToken();
|
|
41036
|
-
|
|
41218
|
+
log24.info("Scheduled token refresh completed");
|
|
41037
41219
|
} catch (err) {
|
|
41038
|
-
|
|
41220
|
+
log24.error("Scheduled token refresh failed", {
|
|
41039
41221
|
error: err instanceof Error ? err.message : String(err)
|
|
41040
41222
|
});
|
|
41041
41223
|
}
|
|
@@ -41066,13 +41248,13 @@ var wrapper_default = import_websocket.default;
|
|
|
41066
41248
|
|
|
41067
41249
|
// src/transport/ws-client.ts
|
|
41068
41250
|
var import_node_events = require("events");
|
|
41069
|
-
var
|
|
41251
|
+
var log25 = createLogger("transport/ws-client");
|
|
41070
41252
|
var WSClient = class extends import_node_events.EventEmitter {
|
|
41071
41253
|
/** 底层 WebSocket 实例 */
|
|
41072
41254
|
ws = null;
|
|
41073
41255
|
constructor() {
|
|
41074
41256
|
super();
|
|
41075
|
-
|
|
41257
|
+
log25.info("WSClient initialized");
|
|
41076
41258
|
}
|
|
41077
41259
|
/**
|
|
41078
41260
|
* 连接到 WebSocket 服务器并绑定事件。
|
|
@@ -41088,7 +41270,7 @@ var WSClient = class extends import_node_events.EventEmitter {
|
|
|
41088
41270
|
this.ws = null;
|
|
41089
41271
|
}
|
|
41090
41272
|
const { url: url2, protocols, headers } = options;
|
|
41091
|
-
|
|
41273
|
+
log25.info("ws:connecting", { url: url2 });
|
|
41092
41274
|
return new Promise((resolve3, reject) => {
|
|
41093
41275
|
const ws = new wrapper_default(url2, protocols, {
|
|
41094
41276
|
headers,
|
|
@@ -41098,7 +41280,7 @@ var WSClient = class extends import_node_events.EventEmitter {
|
|
|
41098
41280
|
let connected = false;
|
|
41099
41281
|
ws.on("open", () => {
|
|
41100
41282
|
connected = true;
|
|
41101
|
-
|
|
41283
|
+
log25.info("ws:connected", { url: url2 });
|
|
41102
41284
|
this.emit("open");
|
|
41103
41285
|
resolve3();
|
|
41104
41286
|
});
|
|
@@ -41109,11 +41291,11 @@ var WSClient = class extends import_node_events.EventEmitter {
|
|
|
41109
41291
|
this.emit("pong");
|
|
41110
41292
|
});
|
|
41111
41293
|
ws.on("close", (code, reason) => {
|
|
41112
|
-
|
|
41294
|
+
log25.info("ws:closed", { code, reason: reason.toString() });
|
|
41113
41295
|
this.emit("close", code, reason.toString());
|
|
41114
41296
|
});
|
|
41115
41297
|
ws.on("error", (err) => {
|
|
41116
|
-
|
|
41298
|
+
log25.error("ws:error", { error: err.message });
|
|
41117
41299
|
if (!connected) {
|
|
41118
41300
|
reject(err);
|
|
41119
41301
|
} else {
|
|
@@ -41126,7 +41308,7 @@ var WSClient = class extends import_node_events.EventEmitter {
|
|
|
41126
41308
|
/** 发送数据到服务器 — 前置检查连接状态 */
|
|
41127
41309
|
send(data) {
|
|
41128
41310
|
if (!this.ws || this.ws.readyState !== wrapper_default.OPEN) {
|
|
41129
|
-
|
|
41311
|
+
log25.warn("ws:send skipped, not connected", { readyState: this.ws?.readyState });
|
|
41130
41312
|
return;
|
|
41131
41313
|
}
|
|
41132
41314
|
this.ws.send(data);
|
|
@@ -41143,7 +41325,7 @@ var WSClient = class extends import_node_events.EventEmitter {
|
|
|
41143
41325
|
this.ws.removeAllListeners();
|
|
41144
41326
|
this.ws.close(code, reason);
|
|
41145
41327
|
this.ws = null;
|
|
41146
|
-
|
|
41328
|
+
log25.info("ws:close requested", { code, reason });
|
|
41147
41329
|
}
|
|
41148
41330
|
}
|
|
41149
41331
|
/** 当前连接状态 (0=CONNECTING, 1=OPEN, 2=CLOSING, 3=CLOSED) */
|
|
@@ -41153,7 +41335,7 @@ var WSClient = class extends import_node_events.EventEmitter {
|
|
|
41153
41335
|
};
|
|
41154
41336
|
|
|
41155
41337
|
// src/transport/dedup.ts
|
|
41156
|
-
var
|
|
41338
|
+
var log26 = createLogger("transport/dedup");
|
|
41157
41339
|
var MessageDedup = class {
|
|
41158
41340
|
/** 去重缓存生存时间 (ms) */
|
|
41159
41341
|
ttlMs;
|
|
@@ -41164,7 +41346,7 @@ var MessageDedup = class {
|
|
|
41164
41346
|
constructor(config2) {
|
|
41165
41347
|
this.ttlMs = config2?.ttlMs ?? 3e5;
|
|
41166
41348
|
this.maxEntries = config2?.maxEntries ?? 5e3;
|
|
41167
|
-
|
|
41349
|
+
log26.info("MessageDedup initialized", { ttlMs: this.ttlMs, maxEntries: this.maxEntries });
|
|
41168
41350
|
}
|
|
41169
41351
|
/**
|
|
41170
41352
|
* 检查消息是否重复。
|
|
@@ -41202,7 +41384,7 @@ var MessageDedup = class {
|
|
|
41202
41384
|
var import_node_crypto3 = require("crypto");
|
|
41203
41385
|
|
|
41204
41386
|
// src/transport/rate-limiter.ts
|
|
41205
|
-
var
|
|
41387
|
+
var log27 = createLogger("transport/rate-limiter");
|
|
41206
41388
|
var RateLimiter = class {
|
|
41207
41389
|
/** 每秒补充的 token 数 */
|
|
41208
41390
|
ratePerSecond;
|
|
@@ -41225,7 +41407,7 @@ var RateLimiter = class {
|
|
|
41225
41407
|
this.maxWaitMs = options.maxWaitMs ?? 5e3;
|
|
41226
41408
|
this.tokens = this.burst;
|
|
41227
41409
|
this.lastRefillTime = Date.now();
|
|
41228
|
-
|
|
41410
|
+
log27.info("RateLimiter initialized", {
|
|
41229
41411
|
ratePerSecond: this.ratePerSecond,
|
|
41230
41412
|
burst: this.burst,
|
|
41231
41413
|
maxWaitMs: this.maxWaitMs
|
|
@@ -41248,7 +41430,7 @@ var RateLimiter = class {
|
|
|
41248
41430
|
const waitMs = (1 - this.tokens) / this.ratePerSecond * 1e3;
|
|
41249
41431
|
if (waitMs > this.maxWaitMs) {
|
|
41250
41432
|
this.throttledCount++;
|
|
41251
|
-
|
|
41433
|
+
log27.warn("rate-limit:throttled", {
|
|
41252
41434
|
waitMs: Math.round(waitMs),
|
|
41253
41435
|
maxWaitMs: this.maxWaitMs,
|
|
41254
41436
|
availableTokens: this.tokens.toFixed(2)
|
|
@@ -41302,7 +41484,7 @@ var RateLimiter = class {
|
|
|
41302
41484
|
};
|
|
41303
41485
|
|
|
41304
41486
|
// src/transport/message-pipe.ts
|
|
41305
|
-
var
|
|
41487
|
+
var log28 = createLogger("transport/message-pipe");
|
|
41306
41488
|
var CallbackDataSchema = external_exports.object({
|
|
41307
41489
|
appId: external_exports.number(),
|
|
41308
41490
|
loginId: external_exports.string().optional(),
|
|
@@ -41358,17 +41540,17 @@ var MessagePipe = class _MessagePipe {
|
|
|
41358
41540
|
this.wsClient.on("message", (rawData) => {
|
|
41359
41541
|
if (this.inboundSemaphore.activeCount >= (deps.maxInboundConcurrency ?? 5) && this.inboundSemaphore.waitingCount >= (deps.maxWaitingQueue ?? 15)) {
|
|
41360
41542
|
metrics.increment("inbound.backpressure_rejected");
|
|
41361
|
-
|
|
41543
|
+
log28.warn("backpressure:rejected", {
|
|
41362
41544
|
active: this.inboundSemaphore.activeCount,
|
|
41363
41545
|
waiting: this.inboundSemaphore.waitingCount
|
|
41364
41546
|
});
|
|
41365
41547
|
return;
|
|
41366
41548
|
}
|
|
41367
41549
|
this.handleInbound(rawData).catch((err) => {
|
|
41368
|
-
|
|
41550
|
+
log28.error("\u274C \u5165\u7AD9\u5904\u7406\u5F02\u5E38", { step: "handleInbound", error: err.message });
|
|
41369
41551
|
});
|
|
41370
41552
|
});
|
|
41371
|
-
|
|
41553
|
+
log28.info("MessagePipe initialized");
|
|
41372
41554
|
}
|
|
41373
41555
|
/** 获取入站并发信号量 — 由 InboundPipeline 用于 acquire/release */
|
|
41374
41556
|
get semaphore() {
|
|
@@ -41377,7 +41559,7 @@ var MessagePipe = class _MessagePipe {
|
|
|
41377
41559
|
/** 注册入站消息回调 — 解密后的消息会通过此回调传给 L4 层 */
|
|
41378
41560
|
onMessage(callback) {
|
|
41379
41561
|
this.messageCallback = callback;
|
|
41380
|
-
|
|
41562
|
+
log28.info("Inbound message callback registered");
|
|
41381
41563
|
}
|
|
41382
41564
|
/**
|
|
41383
41565
|
* 🧪 DEBUG — 注入模拟 WS 原始帧,走完完整的 7 步入站流水线。
|
|
@@ -41414,7 +41596,7 @@ var MessagePipe = class _MessagePipe {
|
|
|
41414
41596
|
keyId = result.keyId;
|
|
41415
41597
|
sessionKey = result.sessionKey;
|
|
41416
41598
|
fillKey = result.fillKey;
|
|
41417
|
-
|
|
41599
|
+
log28.debug("\u{1F512} \u6587\u4EF6\u5206\u7247\u52A0\u5BC6", {
|
|
41418
41600
|
chunk: `${i + 1}/${totalChunks}`,
|
|
41419
41601
|
originalSize: chunk.length,
|
|
41420
41602
|
encryptedSize: result.fileBuffer.length,
|
|
@@ -41422,7 +41604,7 @@ var MessagePipe = class _MessagePipe {
|
|
|
41422
41604
|
});
|
|
41423
41605
|
}
|
|
41424
41606
|
const encryptedBuffer = Buffer.concat(encryptedChunks);
|
|
41425
|
-
|
|
41607
|
+
log28.info("\u{1F512} \u6587\u4EF6\u52A0\u5BC6\u5B8C\u6210", {
|
|
41426
41608
|
originalSize: buffer.length,
|
|
41427
41609
|
encryptedSize: encryptedBuffer.length,
|
|
41428
41610
|
totalChunks,
|
|
@@ -41456,7 +41638,7 @@ var MessagePipe = class _MessagePipe {
|
|
|
41456
41638
|
decryptedChunks.push(result.fileBuffer);
|
|
41457
41639
|
sessionKey = result.sessionKey;
|
|
41458
41640
|
fillKey = result.fillKey;
|
|
41459
|
-
|
|
41641
|
+
log28.debug("\u{1F513} \u6587\u4EF6\u5206\u7247\u89E3\u5BC6", {
|
|
41460
41642
|
chunk: `${i + 1}/${totalChunks}`,
|
|
41461
41643
|
encryptedSize: chunk.length,
|
|
41462
41644
|
decryptedSize: result.fileBuffer.length,
|
|
@@ -41464,7 +41646,7 @@ var MessagePipe = class _MessagePipe {
|
|
|
41464
41646
|
});
|
|
41465
41647
|
}
|
|
41466
41648
|
const decryptedBuffer = Buffer.concat(decryptedChunks);
|
|
41467
|
-
|
|
41649
|
+
log28.info("\u{1F513} \u6587\u4EF6\u89E3\u5BC6\u5B8C\u6210", {
|
|
41468
41650
|
encryptedSize: buffer.length,
|
|
41469
41651
|
decryptedSize: decryptedBuffer.length,
|
|
41470
41652
|
totalChunks,
|
|
@@ -41521,11 +41703,11 @@ var MessagePipe = class _MessagePipe {
|
|
|
41521
41703
|
if (this.encryptionMode === "quantum_only") {
|
|
41522
41704
|
if (isFileMessage && msg.encryptionMeta) {
|
|
41523
41705
|
extraContent = _MessagePipe.buildFileEncryptExtra(msg.encryptionMeta.iv, msg.encryptionMeta.keyId);
|
|
41524
|
-
|
|
41706
|
+
log28.debug("\u{1F512} \u51FA\u7AD9\u6587\u4EF6\u6D88\u606F\u5DF2\u6807\u8BB0\u52A0\u5BC6 (quantum_only)", { sessionId: msg.encryptionMeta.keyId, msgType: msg.msgType });
|
|
41525
41707
|
} else if (isFileMessage) {
|
|
41526
41708
|
const { keyId, iv } = await this.crypto.encrypt(msg.content);
|
|
41527
41709
|
extraContent = _MessagePipe.buildFileEncryptExtra(iv, keyId);
|
|
41528
|
-
|
|
41710
|
+
log28.debug("\u{1F512} \u51FA\u7AD9\u6587\u4EF6\u6D88\u606F\u5DF2\u6807\u8BB0\u52A0\u5BC6 (quantum_only, fallback)", { sessionId: keyId, msgType: msg.msgType });
|
|
41529
41711
|
} else {
|
|
41530
41712
|
const { ciphertext, keyId, iv } = await this.crypto.encrypt(msg.content);
|
|
41531
41713
|
extraContent = JSON.stringify({
|
|
@@ -41534,17 +41716,17 @@ var MessagePipe = class _MessagePipe {
|
|
|
41534
41716
|
sessionId: keyId
|
|
41535
41717
|
});
|
|
41536
41718
|
content = JSON.stringify({ content: "" });
|
|
41537
|
-
|
|
41719
|
+
log28.debug("\u{1F512} \u51FA\u7AD9\u6D88\u606F\u5DF2\u52A0\u5BC6 (quantum_only)", { sessionId: keyId });
|
|
41538
41720
|
}
|
|
41539
41721
|
} else {
|
|
41540
41722
|
try {
|
|
41541
41723
|
if (isFileMessage && msg.encryptionMeta) {
|
|
41542
41724
|
extraContent = _MessagePipe.buildFileEncryptExtra(msg.encryptionMeta.iv, msg.encryptionMeta.keyId);
|
|
41543
|
-
|
|
41725
|
+
log28.debug("\u{1F512} \u51FA\u7AD9\u6587\u4EF6\u6D88\u606F\u5DF2\u6807\u8BB0\u52A0\u5BC6 (quantum_and_plain)", { sessionId: msg.encryptionMeta.keyId, msgType: msg.msgType });
|
|
41544
41726
|
} else if (isFileMessage) {
|
|
41545
41727
|
const { keyId, iv } = await this.crypto.encrypt(msg.content);
|
|
41546
41728
|
extraContent = _MessagePipe.buildFileEncryptExtra(iv, keyId);
|
|
41547
|
-
|
|
41729
|
+
log28.debug("\u{1F512} \u51FA\u7AD9\u6587\u4EF6\u6D88\u606F\u5DF2\u6807\u8BB0\u52A0\u5BC6 (quantum_and_plain, fallback)", { sessionId: keyId, msgType: msg.msgType });
|
|
41548
41730
|
} else {
|
|
41549
41731
|
const { ciphertext, keyId, iv } = await this.crypto.encrypt(msg.content);
|
|
41550
41732
|
extraContent = JSON.stringify({
|
|
@@ -41553,11 +41735,11 @@ var MessagePipe = class _MessagePipe {
|
|
|
41553
41735
|
sessionId: keyId
|
|
41554
41736
|
});
|
|
41555
41737
|
content = JSON.stringify({ content: "" });
|
|
41556
|
-
|
|
41738
|
+
log28.debug("\u{1F512} \u51FA\u7AD9\u6D88\u606F\u5DF2\u52A0\u5BC6 (quantum_and_plain)", { sessionId: keyId });
|
|
41557
41739
|
}
|
|
41558
41740
|
} catch (err) {
|
|
41559
41741
|
const event = err instanceof CryptoTimeoutError ? "encryption_timeout_downgrade" : "encryption_downgrade";
|
|
41560
|
-
|
|
41742
|
+
log28.warn(`SECURITY_AUDIT:${event}`, {
|
|
41561
41743
|
event,
|
|
41562
41744
|
chatId: msg.chatId,
|
|
41563
41745
|
msgType: msg.msgType,
|
|
@@ -41586,7 +41768,7 @@ var MessagePipe = class _MessagePipe {
|
|
|
41586
41768
|
if (!result) {
|
|
41587
41769
|
throw new Error(`\u6D88\u606F\u53D1\u9001\u5931\u8D25: POST ${this.messageServiceBaseUrl}/messages/v1/send \u672A\u8FD4\u56DE\u6709\u6548\u54CD\u5E94`);
|
|
41588
41770
|
}
|
|
41589
|
-
|
|
41771
|
+
log28.info("\u{1F4E4} outbound:sent \u2192 IM \u670D\u52A1\u5668", {
|
|
41590
41772
|
chatId: msg.chatId,
|
|
41591
41773
|
encrypted: Boolean(extraContent),
|
|
41592
41774
|
requestId: result.request_id,
|
|
@@ -41610,10 +41792,10 @@ var MessagePipe = class _MessagePipe {
|
|
|
41610
41792
|
};
|
|
41611
41793
|
const result = await this.callMessageApi("/messages/v1/recall", body, "recall");
|
|
41612
41794
|
if (!result) {
|
|
41613
|
-
|
|
41795
|
+
log28.warn("recall:failed \u2014 callMessageApi returned null");
|
|
41614
41796
|
return;
|
|
41615
41797
|
}
|
|
41616
|
-
|
|
41798
|
+
log28.info("recall:sent", {
|
|
41617
41799
|
messageId: params.messageId,
|
|
41618
41800
|
requestId: result.request_id
|
|
41619
41801
|
});
|
|
@@ -41635,7 +41817,7 @@ var MessagePipe = class _MessagePipe {
|
|
|
41635
41817
|
"Authorization": `Bearer ${token2}`,
|
|
41636
41818
|
"Content-Type": "application/json"
|
|
41637
41819
|
};
|
|
41638
|
-
|
|
41820
|
+
log28.info(`${logTag}:DEBUG:request`, {
|
|
41639
41821
|
url: url2,
|
|
41640
41822
|
method: "POST",
|
|
41641
41823
|
headers: {
|
|
@@ -41659,7 +41841,7 @@ var MessagePipe = class _MessagePipe {
|
|
|
41659
41841
|
resp.headers.forEach((v, k) => {
|
|
41660
41842
|
respHeaders[k] = v;
|
|
41661
41843
|
});
|
|
41662
|
-
|
|
41844
|
+
log28.error(`${logTag}:http-error`, {
|
|
41663
41845
|
status: resp.status,
|
|
41664
41846
|
statusText: resp.statusText,
|
|
41665
41847
|
url: url2,
|
|
@@ -41668,7 +41850,7 @@ var MessagePipe = class _MessagePipe {
|
|
|
41668
41850
|
responseBody: respBody
|
|
41669
41851
|
});
|
|
41670
41852
|
if (resp.status === 401 && this.invalidateTokenFn) {
|
|
41671
|
-
|
|
41853
|
+
log28.warn(`${logTag}:token-expired, invalidating cached token for retry`);
|
|
41672
41854
|
this.invalidateTokenFn();
|
|
41673
41855
|
return { code: -1, msg: `HTTP ${resp.status}`, _retryable: true };
|
|
41674
41856
|
}
|
|
@@ -41676,7 +41858,7 @@ var MessagePipe = class _MessagePipe {
|
|
|
41676
41858
|
}
|
|
41677
41859
|
const result = await resp.json();
|
|
41678
41860
|
if (result.code !== 0 && result.code !== 200) {
|
|
41679
|
-
|
|
41861
|
+
log28.error(`${logTag}:api-error`, {
|
|
41680
41862
|
code: result.code,
|
|
41681
41863
|
msg: result.msg,
|
|
41682
41864
|
requestId: result.request_id,
|
|
@@ -41697,7 +41879,7 @@ var MessagePipe = class _MessagePipe {
|
|
|
41697
41879
|
const rateLimitResult = await this.rateLimiter.acquire();
|
|
41698
41880
|
if (rateLimitResult === "throttled") {
|
|
41699
41881
|
metrics.increment("outbound.dropped");
|
|
41700
|
-
|
|
41882
|
+
log28.warn(`${logTag}:rate-limit-dropped`, {
|
|
41701
41883
|
url: url2,
|
|
41702
41884
|
body: { receive_id: body.receive_id, msg_type: body.msg_type }
|
|
41703
41885
|
});
|
|
@@ -41707,7 +41889,7 @@ var MessagePipe = class _MessagePipe {
|
|
|
41707
41889
|
const result = await this._callMessageApiOnce(url2, body, logTag);
|
|
41708
41890
|
if (result && "_retryable" in result) {
|
|
41709
41891
|
if (result._retryable) {
|
|
41710
|
-
|
|
41892
|
+
log28.warn(`${logTag}:retrying after ${result.msg}`, { url: url2 });
|
|
41711
41893
|
await new Promise((r) => setTimeout(r, 1e3));
|
|
41712
41894
|
try {
|
|
41713
41895
|
const retryResult = await this._callMessageApiOnce(url2, body, `${logTag}:retry`);
|
|
@@ -41715,7 +41897,7 @@ var MessagePipe = class _MessagePipe {
|
|
|
41715
41897
|
return retryResult;
|
|
41716
41898
|
}
|
|
41717
41899
|
} catch (retryErr) {
|
|
41718
|
-
|
|
41900
|
+
log28.error(`${logTag}:retry-failed`, { error: retryErr.message });
|
|
41719
41901
|
}
|
|
41720
41902
|
}
|
|
41721
41903
|
metrics.increment("outbound.failed");
|
|
@@ -41723,7 +41905,7 @@ var MessagePipe = class _MessagePipe {
|
|
|
41723
41905
|
}
|
|
41724
41906
|
return result;
|
|
41725
41907
|
} catch (err) {
|
|
41726
|
-
|
|
41908
|
+
log28.warn(`${logTag}:network-error, retrying`, { url: url2, error: err.message });
|
|
41727
41909
|
await new Promise((r) => setTimeout(r, 1e3));
|
|
41728
41910
|
try {
|
|
41729
41911
|
const retryResult = await this._callMessageApiOnce(url2, body, `${logTag}:retry`);
|
|
@@ -41734,7 +41916,7 @@ var MessagePipe = class _MessagePipe {
|
|
|
41734
41916
|
return null;
|
|
41735
41917
|
} catch (retryErr) {
|
|
41736
41918
|
metrics.increment("outbound.failed");
|
|
41737
|
-
|
|
41919
|
+
log28.error(`${logTag}:retry-network-error`, {
|
|
41738
41920
|
url: url2,
|
|
41739
41921
|
error: retryErr.message
|
|
41740
41922
|
});
|
|
@@ -41757,7 +41939,7 @@ var MessagePipe = class _MessagePipe {
|
|
|
41757
41939
|
try {
|
|
41758
41940
|
frame = JSON.parse(String(rawData));
|
|
41759
41941
|
} catch (err) {
|
|
41760
|
-
|
|
41942
|
+
log28.warn("\u26A0\uFE0F WS \u5E27 JSON \u89E3\u6790\u5931\u8D25", { error: err.message });
|
|
41761
41943
|
return;
|
|
41762
41944
|
}
|
|
41763
41945
|
const timestamp = frame["X-CTQ-Timestamp"];
|
|
@@ -41768,7 +41950,7 @@ var MessagePipe = class _MessagePipe {
|
|
|
41768
41950
|
const signatureInput = timestamp + nonce + frame.data;
|
|
41769
41951
|
const expected = (0, import_node_crypto3.createHmac)("sha256", token2).update(signatureInput).digest("hex");
|
|
41770
41952
|
if (expected !== signature) {
|
|
41771
|
-
|
|
41953
|
+
log28.warn("\u26A0\uFE0F HMAC \u9A8C\u7B7E\u5931\u8D25\uFF0C\u4E22\u5F03\u5E27", { timestamp, nonce });
|
|
41772
41954
|
return;
|
|
41773
41955
|
}
|
|
41774
41956
|
}
|
|
@@ -41777,27 +41959,27 @@ var MessagePipe = class _MessagePipe {
|
|
|
41777
41959
|
const parsed = JSON.parse(frame.data);
|
|
41778
41960
|
const result = CallbackDataSchema.safeParse(parsed);
|
|
41779
41961
|
if (!result.success) {
|
|
41780
|
-
|
|
41962
|
+
log28.warn("\u26A0\uFE0F CallbackData validation failed", {
|
|
41781
41963
|
errors: result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`)
|
|
41782
41964
|
});
|
|
41783
41965
|
return;
|
|
41784
41966
|
}
|
|
41785
41967
|
callbackData = result.data;
|
|
41786
41968
|
} catch (err) {
|
|
41787
|
-
|
|
41969
|
+
log28.warn("\u26A0\uFE0F CallbackData \u89E3\u6790\u5931\u8D25", { error: err.message });
|
|
41788
41970
|
return;
|
|
41789
41971
|
}
|
|
41790
41972
|
const contentSize = JSON.stringify(callbackData.content).length;
|
|
41791
41973
|
const MAX_CONTENT_SIZE = 1 * 1024 * 1024;
|
|
41792
41974
|
if (contentSize > MAX_CONTENT_SIZE) {
|
|
41793
|
-
|
|
41975
|
+
log28.warn("\u26A0\uFE0F message content exceeds size limit", {
|
|
41794
41976
|
msgUid: callbackData.msgUid,
|
|
41795
41977
|
contentSize,
|
|
41796
41978
|
maxSize: MAX_CONTENT_SIZE
|
|
41797
41979
|
});
|
|
41798
41980
|
return;
|
|
41799
41981
|
}
|
|
41800
|
-
|
|
41982
|
+
log28.info("\u{1F4E9} \u5165\u7AD9\u539F\u59CB\u6570\u636E", {
|
|
41801
41983
|
appId: callbackData.appId,
|
|
41802
41984
|
msgUid: callbackData.msgUid,
|
|
41803
41985
|
eventType: callbackData.eventType,
|
|
@@ -41819,21 +42001,21 @@ var MessagePipe = class _MessagePipe {
|
|
|
41819
42001
|
} else if (parsed.sessionId) {
|
|
41820
42002
|
isEncrypted = true;
|
|
41821
42003
|
fileEncryptionMeta = { keyId: parsed.sessionId, iv: parsed.cryptoIv ?? "" };
|
|
41822
|
-
|
|
42004
|
+
log28.info("\u{1F512} \u5165\u7AD9\u6587\u4EF6\u6D88\u606F\u5DF2\u6807\u8BB0\u52A0\u5BC6", { msgUid: callbackData.msgUid, keyId: parsed.sessionId });
|
|
41823
42005
|
}
|
|
41824
42006
|
} catch {
|
|
41825
|
-
|
|
42007
|
+
log28.debug("\u2139\uFE0F extraContent \u4E0D\u662F\u6709\u6548 JSON\uFF0C\u89C6\u4E3A\u660E\u6587", { msgUid: callbackData.msgUid });
|
|
41826
42008
|
}
|
|
41827
42009
|
}
|
|
41828
42010
|
let contentObj;
|
|
41829
42011
|
if (this.encryptionMode === "quantum_only") {
|
|
41830
42012
|
if (!this.quantumAccount) {
|
|
41831
|
-
|
|
42013
|
+
log28.info("\u26A0\uFE0F quantum_only: \u672A\u914D\u7F6E quantumAccount\uFF0C\u53D1\u9001\u5F15\u5BFC\u63D0\u793A", { chatId: callbackData.userId });
|
|
41832
42014
|
await this.sendHintMessage(callbackData, HINT_NO_QUANTUM_ACCOUNT);
|
|
41833
42015
|
return;
|
|
41834
42016
|
}
|
|
41835
42017
|
if (this.cryptoIsPassthrough) {
|
|
41836
|
-
|
|
42018
|
+
log28.error("\u26A0\uFE0F quantum_only: CryptoEngine \u5904\u4E8E passthrough \u6A21\u5F0F\uFF0C\u65E0\u6CD5\u89E3\u5BC6\u6D88\u606F", {
|
|
41837
42019
|
msgUid: callbackData.msgUid,
|
|
41838
42020
|
reason: "crypto init failed, engine degraded to passthrough"
|
|
41839
42021
|
});
|
|
@@ -41844,14 +42026,14 @@ var MessagePipe = class _MessagePipe {
|
|
|
41844
42026
|
return;
|
|
41845
42027
|
}
|
|
41846
42028
|
if (!isEncrypted) {
|
|
41847
|
-
|
|
42029
|
+
log28.info("\u26A0\uFE0F quantum_only: \u6536\u5230\u660E\u6587\u6D88\u606F\uFF0C\u62D2\u7EDD\u5904\u7406", { msgUid: callbackData.msgUid });
|
|
41848
42030
|
await this.sendHintMessage(callbackData, HINT_PLAINTEXT_NOT_SUPPORTED);
|
|
41849
42031
|
return;
|
|
41850
42032
|
}
|
|
41851
42033
|
try {
|
|
41852
42034
|
contentObj = await this.decryptExtra(callbackData);
|
|
41853
42035
|
} catch (err) {
|
|
41854
|
-
|
|
42036
|
+
log28.error("\u274C quantum_only: \u6D88\u606F\u89E3\u5BC6\u5931\u8D25", {
|
|
41855
42037
|
msgUid: callbackData.msgUid,
|
|
41856
42038
|
error: err.message
|
|
41857
42039
|
});
|
|
@@ -41865,7 +42047,7 @@ var MessagePipe = class _MessagePipe {
|
|
|
41865
42047
|
if (isEncrypted) {
|
|
41866
42048
|
if (!this.quantumAccount || this.cryptoIsPassthrough) {
|
|
41867
42049
|
const reason = !this.quantumAccount ? "\u672A\u914D\u7F6E quantumAccount" : "CryptoEngine \u5904\u4E8E passthrough \u6A21\u5F0F (crypto \u521D\u59CB\u5316\u5931\u8D25)";
|
|
41868
|
-
|
|
42050
|
+
log28.warn("\u26A0\uFE0F quantum_and_plain: \u65E0\u6CD5\u89E3\u5BC6\u52A0\u5BC6\u6D88\u606F", {
|
|
41869
42051
|
msgUid: callbackData.msgUid,
|
|
41870
42052
|
reason
|
|
41871
42053
|
});
|
|
@@ -41876,7 +42058,7 @@ var MessagePipe = class _MessagePipe {
|
|
|
41876
42058
|
try {
|
|
41877
42059
|
contentObj = await this.decryptExtra(callbackData);
|
|
41878
42060
|
} catch (err) {
|
|
41879
|
-
|
|
42061
|
+
log28.error("\u274C quantum_and_plain: \u6D88\u606F\u89E3\u5BC6\u5931\u8D25", {
|
|
41880
42062
|
msgUid: callbackData.msgUid,
|
|
41881
42063
|
error: err.message
|
|
41882
42064
|
});
|
|
@@ -41891,7 +42073,7 @@ var MessagePipe = class _MessagePipe {
|
|
|
41891
42073
|
}
|
|
41892
42074
|
}
|
|
41893
42075
|
if (callbackData.eventType !== "callback:direct") {
|
|
41894
|
-
|
|
42076
|
+
log28.debug("\u2139\uFE0F \u5FFD\u7565\u975E\u76EE\u6807\u4E8B\u4EF6", { eventType: callbackData.eventType });
|
|
41895
42077
|
return;
|
|
41896
42078
|
}
|
|
41897
42079
|
const msg = {
|
|
@@ -41904,16 +42086,16 @@ var MessagePipe = class _MessagePipe {
|
|
|
41904
42086
|
isEncrypted,
|
|
41905
42087
|
fileEncryptionMeta
|
|
41906
42088
|
};
|
|
41907
|
-
|
|
42089
|
+
log28.debug("\u{1F4E8} \u89E3\u6790 WS \u5E27", { messageId: msg.messageId, eventType: callbackData.eventType });
|
|
41908
42090
|
if (this.dedup.isDuplicate(msg.messageId)) {
|
|
41909
|
-
|
|
42091
|
+
log28.debug("\u{1F501} \u91CD\u590D\u6D88\u606F\u5DF2\u8DF3\u8FC7", { messageId: msg.messageId });
|
|
41910
42092
|
return;
|
|
41911
42093
|
}
|
|
41912
|
-
|
|
42094
|
+
log28.info("\u2705 \u5165\u7AD9\u6D88\u606F\u9A8C\u8BC1\u901A\u8FC7", { messageId: msg.messageId, chatId: msg.chatId });
|
|
41913
42095
|
if (this.messageCallback) {
|
|
41914
42096
|
this.messageCallback(msg);
|
|
41915
42097
|
} else {
|
|
41916
|
-
|
|
42098
|
+
log28.warn("\u26A0\uFE0F \u6D88\u606F\u56DE\u8C03\u672A\u6CE8\u518C\uFF0C\u65E0\u6CD5\u5904\u7406", { messageId: msg.messageId });
|
|
41917
42099
|
}
|
|
41918
42100
|
}
|
|
41919
42101
|
// ── 私有辅助方法 ──
|
|
@@ -41932,9 +42114,9 @@ var MessagePipe = class _MessagePipe {
|
|
|
41932
42114
|
content: JSON.stringify({ content: hintText }),
|
|
41933
42115
|
skipEncrypt: true
|
|
41934
42116
|
});
|
|
41935
|
-
|
|
42117
|
+
log28.info("\u{1F4A1} \u5DF2\u53D1\u9001\u6A21\u5F0F\u63D0\u793A\u6D88\u606F", { chatId });
|
|
41936
42118
|
} catch (err) {
|
|
41937
|
-
|
|
42119
|
+
log28.error("\u274C \u63D0\u793A\u6D88\u606F\u53D1\u9001\u5931\u8D25", { error: err.message });
|
|
41938
42120
|
}
|
|
41939
42121
|
}
|
|
41940
42122
|
/**
|
|
@@ -41946,12 +42128,12 @@ var MessagePipe = class _MessagePipe {
|
|
|
41946
42128
|
const encryptMsg = extraData.encryptMsg ?? "";
|
|
41947
42129
|
const sessionId = extraData.sessionId ?? "";
|
|
41948
42130
|
if (!encryptMsg) {
|
|
41949
|
-
|
|
42131
|
+
log28.warn("\u26A0\uFE0F extraContent \u4E2D encryptMsg \u4E3A\u7A7A\uFF0C\u4F7F\u7528\u539F\u59CB content", { msgUid: callbackData.msgUid });
|
|
41950
42132
|
return callbackData.content;
|
|
41951
42133
|
}
|
|
41952
42134
|
const cryptoIv = extraData.cryptoIv ?? "";
|
|
41953
42135
|
const decrypted = await this.crypto.decrypt(encryptMsg, sessionId, cryptoIv);
|
|
41954
|
-
|
|
42136
|
+
log28.debug("\u{1F513} \u6D88\u606F\u89E3\u5BC6\u6210\u529F", { msgUid: callbackData.msgUid, sessionId, hasIv: Boolean(cryptoIv) });
|
|
41955
42137
|
try {
|
|
41956
42138
|
return JSON.parse(decrypted);
|
|
41957
42139
|
} catch {
|
|
@@ -41961,7 +42143,7 @@ var MessagePipe = class _MessagePipe {
|
|
|
41961
42143
|
};
|
|
41962
42144
|
|
|
41963
42145
|
// src/transport/connection-manager.ts
|
|
41964
|
-
var
|
|
42146
|
+
var log29 = createLogger("transport/connection-manager");
|
|
41965
42147
|
function sleep2(ms) {
|
|
41966
42148
|
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
41967
42149
|
}
|
|
@@ -42000,7 +42182,7 @@ var ConnectionManager = class {
|
|
|
42000
42182
|
tailBackoffDelays: options?.tailBackoffDelays ?? [12e4, 24e4, 48e4],
|
|
42001
42183
|
persistentRetryIntervalMs: options?.persistentRetryIntervalMs ?? 3e5
|
|
42002
42184
|
};
|
|
42003
|
-
|
|
42185
|
+
log29.info("ConnectionManager initialized", this.options);
|
|
42004
42186
|
}
|
|
42005
42187
|
/**
|
|
42006
42188
|
* 启动连接 — 连接 WS + 开始心跳 + 注册重连逻辑
|
|
@@ -42017,13 +42199,13 @@ var ConnectionManager = class {
|
|
|
42017
42199
|
const wsUrl = url2.replace(/\/+$/, "") + "/events/stream";
|
|
42018
42200
|
if (!wsUrl.startsWith("wss://")) {
|
|
42019
42201
|
if (getEnv("LZMX_ALLOW_INSECURE_WS") === "true") {
|
|
42020
|
-
|
|
42202
|
+
log29.warn("SECURITY_AUDIT: insecure WS allowed via LZMX_ALLOW_INSECURE_WS", { url: wsUrl });
|
|
42021
42203
|
} else {
|
|
42022
42204
|
throw new Error("Insecure WebSocket (ws://) is not allowed. Set LZMX_ALLOW_INSECURE_WS=true to override.");
|
|
42023
42205
|
}
|
|
42024
42206
|
}
|
|
42025
42207
|
const token2 = await tokenFn();
|
|
42026
|
-
|
|
42208
|
+
log29.debug("ws:auth", { authorization: sanitize(token2) });
|
|
42027
42209
|
await this.client.connect({
|
|
42028
42210
|
url: wsUrl,
|
|
42029
42211
|
token: token2,
|
|
@@ -42034,7 +42216,7 @@ var ConnectionManager = class {
|
|
|
42034
42216
|
});
|
|
42035
42217
|
this.registerEvents();
|
|
42036
42218
|
this.startHeartbeat();
|
|
42037
|
-
|
|
42219
|
+
log29.info("ConnectionManager started \u2713", { url: url2 });
|
|
42038
42220
|
}
|
|
42039
42221
|
/** 注册 close / error / pong 事件 */
|
|
42040
42222
|
registerEvents() {
|
|
@@ -42043,18 +42225,18 @@ var ConnectionManager = class {
|
|
|
42043
42225
|
this.client.removeAllListeners("pong");
|
|
42044
42226
|
this.client.on("close", () => {
|
|
42045
42227
|
if (this.running) {
|
|
42046
|
-
|
|
42228
|
+
log29.warn("ws:disconnected, scheduling reconnect");
|
|
42047
42229
|
this.scheduleReconnect();
|
|
42048
42230
|
}
|
|
42049
42231
|
});
|
|
42050
42232
|
this.client.on("error", (err) => {
|
|
42051
|
-
|
|
42233
|
+
log29.error("ws:connection-error", { error: err.message });
|
|
42052
42234
|
});
|
|
42053
42235
|
this.client.on("pong", () => {
|
|
42054
42236
|
this.awaitingPong = false;
|
|
42055
42237
|
this.consecutivePongTimeouts = 0;
|
|
42056
42238
|
this.clearPongTimeout();
|
|
42057
|
-
|
|
42239
|
+
log29.debug("heartbeat: pong received");
|
|
42058
42240
|
});
|
|
42059
42241
|
}
|
|
42060
42242
|
/** 启动心跳保活 — 定时发送 WebSocket Ping 帧 */
|
|
@@ -42064,12 +42246,12 @@ var ConnectionManager = class {
|
|
|
42064
42246
|
this.consecutivePongTimeouts = 0;
|
|
42065
42247
|
this.heartbeatTimer = setInterval(() => {
|
|
42066
42248
|
if (this.client.readyState !== wrapper_default.OPEN) {
|
|
42067
|
-
|
|
42249
|
+
log29.warn("heartbeat: connection not open, scheduling reconnect");
|
|
42068
42250
|
this.scheduleReconnect();
|
|
42069
42251
|
return;
|
|
42070
42252
|
}
|
|
42071
42253
|
if (this.awaitingPong) {
|
|
42072
|
-
|
|
42254
|
+
log29.warn("heartbeat: previous ping still pending, skip overlapping ping", {
|
|
42073
42255
|
consecutiveTimeouts: this.consecutivePongTimeouts,
|
|
42074
42256
|
maxMisses: this.options.heartbeatMaxMisses
|
|
42075
42257
|
});
|
|
@@ -42077,7 +42259,7 @@ var ConnectionManager = class {
|
|
|
42077
42259
|
}
|
|
42078
42260
|
this.awaitingPong = true;
|
|
42079
42261
|
this.client.ping();
|
|
42080
|
-
|
|
42262
|
+
log29.debug("heartbeat: ping sent");
|
|
42081
42263
|
this.clearPongTimeout();
|
|
42082
42264
|
this.pongTimeoutTimer = setTimeout(() => {
|
|
42083
42265
|
this.pongTimeoutTimer = null;
|
|
@@ -42087,7 +42269,7 @@ var ConnectionManager = class {
|
|
|
42087
42269
|
this.awaitingPong = false;
|
|
42088
42270
|
this.consecutivePongTimeouts += 1;
|
|
42089
42271
|
if (this.consecutivePongTimeouts >= this.options.heartbeatMaxMisses) {
|
|
42090
|
-
|
|
42272
|
+
log29.warn("heartbeat: pong timeout threshold reached, closing connection", {
|
|
42091
42273
|
consecutiveTimeouts: this.consecutivePongTimeouts,
|
|
42092
42274
|
maxMisses: this.options.heartbeatMaxMisses
|
|
42093
42275
|
});
|
|
@@ -42095,7 +42277,7 @@ var ConnectionManager = class {
|
|
|
42095
42277
|
this.scheduleReconnect();
|
|
42096
42278
|
return;
|
|
42097
42279
|
}
|
|
42098
|
-
|
|
42280
|
+
log29.warn("heartbeat: pong timeout tolerated, waiting for next heartbeat", {
|
|
42099
42281
|
consecutiveTimeouts: this.consecutivePongTimeouts,
|
|
42100
42282
|
maxMisses: this.options.heartbeatMaxMisses
|
|
42101
42283
|
});
|
|
@@ -42156,13 +42338,13 @@ var ConnectionManager = class {
|
|
|
42156
42338
|
const { delay, phase } = this.computeReconnectDelay();
|
|
42157
42339
|
const isPersistent = phase === "persistent";
|
|
42158
42340
|
if (isPersistent) {
|
|
42159
|
-
|
|
42341
|
+
log29.warn("ws:persistent-retry", {
|
|
42160
42342
|
attempt: this.reconnectAttempts + 1,
|
|
42161
42343
|
delayMs: delay,
|
|
42162
42344
|
message: "\u5DF2\u8D85\u8FC7\u6700\u5927\u91CD\u8FDE\u6B21\u6570\uFF0C\u8FDB\u5165\u6301\u7EED\u91CD\u8BD5\u6A21\u5F0F (\u6BCF 5 \u5206\u949F)"
|
|
42163
42345
|
});
|
|
42164
42346
|
} else {
|
|
42165
|
-
|
|
42347
|
+
log29.info("ws:reconnecting", {
|
|
42166
42348
|
attempt: this.reconnectAttempts + 1,
|
|
42167
42349
|
delayMs: delay,
|
|
42168
42350
|
phase
|
|
@@ -42173,7 +42355,7 @@ var ConnectionManager = class {
|
|
|
42173
42355
|
this.reconnectAttempts++;
|
|
42174
42356
|
try {
|
|
42175
42357
|
const token2 = await this.tokenFn();
|
|
42176
|
-
|
|
42358
|
+
log29.debug("ws:reconnect-auth", { authorization: sanitize(token2) });
|
|
42177
42359
|
const wsUrl = this.url.replace(/\/+$/, "") + "/events/stream";
|
|
42178
42360
|
await this.client.connect({
|
|
42179
42361
|
url: wsUrl,
|
|
@@ -42187,10 +42369,10 @@ var ConnectionManager = class {
|
|
|
42187
42369
|
this.reconnectAttempts = 0;
|
|
42188
42370
|
this.registerEvents();
|
|
42189
42371
|
this.startHeartbeat();
|
|
42190
|
-
|
|
42372
|
+
log29.info("ws:reconnected", { totalAttempts, url: this.url });
|
|
42191
42373
|
return;
|
|
42192
42374
|
} catch (err) {
|
|
42193
|
-
|
|
42375
|
+
log29.warn("ws:reconnect-failed", {
|
|
42194
42376
|
attempt: this.reconnectAttempts,
|
|
42195
42377
|
phase,
|
|
42196
42378
|
error: err.message
|
|
@@ -42203,7 +42385,7 @@ var ConnectionManager = class {
|
|
|
42203
42385
|
this.running = false;
|
|
42204
42386
|
this.stopHeartbeat();
|
|
42205
42387
|
this.client.close(1e3, "shutdown");
|
|
42206
|
-
|
|
42388
|
+
log29.info("ConnectionManager stopped");
|
|
42207
42389
|
}
|
|
42208
42390
|
/** 当前是否已连接 (WebSocket readyState === OPEN) */
|
|
42209
42391
|
get isConnected() {
|
|
@@ -42212,7 +42394,7 @@ var ConnectionManager = class {
|
|
|
42212
42394
|
};
|
|
42213
42395
|
|
|
42214
42396
|
// src/push/cockatoo-client.ts
|
|
42215
|
-
var
|
|
42397
|
+
var log30 = createLogger("push/cockatoo-client");
|
|
42216
42398
|
var DEFAULT_TIMEOUT_MS2 = 3e4;
|
|
42217
42399
|
var CockatooPushError = class extends Error {
|
|
42218
42400
|
constructor(status, body, endpoint) {
|
|
@@ -42249,7 +42431,7 @@ var CockatooClient = class {
|
|
|
42249
42431
|
const base = config2.endpoint.replace(/\/+$/, "");
|
|
42250
42432
|
this.pushUrl = `${base}/api/v1/push`;
|
|
42251
42433
|
this.healthUrl = `${base}/health`;
|
|
42252
|
-
|
|
42434
|
+
log30.info("CockatooClient initialized", { endpoint: config2.endpoint });
|
|
42253
42435
|
}
|
|
42254
42436
|
/**
|
|
42255
42437
|
* 推送消息到 Cockatoo 服务。
|
|
@@ -42280,7 +42462,7 @@ var CockatooClient = class {
|
|
|
42280
42462
|
}
|
|
42281
42463
|
throw new CockatooPushError(resp.status, body, this.pushUrl);
|
|
42282
42464
|
}
|
|
42283
|
-
|
|
42465
|
+
log30.debug("push:sent", { type: payload.type });
|
|
42284
42466
|
}
|
|
42285
42467
|
/**
|
|
42286
42468
|
* 执行一次健康检查。
|
|
@@ -42298,11 +42480,11 @@ var CockatooClient = class {
|
|
|
42298
42480
|
});
|
|
42299
42481
|
const isHealthy = resp.ok;
|
|
42300
42482
|
if (!isHealthy) {
|
|
42301
|
-
|
|
42483
|
+
log30.warn("health-check:unhealthy", { status: resp.status });
|
|
42302
42484
|
}
|
|
42303
42485
|
return isHealthy;
|
|
42304
42486
|
} catch (err) {
|
|
42305
|
-
|
|
42487
|
+
log30.warn("health-check:error", { error: err.message });
|
|
42306
42488
|
return false;
|
|
42307
42489
|
}
|
|
42308
42490
|
}
|
|
@@ -42314,7 +42496,7 @@ var CockatooClient = class {
|
|
|
42314
42496
|
this.healthy = await this.healthCheck();
|
|
42315
42497
|
} catch {
|
|
42316
42498
|
this.healthy = false;
|
|
42317
|
-
|
|
42499
|
+
log30.warn("Cockatoo health check failed");
|
|
42318
42500
|
}
|
|
42319
42501
|
}, this.config.healthCheckIntervalMs ?? 6e4);
|
|
42320
42502
|
if (typeof this.healthCheckTimer === "object" && "unref" in this.healthCheckTimer) {
|
|
@@ -42335,8 +42517,8 @@ var CockatooClient = class {
|
|
|
42335
42517
|
};
|
|
42336
42518
|
|
|
42337
42519
|
// src/push/push-queue.ts
|
|
42338
|
-
var
|
|
42339
|
-
var
|
|
42520
|
+
var log31 = createLogger("push/push-queue");
|
|
42521
|
+
var RETRY_BASE_MS3 = 1e3;
|
|
42340
42522
|
var PushQueue = class {
|
|
42341
42523
|
client;
|
|
42342
42524
|
/** 队列最大容量 */
|
|
@@ -42377,7 +42559,7 @@ var PushQueue = class {
|
|
|
42377
42559
|
this.unhealthyRetryMs = config2?.unhealthyRetryMs ?? 5e3;
|
|
42378
42560
|
this.drainOnStop = config2?.drainOnStop ?? false;
|
|
42379
42561
|
this.drainTimeoutMs = config2?.drainTimeoutMs ?? 5e3;
|
|
42380
|
-
|
|
42562
|
+
log31.info("PushQueue initialized", {
|
|
42381
42563
|
maxSize: this.maxSize,
|
|
42382
42564
|
retryAttempts: this.retryAttempts,
|
|
42383
42565
|
processIntervalMs: this.processIntervalMs
|
|
@@ -42388,7 +42570,7 @@ var PushQueue = class {
|
|
|
42388
42570
|
start() {
|
|
42389
42571
|
if (this.running) return;
|
|
42390
42572
|
this.running = true;
|
|
42391
|
-
|
|
42573
|
+
log31.info("PushQueue started");
|
|
42392
42574
|
this.scheduleNext(0);
|
|
42393
42575
|
}
|
|
42394
42576
|
/**
|
|
@@ -42402,10 +42584,10 @@ var PushQueue = class {
|
|
|
42402
42584
|
this.running = false;
|
|
42403
42585
|
this.clearTimer();
|
|
42404
42586
|
if (this.drainOnStop && this.queue.length > 0) {
|
|
42405
|
-
|
|
42587
|
+
log31.info("PushQueue draining", { remaining: this.queue.length });
|
|
42406
42588
|
await this.drain();
|
|
42407
42589
|
}
|
|
42408
|
-
|
|
42590
|
+
log31.info("PushQueue stopped", {
|
|
42409
42591
|
remaining: this.queue.length,
|
|
42410
42592
|
sent: this.sentCount,
|
|
42411
42593
|
dropped: this.droppedCount,
|
|
@@ -42420,13 +42602,13 @@ var PushQueue = class {
|
|
|
42420
42602
|
if (this.queue.length >= this.maxSize) {
|
|
42421
42603
|
const dropped = this.queue.shift();
|
|
42422
42604
|
this.droppedCount++;
|
|
42423
|
-
|
|
42605
|
+
log31.warn("queue:full, dropping oldest", {
|
|
42424
42606
|
droppedType: dropped?.payload.type,
|
|
42425
42607
|
queueSize: this.queue.length
|
|
42426
42608
|
});
|
|
42427
42609
|
}
|
|
42428
42610
|
this.queue.push({ payload, retries: 0, eligibleAt: 0 });
|
|
42429
|
-
|
|
42611
|
+
log31.debug("queue:enqueued", { type: payload.type, queueSize: this.queue.length });
|
|
42430
42612
|
}
|
|
42431
42613
|
/** 当前队列长度 */
|
|
42432
42614
|
get size() {
|
|
@@ -42451,7 +42633,7 @@ var PushQueue = class {
|
|
|
42451
42633
|
this.clearTimer();
|
|
42452
42634
|
this.processTimer = setTimeout(() => {
|
|
42453
42635
|
this.tick().catch((err) => {
|
|
42454
|
-
|
|
42636
|
+
log31.error("tick:unexpected-error", { error: err.message });
|
|
42455
42637
|
if (this.running) {
|
|
42456
42638
|
this.scheduleNext(this.idleIntervalMs);
|
|
42457
42639
|
}
|
|
@@ -42473,7 +42655,7 @@ var PushQueue = class {
|
|
|
42473
42655
|
async tick() {
|
|
42474
42656
|
if (!this.running) return;
|
|
42475
42657
|
if (!this.client.isHealthy) {
|
|
42476
|
-
|
|
42658
|
+
log31.debug("tick:service-unhealthy, pausing");
|
|
42477
42659
|
this.scheduleNext(this.unhealthyRetryMs);
|
|
42478
42660
|
return;
|
|
42479
42661
|
}
|
|
@@ -42493,7 +42675,7 @@ var PushQueue = class {
|
|
|
42493
42675
|
try {
|
|
42494
42676
|
await this.processItem(item);
|
|
42495
42677
|
} catch (err) {
|
|
42496
|
-
|
|
42678
|
+
log31.error("tick:process-unexpected", { error: err.message });
|
|
42497
42679
|
} finally {
|
|
42498
42680
|
this.processing = false;
|
|
42499
42681
|
}
|
|
@@ -42512,14 +42694,14 @@ var PushQueue = class {
|
|
|
42512
42694
|
try {
|
|
42513
42695
|
await this.client.push(item.payload);
|
|
42514
42696
|
this.sentCount++;
|
|
42515
|
-
|
|
42697
|
+
log31.debug("push:success", {
|
|
42516
42698
|
type: item.payload.type,
|
|
42517
42699
|
retries: item.retries
|
|
42518
42700
|
});
|
|
42519
42701
|
} catch (err) {
|
|
42520
42702
|
if (err instanceof CockatooPushError && err.isClientError) {
|
|
42521
42703
|
this.droppedCount++;
|
|
42522
|
-
|
|
42704
|
+
log31.warn("push:4xx-dropped", {
|
|
42523
42705
|
type: item.payload.type,
|
|
42524
42706
|
status: err.status,
|
|
42525
42707
|
retries: item.retries
|
|
@@ -42528,7 +42710,7 @@ var PushQueue = class {
|
|
|
42528
42710
|
}
|
|
42529
42711
|
if (item.retries >= this.retryAttempts) {
|
|
42530
42712
|
this.droppedCount++;
|
|
42531
|
-
|
|
42713
|
+
log31.error("push:max-retries-dropped", {
|
|
42532
42714
|
type: item.payload.type,
|
|
42533
42715
|
retries: item.retries,
|
|
42534
42716
|
error: err.message
|
|
@@ -42537,11 +42719,11 @@ var PushQueue = class {
|
|
|
42537
42719
|
}
|
|
42538
42720
|
item.retries++;
|
|
42539
42721
|
this.retryCount++;
|
|
42540
|
-
const backoffMs =
|
|
42722
|
+
const backoffMs = RETRY_BASE_MS3 * Math.pow(2, item.retries - 1);
|
|
42541
42723
|
item.eligibleAt = Date.now() + backoffMs;
|
|
42542
42724
|
this.queue.push(item);
|
|
42543
42725
|
const errorDetail = err instanceof CockatooPushError ? `HTTP ${err.status}` : err.message;
|
|
42544
|
-
|
|
42726
|
+
log31.warn("push:retry-enqueued", {
|
|
42545
42727
|
type: item.payload.type,
|
|
42546
42728
|
retries: item.retries,
|
|
42547
42729
|
backoffMs,
|
|
@@ -42565,22 +42747,22 @@ var PushQueue = class {
|
|
|
42565
42747
|
try {
|
|
42566
42748
|
await this.client.push(item.payload);
|
|
42567
42749
|
this.sentCount++;
|
|
42568
|
-
|
|
42750
|
+
log31.debug("drain:sent", { type: item.payload.type });
|
|
42569
42751
|
} catch (err) {
|
|
42570
42752
|
this.droppedCount++;
|
|
42571
|
-
|
|
42753
|
+
log31.warn("drain:dropped", {
|
|
42572
42754
|
type: item.payload.type,
|
|
42573
42755
|
error: err.message
|
|
42574
42756
|
});
|
|
42575
42757
|
}
|
|
42576
42758
|
}
|
|
42577
42759
|
if (this.queue.length > 0) {
|
|
42578
|
-
|
|
42760
|
+
log31.warn("drain:timeout", {
|
|
42579
42761
|
remaining: this.queue.length,
|
|
42580
42762
|
timeoutMs: this.drainTimeoutMs
|
|
42581
42763
|
});
|
|
42582
42764
|
} else {
|
|
42583
|
-
|
|
42765
|
+
log31.info("drain:complete");
|
|
42584
42766
|
}
|
|
42585
42767
|
}
|
|
42586
42768
|
// ── 内部工具 ──
|
|
@@ -42594,13 +42776,13 @@ var PushQueue = class {
|
|
|
42594
42776
|
};
|
|
42595
42777
|
|
|
42596
42778
|
// src/index.ts
|
|
42597
|
-
var
|
|
42779
|
+
var log32 = createLogger("plugin");
|
|
42598
42780
|
function logRuntimeInfo(runtime2) {
|
|
42599
|
-
|
|
42781
|
+
log32.info("Runtime info", buildRuntimeInfoLogMeta(runtime2));
|
|
42600
42782
|
}
|
|
42601
42783
|
async function startPlugin(accountConfig, internalOverrides) {
|
|
42602
42784
|
const config2 = buildPluginConfig(accountConfig, internalOverrides);
|
|
42603
|
-
|
|
42785
|
+
log32.info("Config built \u2713", { pluginId: config2.pluginId });
|
|
42604
42786
|
let cryptoEngine;
|
|
42605
42787
|
if (config2.crypto.enabled && accountConfig.quantumAccount) {
|
|
42606
42788
|
try {
|
|
@@ -42613,9 +42795,9 @@ async function startPlugin(accountConfig, internalOverrides) {
|
|
|
42613
42795
|
config2.crypto.operationTimeoutMs
|
|
42614
42796
|
);
|
|
42615
42797
|
await cryptoEngine.init();
|
|
42616
|
-
|
|
42798
|
+
log32.info("Crypto initialized \u2713");
|
|
42617
42799
|
} catch (err) {
|
|
42618
|
-
|
|
42800
|
+
log32.warn("Crypto init failed, falling back to passthrough mode", {
|
|
42619
42801
|
error: err instanceof Error ? err.message : String(err)
|
|
42620
42802
|
});
|
|
42621
42803
|
cryptoEngine = CryptoEngine.createPassthrough();
|
|
@@ -42623,14 +42805,14 @@ async function startPlugin(accountConfig, internalOverrides) {
|
|
|
42623
42805
|
} else {
|
|
42624
42806
|
cryptoEngine = CryptoEngine.createPassthrough();
|
|
42625
42807
|
const reason = !config2.crypto.enabled ? "disabled by config" : "quantumAccount not provided";
|
|
42626
|
-
|
|
42808
|
+
log32.info(`Crypto passthrough mode \u2713 (${reason})`);
|
|
42627
42809
|
}
|
|
42628
42810
|
const oauthClient = new OAuthClient({
|
|
42629
42811
|
baseUrl: config2.auth.serverUrl,
|
|
42630
42812
|
appId: accountConfig.appId,
|
|
42631
42813
|
appSecret: accountConfig.appSecret
|
|
42632
42814
|
});
|
|
42633
|
-
const tokenStorePath = (0, import_node_path5.join)((0,
|
|
42815
|
+
const tokenStorePath = (0, import_node_path5.join)((0, import_node_os5.homedir)(), TOKEN_STORE_DIR, "tokens", accountConfig.appId);
|
|
42634
42816
|
const tokenStore = new TokenStore(tokenStorePath, cryptoEngine);
|
|
42635
42817
|
const credentialHash = (0, import_node_crypto4.createHash)("sha256").update(`${accountConfig.appId}:${accountConfig.appSecret}`).digest("hex");
|
|
42636
42818
|
const tokenManager = new TokenManager({
|
|
@@ -42639,7 +42821,7 @@ async function startPlugin(accountConfig, internalOverrides) {
|
|
|
42639
42821
|
refreshAheadMs: config2.auth.refreshAheadMs,
|
|
42640
42822
|
credentialHash
|
|
42641
42823
|
});
|
|
42642
|
-
|
|
42824
|
+
log32.info("Auth initialized \u2713");
|
|
42643
42825
|
let pushQueue = null;
|
|
42644
42826
|
let cockatooClient = null;
|
|
42645
42827
|
if (config2.push?.enabled) {
|
|
@@ -42654,7 +42836,7 @@ async function startPlugin(accountConfig, internalOverrides) {
|
|
|
42654
42836
|
});
|
|
42655
42837
|
cockatooClient.startHealthCheck();
|
|
42656
42838
|
pushQueue.start();
|
|
42657
|
-
|
|
42839
|
+
log32.info("Push initialized \u2713");
|
|
42658
42840
|
}
|
|
42659
42841
|
const wsClient = new WSClient();
|
|
42660
42842
|
const dedup = new MessageDedup(config2.transport.dedup);
|
|
@@ -42681,14 +42863,14 @@ async function startPlugin(accountConfig, internalOverrides) {
|
|
|
42681
42863
|
reconnectMaxMs: config2.transport.reconnectMaxMs,
|
|
42682
42864
|
maxReconnectAttempts: config2.transport.maxReconnectAttempts
|
|
42683
42865
|
});
|
|
42684
|
-
|
|
42866
|
+
log32.info("Transport initialized \u2713");
|
|
42685
42867
|
initUploadSemaphore(config2.file.maxUploadConcurrency);
|
|
42686
|
-
|
|
42868
|
+
log32.info("Upload semaphore initialized \u2713", { maxConcurrency: config2.file.maxUploadConcurrency });
|
|
42687
42869
|
if (config2.metrics.enabled) {
|
|
42688
42870
|
metrics.startPeriodicLog(config2.metrics.logIntervalMs);
|
|
42689
|
-
|
|
42871
|
+
log32.info("Metrics initialized \u2713", { intervalMs: config2.metrics.logIntervalMs });
|
|
42690
42872
|
}
|
|
42691
|
-
|
|
42873
|
+
log32.info("Plugin started \u2713");
|
|
42692
42874
|
return {
|
|
42693
42875
|
config: config2,
|
|
42694
42876
|
messagePipe,
|
|
@@ -42696,7 +42878,7 @@ async function startPlugin(accountConfig, internalOverrides) {
|
|
|
42696
42878
|
tokenManager,
|
|
42697
42879
|
pushQueue,
|
|
42698
42880
|
shutdown: async () => {
|
|
42699
|
-
|
|
42881
|
+
log32.info("Shutting down...");
|
|
42700
42882
|
await connectionManager.stop();
|
|
42701
42883
|
if (pushQueue) await pushQueue.stop();
|
|
42702
42884
|
if (cockatooClient) cockatooClient.stopHealthCheck();
|
|
@@ -42704,7 +42886,7 @@ async function startPlugin(accountConfig, internalOverrides) {
|
|
|
42704
42886
|
metrics.stop();
|
|
42705
42887
|
destroyEncryptionMaps();
|
|
42706
42888
|
resetOutbound();
|
|
42707
|
-
|
|
42889
|
+
log32.info("Shutdown complete \u2713");
|
|
42708
42890
|
}
|
|
42709
42891
|
};
|
|
42710
42892
|
}
|
|
@@ -42720,7 +42902,7 @@ try {
|
|
|
42720
42902
|
registerFull(api) {
|
|
42721
42903
|
setPluginRuntime(api.runtime);
|
|
42722
42904
|
logRuntimeInfo(api.runtime);
|
|
42723
|
-
|
|
42905
|
+
log32.info("plugin registered (v3 path) \u2713");
|
|
42724
42906
|
}
|
|
42725
42907
|
});
|
|
42726
42908
|
} else {
|
|
@@ -42732,7 +42914,7 @@ try {
|
|
|
42732
42914
|
setPluginRuntime(api.runtime);
|
|
42733
42915
|
logRuntimeInfo(api.runtime);
|
|
42734
42916
|
api.registerChannel({ plugin: quantumImPlugin });
|
|
42735
|
-
|
|
42917
|
+
log32.info("plugin registered (v2 path) \u2713");
|
|
42736
42918
|
}
|
|
42737
42919
|
};
|
|
42738
42920
|
}
|
|
@@ -42745,7 +42927,7 @@ try {
|
|
|
42745
42927
|
setPluginRuntime(api.runtime);
|
|
42746
42928
|
logRuntimeInfo(api.runtime);
|
|
42747
42929
|
api.registerChannel({ plugin: quantumImPlugin });
|
|
42748
|
-
|
|
42930
|
+
log32.info("plugin registered (fallback path) \u2713");
|
|
42749
42931
|
}
|
|
42750
42932
|
};
|
|
42751
42933
|
}
|