@cxyhhhhh/openclaw-qqbot 2.0.0-dev.202607091556 → 2.0.0-dev.202607092101
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 +615 -241
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -7
- package/openclaw.plugin.json +1 -1
- package/package.json +2 -2
- package/scripts/upgrade-via-npm.sh +41 -10
- package/skills/qqbot-group/SKILL.md +75 -0
- package/skills/qqbot-group/references/api_reference.md +94 -0
- package/src/adapter/contract.ts +1 -1
- package/src/channel.ts +44 -2
- package/src/commands/bot-logs.ts +4 -2
- package/src/gateway/event-handlers.ts +33 -1
- package/src/gateway/middleware-setup.ts +5 -1
- package/src/gateway/qqbot-gateway.ts +56 -22
- package/src/outbound/deliver-pipeline.ts +37 -0
- package/src/outbound/image-size.ts +7 -1
- package/src/outbound/local-file-router.ts +25 -0
- package/src/outbound/media-send.ts +49 -15
- package/src/outbound/outbound-service.ts +82 -116
- package/src/outbound/sanitize.ts +32 -0
package/dist/index.cjs
CHANGED
|
@@ -31,9 +31,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
31
31
|
));
|
|
32
32
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
33
33
|
|
|
34
|
-
// node_modules/.pnpm/ws@8.
|
|
34
|
+
// node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/constants.js
|
|
35
35
|
var require_constants = __commonJS({
|
|
36
|
-
"node_modules/.pnpm/ws@8.
|
|
36
|
+
"node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/constants.js"(exports2, module2) {
|
|
37
37
|
"use strict";
|
|
38
38
|
var BINARY_TYPES = ["nodebuffer", "arraybuffer", "fragments"];
|
|
39
39
|
var hasBlob = typeof Blob !== "undefined";
|
|
@@ -54,9 +54,9 @@ var require_constants = __commonJS({
|
|
|
54
54
|
}
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
-
// node_modules/.pnpm/ws@8.
|
|
57
|
+
// node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/buffer-util.js
|
|
58
58
|
var require_buffer_util = __commonJS({
|
|
59
|
-
"node_modules/.pnpm/ws@8.
|
|
59
|
+
"node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/buffer-util.js"(exports2, module2) {
|
|
60
60
|
"use strict";
|
|
61
61
|
var { EMPTY_BUFFER } = require_constants();
|
|
62
62
|
var FastBuffer = Buffer[Symbol.species];
|
|
@@ -129,9 +129,9 @@ var require_buffer_util = __commonJS({
|
|
|
129
129
|
}
|
|
130
130
|
});
|
|
131
131
|
|
|
132
|
-
// node_modules/.pnpm/ws@8.
|
|
132
|
+
// node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/limiter.js
|
|
133
133
|
var require_limiter = __commonJS({
|
|
134
|
-
"node_modules/.pnpm/ws@8.
|
|
134
|
+
"node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/limiter.js"(exports2, module2) {
|
|
135
135
|
"use strict";
|
|
136
136
|
var kDone = /* @__PURE__ */ Symbol("kDone");
|
|
137
137
|
var kRun = /* @__PURE__ */ Symbol("kRun");
|
|
@@ -179,9 +179,9 @@ var require_limiter = __commonJS({
|
|
|
179
179
|
}
|
|
180
180
|
});
|
|
181
181
|
|
|
182
|
-
// node_modules/.pnpm/ws@8.
|
|
182
|
+
// node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/permessage-deflate.js
|
|
183
183
|
var require_permessage_deflate = __commonJS({
|
|
184
|
-
"node_modules/.pnpm/ws@8.
|
|
184
|
+
"node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/permessage-deflate.js"(exports2, module2) {
|
|
185
185
|
"use strict";
|
|
186
186
|
var zlib = require("zlib");
|
|
187
187
|
var bufferUtil = require_buffer_util();
|
|
@@ -562,9 +562,9 @@ var require_permessage_deflate = __commonJS({
|
|
|
562
562
|
}
|
|
563
563
|
});
|
|
564
564
|
|
|
565
|
-
// node_modules/.pnpm/ws@8.
|
|
565
|
+
// node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/validation.js
|
|
566
566
|
var require_validation = __commonJS({
|
|
567
|
-
"node_modules/.pnpm/ws@8.
|
|
567
|
+
"node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/validation.js"(exports2, module2) {
|
|
568
568
|
"use strict";
|
|
569
569
|
var { isUtf8 } = require("buffer");
|
|
570
570
|
var { hasBlob } = require_constants();
|
|
@@ -763,9 +763,9 @@ var require_validation = __commonJS({
|
|
|
763
763
|
}
|
|
764
764
|
});
|
|
765
765
|
|
|
766
|
-
// node_modules/.pnpm/ws@8.
|
|
766
|
+
// node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/receiver.js
|
|
767
767
|
var require_receiver = __commonJS({
|
|
768
|
-
"node_modules/.pnpm/ws@8.
|
|
768
|
+
"node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/receiver.js"(exports2, module2) {
|
|
769
769
|
"use strict";
|
|
770
770
|
var { Writable } = require("stream");
|
|
771
771
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -798,6 +798,10 @@ var require_receiver = __commonJS({
|
|
|
798
798
|
* extensions
|
|
799
799
|
* @param {Boolean} [options.isServer=false] Specifies whether to operate in
|
|
800
800
|
* client or server mode
|
|
801
|
+
* @param {Number} [options.maxBufferedChunks=0] The maximum number of
|
|
802
|
+
* buffered data chunks
|
|
803
|
+
* @param {Number} [options.maxFragments=0] The maximum number of message
|
|
804
|
+
* fragments
|
|
801
805
|
* @param {Number} [options.maxPayload=0] The maximum allowed message length
|
|
802
806
|
* @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
|
|
803
807
|
* not to skip UTF-8 validation for text and close messages
|
|
@@ -808,6 +812,8 @@ var require_receiver = __commonJS({
|
|
|
808
812
|
this._binaryType = options.binaryType || BINARY_TYPES[0];
|
|
809
813
|
this._extensions = options.extensions || {};
|
|
810
814
|
this._isServer = !!options.isServer;
|
|
815
|
+
this._maxBufferedChunks = options.maxBufferedChunks | 0;
|
|
816
|
+
this._maxFragments = options.maxFragments | 0;
|
|
811
817
|
this._maxPayload = options.maxPayload | 0;
|
|
812
818
|
this._skipUTF8Validation = !!options.skipUTF8Validation;
|
|
813
819
|
this[kWebSocket] = void 0;
|
|
@@ -837,6 +843,18 @@ var require_receiver = __commonJS({
|
|
|
837
843
|
*/
|
|
838
844
|
_write(chunk, encoding, cb) {
|
|
839
845
|
if (this._opcode === 8 && this._state == GET_INFO) return cb();
|
|
846
|
+
if (this._maxBufferedChunks > 0 && this._buffers.length >= this._maxBufferedChunks) {
|
|
847
|
+
cb(
|
|
848
|
+
this.createError(
|
|
849
|
+
RangeError,
|
|
850
|
+
"Too many buffered chunks",
|
|
851
|
+
false,
|
|
852
|
+
1008,
|
|
853
|
+
"WS_ERR_TOO_MANY_BUFFERED_PARTS"
|
|
854
|
+
)
|
|
855
|
+
);
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
840
858
|
this._bufferedBytes += chunk.length;
|
|
841
859
|
this._buffers.push(chunk);
|
|
842
860
|
this.startLoop(cb);
|
|
@@ -1166,6 +1184,17 @@ var require_receiver = __commonJS({
|
|
|
1166
1184
|
return;
|
|
1167
1185
|
}
|
|
1168
1186
|
if (data.length) {
|
|
1187
|
+
if (this._maxFragments > 0 && this._fragments.length >= this._maxFragments) {
|
|
1188
|
+
const error = this.createError(
|
|
1189
|
+
RangeError,
|
|
1190
|
+
"Too many message fragments",
|
|
1191
|
+
false,
|
|
1192
|
+
1008,
|
|
1193
|
+
"WS_ERR_TOO_MANY_BUFFERED_PARTS"
|
|
1194
|
+
);
|
|
1195
|
+
cb(error);
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1169
1198
|
this._messageLength = this._totalPayloadLength;
|
|
1170
1199
|
this._fragments.push(data);
|
|
1171
1200
|
}
|
|
@@ -1195,6 +1224,17 @@ var require_receiver = __commonJS({
|
|
|
1195
1224
|
cb(error);
|
|
1196
1225
|
return;
|
|
1197
1226
|
}
|
|
1227
|
+
if (this._maxFragments > 0 && this._fragments.length >= this._maxFragments) {
|
|
1228
|
+
const error = this.createError(
|
|
1229
|
+
RangeError,
|
|
1230
|
+
"Too many message fragments",
|
|
1231
|
+
false,
|
|
1232
|
+
1008,
|
|
1233
|
+
"WS_ERR_TOO_MANY_BUFFERED_PARTS"
|
|
1234
|
+
);
|
|
1235
|
+
cb(error);
|
|
1236
|
+
return;
|
|
1237
|
+
}
|
|
1198
1238
|
this._fragments.push(buf);
|
|
1199
1239
|
}
|
|
1200
1240
|
this.dataMessage(cb);
|
|
@@ -1355,9 +1395,9 @@ var require_receiver = __commonJS({
|
|
|
1355
1395
|
}
|
|
1356
1396
|
});
|
|
1357
1397
|
|
|
1358
|
-
// node_modules/.pnpm/ws@8.
|
|
1398
|
+
// node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/sender.js
|
|
1359
1399
|
var require_sender = __commonJS({
|
|
1360
|
-
"node_modules/.pnpm/ws@8.
|
|
1400
|
+
"node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/sender.js"(exports2, module2) {
|
|
1361
1401
|
"use strict";
|
|
1362
1402
|
var { Duplex } = require("stream");
|
|
1363
1403
|
var { randomFillSync } = require("crypto");
|
|
@@ -1848,9 +1888,9 @@ var require_sender = __commonJS({
|
|
|
1848
1888
|
}
|
|
1849
1889
|
});
|
|
1850
1890
|
|
|
1851
|
-
// node_modules/.pnpm/ws@8.
|
|
1891
|
+
// node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/event-target.js
|
|
1852
1892
|
var require_event_target = __commonJS({
|
|
1853
|
-
"node_modules/.pnpm/ws@8.
|
|
1893
|
+
"node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/event-target.js"(exports2, module2) {
|
|
1854
1894
|
"use strict";
|
|
1855
1895
|
var { kForOnEventAttribute, kListener } = require_constants();
|
|
1856
1896
|
var kCode = /* @__PURE__ */ Symbol("kCode");
|
|
@@ -2077,9 +2117,9 @@ var require_event_target = __commonJS({
|
|
|
2077
2117
|
}
|
|
2078
2118
|
});
|
|
2079
2119
|
|
|
2080
|
-
// node_modules/.pnpm/ws@8.
|
|
2120
|
+
// node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/extension.js
|
|
2081
2121
|
var require_extension = __commonJS({
|
|
2082
|
-
"node_modules/.pnpm/ws@8.
|
|
2122
|
+
"node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/extension.js"(exports2, module2) {
|
|
2083
2123
|
"use strict";
|
|
2084
2124
|
var { tokenChars } = require_validation();
|
|
2085
2125
|
function push(dest, name, elem) {
|
|
@@ -2230,14 +2270,14 @@ var require_extension = __commonJS({
|
|
|
2230
2270
|
}
|
|
2231
2271
|
});
|
|
2232
2272
|
|
|
2233
|
-
// node_modules/.pnpm/ws@8.
|
|
2273
|
+
// node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/websocket.js
|
|
2234
2274
|
var require_websocket = __commonJS({
|
|
2235
|
-
"node_modules/.pnpm/ws@8.
|
|
2275
|
+
"node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/websocket.js"(exports2, module2) {
|
|
2236
2276
|
"use strict";
|
|
2237
2277
|
var EventEmitter = require("events");
|
|
2238
2278
|
var https3 = require("https");
|
|
2239
2279
|
var http2 = require("http");
|
|
2240
|
-
var
|
|
2280
|
+
var net2 = require("net");
|
|
2241
2281
|
var tls = require("tls");
|
|
2242
2282
|
var { randomBytes: randomBytes2, createHash: createHash3 } = require("crypto");
|
|
2243
2283
|
var { Duplex, Readable } = require("stream");
|
|
@@ -2401,6 +2441,10 @@ var require_websocket = __commonJS({
|
|
|
2401
2441
|
* multiple times in the same tick
|
|
2402
2442
|
* @param {Function} [options.generateMask] The function used to generate the
|
|
2403
2443
|
* masking key
|
|
2444
|
+
* @param {Number} [options.maxBufferedChunks=0] The maximum number of
|
|
2445
|
+
* buffered data chunks
|
|
2446
|
+
* @param {Number} [options.maxFragments=0] The maximum number of message
|
|
2447
|
+
* fragments
|
|
2404
2448
|
* @param {Number} [options.maxPayload=0] The maximum allowed message size
|
|
2405
2449
|
* @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
|
|
2406
2450
|
* not to skip UTF-8 validation for text and close messages
|
|
@@ -2412,6 +2456,8 @@ var require_websocket = __commonJS({
|
|
|
2412
2456
|
binaryType: this.binaryType,
|
|
2413
2457
|
extensions: this._extensions,
|
|
2414
2458
|
isServer: this._isServer,
|
|
2459
|
+
maxBufferedChunks: options.maxBufferedChunks,
|
|
2460
|
+
maxFragments: options.maxFragments,
|
|
2415
2461
|
maxPayload: options.maxPayload,
|
|
2416
2462
|
skipUTF8Validation: options.skipUTF8Validation
|
|
2417
2463
|
});
|
|
@@ -2711,6 +2757,8 @@ var require_websocket = __commonJS({
|
|
|
2711
2757
|
autoPong: true,
|
|
2712
2758
|
closeTimeout: CLOSE_TIMEOUT,
|
|
2713
2759
|
protocolVersion: protocolVersions[1],
|
|
2760
|
+
maxBufferedChunks: 1024 * 1024,
|
|
2761
|
+
maxFragments: 128 * 1024,
|
|
2714
2762
|
maxPayload: 100 * 1024 * 1024,
|
|
2715
2763
|
skipUTF8Validation: false,
|
|
2716
2764
|
perMessageDeflate: true,
|
|
@@ -2953,6 +3001,8 @@ var require_websocket = __commonJS({
|
|
|
2953
3001
|
websocket.setSocket(socket, head, {
|
|
2954
3002
|
allowSynchronousEvents: opts.allowSynchronousEvents,
|
|
2955
3003
|
generateMask: opts.generateMask,
|
|
3004
|
+
maxBufferedChunks: opts.maxBufferedChunks,
|
|
3005
|
+
maxFragments: opts.maxFragments,
|
|
2956
3006
|
maxPayload: opts.maxPayload,
|
|
2957
3007
|
skipUTF8Validation: opts.skipUTF8Validation
|
|
2958
3008
|
});
|
|
@@ -2971,12 +3021,12 @@ var require_websocket = __commonJS({
|
|
|
2971
3021
|
}
|
|
2972
3022
|
function netConnect(options) {
|
|
2973
3023
|
options.path = options.socketPath;
|
|
2974
|
-
return
|
|
3024
|
+
return net2.connect(options);
|
|
2975
3025
|
}
|
|
2976
3026
|
function tlsConnect(options) {
|
|
2977
3027
|
options.path = void 0;
|
|
2978
3028
|
if (!options.servername && options.servername !== "") {
|
|
2979
|
-
options.servername =
|
|
3029
|
+
options.servername = net2.isIP(options.host) ? "" : options.host;
|
|
2980
3030
|
}
|
|
2981
3031
|
return tls.connect(options);
|
|
2982
3032
|
}
|
|
@@ -3116,9 +3166,9 @@ var require_websocket = __commonJS({
|
|
|
3116
3166
|
}
|
|
3117
3167
|
});
|
|
3118
3168
|
|
|
3119
|
-
// node_modules/.pnpm/ws@8.
|
|
3169
|
+
// node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/stream.js
|
|
3120
3170
|
var require_stream = __commonJS({
|
|
3121
|
-
"node_modules/.pnpm/ws@8.
|
|
3171
|
+
"node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/stream.js"(exports2, module2) {
|
|
3122
3172
|
"use strict";
|
|
3123
3173
|
var WebSocket2 = require_websocket();
|
|
3124
3174
|
var { Duplex } = require("stream");
|
|
@@ -3214,9 +3264,9 @@ var require_stream = __commonJS({
|
|
|
3214
3264
|
}
|
|
3215
3265
|
});
|
|
3216
3266
|
|
|
3217
|
-
// node_modules/.pnpm/ws@8.
|
|
3267
|
+
// node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/subprotocol.js
|
|
3218
3268
|
var require_subprotocol = __commonJS({
|
|
3219
|
-
"node_modules/.pnpm/ws@8.
|
|
3269
|
+
"node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/subprotocol.js"(exports2, module2) {
|
|
3220
3270
|
"use strict";
|
|
3221
3271
|
var { tokenChars } = require_validation();
|
|
3222
3272
|
function parse(header) {
|
|
@@ -3259,9 +3309,9 @@ var require_subprotocol = __commonJS({
|
|
|
3259
3309
|
}
|
|
3260
3310
|
});
|
|
3261
3311
|
|
|
3262
|
-
// node_modules/.pnpm/ws@8.
|
|
3312
|
+
// node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/websocket-server.js
|
|
3263
3313
|
var require_websocket_server = __commonJS({
|
|
3264
|
-
"node_modules/.pnpm/ws@8.
|
|
3314
|
+
"node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/websocket-server.js"(exports2, module2) {
|
|
3265
3315
|
"use strict";
|
|
3266
3316
|
var EventEmitter = require("events");
|
|
3267
3317
|
var http2 = require("http");
|
|
@@ -3295,6 +3345,10 @@ var require_websocket_server = __commonJS({
|
|
|
3295
3345
|
* called
|
|
3296
3346
|
* @param {Function} [options.handleProtocols] A hook to handle protocols
|
|
3297
3347
|
* @param {String} [options.host] The hostname where to bind the server
|
|
3348
|
+
* @param {Number} [options.maxBufferedChunks=1048576] The maximum number of
|
|
3349
|
+
* buffered data chunks
|
|
3350
|
+
* @param {Number} [options.maxFragments=131072] The maximum number of message
|
|
3351
|
+
* fragments
|
|
3298
3352
|
* @param {Number} [options.maxPayload=104857600] The maximum allowed message
|
|
3299
3353
|
* size
|
|
3300
3354
|
* @param {Boolean} [options.noServer=false] Enable no server mode
|
|
@@ -3316,6 +3370,8 @@ var require_websocket_server = __commonJS({
|
|
|
3316
3370
|
options = {
|
|
3317
3371
|
allowSynchronousEvents: true,
|
|
3318
3372
|
autoPong: true,
|
|
3373
|
+
maxBufferedChunks: 1024 * 1024,
|
|
3374
|
+
maxFragments: 128 * 1024,
|
|
3319
3375
|
maxPayload: 100 * 1024 * 1024,
|
|
3320
3376
|
skipUTF8Validation: false,
|
|
3321
3377
|
perMessageDeflate: false,
|
|
@@ -3595,6 +3651,8 @@ var require_websocket_server = __commonJS({
|
|
|
3595
3651
|
socket.removeListener("error", socketOnError);
|
|
3596
3652
|
ws.setSocket(socket, head, {
|
|
3597
3653
|
allowSynchronousEvents: this.options.allowSynchronousEvents,
|
|
3654
|
+
maxBufferedChunks: this.options.maxBufferedChunks,
|
|
3655
|
+
maxFragments: this.options.maxFragments,
|
|
3598
3656
|
maxPayload: this.options.maxPayload,
|
|
3599
3657
|
skipUTF8Validation: this.options.skipUTF8Validation
|
|
3600
3658
|
});
|
|
@@ -5015,16 +5073,16 @@ var import_node_os = __toESM(require("os"), 1);
|
|
|
5015
5073
|
// src/outbound/outbound-service.ts
|
|
5016
5074
|
var path3 = __toESM(require("path"), 1);
|
|
5017
5075
|
|
|
5018
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
5076
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/QQBot.js
|
|
5019
5077
|
var fs3 = __toESM(require("fs"), 1);
|
|
5020
5078
|
var path = __toESM(require("path"), 1);
|
|
5021
5079
|
|
|
5022
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
5023
|
-
function resolvePolicy(ctx,
|
|
5080
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/types.js
|
|
5081
|
+
function resolvePolicy(ctx, path22, explicit, defaultValue) {
|
|
5024
5082
|
if (explicit !== void 0 && explicit !== null) {
|
|
5025
5083
|
return explicit;
|
|
5026
5084
|
}
|
|
5027
|
-
const keys =
|
|
5085
|
+
const keys = path22.split(".");
|
|
5028
5086
|
let value = ctx.state.policy;
|
|
5029
5087
|
for (const key of keys) {
|
|
5030
5088
|
if (value === null || value === void 0)
|
|
@@ -5095,17 +5153,17 @@ function createMiddlewareContext(params) {
|
|
|
5095
5153
|
return ctx;
|
|
5096
5154
|
}
|
|
5097
5155
|
|
|
5098
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
5156
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/types.js
|
|
5099
5157
|
var ApiError = class extends Error {
|
|
5100
5158
|
httpStatus;
|
|
5101
5159
|
path;
|
|
5102
5160
|
bizCode;
|
|
5103
5161
|
bizMessage;
|
|
5104
5162
|
name = "ApiError";
|
|
5105
|
-
constructor(message, httpStatus,
|
|
5163
|
+
constructor(message, httpStatus, path22, bizCode, bizMessage) {
|
|
5106
5164
|
super(message);
|
|
5107
5165
|
this.httpStatus = httpStatus;
|
|
5108
|
-
this.path =
|
|
5166
|
+
this.path = path22;
|
|
5109
5167
|
this.bizCode = bizCode;
|
|
5110
5168
|
this.bizMessage = bizMessage;
|
|
5111
5169
|
}
|
|
@@ -5128,7 +5186,7 @@ var StreamContentType = {
|
|
|
5128
5186
|
MARKDOWN: "markdown"
|
|
5129
5187
|
};
|
|
5130
5188
|
|
|
5131
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
5189
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/format.js
|
|
5132
5190
|
function formatErrorMessage(err) {
|
|
5133
5191
|
if (err instanceof Error) {
|
|
5134
5192
|
let formatted = err.message || err.name || "Error";
|
|
@@ -5175,7 +5233,7 @@ function formatFileSize(bytes) {
|
|
|
5175
5233
|
return `${(bytes / 1024 / 1024 / 1024).toFixed(2)} GB`;
|
|
5176
5234
|
}
|
|
5177
5235
|
|
|
5178
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
5236
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/api-client.js
|
|
5179
5237
|
var DEFAULT_BASE_URL = "https://api.sgroup.qq.com";
|
|
5180
5238
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
5181
5239
|
var FILE_UPLOAD_TIMEOUT_MS = 12e4;
|
|
@@ -5193,14 +5251,14 @@ var ApiClient = class {
|
|
|
5193
5251
|
const ua = config.userAgent ?? "qqbot-nodejs/unknown";
|
|
5194
5252
|
this.resolveUserAgent = typeof ua === "function" ? ua : () => ua;
|
|
5195
5253
|
}
|
|
5196
|
-
async request(accessToken, method,
|
|
5197
|
-
const url = `${this.baseUrl}${
|
|
5254
|
+
async request(accessToken, method, path22, body, options) {
|
|
5255
|
+
const url = `${this.baseUrl}${path22}`;
|
|
5198
5256
|
const headers = {
|
|
5199
5257
|
Authorization: `QQBot ${accessToken}`,
|
|
5200
5258
|
"Content-Type": "application/json",
|
|
5201
5259
|
"User-Agent": this.resolveUserAgent()
|
|
5202
5260
|
};
|
|
5203
|
-
const isFileUpload = options?.uploadRequest === true ||
|
|
5261
|
+
const isFileUpload = options?.uploadRequest === true || path22.includes("/files") || path22.includes("/upload_prepare") || path22.includes("/upload_part_finish");
|
|
5204
5262
|
const timeout = options?.timeoutMs ?? (isFileUpload ? this.fileUploadTimeoutMs : this.defaultTimeoutMs);
|
|
5205
5263
|
const controller = new AbortController();
|
|
5206
5264
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
@@ -5225,10 +5283,10 @@ var ApiClient = class {
|
|
|
5225
5283
|
clearTimeout(timeoutId);
|
|
5226
5284
|
if (err instanceof Error && err.name === "AbortError") {
|
|
5227
5285
|
this.logger?.error?.(`[qqbot:api] <<< Timeout after ${timeout}ms`);
|
|
5228
|
-
throw new ApiError(`Request timeout [${
|
|
5286
|
+
throw new ApiError(`Request timeout [${path22}]: exceeded ${timeout}ms`, 0, path22);
|
|
5229
5287
|
}
|
|
5230
5288
|
this.logger?.error?.(`[qqbot:api] <<< Network error: ${formatErrorMessage(err)}`);
|
|
5231
|
-
throw new ApiError(`Network error [${
|
|
5289
|
+
throw new ApiError(`Network error [${path22}]: ${formatErrorMessage(err)}`, 0, path22);
|
|
5232
5290
|
} finally {
|
|
5233
5291
|
clearTimeout(timeoutId);
|
|
5234
5292
|
}
|
|
@@ -5238,7 +5296,7 @@ var ApiClient = class {
|
|
|
5238
5296
|
try {
|
|
5239
5297
|
rawBody = await res.text();
|
|
5240
5298
|
} catch (err) {
|
|
5241
|
-
throw new ApiError(`Failed to read response [${
|
|
5299
|
+
throw new ApiError(`Failed to read response [${path22}]: ${formatErrorMessage(err)}`, res.status, path22);
|
|
5242
5300
|
}
|
|
5243
5301
|
this.logger?.debug?.(`[qqbot:api] <<< Body: ${rawBody}`);
|
|
5244
5302
|
const contentType = res.headers.get("content-type") ?? "";
|
|
@@ -5246,36 +5304,36 @@ var ApiClient = class {
|
|
|
5246
5304
|
if (!res.ok) {
|
|
5247
5305
|
if (isHtmlResponse) {
|
|
5248
5306
|
const statusHint = res.status === 502 || res.status === 503 || res.status === 504 ? "\u8C03\u7528\u53D1\u751F\u5F02\u5E38\uFF0C\u8BF7\u7A0D\u5019\u91CD\u8BD5" : res.status === 429 ? "\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u5DF2\u88AB\u9650\u6D41" : `\u5F00\u653E\u5E73\u53F0\u8FD4\u56DE HTTP ${res.status}`;
|
|
5249
|
-
throw new ApiError(`${statusHint}\uFF08${
|
|
5307
|
+
throw new ApiError(`${statusHint}\uFF08${path22}\uFF09\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`, res.status, path22);
|
|
5250
5308
|
}
|
|
5251
5309
|
try {
|
|
5252
5310
|
const error = JSON.parse(rawBody);
|
|
5253
5311
|
const bizCode = error.code ?? error.err_code;
|
|
5254
|
-
throw new ApiError(`API Error [${
|
|
5312
|
+
throw new ApiError(`API Error [${path22}]: ${error.message ?? rawBody}`, res.status, path22, bizCode, error.message);
|
|
5255
5313
|
} catch (parseErr) {
|
|
5256
5314
|
if (parseErr instanceof ApiError) {
|
|
5257
5315
|
throw parseErr;
|
|
5258
5316
|
}
|
|
5259
|
-
throw new ApiError(`API Error [${
|
|
5317
|
+
throw new ApiError(`API Error [${path22}] HTTP ${res.status}: ${rawBody.slice(0, 200)}`, res.status, path22);
|
|
5260
5318
|
}
|
|
5261
5319
|
}
|
|
5262
5320
|
if (isHtmlResponse) {
|
|
5263
|
-
throw new ApiError(`QQ \u670D\u52A1\u7AEF\u8FD4\u56DE\u4E86\u975E JSON \u54CD\u5E94\uFF08${
|
|
5321
|
+
throw new ApiError(`QQ \u670D\u52A1\u7AEF\u8FD4\u56DE\u4E86\u975E JSON \u54CD\u5E94\uFF08${path22}\uFF09\uFF0C\u53EF\u80FD\u662F\u4E34\u65F6\u6545\u969C\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`, res.status, path22);
|
|
5264
5322
|
}
|
|
5265
5323
|
try {
|
|
5266
5324
|
return JSON.parse(rawBody);
|
|
5267
5325
|
} catch {
|
|
5268
|
-
throw new ApiError(`\u5F00\u653E\u5E73\u53F0\u54CD\u5E94\u683C\u5F0F\u5F02\u5E38\uFF08${
|
|
5326
|
+
throw new ApiError(`\u5F00\u653E\u5E73\u53F0\u54CD\u5E94\u683C\u5F0F\u5F02\u5E38\uFF08${path22}\uFF09\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`, res.status, path22);
|
|
5269
5327
|
}
|
|
5270
5328
|
}
|
|
5271
5329
|
};
|
|
5272
5330
|
|
|
5273
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
5331
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/media-chunked.js
|
|
5274
5332
|
var crypto = __toESM(require("crypto"), 1);
|
|
5275
5333
|
var fs = __toESM(require("fs"), 1);
|
|
5276
5334
|
var https = __toESM(require("https"), 1);
|
|
5277
5335
|
|
|
5278
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
5336
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/retry.js
|
|
5279
5337
|
async function withRetry(fn, policy, persistentPolicy, logger) {
|
|
5280
5338
|
let lastError = null;
|
|
5281
5339
|
for (let attempt = 0; attempt <= policy.maxRetries; attempt++) {
|
|
@@ -5367,7 +5425,7 @@ function buildPartFinishPersistentPolicy(retryTimeoutMs, retryableCodes = PART_F
|
|
|
5367
5425
|
var PART_FINISH_RETRYABLE_CODES = /* @__PURE__ */ new Set([40093001]);
|
|
5368
5426
|
var UPLOAD_PREPARE_FALLBACK_CODE = 40093002;
|
|
5369
5427
|
|
|
5370
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
5428
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/routes.js
|
|
5371
5429
|
function messagePath(scope, targetId) {
|
|
5372
5430
|
return scope === "c2c" ? `/v2/users/${targetId}/messages` : `/v2/groups/${targetId}/messages`;
|
|
5373
5431
|
}
|
|
@@ -5404,7 +5462,7 @@ function getNextMsgSeq(_msgId) {
|
|
|
5404
5462
|
return (timePart ^ random) % 65536;
|
|
5405
5463
|
}
|
|
5406
5464
|
|
|
5407
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
5465
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/media-chunked.js
|
|
5408
5466
|
var UploadDailyLimitExceededError = class extends Error {
|
|
5409
5467
|
filePath;
|
|
5410
5468
|
fileSize;
|
|
@@ -5488,9 +5546,9 @@ var ChunkedMediaApi = class {
|
|
|
5488
5546
|
}
|
|
5489
5547
|
async callUploadPrepare(opts, fileName, fileSize, hashes, pathLabel) {
|
|
5490
5548
|
const token = await this.tokenManager.getAccessToken(opts.creds.appId, opts.creds.clientSecret);
|
|
5491
|
-
const
|
|
5549
|
+
const path22 = uploadPreparePath(opts.scope, opts.targetId);
|
|
5492
5550
|
try {
|
|
5493
|
-
return await this.client.request(token, "POST",
|
|
5551
|
+
return await this.client.request(token, "POST", path22, {
|
|
5494
5552
|
file_type: opts.fileType,
|
|
5495
5553
|
file_name: fileName,
|
|
5496
5554
|
file_size: fileSize,
|
|
@@ -5507,10 +5565,10 @@ var ChunkedMediaApi = class {
|
|
|
5507
5565
|
}
|
|
5508
5566
|
async callUploadPartFinish(opts, uploadId, partIndex, blockSize, md5, retryTimeoutMs) {
|
|
5509
5567
|
const persistentPolicy = buildPartFinishPersistentPolicy(retryTimeoutMs);
|
|
5510
|
-
const
|
|
5568
|
+
const path22 = uploadPartFinishPath(opts.scope, opts.targetId);
|
|
5511
5569
|
await withRetry(async () => {
|
|
5512
5570
|
const token = await this.tokenManager.getAccessToken(opts.creds.appId, opts.creds.clientSecret);
|
|
5513
|
-
return this.client.request(token, "POST",
|
|
5571
|
+
return this.client.request(token, "POST", path22, {
|
|
5514
5572
|
upload_id: uploadId,
|
|
5515
5573
|
part_index: partIndex,
|
|
5516
5574
|
block_size: blockSize,
|
|
@@ -5519,10 +5577,10 @@ var ChunkedMediaApi = class {
|
|
|
5519
5577
|
}, PART_FINISH_RETRY_POLICY, persistentPolicy, this.logger);
|
|
5520
5578
|
}
|
|
5521
5579
|
async callCompleteUpload(opts, uploadId) {
|
|
5522
|
-
const
|
|
5580
|
+
const path22 = uploadCompletePath(opts.scope, opts.targetId);
|
|
5523
5581
|
return withRetry(async () => {
|
|
5524
5582
|
const token = await this.tokenManager.getAccessToken(opts.creds.appId, opts.creds.clientSecret);
|
|
5525
|
-
return this.client.request(token, "POST",
|
|
5583
|
+
return this.client.request(token, "POST", path22, { upload_id: uploadId }, { uploadRequest: true });
|
|
5526
5584
|
}, COMPLETE_UPLOAD_RETRY_POLICY, void 0, this.logger);
|
|
5527
5585
|
}
|
|
5528
5586
|
};
|
|
@@ -5663,7 +5721,7 @@ function sleep2(ms) {
|
|
|
5663
5721
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
5664
5722
|
}
|
|
5665
5723
|
|
|
5666
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
5724
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/media.js
|
|
5667
5725
|
var fs2 = __toESM(require("fs"), 1);
|
|
5668
5726
|
var MediaApi = class {
|
|
5669
5727
|
client;
|
|
@@ -5716,8 +5774,8 @@ var MediaApi = class {
|
|
|
5716
5774
|
body.file_name = this.sanitize(opts.fileName);
|
|
5717
5775
|
}
|
|
5718
5776
|
const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);
|
|
5719
|
-
const
|
|
5720
|
-
const result = await withRetry(() => this.client.request(token, "POST",
|
|
5777
|
+
const path22 = mediaUploadPath(scope, targetId);
|
|
5778
|
+
const result = await withRetry(() => this.client.request(token, "POST", path22, body, {
|
|
5721
5779
|
redactBodyKeys: ["file_data"],
|
|
5722
5780
|
uploadRequest: true
|
|
5723
5781
|
}), UPLOAD_RETRY_POLICY, void 0, this.logger);
|
|
@@ -5733,8 +5791,8 @@ var MediaApi = class {
|
|
|
5733
5791
|
async sendMediaMessage(scope, targetId, fileInfo, creds, opts) {
|
|
5734
5792
|
const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);
|
|
5735
5793
|
const msgSeq = opts?.msgId ? getNextMsgSeq(opts.msgId) : 1;
|
|
5736
|
-
const
|
|
5737
|
-
return this.client.request(token, "POST",
|
|
5794
|
+
const path22 = messagePath(scope, targetId);
|
|
5795
|
+
return this.client.request(token, "POST", path22, {
|
|
5738
5796
|
msg_type: 7,
|
|
5739
5797
|
media: { file_info: fileInfo },
|
|
5740
5798
|
msg_seq: msgSeq,
|
|
@@ -5744,7 +5802,7 @@ var MediaApi = class {
|
|
|
5744
5802
|
}
|
|
5745
5803
|
};
|
|
5746
5804
|
|
|
5747
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
5805
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/messages.js
|
|
5748
5806
|
var MessageApi = class {
|
|
5749
5807
|
client;
|
|
5750
5808
|
tokenManager;
|
|
@@ -5773,8 +5831,8 @@ var MessageApi = class {
|
|
|
5773
5831
|
const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);
|
|
5774
5832
|
const msgSeq = opts?.msgId ? getNextMsgSeq(opts.msgId) : 1;
|
|
5775
5833
|
const body = this.buildMessageBody(content, opts?.msgId, msgSeq, opts?.messageReference, opts?.inlineKeyboard);
|
|
5776
|
-
const
|
|
5777
|
-
return this.sendAndNotify(creds.appId, token, "POST",
|
|
5834
|
+
const path22 = messagePath(scope, targetId);
|
|
5835
|
+
return this.sendAndNotify(creds.appId, token, "POST", path22, body, { text: content });
|
|
5778
5836
|
}
|
|
5779
5837
|
async sendProactiveMessage(scope, targetId, content, creds) {
|
|
5780
5838
|
if (!content?.trim()) {
|
|
@@ -5782,8 +5840,8 @@ var MessageApi = class {
|
|
|
5782
5840
|
}
|
|
5783
5841
|
const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);
|
|
5784
5842
|
const body = this.buildProactiveBody(content);
|
|
5785
|
-
const
|
|
5786
|
-
return this.sendAndNotify(creds.appId, token, "POST",
|
|
5843
|
+
const path22 = messagePath(scope, targetId);
|
|
5844
|
+
return this.sendAndNotify(creds.appId, token, "POST", path22, body, { text: content });
|
|
5787
5845
|
}
|
|
5788
5846
|
async sendChannelMessage(opts) {
|
|
5789
5847
|
const token = await this.tokenManager.getAccessToken(opts.creds.appId, opts.creds.clientSecret);
|
|
@@ -5831,7 +5889,7 @@ var MessageApi = class {
|
|
|
5831
5889
|
*/
|
|
5832
5890
|
async sendC2CStreamMessage(creds, openid, req4) {
|
|
5833
5891
|
const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);
|
|
5834
|
-
const
|
|
5892
|
+
const path22 = streamMessagePath(openid);
|
|
5835
5893
|
const body = {
|
|
5836
5894
|
input_mode: req4.input_mode,
|
|
5837
5895
|
input_state: req4.input_state,
|
|
@@ -5845,7 +5903,7 @@ var MessageApi = class {
|
|
|
5845
5903
|
if (req4.stream_msg_id) {
|
|
5846
5904
|
body.stream_msg_id = req4.stream_msg_id;
|
|
5847
5905
|
}
|
|
5848
|
-
return this.client.request(token, "POST",
|
|
5906
|
+
return this.client.request(token, "POST", path22, body);
|
|
5849
5907
|
}
|
|
5850
5908
|
/**
|
|
5851
5909
|
* Raw message send — transparently forwards all fields to the QQ Open Platform API.
|
|
@@ -5859,7 +5917,7 @@ var MessageApi = class {
|
|
|
5859
5917
|
*/
|
|
5860
5918
|
async sendRaw(scope, targetId, creds, body) {
|
|
5861
5919
|
const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);
|
|
5862
|
-
const
|
|
5920
|
+
const path22 = messagePath(scope, targetId);
|
|
5863
5921
|
if (body.msg_seq === void 0) {
|
|
5864
5922
|
body.msg_seq = body.msg_id ? getNextMsgSeq(body.msg_id) : 1;
|
|
5865
5923
|
}
|
|
@@ -5876,7 +5934,7 @@ var MessageApi = class {
|
|
|
5876
5934
|
body.msg_type = 0;
|
|
5877
5935
|
}
|
|
5878
5936
|
const cleaned = Object.fromEntries(Object.entries(body).filter(([, v]) => v !== void 0));
|
|
5879
|
-
return this.sendAndNotify(creds.appId, token, "POST",
|
|
5937
|
+
return this.sendAndNotify(creds.appId, token, "POST", path22, cleaned, { text: cleaned.content ?? cleaned.markdown?.content });
|
|
5880
5938
|
}
|
|
5881
5939
|
/**
|
|
5882
5940
|
* Send a message to a guild text channel.
|
|
@@ -5900,11 +5958,11 @@ var MessageApi = class {
|
|
|
5900
5958
|
*/
|
|
5901
5959
|
async recallMessage(scope, targetId, messageId, creds) {
|
|
5902
5960
|
const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);
|
|
5903
|
-
const
|
|
5904
|
-
await this.client.request(token, "DELETE",
|
|
5961
|
+
const path22 = `${messagePath(scope, targetId)}/${messageId}`;
|
|
5962
|
+
await this.client.request(token, "DELETE", path22);
|
|
5905
5963
|
}
|
|
5906
|
-
async sendAndNotify(_appId, accessToken, method,
|
|
5907
|
-
const result = await this.client.request(accessToken, method,
|
|
5964
|
+
async sendAndNotify(_appId, accessToken, method, path22, body, meta) {
|
|
5965
|
+
const result = await this.client.request(accessToken, method, path22, body);
|
|
5908
5966
|
if (result.ext_info?.ref_idx && this.messageSentHook) {
|
|
5909
5967
|
try {
|
|
5910
5968
|
this.messageSentHook(result.ext_info.ref_idx, meta);
|
|
@@ -5932,7 +5990,7 @@ var MessageApi = class {
|
|
|
5932
5990
|
}
|
|
5933
5991
|
};
|
|
5934
5992
|
|
|
5935
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
5993
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/api/token.js
|
|
5936
5994
|
var DEFAULT_TOKEN_BASE_URL = "https://bots.qq.com";
|
|
5937
5995
|
var TOKEN_PATH = "/app/getAppAccessToken";
|
|
5938
5996
|
var TokenManager = class {
|
|
@@ -6108,7 +6166,7 @@ var TokenManager = class {
|
|
|
6108
6166
|
}
|
|
6109
6167
|
};
|
|
6110
6168
|
|
|
6111
|
-
// node_modules/.pnpm/ws@8.
|
|
6169
|
+
// node_modules/.pnpm/ws@8.21.0/node_modules/ws/wrapper.mjs
|
|
6112
6170
|
var import_stream = __toESM(require_stream(), 1);
|
|
6113
6171
|
var import_extension = __toESM(require_extension(), 1);
|
|
6114
6172
|
var import_permessage_deflate = __toESM(require_permessage_deflate(), 1);
|
|
@@ -6119,7 +6177,7 @@ var import_websocket = __toESM(require_websocket(), 1);
|
|
|
6119
6177
|
var import_websocket_server = __toESM(require_websocket_server(), 1);
|
|
6120
6178
|
var wrapper_default = import_websocket.default;
|
|
6121
6179
|
|
|
6122
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
6180
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/gateway/codec.js
|
|
6123
6181
|
function decodeGatewayMessageData(data) {
|
|
6124
6182
|
if (typeof data === "string") {
|
|
6125
6183
|
return data;
|
|
@@ -6146,7 +6204,7 @@ function readOptionalMessageSceneExt(event) {
|
|
|
6146
6204
|
return scene?.ext;
|
|
6147
6205
|
}
|
|
6148
6206
|
|
|
6149
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
6207
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/gateway/constants.js
|
|
6150
6208
|
var INTENTS = {
|
|
6151
6209
|
GUILDS: 1 << 0,
|
|
6152
6210
|
GUILD_MEMBERS: 1 << 1,
|
|
@@ -6219,7 +6277,7 @@ var GatewayEvent = {
|
|
|
6219
6277
|
MESSAGE_REACTION_REMOVE: "MESSAGE_REACTION_REMOVE"
|
|
6220
6278
|
};
|
|
6221
6279
|
|
|
6222
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
6280
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/gateway/event-dispatcher.js
|
|
6223
6281
|
var REF_INDEX_KEY = "msg_idx";
|
|
6224
6282
|
function parseRefIndices(ext, msgType, msgElements) {
|
|
6225
6283
|
let refMsgIdx;
|
|
@@ -6360,7 +6418,7 @@ function dispatchEvent(eventType, data, _accountId, _log) {
|
|
|
6360
6418
|
return { action: "raw", type: eventType, data };
|
|
6361
6419
|
}
|
|
6362
6420
|
|
|
6363
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
6421
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/gateway/reconnect.js
|
|
6364
6422
|
var ReconnectState = class {
|
|
6365
6423
|
accountId;
|
|
6366
6424
|
log;
|
|
@@ -6471,7 +6529,7 @@ var ReconnectState = class {
|
|
|
6471
6529
|
}
|
|
6472
6530
|
};
|
|
6473
6531
|
|
|
6474
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
6532
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/gateway/gateway-connection.js
|
|
6475
6533
|
var GatewayConnection = class {
|
|
6476
6534
|
isAborted = false;
|
|
6477
6535
|
currentWs = null;
|
|
@@ -6729,7 +6787,7 @@ function previewPayload(data) {
|
|
|
6729
6787
|
}
|
|
6730
6788
|
}
|
|
6731
6789
|
|
|
6732
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
6790
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/transport/webhook-verify.js
|
|
6733
6791
|
var crypto2 = __toESM(require("crypto"), 1);
|
|
6734
6792
|
function deriveSeed(botSecret) {
|
|
6735
6793
|
let seed = botSecret;
|
|
@@ -6781,14 +6839,14 @@ function signValidationResponse(params) {
|
|
|
6781
6839
|
};
|
|
6782
6840
|
}
|
|
6783
6841
|
|
|
6784
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
6842
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/transport/webhook-server-node.js
|
|
6785
6843
|
var http = __toESM(require("http"), 1);
|
|
6786
6844
|
var NodeHttpWebhookServer = class {
|
|
6787
6845
|
server = null;
|
|
6788
|
-
async listen(port,
|
|
6846
|
+
async listen(port, path22, handler) {
|
|
6789
6847
|
return new Promise((resolve2, reject) => {
|
|
6790
6848
|
const server = http.createServer(async (req4, res) => {
|
|
6791
|
-
if (req4.method !== "POST" || req4.url !==
|
|
6849
|
+
if (req4.method !== "POST" || req4.url !== path22) {
|
|
6792
6850
|
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
6793
6851
|
res.end("Not Found");
|
|
6794
6852
|
return;
|
|
@@ -6829,7 +6887,7 @@ var NodeHttpWebhookServer = class {
|
|
|
6829
6887
|
}
|
|
6830
6888
|
};
|
|
6831
6889
|
|
|
6832
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
6890
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/transport/webhook.js
|
|
6833
6891
|
var OP_DISPATCH = 0;
|
|
6834
6892
|
var OP_HTTP_CALLBACK_ACK = 12;
|
|
6835
6893
|
var OP_VALIDATION = 13;
|
|
@@ -6850,11 +6908,11 @@ var WebhookTransport = class {
|
|
|
6850
6908
|
}
|
|
6851
6909
|
async start() {
|
|
6852
6910
|
const port = this.opts.port ?? 8080;
|
|
6853
|
-
const
|
|
6854
|
-
this.log?.info?.(`[webhook] starting on port ${port}, path ${
|
|
6855
|
-
await this.server.listen(port,
|
|
6856
|
-
this.log?.info?.(`[webhook] listening on :${port}${
|
|
6857
|
-
this.callbacks.onReady?.({ transport: "webhook", port, path:
|
|
6911
|
+
const path22 = this.opts.path ?? "/";
|
|
6912
|
+
this.log?.info?.(`[webhook] starting on port ${port}, path ${path22}`);
|
|
6913
|
+
await this.server.listen(port, path22, (req4) => this.handleRequest(req4));
|
|
6914
|
+
this.log?.info?.(`[webhook] listening on :${port}${path22}`);
|
|
6915
|
+
this.callbacks.onReady?.({ transport: "webhook", port, path: path22 });
|
|
6858
6916
|
if (this.opts.abortSignal) {
|
|
6859
6917
|
await new Promise((resolve2) => {
|
|
6860
6918
|
if (this.opts.abortSignal.aborted) {
|
|
@@ -6973,7 +7031,7 @@ function getHeader(headers, key) {
|
|
|
6973
7031
|
return val;
|
|
6974
7032
|
}
|
|
6975
7033
|
|
|
6976
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
7034
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/file-utils.js
|
|
6977
7035
|
var MAX_UPLOAD_SIZE = 20 * 1024 * 1024;
|
|
6978
7036
|
var CHUNKED_UPLOAD_MAX_SIZE = 100 * 1024 * 1024;
|
|
6979
7037
|
var LARGE_FILE_THRESHOLD = 5 * 1024 * 1024;
|
|
@@ -6991,7 +7049,7 @@ function sanitizeFileName(name) {
|
|
|
6991
7049
|
return cleaned || "file";
|
|
6992
7050
|
}
|
|
6993
7051
|
|
|
6994
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
7052
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/upload-cache.js
|
|
6995
7053
|
var crypto3 = __toESM(require("crypto"), 1);
|
|
6996
7054
|
var MAX_CACHE_SIZE = 500;
|
|
6997
7055
|
function computeFileHash(data) {
|
|
@@ -7056,7 +7114,7 @@ var UploadCache = class {
|
|
|
7056
7114
|
}
|
|
7057
7115
|
};
|
|
7058
7116
|
|
|
7059
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
7117
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/streaming.js
|
|
7060
7118
|
var DEFAULT_THROTTLE_MS = 500;
|
|
7061
7119
|
var MIN_THROTTLE_MS = 300;
|
|
7062
7120
|
var MAX_FLUSH_RETRIES = 3;
|
|
@@ -7224,7 +7282,7 @@ var StreamSession = class {
|
|
|
7224
7282
|
}
|
|
7225
7283
|
};
|
|
7226
7284
|
|
|
7227
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
7285
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/QQBot.js
|
|
7228
7286
|
var MsgType = {
|
|
7229
7287
|
/** Plain text. */
|
|
7230
7288
|
TEXT: 0,
|
|
@@ -7744,25 +7802,25 @@ var QQBot = class {
|
|
|
7744
7802
|
if (this._apiGateway)
|
|
7745
7803
|
return this._apiGateway;
|
|
7746
7804
|
this._apiGateway = {
|
|
7747
|
-
get: (
|
|
7748
|
-
post: (
|
|
7749
|
-
put: (
|
|
7750
|
-
patch: (
|
|
7751
|
-
delete: (
|
|
7805
|
+
get: (path22, query) => this.apiRequest("GET", path22, void 0, query),
|
|
7806
|
+
post: (path22, body) => this.apiRequest("POST", path22, body),
|
|
7807
|
+
put: (path22, body) => this.apiRequest("PUT", path22, body),
|
|
7808
|
+
patch: (path22, body) => this.apiRequest("PATCH", path22, body),
|
|
7809
|
+
delete: (path22) => this.apiRequest("DELETE", path22),
|
|
7752
7810
|
getToken: () => this.tokenManager.getAccessToken(this.creds.appId, this.creds.clientSecret)
|
|
7753
7811
|
};
|
|
7754
7812
|
return this._apiGateway;
|
|
7755
7813
|
}
|
|
7756
|
-
async apiRequest(method,
|
|
7814
|
+
async apiRequest(method, path22, body, query) {
|
|
7757
7815
|
const token = await this.tokenManager.getAccessToken(this.creds.appId, this.creds.clientSecret);
|
|
7758
|
-
let fullPath =
|
|
7816
|
+
let fullPath = path22;
|
|
7759
7817
|
if (query && Object.keys(query).length > 0) {
|
|
7760
7818
|
const params = new URLSearchParams();
|
|
7761
7819
|
for (const [k, v] of Object.entries(query)) {
|
|
7762
7820
|
if (v !== void 0 && v !== null)
|
|
7763
7821
|
params.set(k, String(v));
|
|
7764
7822
|
}
|
|
7765
|
-
fullPath = `${
|
|
7823
|
+
fullPath = `${path22}?${params.toString()}`;
|
|
7766
7824
|
}
|
|
7767
7825
|
return this.apiClient.request(token, method, fullPath, body ?? void 0);
|
|
7768
7826
|
}
|
|
@@ -7912,7 +7970,7 @@ var QQBot = class {
|
|
|
7912
7970
|
}
|
|
7913
7971
|
};
|
|
7914
7972
|
|
|
7915
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
7973
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/message-filter.js
|
|
7916
7974
|
function messageFilter(options = {}) {
|
|
7917
7975
|
const skipSelfEcho = options.skipSelfEcho ?? true;
|
|
7918
7976
|
const dedupOpts = options.dedup !== false ? { windowMs: 5e3, maxSize: 1e3, ...options.dedup ?? {} } : null;
|
|
@@ -7950,7 +8008,7 @@ function messageFilter(options = {}) {
|
|
|
7950
8008
|
};
|
|
7951
8009
|
}
|
|
7952
8010
|
|
|
7953
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
8011
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/content-sanitizer.js
|
|
7954
8012
|
function contentSanitizer(options = {}) {
|
|
7955
8013
|
const { stripBotMention = true, stripAllMentions = false, collapseWhitespace = false, parseFaceTags: parseFaceTags2 = false, transform } = options;
|
|
7956
8014
|
return async (ctx, next) => {
|
|
@@ -8045,7 +8103,7 @@ function faceToEmoji(id) {
|
|
|
8045
8103
|
return map[id];
|
|
8046
8104
|
}
|
|
8047
8105
|
|
|
8048
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
8106
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/rate-limiter.js
|
|
8049
8107
|
var SlidingWindow = class {
|
|
8050
8108
|
buckets = /* @__PURE__ */ new Map();
|
|
8051
8109
|
max;
|
|
@@ -8099,11 +8157,11 @@ function rateLimiter(options = {}) {
|
|
|
8099
8157
|
};
|
|
8100
8158
|
}
|
|
8101
8159
|
|
|
8102
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
8160
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/concurrency-guard.js
|
|
8103
8161
|
function concurrencyGuard(options = {}) {
|
|
8104
8162
|
const strategy = options.strategy ?? "queue";
|
|
8105
8163
|
const maxQueue = options.maxQueue ?? 3;
|
|
8106
|
-
const { onDrop, onMerge, onDispatch } = options;
|
|
8164
|
+
const { onDrop, onMerge, onDispatch, urgentPredicate } = options;
|
|
8107
8165
|
const locks = /* @__PURE__ */ new Map();
|
|
8108
8166
|
function getState(key) {
|
|
8109
8167
|
let s = locks.get(key);
|
|
@@ -8156,6 +8214,15 @@ function concurrencyGuard(options = {}) {
|
|
|
8156
8214
|
state.mergeBuffer = [];
|
|
8157
8215
|
state.mergeWaiters = [];
|
|
8158
8216
|
}
|
|
8217
|
+
if (urgentPredicate?.(ctx)) {
|
|
8218
|
+
ctx.log.debug?.(`[concurrency:merge] urgent for ${key}`);
|
|
8219
|
+
for (const w2 of state.mergeWaiters)
|
|
8220
|
+
w2.resolve();
|
|
8221
|
+
state.mergeBuffer.length = 0;
|
|
8222
|
+
state.mergeWaiters.length = 0;
|
|
8223
|
+
await next();
|
|
8224
|
+
return;
|
|
8225
|
+
}
|
|
8159
8226
|
if (state.mergeBuffer.length >= maxQueue) {
|
|
8160
8227
|
ctx.log.debug?.(`[concurrency:merge] buffer full (${maxQueue}), drop for ${key}`);
|
|
8161
8228
|
await onDrop?.(ctx);
|
|
@@ -8303,7 +8370,7 @@ function concurrencyGuard(options = {}) {
|
|
|
8303
8370
|
return guard;
|
|
8304
8371
|
}
|
|
8305
8372
|
|
|
8306
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
8373
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/mention-gate.js
|
|
8307
8374
|
function detectMentionInContent(content, appId) {
|
|
8308
8375
|
if (!content || !appId)
|
|
8309
8376
|
return false;
|
|
@@ -8359,7 +8426,7 @@ function mentionGate(options = {}) {
|
|
|
8359
8426
|
};
|
|
8360
8427
|
}
|
|
8361
8428
|
|
|
8362
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
8429
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/quote-ref.js
|
|
8363
8430
|
var MemoryRefIndexStore = class {
|
|
8364
8431
|
map = /* @__PURE__ */ new Map();
|
|
8365
8432
|
maxSize;
|
|
@@ -8477,7 +8544,7 @@ function buildText(content, attachments) {
|
|
|
8477
8544
|
return parts.join("\n") || "[empty message]";
|
|
8478
8545
|
}
|
|
8479
8546
|
|
|
8480
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
8547
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/envelope-formatter.js
|
|
8481
8548
|
function envelopeFormatter(options = {}) {
|
|
8482
8549
|
const { historyLimit = 5, includeQuote = true, includeSender = true, format } = options;
|
|
8483
8550
|
return async (ctx, next) => {
|
|
@@ -8549,7 +8616,7 @@ ${parts.join("\n")}
|
|
|
8549
8616
|
return sections.join("\n\n");
|
|
8550
8617
|
}
|
|
8551
8618
|
|
|
8552
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
8619
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/slash-command.js
|
|
8553
8620
|
function slashCommand(options = {}) {
|
|
8554
8621
|
const prefixes = options.prefixes ?? ["/"];
|
|
8555
8622
|
const catchErrors = options.catchErrors ?? true;
|
|
@@ -8701,7 +8768,7 @@ async function sendCommandResult(ctx, result) {
|
|
|
8701
8768
|
}
|
|
8702
8769
|
}
|
|
8703
8770
|
|
|
8704
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
8771
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/history-buffer.js
|
|
8705
8772
|
var MemoryHistoryStore = class {
|
|
8706
8773
|
buffers = /* @__PURE__ */ new Map();
|
|
8707
8774
|
append(groupKey, entry, limit) {
|
|
@@ -8766,7 +8833,7 @@ function historyBuffer(options = {}) {
|
|
|
8766
8833
|
return m3;
|
|
8767
8834
|
}
|
|
8768
8835
|
|
|
8769
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
8836
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/typing-indicator.js
|
|
8770
8837
|
var DEFAULT_DURATION_SEC = 60;
|
|
8771
8838
|
var DEFAULT_KEEPALIVE_INTERVAL_MS = 5e4;
|
|
8772
8839
|
function typingIndicator(options = {}) {
|
|
@@ -8803,7 +8870,7 @@ function typingIndicator(options = {}) {
|
|
|
8803
8870
|
};
|
|
8804
8871
|
}
|
|
8805
8872
|
|
|
8806
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
8873
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/middleware/error-handler.js
|
|
8807
8874
|
var DEFAULT_FORMAT = (err) => {
|
|
8808
8875
|
if (err instanceof ApiError) {
|
|
8809
8876
|
if (err.bizMessage)
|
|
@@ -8841,7 +8908,7 @@ function errorHandler(options = {}) {
|
|
|
8841
8908
|
};
|
|
8842
8909
|
}
|
|
8843
8910
|
|
|
8844
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
8911
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/storage/kv-store.js
|
|
8845
8912
|
var import_node_fs = __toESM(require("fs"), 1);
|
|
8846
8913
|
var import_node_path = __toESM(require("path"), 1);
|
|
8847
8914
|
var FileKVStore = class {
|
|
@@ -8951,7 +9018,7 @@ var FileKVStore = class {
|
|
|
8951
9018
|
}
|
|
8952
9019
|
};
|
|
8953
9020
|
|
|
8954
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
9021
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/storage/session-adapter.js
|
|
8955
9022
|
function kvSessionPersistence(opts) {
|
|
8956
9023
|
const prefix = opts.prefix ?? "qqbot:session:";
|
|
8957
9024
|
const key = `${prefix}${opts.accountId}`;
|
|
@@ -9004,13 +9071,105 @@ function parseTarget(to) {
|
|
|
9004
9071
|
return { scope: "c2c", targetId: id };
|
|
9005
9072
|
}
|
|
9006
9073
|
|
|
9074
|
+
// src/outbound/reply-limiter.ts
|
|
9075
|
+
var ReplyLimiter = class {
|
|
9076
|
+
limit;
|
|
9077
|
+
ttlMs;
|
|
9078
|
+
maxTracked;
|
|
9079
|
+
messages = /* @__PURE__ */ new Map();
|
|
9080
|
+
constructor(config) {
|
|
9081
|
+
this.limit = config?.limit ?? 4;
|
|
9082
|
+
this.ttlMs = config?.ttlMs ?? 36e5;
|
|
9083
|
+
this.maxTracked = config?.maxTrackedMessages ?? 1e4;
|
|
9084
|
+
}
|
|
9085
|
+
/**
|
|
9086
|
+
* 检查是否允许对指定消息继续被动回复
|
|
9087
|
+
*/
|
|
9088
|
+
checkLimit(messageId) {
|
|
9089
|
+
const now = Date.now();
|
|
9090
|
+
const tracked = this.messages.get(messageId);
|
|
9091
|
+
if (!tracked) {
|
|
9092
|
+
return { allowed: true, remaining: this.limit, shouldFallbackToProactive: false };
|
|
9093
|
+
}
|
|
9094
|
+
if (now - tracked.firstSeenAt > this.ttlMs) {
|
|
9095
|
+
this.messages.delete(messageId);
|
|
9096
|
+
return {
|
|
9097
|
+
allowed: false,
|
|
9098
|
+
remaining: 0,
|
|
9099
|
+
shouldFallbackToProactive: true,
|
|
9100
|
+
fallbackReason: "expired"
|
|
9101
|
+
};
|
|
9102
|
+
}
|
|
9103
|
+
const remaining = Math.max(0, this.limit - tracked.count);
|
|
9104
|
+
if (remaining <= 0) {
|
|
9105
|
+
return {
|
|
9106
|
+
allowed: false,
|
|
9107
|
+
remaining: 0,
|
|
9108
|
+
shouldFallbackToProactive: true,
|
|
9109
|
+
fallbackReason: "limit_exceeded"
|
|
9110
|
+
};
|
|
9111
|
+
}
|
|
9112
|
+
return { allowed: true, remaining, shouldFallbackToProactive: false };
|
|
9113
|
+
}
|
|
9114
|
+
/**
|
|
9115
|
+
* 记录一次被动回复
|
|
9116
|
+
*/
|
|
9117
|
+
record(messageId) {
|
|
9118
|
+
const now = Date.now();
|
|
9119
|
+
const tracked = this.messages.get(messageId);
|
|
9120
|
+
if (tracked) {
|
|
9121
|
+
tracked.count++;
|
|
9122
|
+
} else {
|
|
9123
|
+
if (this.messages.size >= this.maxTracked) {
|
|
9124
|
+
const firstKey = this.messages.keys().next().value;
|
|
9125
|
+
if (firstKey) this.messages.delete(firstKey);
|
|
9126
|
+
}
|
|
9127
|
+
this.messages.set(messageId, { count: 1, firstSeenAt: now });
|
|
9128
|
+
}
|
|
9129
|
+
}
|
|
9130
|
+
/**
|
|
9131
|
+
* 获取统计信息
|
|
9132
|
+
*/
|
|
9133
|
+
getStats() {
|
|
9134
|
+
let totalReplies = 0;
|
|
9135
|
+
for (const [, v] of this.messages) {
|
|
9136
|
+
totalReplies += v.count;
|
|
9137
|
+
}
|
|
9138
|
+
return { trackedMessages: this.messages.size, totalReplies };
|
|
9139
|
+
}
|
|
9140
|
+
/**
|
|
9141
|
+
* 清除所有跟踪数据
|
|
9142
|
+
*/
|
|
9143
|
+
clear() {
|
|
9144
|
+
this.messages.clear();
|
|
9145
|
+
}
|
|
9146
|
+
};
|
|
9147
|
+
|
|
9007
9148
|
// src/outbound/outbound-service.ts
|
|
9008
9149
|
var gateways = /* @__PURE__ */ new Map();
|
|
9150
|
+
var limiters = /* @__PURE__ */ new Map();
|
|
9151
|
+
function getLimiter(accountId) {
|
|
9152
|
+
let l3 = limiters.get(accountId);
|
|
9153
|
+
if (!l3) {
|
|
9154
|
+
l3 = new ReplyLimiter();
|
|
9155
|
+
limiters.set(accountId, l3);
|
|
9156
|
+
}
|
|
9157
|
+
return l3;
|
|
9158
|
+
}
|
|
9159
|
+
function resolveMsgId(replyToId, accountId) {
|
|
9160
|
+
if (!replyToId) return void 0;
|
|
9161
|
+
const limiter = getLimiter(accountId);
|
|
9162
|
+
const result = limiter.checkLimit(replyToId);
|
|
9163
|
+
if (!result.allowed) return void 0;
|
|
9164
|
+
limiter.record(replyToId);
|
|
9165
|
+
return replyToId;
|
|
9166
|
+
}
|
|
9009
9167
|
function registerGateway(accountId, gw) {
|
|
9010
9168
|
gateways.set(accountId, gw);
|
|
9011
9169
|
}
|
|
9012
9170
|
function unregisterGateway(accountId) {
|
|
9013
9171
|
gateways.delete(accountId);
|
|
9172
|
+
limiters.delete(accountId);
|
|
9014
9173
|
}
|
|
9015
9174
|
function getGateway(accountId) {
|
|
9016
9175
|
return gateways.get(accountId);
|
|
@@ -9022,62 +9181,55 @@ var MEDIA_KIND_TO_FILE_TYPE = {
|
|
|
9022
9181
|
file: MediaFileType.FILE
|
|
9023
9182
|
};
|
|
9024
9183
|
async function sendText(params) {
|
|
9025
|
-
const
|
|
9026
|
-
|
|
9027
|
-
|
|
9028
|
-
}
|
|
9184
|
+
const accountId = params.account.accountId;
|
|
9185
|
+
const gw = gateways.get(accountId);
|
|
9186
|
+
if (!gw) return { error: `Bot "${accountId}" not running` };
|
|
9029
9187
|
try {
|
|
9030
9188
|
const target = parseTarget(params.to);
|
|
9031
|
-
const
|
|
9189
|
+
const msgId = resolveMsgId(params.replyToId, accountId);
|
|
9190
|
+
const result = await gw.sendText(target, params.text, { msgId });
|
|
9032
9191
|
return { messageId: result.id };
|
|
9033
9192
|
} catch (err) {
|
|
9034
9193
|
return formatError(err);
|
|
9035
9194
|
}
|
|
9036
9195
|
}
|
|
9037
9196
|
async function sendMedia(params) {
|
|
9038
|
-
const
|
|
9039
|
-
|
|
9040
|
-
|
|
9041
|
-
}
|
|
9197
|
+
const accountId = params.account.accountId;
|
|
9198
|
+
const gw = gateways.get(accountId);
|
|
9199
|
+
if (!gw) return { error: `Bot "${accountId}" not running` };
|
|
9042
9200
|
try {
|
|
9043
9201
|
const target = parseTarget(params.to);
|
|
9044
9202
|
const kind = params.mediaKind ?? "image";
|
|
9203
|
+
const msgId = resolveMsgId(params.replyToId, accountId);
|
|
9045
9204
|
if (kind === "voice") {
|
|
9046
|
-
const
|
|
9047
|
-
const
|
|
9048
|
-
const source = isLocalPath ? { localPath: params.mediaUrl } : isUrl ? { url: params.mediaUrl } : { base64: params.mediaUrl };
|
|
9049
|
-
const result2 = await gw.sendVoice(
|
|
9050
|
-
target,
|
|
9051
|
-
source,
|
|
9052
|
-
{ text: params.text, msgId: params.replyToId }
|
|
9053
|
-
);
|
|
9205
|
+
const source = resolveVoiceSource(params.mediaUrl);
|
|
9206
|
+
const result2 = await gw.sendVoice(target, source, { text: params.text, msgId });
|
|
9054
9207
|
return { messageId: result2.id };
|
|
9055
9208
|
}
|
|
9056
9209
|
if (kind === "video") {
|
|
9057
|
-
const result2 = await gw.sendVideo(target, params.mediaUrl, {
|
|
9058
|
-
text: params.text,
|
|
9059
|
-
msgId: params.replyToId
|
|
9060
|
-
});
|
|
9210
|
+
const result2 = await gw.sendVideo(target, params.mediaUrl, { text: params.text, msgId });
|
|
9061
9211
|
return { messageId: result2.id };
|
|
9062
9212
|
}
|
|
9063
9213
|
if (kind === "file") {
|
|
9064
|
-
const result2 = await gw.sendFile(target, params.mediaUrl, {
|
|
9065
|
-
text: params.text,
|
|
9066
|
-
msgId: params.replyToId
|
|
9067
|
-
});
|
|
9214
|
+
const result2 = await gw.sendFile(target, params.mediaUrl, { text: params.text, msgId });
|
|
9068
9215
|
return { messageId: result2.id };
|
|
9069
9216
|
}
|
|
9070
9217
|
const fileType = MEDIA_KIND_TO_FILE_TYPE[kind];
|
|
9071
|
-
const result = await gw.sendMedia(target, params.mediaUrl, {
|
|
9072
|
-
text: params.text,
|
|
9073
|
-
msgId: params.replyToId,
|
|
9074
|
-
fileType
|
|
9075
|
-
});
|
|
9218
|
+
const result = await gw.sendMedia(target, params.mediaUrl, { text: params.text, msgId, fileType });
|
|
9076
9219
|
return { messageId: result.id };
|
|
9077
9220
|
} catch (err) {
|
|
9078
9221
|
return formatError(err);
|
|
9079
9222
|
}
|
|
9080
9223
|
}
|
|
9224
|
+
function resolveVoiceSource(source) {
|
|
9225
|
+
if (source.startsWith("http://") || source.startsWith("https://")) return { url: source };
|
|
9226
|
+
if (source.startsWith("/") || source.startsWith("./") || source.startsWith("../")) return { localPath: source };
|
|
9227
|
+
if (source.startsWith("data:")) {
|
|
9228
|
+
const i = source.indexOf(",");
|
|
9229
|
+
return { base64: i > 0 ? source.slice(i + 1) : source };
|
|
9230
|
+
}
|
|
9231
|
+
return { base64: source };
|
|
9232
|
+
}
|
|
9081
9233
|
function formatError(err) {
|
|
9082
9234
|
if (err instanceof Error) {
|
|
9083
9235
|
const result = { error: err.message };
|
|
@@ -9093,7 +9245,7 @@ var import_node_path2 = __toESM(require("path"), 1);
|
|
|
9093
9245
|
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
9094
9246
|
var _cachedOpenclawVersion;
|
|
9095
9247
|
function getPackageVersion() {
|
|
9096
|
-
return true ? "2.0.0-dev.
|
|
9248
|
+
return true ? "2.0.0-dev.202607092101" : "unknown";
|
|
9097
9249
|
}
|
|
9098
9250
|
function getOpenclawVersion(runtimeVersion) {
|
|
9099
9251
|
if (_cachedOpenclawVersion) return _cachedOpenclawVersion;
|
|
@@ -9508,12 +9660,12 @@ function tryGetQQBotRuntime() {
|
|
|
9508
9660
|
|
|
9509
9661
|
// src/adapter/resolve.ts
|
|
9510
9662
|
function probeFunction(rt, paths) {
|
|
9511
|
-
for (const
|
|
9663
|
+
for (const path22 of paths) {
|
|
9512
9664
|
let target = rt;
|
|
9513
9665
|
let parent = rt;
|
|
9514
|
-
for (let i = 0; i <
|
|
9666
|
+
for (let i = 0; i < path22.length; i++) {
|
|
9515
9667
|
parent = target;
|
|
9516
|
-
target = target?.[
|
|
9668
|
+
target = target?.[path22[i]];
|
|
9517
9669
|
if (target === void 0 || target === null) break;
|
|
9518
9670
|
}
|
|
9519
9671
|
if (typeof target === "function") {
|
|
@@ -9675,6 +9827,63 @@ function resolveAgentWorkspace(cfg, agentId) {
|
|
|
9675
9827
|
return getQQBotMediaDir();
|
|
9676
9828
|
}
|
|
9677
9829
|
|
|
9830
|
+
// src/utils/ssrf-guard.ts
|
|
9831
|
+
var import_node_net = __toESM(require("net"), 1);
|
|
9832
|
+
var import_promises = __toESM(require("dns/promises"), 1);
|
|
9833
|
+
var RESERVED_V4_PREFIXES = [
|
|
9834
|
+
"127.",
|
|
9835
|
+
// loopback
|
|
9836
|
+
"10.",
|
|
9837
|
+
// class-A private
|
|
9838
|
+
"192.168.",
|
|
9839
|
+
// class-C private
|
|
9840
|
+
"169.254."
|
|
9841
|
+
// link-local / cloud metadata
|
|
9842
|
+
];
|
|
9843
|
+
var PRIVATE_172_RE = /^172\.(1[6-9]|2\d|3[01])\./;
|
|
9844
|
+
function isReservedAddr(ip) {
|
|
9845
|
+
if (ip === "0.0.0.0") return true;
|
|
9846
|
+
for (const pfx of RESERVED_V4_PREFIXES) {
|
|
9847
|
+
if (ip.startsWith(pfx)) return true;
|
|
9848
|
+
}
|
|
9849
|
+
if (PRIVATE_172_RE.test(ip)) return true;
|
|
9850
|
+
const lower = ip.toLowerCase();
|
|
9851
|
+
if (lower === "::1" || lower === "::") return true;
|
|
9852
|
+
if (lower.startsWith("fe80:")) return true;
|
|
9853
|
+
if (lower.startsWith("fc") || lower.startsWith("fd")) return true;
|
|
9854
|
+
return false;
|
|
9855
|
+
}
|
|
9856
|
+
var ALLOWED_SCHEMES = /* @__PURE__ */ new Set(["http:", "https:"]);
|
|
9857
|
+
async function validateRemoteUrl(raw) {
|
|
9858
|
+
const url = new URL(raw);
|
|
9859
|
+
if (!ALLOWED_SCHEMES.has(url.protocol)) {
|
|
9860
|
+
throw new Error(
|
|
9861
|
+
`\u4E0D\u652F\u6301\u7684\u534F\u8BAE "${url.protocol}"\uFF0C\u4EC5\u5141\u8BB8 http/https\uFF08URL: ${raw}\uFF09`
|
|
9862
|
+
);
|
|
9863
|
+
}
|
|
9864
|
+
const host = url.hostname.replace(/^\[|\]$/g, "");
|
|
9865
|
+
if (import_node_net.default.isIP(host)) {
|
|
9866
|
+
assertPublicAddr(host, raw);
|
|
9867
|
+
return;
|
|
9868
|
+
}
|
|
9869
|
+
try {
|
|
9870
|
+
const ips = await import_promises.default.resolve(host);
|
|
9871
|
+
for (const ip of ips) {
|
|
9872
|
+
assertPublicAddr(ip, raw, host);
|
|
9873
|
+
}
|
|
9874
|
+
} catch (err) {
|
|
9875
|
+
if (err instanceof Error && err.message.includes("\u5185\u7F51")) throw err;
|
|
9876
|
+
console.warn(`[url-check] DNS \u89E3\u6790 "${host}" \u5931\u8D25: ${err}`);
|
|
9877
|
+
}
|
|
9878
|
+
}
|
|
9879
|
+
function assertPublicAddr(ip, originalUrl, domain) {
|
|
9880
|
+
if (!isReservedAddr(ip)) return;
|
|
9881
|
+
const target = domain ? `\u57DF\u540D "${domain}" \u89E3\u6790\u5230\u5185\u7F51\u5730\u5740 "${ip}"` : `\u5185\u7F51\u5730\u5740 "${ip}"`;
|
|
9882
|
+
throw new Error(
|
|
9883
|
+
`\u7981\u6B62\u8BBF\u95EE${target}\uFF0C\u5DF2\u62E6\u622A\u6F5C\u5728\u7684 SSRF \u8BF7\u6C42\uFF08URL: ${originalUrl}\uFF09`
|
|
9884
|
+
);
|
|
9885
|
+
}
|
|
9886
|
+
|
|
9678
9887
|
// src/outbound/local-file-router.ts
|
|
9679
9888
|
var path7 = __toESM(require("path"), 1);
|
|
9680
9889
|
var fs8 = __toESM(require("fs"), 1);
|
|
@@ -9709,6 +9918,9 @@ function isLocalFilePath(source) {
|
|
|
9709
9918
|
if (source.startsWith(".\\") || source.startsWith("..\\")) return true;
|
|
9710
9919
|
return false;
|
|
9711
9920
|
}
|
|
9921
|
+
function isDataUrl(source) {
|
|
9922
|
+
return source.startsWith("data:");
|
|
9923
|
+
}
|
|
9712
9924
|
var IMAGE_EXTS = /* @__PURE__ */ new Set([".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp", ".svg", ".ico"]);
|
|
9713
9925
|
var VOICE_EXTS = /* @__PURE__ */ new Set([".wav", ".mp3", ".silk", ".amr", ".ogg", ".flac", ".aac", ".m4a"]);
|
|
9714
9926
|
var VIDEO_EXTS = /* @__PURE__ */ new Set([".mp4", ".avi", ".mov", ".mkv", ".webm", ".flv", ".wmv"]);
|
|
@@ -9726,14 +9938,48 @@ function inferMediaKindFromMime(mime) {
|
|
|
9726
9938
|
if (lower.startsWith("video/")) return "video";
|
|
9727
9939
|
return "file";
|
|
9728
9940
|
}
|
|
9941
|
+
function isPathInAllowedRoots(absPath, allowedRoots) {
|
|
9942
|
+
if (!allowedRoots.length) return false;
|
|
9943
|
+
try {
|
|
9944
|
+
const real = fs8.realpathSync(absPath);
|
|
9945
|
+
return allowedRoots.some((root) => {
|
|
9946
|
+
try {
|
|
9947
|
+
const rootReal = fs8.existsSync(root) ? fs8.realpathSync(root) : root;
|
|
9948
|
+
return real.startsWith(rootReal + path7.sep) || real === rootReal;
|
|
9949
|
+
} catch {
|
|
9950
|
+
return false;
|
|
9951
|
+
}
|
|
9952
|
+
});
|
|
9953
|
+
} catch {
|
|
9954
|
+
return false;
|
|
9955
|
+
}
|
|
9956
|
+
}
|
|
9729
9957
|
|
|
9730
9958
|
// src/outbound/media-send.ts
|
|
9959
|
+
function resolveTempRoots() {
|
|
9960
|
+
const roots = /* @__PURE__ */ new Set();
|
|
9961
|
+
try {
|
|
9962
|
+
const tmp = os4.tmpdir();
|
|
9963
|
+
roots.add(fs9.existsSync(tmp) ? fs9.realpathSync(tmp) : tmp);
|
|
9964
|
+
} catch {
|
|
9965
|
+
}
|
|
9966
|
+
if (process.platform !== "win32") {
|
|
9967
|
+
try {
|
|
9968
|
+
roots.add(fs9.realpathSync("/tmp"));
|
|
9969
|
+
} catch {
|
|
9970
|
+
}
|
|
9971
|
+
}
|
|
9972
|
+
return [...roots];
|
|
9973
|
+
}
|
|
9731
9974
|
var ALLOWED_MEDIA_ROOTS = [
|
|
9732
9975
|
path8.join(os4.homedir(), ".openclaw", "media"),
|
|
9733
9976
|
path8.join(os4.homedir(), ".openclaw", "workspace"),
|
|
9734
9977
|
// 框架 outbound 目录(saveMediaBuffer 写入)
|
|
9735
|
-
path8.join(os4.homedir(), ".openclaw", "outbound")
|
|
9978
|
+
path8.join(os4.homedir(), ".openclaw", "outbound"),
|
|
9979
|
+
// TTS 语音临时目录(deliver-pipeline 已通过 isTtsPathSafe 预检)
|
|
9980
|
+
...resolveTempRoots()
|
|
9736
9981
|
];
|
|
9982
|
+
var MAX_DATA_URL_BYTES = 10 * 1024 * 1024;
|
|
9737
9983
|
async function sendMedia2(params) {
|
|
9738
9984
|
const { source, accountId, log: log4 } = params;
|
|
9739
9985
|
const mlog = log4?.child("media");
|
|
@@ -9743,7 +9989,7 @@ async function sendMedia2(params) {
|
|
|
9743
9989
|
}
|
|
9744
9990
|
const wsDir = resolveWorkspaceFromAgent(params.agentId);
|
|
9745
9991
|
mlog?.debug(`resolveMediaPath source=${source} agentId=${params.agentId ?? "none"} workspaceDir=${wsDir ?? "none"}`);
|
|
9746
|
-
const resolved = resolveMediaPath(source, mlog, wsDir);
|
|
9992
|
+
const resolved = await resolveMediaPath(source, mlog, wsDir);
|
|
9747
9993
|
if (!resolved.ok) {
|
|
9748
9994
|
mlog?.error(`resolveMediaPath failed: ${resolved.error}`);
|
|
9749
9995
|
return { error: resolved.error };
|
|
@@ -9766,8 +10012,24 @@ async function sendMedia2(params) {
|
|
|
9766
10012
|
return sendImageMedia(gw, target, resolved.path, params);
|
|
9767
10013
|
}
|
|
9768
10014
|
}
|
|
9769
|
-
function resolveMediaPath(source, log4, workspaceDir) {
|
|
10015
|
+
async function resolveMediaPath(source, log4, workspaceDir) {
|
|
9770
10016
|
const normalized = normalizePath(source);
|
|
10017
|
+
if (isDataUrl(normalized)) {
|
|
10018
|
+
if (normalized.length > MAX_DATA_URL_BYTES) {
|
|
10019
|
+
const sizeMB = (normalized.length / (1024 * 1024)).toFixed(1);
|
|
10020
|
+
return { ok: false, error: `Data URL \u8FC7\u5927\uFF08${sizeMB}MB\uFF0C\u6700\u5927 10MB\uFF09` };
|
|
10021
|
+
}
|
|
10022
|
+
return { ok: true, path: normalized, isLocal: false };
|
|
10023
|
+
}
|
|
10024
|
+
if (normalized.startsWith("http://") || normalized.startsWith("https://")) {
|
|
10025
|
+
try {
|
|
10026
|
+
await validateRemoteUrl(normalized);
|
|
10027
|
+
} catch (err) {
|
|
10028
|
+
log4?.warn(`SSRF blocked for media URL: ${normalized}`);
|
|
10029
|
+
return { ok: false, error: `\u5A92\u4F53 URL \u88AB SSRF \u9632\u62A4\u62E6\u622A: ${err instanceof Error ? err.message : String(err)}` };
|
|
10030
|
+
}
|
|
10031
|
+
return { ok: true, path: normalized, isLocal: false };
|
|
10032
|
+
}
|
|
9771
10033
|
if (!isLocalFilePath(normalized)) {
|
|
9772
10034
|
const resolved2 = resolveWorkingFile(normalized, workspaceDir);
|
|
9773
10035
|
if (resolved2) {
|
|
@@ -9785,16 +10047,10 @@ function resolveMediaPath(source, log4, workspaceDir) {
|
|
|
9785
10047
|
} catch {
|
|
9786
10048
|
return { ok: false, error: `Cannot resolve path: ${resolved}` };
|
|
9787
10049
|
}
|
|
9788
|
-
const allowed = ALLOWED_MEDIA_ROOTS
|
|
9789
|
-
try {
|
|
9790
|
-
const resolvedRoot = fs9.existsSync(root) ? fs9.realpathSync(root) : root;
|
|
9791
|
-
return real.startsWith(resolvedRoot + path8.sep) || real === resolvedRoot;
|
|
9792
|
-
} catch {
|
|
9793
|
-
return false;
|
|
9794
|
-
}
|
|
9795
|
-
});
|
|
10050
|
+
const allowed = isPathInAllowedRoots(real, ALLOWED_MEDIA_ROOTS);
|
|
9796
10051
|
if (!allowed) {
|
|
9797
|
-
log4?.warn(`path not in allowed directory: ${real}`);
|
|
10052
|
+
log4?.warn(`path blocked \u2014 not in allowed directory: ${real}`);
|
|
10053
|
+
return { ok: false, error: `\u6587\u4EF6\u8DEF\u5F84\u4E0D\u5728\u5141\u8BB8\u7684\u76EE\u5F55\u4E2D` };
|
|
9798
10054
|
}
|
|
9799
10055
|
return { ok: true, path: real, isLocal: true };
|
|
9800
10056
|
}
|
|
@@ -9830,7 +10086,7 @@ async function sendImageMedia(gw, target, source, params) {
|
|
|
9830
10086
|
}
|
|
9831
10087
|
}
|
|
9832
10088
|
async function sendVoiceMedia(gw, target, source, params) {
|
|
9833
|
-
const voiceSource =
|
|
10089
|
+
const voiceSource = resolveVoiceSource2(source);
|
|
9834
10090
|
try {
|
|
9835
10091
|
const result = await gw.sendVoice(target, voiceSource, {
|
|
9836
10092
|
msgId: params.replyToId
|
|
@@ -9875,7 +10131,7 @@ async function sendFileMedia(gw, target, source, params) {
|
|
|
9875
10131
|
return { error: formatErr(err) };
|
|
9876
10132
|
}
|
|
9877
10133
|
}
|
|
9878
|
-
function
|
|
10134
|
+
function resolveVoiceSource2(source) {
|
|
9879
10135
|
if (source.startsWith("http://") || source.startsWith("https://")) {
|
|
9880
10136
|
return { url: source };
|
|
9881
10137
|
}
|
|
@@ -10173,6 +10429,31 @@ var qqbotSetupWizard = {
|
|
|
10173
10429
|
}
|
|
10174
10430
|
};
|
|
10175
10431
|
|
|
10432
|
+
// src/outbound/sanitize.ts
|
|
10433
|
+
var INTERNAL_TAGS = [
|
|
10434
|
+
// 框架脚手架标签
|
|
10435
|
+
/<system-reminder\b[^>]*>[\s\S]*?<\/system-reminder>/gi,
|
|
10436
|
+
/<previous_response\b[^>]*>[\s\S]*?<\/previous_response>/gi,
|
|
10437
|
+
/<\s*\/?\s*(?:system-reminder|previous_response)\b[^>]*\/?\s*>/gi,
|
|
10438
|
+
// 模型推理/思考内容
|
|
10439
|
+
// deepseek: `think`...`/think` — 匹配完整标签块,标签名 think 必须完整
|
|
10440
|
+
// 格式说明:deepseek 用 `` ` `` (反引号) 替代 XML 的 `<` `>` 作为标签定界符
|
|
10441
|
+
// `think` ≡ <think> 开标签
|
|
10442
|
+
// `/think` ≡ </think> 闭标签
|
|
10443
|
+
/`think`[\s\S]*?`\/think`/gi,
|
|
10444
|
+
/<\s*\/?\s*think\b[^>]*\/?\s*>/gi,
|
|
10445
|
+
// claude: <thinking>...</thinking>
|
|
10446
|
+
/<thinking\b[^>]*>[\s\S]*?<\/thinking>/gi,
|
|
10447
|
+
/<\s*\/?\s*thinking\b[^>]*\/?\s*>/gi
|
|
10448
|
+
];
|
|
10449
|
+
function sanitizeQQBotText(text) {
|
|
10450
|
+
let result = text;
|
|
10451
|
+
for (const re of INTERNAL_TAGS) {
|
|
10452
|
+
result = result.replace(re, "");
|
|
10453
|
+
}
|
|
10454
|
+
return result.trim();
|
|
10455
|
+
}
|
|
10456
|
+
|
|
10176
10457
|
// src/gateway/qqbot-gateway.ts
|
|
10177
10458
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
10178
10459
|
|
|
@@ -10655,6 +10936,7 @@ function botClearStorage(_account) {
|
|
|
10655
10936
|
var import_node_fs5 = __toESM(require("fs"), 1);
|
|
10656
10937
|
var import_node_path5 = __toESM(require("path"), 1);
|
|
10657
10938
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
10939
|
+
var import_node_crypto2 = __toESM(require("crypto"), 1);
|
|
10658
10940
|
var MAX_LINES_PER_FILE = 1e3;
|
|
10659
10941
|
var MAX_FILES = 4;
|
|
10660
10942
|
var LOG_KEYWORDS = ["gateway", "openclaw", "clawdbot", "moltbot"];
|
|
@@ -10834,7 +11116,8 @@ function botLogs(runtime2) {
|
|
|
10834
11116
|
const tmpDir = getQQBotMediaDir("exports");
|
|
10835
11117
|
if (!import_node_fs5.default.existsSync(tmpDir)) import_node_fs5.default.mkdirSync(tmpDir, { recursive: true });
|
|
10836
11118
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
10837
|
-
const
|
|
11119
|
+
const suffix = import_node_crypto2.default.randomBytes(4).toString("hex");
|
|
11120
|
+
const tmpFile = import_node_path5.default.join(tmpDir, `bot-logs-${timestamp}-${suffix}.txt`);
|
|
10838
11121
|
import_node_fs5.default.writeFileSync(tmpFile, lines.join("\n"), "utf8");
|
|
10839
11122
|
let summary = `${recentFiles.length} \u4E2A\u65E5\u5FD7\u6587\u4EF6\uFF0C\u5171 ${totalIncluded} \u884C`;
|
|
10840
11123
|
if (truncatedCount > 0) summary += `\uFF08${truncatedCount} \u4E2A\u622A\u65AD\uFF0C\u539F\u59CB ${totalOriginal} \u884C\uFF09`;
|
|
@@ -10844,7 +11127,7 @@ function botLogs(runtime2) {
|
|
|
10844
11127
|
await ctx.bot.sendFile(
|
|
10845
11128
|
{ scope: "c2c", targetId: senderId, msgId: ctx.message.messageId },
|
|
10846
11129
|
{ localPath: tmpFile },
|
|
10847
|
-
{ fileName: `bot-logs-${timestamp}.txt` }
|
|
11130
|
+
{ fileName: `bot-logs-${timestamp}-${suffix}.txt` }
|
|
10848
11131
|
);
|
|
10849
11132
|
}
|
|
10850
11133
|
} catch (err) {
|
|
@@ -11161,10 +11444,10 @@ function buildCommandList(account, opts) {
|
|
|
11161
11444
|
// src/middleware/attachment.ts
|
|
11162
11445
|
var path17 = __toESM(require("path"), 1);
|
|
11163
11446
|
|
|
11164
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
11447
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/reply-limiter.js
|
|
11165
11448
|
var DEFAULT_TTL_MS = 60 * 60 * 1e3;
|
|
11166
11449
|
|
|
11167
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
11450
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/media-tags.js
|
|
11168
11451
|
var VALID_TAGS = ["qqimg", "qqvoice", "qqvideo", "qqfile", "qqmedia"];
|
|
11169
11452
|
var TAG_ALIASES = {
|
|
11170
11453
|
qq_img: "qqimg",
|
|
@@ -11213,30 +11496,30 @@ var SELF_CLOSING_TAG_REGEX = new RegExp("`?" + LEFT_BRACKET + "\\s*(" + TAG_NAME
|
|
|
11213
11496
|
var FUZZY_MEDIA_TAG_REGEX = new RegExp("`?" + LEFT_BRACKET + "\\s*(" + TAG_NAME_PATTERN + ")\\s*" + RIGHT_BRACKET + `["']?\\s*([^<\uFF1C<\uFF1E>"'\`]+?)\\s*["']?` + LEFT_BRACKET + "\\s*/?\\s*(?:" + TAG_NAME_PATTERN + ")\\s*" + RIGHT_BRACKET + "`?", "gi");
|
|
11214
11497
|
var MULTILINE_TAG_CLEANUP = new RegExp("(" + LEFT_BRACKET + "\\s*(?:" + TAG_NAME_PATTERN + ")\\s*" + RIGHT_BRACKET + ")([\\s\\S]*?)(" + LEFT_BRACKET + "\\s*/?\\s*(?:" + TAG_NAME_PATTERN + ")\\s*" + RIGHT_BRACKET + ")", "gi");
|
|
11215
11498
|
|
|
11216
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
11499
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/ref-index-store.js
|
|
11217
11500
|
var import_node_fs6 = __toESM(require("fs"), 1);
|
|
11218
11501
|
var DEFAULT_TTL_MS2 = 7 * 24 * 60 * 60 * 1e3;
|
|
11219
11502
|
|
|
11220
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
11503
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/session-store.js
|
|
11221
11504
|
var import_node_fs7 = __toESM(require("fs"), 1);
|
|
11222
11505
|
var import_node_path7 = __toESM(require("path"), 1);
|
|
11223
11506
|
var DEFAULT_EXPIRE_MS = 5 * 60 * 1e3;
|
|
11224
11507
|
|
|
11225
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
11508
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/text-parsing.js
|
|
11226
11509
|
var MAX_FACE_EXT_BYTES = 64 * 1024;
|
|
11227
11510
|
|
|
11228
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
11511
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/media-source.js
|
|
11229
11512
|
var fs14 = __toESM(require("fs"), 1);
|
|
11230
11513
|
|
|
11231
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
11514
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/image-size.js
|
|
11232
11515
|
var import_node_buffer = require("buffer");
|
|
11233
11516
|
|
|
11234
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
11517
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/ffmpeg.js
|
|
11235
11518
|
var import_node_child_process = require("child_process");
|
|
11236
11519
|
var fs15 = __toESM(require("fs"), 1);
|
|
11237
11520
|
var path13 = __toESM(require("path"), 1);
|
|
11238
11521
|
|
|
11239
|
-
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.
|
|
11522
|
+
// node_modules/.pnpm/@cxyhhhhh+qqbot-nodejs@1.0.2-dev.202607092059/node_modules/@cxyhhhhh/qqbot-nodejs/dist/protocol/utils/audio.js
|
|
11240
11523
|
var import_node_child_process2 = require("child_process");
|
|
11241
11524
|
var fs16 = __toESM(require("fs"), 1);
|
|
11242
11525
|
var path14 = __toESM(require("path"), 1);
|
|
@@ -11439,10 +11722,10 @@ function formatDuration2(seconds) {
|
|
|
11439
11722
|
|
|
11440
11723
|
// src/adapter/media.ts
|
|
11441
11724
|
var import_node_module4 = require("module");
|
|
11442
|
-
var
|
|
11725
|
+
var dns2 = __toESM(require("dns"), 1);
|
|
11443
11726
|
var path16 = __toESM(require("path"), 1);
|
|
11444
11727
|
var fs18 = __toESM(require("fs"), 1);
|
|
11445
|
-
var
|
|
11728
|
+
var crypto5 = __toESM(require("crypto"), 1);
|
|
11446
11729
|
var req3 = (0, import_node_module4.createRequire)(__filename);
|
|
11447
11730
|
var _save;
|
|
11448
11731
|
function downloadRemoteMedia(opts) {
|
|
@@ -11478,7 +11761,7 @@ function isPrivateIP(ip) {
|
|
|
11478
11761
|
return PRIVATE_RANGES.some(([mask, prefix]) => val >> 32n - BigInt(prefix) === mask >> 32n - BigInt(prefix));
|
|
11479
11762
|
}
|
|
11480
11763
|
async function assertSafeHostname(hostname) {
|
|
11481
|
-
const addresses = await
|
|
11764
|
+
const addresses = await dns2.promises.resolve4(hostname).catch(() => []);
|
|
11482
11765
|
if (addresses.length === 0) throw new Error(`DNS resolution failed: ${hostname}`);
|
|
11483
11766
|
for (const addr of addresses) {
|
|
11484
11767
|
if (isPrivateIP(addr)) {
|
|
@@ -11503,7 +11786,7 @@ async function downloadViaFetch(opts) {
|
|
|
11503
11786
|
if (buf.length > maxBytes) throw new Error(`Download exceeds ${(maxBytes / 1024 / 1024).toFixed(0)}MB`);
|
|
11504
11787
|
const ext = opts.originalFilename ? path16.extname(opts.originalFilename) || ".bin" : ".bin";
|
|
11505
11788
|
const name = opts.originalFilename ? path16.basename(opts.originalFilename, path16.extname(opts.originalFilename)) : "download";
|
|
11506
|
-
const rand =
|
|
11789
|
+
const rand = crypto5.randomBytes(4).toString("hex");
|
|
11507
11790
|
const filePath = path16.join(dir, `${name}_${Date.now()}_${rand}${ext}`);
|
|
11508
11791
|
fs18.writeFileSync(filePath, buf);
|
|
11509
11792
|
return { path: filePath };
|
|
@@ -12065,6 +12348,10 @@ function setupMiddlewares(bot, account, opts) {
|
|
|
12065
12348
|
bot.use(concurrencyGuard({
|
|
12066
12349
|
strategy: "merge",
|
|
12067
12350
|
maxQueue: 50,
|
|
12351
|
+
/** 紧急指令(/stop)跳过排队,立即处理 */
|
|
12352
|
+
urgentPredicate: (ctx) => {
|
|
12353
|
+
return (ctx.message.content ?? "").trim() === "/stop";
|
|
12354
|
+
},
|
|
12068
12355
|
onMerge: (buffered) => {
|
|
12069
12356
|
const last = buffered[buffered.length - 1];
|
|
12070
12357
|
if (buffered.length === 1) return last;
|
|
@@ -12149,6 +12436,8 @@ function buildEnvelope2(ctx, msg, account) {
|
|
|
12149
12436
|
}
|
|
12150
12437
|
|
|
12151
12438
|
// src/outbound/deliver-pipeline.ts
|
|
12439
|
+
var path18 = __toESM(require("path"), 1);
|
|
12440
|
+
var os7 = __toESM(require("os"), 1);
|
|
12152
12441
|
function resolveMediaUrls(payload) {
|
|
12153
12442
|
if (payload.mediaUrls?.length) {
|
|
12154
12443
|
return payload.mediaUrls.filter(Boolean);
|
|
@@ -12197,6 +12486,7 @@ async function deliverReply(payload, _info, ctx) {
|
|
|
12197
12486
|
}
|
|
12198
12487
|
}
|
|
12199
12488
|
async function sendMediaUrls(ctx, urls) {
|
|
12489
|
+
const failedUrls = [];
|
|
12200
12490
|
for (const url of urls) {
|
|
12201
12491
|
const result = await sendMedia2({
|
|
12202
12492
|
to: ctx.qualifiedTarget,
|
|
@@ -12208,6 +12498,16 @@ async function sendMediaUrls(ctx, urls) {
|
|
|
12208
12498
|
});
|
|
12209
12499
|
if (result.error) {
|
|
12210
12500
|
ctx.log?.error(`[media] ${result.error}`);
|
|
12501
|
+
failedUrls.push(url);
|
|
12502
|
+
}
|
|
12503
|
+
}
|
|
12504
|
+
if (failedUrls.length > 0) {
|
|
12505
|
+
const count = failedUrls.length;
|
|
12506
|
+
const total = urls.length;
|
|
12507
|
+
const failMsg = count === total ? `\u26A0\uFE0F \u5A92\u4F53\u53D1\u9001\u5931\u8D25\uFF08${count} \u4E2A\uFF09\uFF0C\u8BF7\u91CD\u8BD5` : `\u26A0\uFE0F ${count}/${total} \u4E2A\u5A92\u4F53\u53D1\u9001\u5931\u8D25`;
|
|
12508
|
+
const textResult = await ctx.sendText(ctx.qualifiedTarget, failMsg);
|
|
12509
|
+
if (textResult.error) {
|
|
12510
|
+
ctx.log?.error(`[media] failed to send failure notification: ${textResult.error}`);
|
|
12211
12511
|
}
|
|
12212
12512
|
}
|
|
12213
12513
|
}
|
|
@@ -12227,6 +12527,10 @@ async function handleVoiceIntent(text, ctx) {
|
|
|
12227
12527
|
ctx.log?.error(`[tts] TTS failed: ${ttsResult.error ?? "no audio path returned"}`);
|
|
12228
12528
|
return false;
|
|
12229
12529
|
}
|
|
12530
|
+
if (!isTtsPathSafe(ttsResult.audioPath)) {
|
|
12531
|
+
ctx.log?.error(`[tts] TTS audio path blocked: ${ttsResult.audioPath}`);
|
|
12532
|
+
return false;
|
|
12533
|
+
}
|
|
12230
12534
|
if (ctx.audioFileToSilkBase64) {
|
|
12231
12535
|
const silkBase64 = await ctx.audioFileToSilkBase64(ttsResult.audioPath);
|
|
12232
12536
|
if (silkBase64) {
|
|
@@ -12247,6 +12551,15 @@ async function handleVoiceIntent(text, ctx) {
|
|
|
12247
12551
|
return false;
|
|
12248
12552
|
}
|
|
12249
12553
|
}
|
|
12554
|
+
var TTS_ALLOWED_ROOTS = [
|
|
12555
|
+
path18.join(os7.homedir(), ".openclaw"),
|
|
12556
|
+
os7.tmpdir(),
|
|
12557
|
+
"/tmp"
|
|
12558
|
+
];
|
|
12559
|
+
function isTtsPathSafe(audioPath) {
|
|
12560
|
+
if (!path18.isAbsolute(audioPath)) return false;
|
|
12561
|
+
return isPathInAllowedRoots(audioPath, TTS_ALLOWED_ROOTS);
|
|
12562
|
+
}
|
|
12250
12563
|
|
|
12251
12564
|
// src/dispatch/ctx-builder.ts
|
|
12252
12565
|
function buildCtxPayload(params) {
|
|
@@ -13091,10 +13404,10 @@ function getApprovalHandler(accountId) {
|
|
|
13091
13404
|
|
|
13092
13405
|
// src/features/proactive.ts
|
|
13093
13406
|
var fs19 = __toESM(require("fs"), 1);
|
|
13094
|
-
var
|
|
13407
|
+
var path20 = __toESM(require("path"), 1);
|
|
13095
13408
|
var log2 = createPluginLogger({ prefix: "[proactive]" });
|
|
13096
13409
|
var STORAGE_DIR = getQQBotDataDir("data");
|
|
13097
|
-
var KNOWN_USERS_FILE =
|
|
13410
|
+
var KNOWN_USERS_FILE = path20.join(STORAGE_DIR, "known-users.json");
|
|
13098
13411
|
var knownUsersCache = null;
|
|
13099
13412
|
var cacheLastModified = 0;
|
|
13100
13413
|
function ensureStorageDir() {
|
|
@@ -13298,6 +13611,11 @@ async function handleApproval(event, account, log4, ack) {
|
|
|
13298
13611
|
}
|
|
13299
13612
|
const buttonData = event.data?.resolved?.button_data;
|
|
13300
13613
|
if (!buttonData?.startsWith("approve:")) return;
|
|
13614
|
+
const operatorId = resolveOperatorId(event);
|
|
13615
|
+
if (!isApprovalAuthorized(account, operatorId)) {
|
|
13616
|
+
log4.warn(`[approval] unauthorized operator=${operatorId ?? "unknown"} account=${account.accountId}`);
|
|
13617
|
+
return;
|
|
13618
|
+
}
|
|
13301
13619
|
const parts = buttonData.split(":");
|
|
13302
13620
|
if (parts.length < 3) return;
|
|
13303
13621
|
const handler = getApprovalHandler(account.accountId);
|
|
@@ -13307,10 +13625,20 @@ async function handleApproval(event, account, log4, ack) {
|
|
|
13307
13625
|
try {
|
|
13308
13626
|
await handler.resolveApproval(approvalId, decision);
|
|
13309
13627
|
} catch (err) {
|
|
13310
|
-
log4.error(`interaction approve error: ${err}`);
|
|
13628
|
+
log4.error(`interaction approve error: ${err instanceof Error ? err.message : String(err)}`);
|
|
13311
13629
|
}
|
|
13312
13630
|
}
|
|
13313
13631
|
var CHANNEL_VER = getPackageVersion();
|
|
13632
|
+
function resolveOperatorId(event) {
|
|
13633
|
+
const evt = event;
|
|
13634
|
+
return evt.user_openid ?? evt.data?.resolved?.user_id ?? evt.data?.resolved?.user_openid ?? evt.openid;
|
|
13635
|
+
}
|
|
13636
|
+
function isApprovalAuthorized(account, operatorId) {
|
|
13637
|
+
if (!operatorId) return false;
|
|
13638
|
+
const allowFrom = account.config?.allowFrom ?? [];
|
|
13639
|
+
if (!allowFrom.length || allowFrom.includes("*")) return true;
|
|
13640
|
+
return allowFrom.includes(operatorId);
|
|
13641
|
+
}
|
|
13314
13642
|
function buildClawCfg(requireMention, mentionPatterns, groupPolicy) {
|
|
13315
13643
|
return {
|
|
13316
13644
|
channel_type: "qqbot",
|
|
@@ -13340,13 +13668,13 @@ function createPluginWebhookAdapter(params) {
|
|
|
13340
13668
|
let storedPath = "";
|
|
13341
13669
|
const accountId = params.account.accountId;
|
|
13342
13670
|
return {
|
|
13343
|
-
async listen(_port,
|
|
13671
|
+
async listen(_port, path22, handler) {
|
|
13344
13672
|
const ingress = await import("openclaw/plugin-sdk/webhook-ingress").catch(() => null);
|
|
13345
13673
|
if (!ingress?.registerWebhookTargetWithPluginRoute) {
|
|
13346
13674
|
params.log.error("Webhook ingress not available");
|
|
13347
13675
|
return;
|
|
13348
13676
|
}
|
|
13349
|
-
const webhookPath = storedPath =
|
|
13677
|
+
const webhookPath = storedPath = path22 && path22 !== "/" ? path22 : params.account.config.webhook?.path ?? "/qqbot/webhook";
|
|
13350
13678
|
const existing = sharedTargets.get(webhookPath);
|
|
13351
13679
|
if (existing) {
|
|
13352
13680
|
const dupIdx = existing.findIndex((t) => t.accountId === accountId);
|
|
@@ -13393,12 +13721,12 @@ function createPluginWebhookAdapter(params) {
|
|
|
13393
13721
|
}
|
|
13394
13722
|
};
|
|
13395
13723
|
}
|
|
13396
|
-
function createSharedHandler(
|
|
13724
|
+
function createSharedHandler(path22, log4) {
|
|
13397
13725
|
return async (req4, res) => {
|
|
13398
13726
|
try {
|
|
13399
13727
|
const ingress = await import("openclaw/plugin-sdk/webhook-ingress").catch(() => null);
|
|
13400
13728
|
if (!ingress?.withResolvedWebhookRequestPipeline) {
|
|
13401
|
-
await handleSimple(req4, res,
|
|
13729
|
+
await handleSimple(req4, res, path22, log4);
|
|
13402
13730
|
return;
|
|
13403
13731
|
}
|
|
13404
13732
|
await ingress.withResolvedWebhookRequestPipeline({
|
|
@@ -13439,12 +13767,12 @@ function createSharedHandler(path21, log4) {
|
|
|
13439
13767
|
if (payload.op === 13) {
|
|
13440
13768
|
const t = targets[0];
|
|
13441
13769
|
if (!t) {
|
|
13442
|
-
log4.warn?.(`[webhook] op:13 no target on ${
|
|
13770
|
+
log4.warn?.(`[webhook] op:13 no target on ${path22}`);
|
|
13443
13771
|
res.statusCode = 500;
|
|
13444
13772
|
res.end(JSON.stringify({ error: "no target" }));
|
|
13445
13773
|
return;
|
|
13446
13774
|
}
|
|
13447
|
-
const h3 = resolveTargetHandler(
|
|
13775
|
+
const h3 = resolveTargetHandler(path22, t.accountId);
|
|
13448
13776
|
if (!h3) {
|
|
13449
13777
|
log4.warn?.(`[webhook] op:13 no handler for ${t.accountId}`);
|
|
13450
13778
|
res.statusCode = 500;
|
|
@@ -13475,10 +13803,10 @@ function createSharedHandler(path21, log4) {
|
|
|
13475
13803
|
unauthorizedMessage: JSON.stringify({ error: "invalid signature" })
|
|
13476
13804
|
});
|
|
13477
13805
|
if (!matched) {
|
|
13478
|
-
log4.warn?.(`[webhook] signature mismatch on ${
|
|
13806
|
+
log4.warn?.(`[webhook] signature mismatch on ${path22} (${targets.length} target(s))`);
|
|
13479
13807
|
return;
|
|
13480
13808
|
}
|
|
13481
|
-
const h2 = resolveTargetHandler(
|
|
13809
|
+
const h2 = resolveTargetHandler(path22, matched.accountId);
|
|
13482
13810
|
if (!h2) {
|
|
13483
13811
|
log4.error?.(`[webhook] no handler for matched target ${matched.accountId}`);
|
|
13484
13812
|
res.statusCode = 500;
|
|
@@ -13498,8 +13826,8 @@ function createSharedHandler(path21, log4) {
|
|
|
13498
13826
|
}
|
|
13499
13827
|
};
|
|
13500
13828
|
}
|
|
13501
|
-
function resolveTargetHandler(
|
|
13502
|
-
return sharedTargets.get(
|
|
13829
|
+
function resolveTargetHandler(path22, accountId) {
|
|
13830
|
+
return sharedTargets.get(path22)?.find((t) => t.accountId === accountId)?.handler;
|
|
13503
13831
|
}
|
|
13504
13832
|
async function delegateToHandler(handler, req4, res, rawBody) {
|
|
13505
13833
|
const headers = {};
|
|
@@ -13513,7 +13841,7 @@ async function delegateToHandler(handler, req4, res, rawBody) {
|
|
|
13513
13841
|
}
|
|
13514
13842
|
res.end(resp.body);
|
|
13515
13843
|
}
|
|
13516
|
-
async function handleSimple(req4, res,
|
|
13844
|
+
async function handleSimple(req4, res, path22, log4) {
|
|
13517
13845
|
try {
|
|
13518
13846
|
const ct = String(req4.headers["content-type"] ?? "");
|
|
13519
13847
|
if (!ct.includes("application/json")) {
|
|
@@ -13534,7 +13862,7 @@ async function handleSimple(req4, res, path21, log4) {
|
|
|
13534
13862
|
chunks.push(buf);
|
|
13535
13863
|
}
|
|
13536
13864
|
const rawBody = Buffer.concat(chunks);
|
|
13537
|
-
const entries = sharedTargets.get(
|
|
13865
|
+
const entries = sharedTargets.get(path22) ?? [];
|
|
13538
13866
|
for (const entry of entries) {
|
|
13539
13867
|
const resp = await entry.handler({ body: rawBody, headers: mapHeaders(req4) });
|
|
13540
13868
|
if (resp.status < 400) {
|
|
@@ -13565,12 +13893,35 @@ function getHeader2(req4, key) {
|
|
|
13565
13893
|
}
|
|
13566
13894
|
|
|
13567
13895
|
// src/gateway/qqbot-gateway.ts
|
|
13896
|
+
var TEXT_TIMEOUT_MS = 3e4;
|
|
13897
|
+
var MEDIA_TIMEOUT_MS = 3e5;
|
|
13898
|
+
function resolveMs(envKey, defaultMs) {
|
|
13899
|
+
const env = process.env[envKey];
|
|
13900
|
+
if (env) {
|
|
13901
|
+
const v = Number(env);
|
|
13902
|
+
if (!Number.isNaN(v) && v > 0) return v;
|
|
13903
|
+
}
|
|
13904
|
+
return defaultMs;
|
|
13905
|
+
}
|
|
13906
|
+
function withTimeout(promise, ms, label) {
|
|
13907
|
+
if (ms <= 0) return promise;
|
|
13908
|
+
return Promise.race([
|
|
13909
|
+
promise,
|
|
13910
|
+
new Promise(
|
|
13911
|
+
(_2, reject) => setTimeout(() => reject(new Error(`\u51FA\u7AD9\u8D85\u65F6: ${label} (${ms}ms)`)), ms)
|
|
13912
|
+
)
|
|
13913
|
+
]);
|
|
13914
|
+
}
|
|
13568
13915
|
var QQBotGateway = class {
|
|
13569
13916
|
bot;
|
|
13570
13917
|
account;
|
|
13571
13918
|
runtime;
|
|
13572
13919
|
log;
|
|
13920
|
+
textTimeout;
|
|
13921
|
+
mediaTimeout;
|
|
13573
13922
|
constructor(account, runtime2, log4) {
|
|
13923
|
+
this.textTimeout = resolveMs("OPENCLAW_OUTBOUND_TIMEOUT_MS", TEXT_TIMEOUT_MS);
|
|
13924
|
+
this.mediaTimeout = resolveMs("OPENCLAW_OUTBOUND_MEDIA_TIMEOUT_MS", MEDIA_TIMEOUT_MS);
|
|
13574
13925
|
this.account = account;
|
|
13575
13926
|
this.runtime = runtime2;
|
|
13576
13927
|
this.log = log4 ?? createPluginLogger({ prefix: `[qqbot:${account.accountId}]` });
|
|
@@ -13635,69 +13986,66 @@ var QQBotGateway = class {
|
|
|
13635
13986
|
await this.bot.stop();
|
|
13636
13987
|
}
|
|
13637
13988
|
async sendText(target, text, opts) {
|
|
13638
|
-
return
|
|
13989
|
+
return withTimeout(
|
|
13990
|
+
this.bot.sendText(attachMsgId(target, opts), text),
|
|
13991
|
+
this.textTimeout,
|
|
13992
|
+
"sendText"
|
|
13993
|
+
);
|
|
13639
13994
|
}
|
|
13640
13995
|
async sendMedia(target, source, opts) {
|
|
13641
13996
|
const resolvedTarget = attachMsgId(target, opts);
|
|
13642
13997
|
const fileType = opts?.fileType ?? MediaFileType.IMAGE;
|
|
13643
13998
|
const sourceOpts = resolveMediaSource(source);
|
|
13644
|
-
const result = await
|
|
13645
|
-
target: resolvedTarget,
|
|
13646
|
-
|
|
13647
|
-
|
|
13648
|
-
|
|
13649
|
-
});
|
|
13999
|
+
const result = await withTimeout(
|
|
14000
|
+
this.bot.sendMedia({ target: resolvedTarget, fileType, ...sourceOpts, content: opts?.text }),
|
|
14001
|
+
this.mediaTimeout,
|
|
14002
|
+
"sendMedia"
|
|
14003
|
+
);
|
|
13650
14004
|
return result.message ?? { id: "", timestamp: Date.now() };
|
|
13651
14005
|
}
|
|
13652
14006
|
async sendVoice(target, source, opts) {
|
|
13653
14007
|
const resolvedTarget = attachMsgId(target, opts);
|
|
13654
14008
|
if (source.base64) {
|
|
13655
|
-
const result2 = await
|
|
13656
|
-
target: resolvedTarget,
|
|
13657
|
-
|
|
13658
|
-
|
|
13659
|
-
|
|
13660
|
-
});
|
|
14009
|
+
const result2 = await withTimeout(
|
|
14010
|
+
this.bot.sendMedia({ target: resolvedTarget, fileType: MediaFileType.VOICE, fileData: source.base64, content: opts?.text }),
|
|
14011
|
+
this.mediaTimeout,
|
|
14012
|
+
"sendVoice(base64)"
|
|
14013
|
+
);
|
|
13661
14014
|
return result2.message ?? { id: "", timestamp: Date.now() };
|
|
13662
14015
|
}
|
|
13663
14016
|
if (source.localPath) {
|
|
13664
|
-
const result2 = await
|
|
13665
|
-
target: resolvedTarget,
|
|
13666
|
-
|
|
13667
|
-
|
|
13668
|
-
|
|
13669
|
-
});
|
|
14017
|
+
const result2 = await withTimeout(
|
|
14018
|
+
this.bot.sendMedia({ target: resolvedTarget, fileType: MediaFileType.VOICE, localPath: source.localPath, content: opts?.text }),
|
|
14019
|
+
this.mediaTimeout,
|
|
14020
|
+
"sendVoice(path)"
|
|
14021
|
+
);
|
|
13670
14022
|
return result2.message ?? { id: "", timestamp: Date.now() };
|
|
13671
14023
|
}
|
|
13672
|
-
const result = await
|
|
13673
|
-
target: resolvedTarget,
|
|
13674
|
-
|
|
13675
|
-
url
|
|
13676
|
-
|
|
13677
|
-
});
|
|
14024
|
+
const result = await withTimeout(
|
|
14025
|
+
this.bot.sendMedia({ target: resolvedTarget, fileType: MediaFileType.VOICE, url: source.url, content: opts?.text }),
|
|
14026
|
+
this.mediaTimeout,
|
|
14027
|
+
"sendVoice(url)"
|
|
14028
|
+
);
|
|
13678
14029
|
return result.message ?? { id: "", timestamp: Date.now() };
|
|
13679
14030
|
}
|
|
13680
14031
|
async sendVideo(target, source, opts) {
|
|
13681
14032
|
const resolvedTarget = attachMsgId(target, opts);
|
|
13682
14033
|
const sourceOpts = resolveMediaSource(source);
|
|
13683
|
-
const result = await
|
|
13684
|
-
target: resolvedTarget,
|
|
13685
|
-
|
|
13686
|
-
|
|
13687
|
-
|
|
13688
|
-
});
|
|
14034
|
+
const result = await withTimeout(
|
|
14035
|
+
this.bot.sendMedia({ target: resolvedTarget, fileType: MediaFileType.VIDEO, ...sourceOpts, content: opts?.text }),
|
|
14036
|
+
this.mediaTimeout,
|
|
14037
|
+
"sendVideo"
|
|
14038
|
+
);
|
|
13689
14039
|
return result.message ?? { id: "", timestamp: Date.now() };
|
|
13690
14040
|
}
|
|
13691
14041
|
async sendFile(target, source, opts) {
|
|
13692
14042
|
const resolvedTarget = attachMsgId(target, opts);
|
|
13693
14043
|
const sourceOpts = resolveMediaSource(source);
|
|
13694
|
-
const result = await
|
|
13695
|
-
target: resolvedTarget,
|
|
13696
|
-
|
|
13697
|
-
|
|
13698
|
-
|
|
13699
|
-
content: opts?.text
|
|
13700
|
-
});
|
|
14044
|
+
const result = await withTimeout(
|
|
14045
|
+
this.bot.sendMedia({ target: resolvedTarget, fileType: MediaFileType.FILE, ...sourceOpts, fileName: opts?.fileName, content: opts?.text }),
|
|
14046
|
+
this.mediaTimeout,
|
|
14047
|
+
"sendFile"
|
|
14048
|
+
);
|
|
13701
14049
|
return result.message ?? { id: "", timestamp: Date.now() };
|
|
13702
14050
|
}
|
|
13703
14051
|
openStream(target, msgId) {
|
|
@@ -14064,6 +14412,11 @@ function stripMentionText(text, mentions) {
|
|
|
14064
14412
|
|
|
14065
14413
|
// src/channel.ts
|
|
14066
14414
|
var TEXT_CHUNK_LIMIT2 = 5e3;
|
|
14415
|
+
var GFM_TABLE_DATA_RE = /^\|.+\|.*\|/;
|
|
14416
|
+
var GFM_TABLE_SEP_RE = /^\|[\s:-]+\|/;
|
|
14417
|
+
function isGfmTableLine(line) {
|
|
14418
|
+
return GFM_TABLE_DATA_RE.test(line) || GFM_TABLE_SEP_RE.test(line);
|
|
14419
|
+
}
|
|
14067
14420
|
var qqbotPlugin = {
|
|
14068
14421
|
id: "qqbot",
|
|
14069
14422
|
meta: {
|
|
@@ -14179,13 +14532,33 @@ var qqbotPlugin = {
|
|
|
14179
14532
|
// ── 出站 ──
|
|
14180
14533
|
outbound: {
|
|
14181
14534
|
deliveryMode: "direct",
|
|
14535
|
+
sanitizeText: ({ text }) => sanitizeQQBotText(text),
|
|
14182
14536
|
chunker: (text, limit) => {
|
|
14183
14537
|
const adapters = getAdapters(getQQBotRuntime());
|
|
14184
14538
|
if (adapters.chunkMarkdownText) return adapters.chunkMarkdownText(text, limit);
|
|
14185
14539
|
const lines = text.split("\n");
|
|
14186
14540
|
const chunks = [];
|
|
14187
14541
|
let current = "";
|
|
14542
|
+
let tableBuffer = [];
|
|
14543
|
+
const flushTable = () => {
|
|
14544
|
+
if (tableBuffer.length === 0) return;
|
|
14545
|
+
const tableBlock = tableBuffer.join("\n");
|
|
14546
|
+
const candidate = current ? `${current}
|
|
14547
|
+
${tableBlock}` : tableBlock;
|
|
14548
|
+
if (candidate.length > limit && current) {
|
|
14549
|
+
chunks.push(current);
|
|
14550
|
+
current = tableBlock;
|
|
14551
|
+
} else {
|
|
14552
|
+
current = candidate;
|
|
14553
|
+
}
|
|
14554
|
+
tableBuffer = [];
|
|
14555
|
+
};
|
|
14188
14556
|
for (const line of lines) {
|
|
14557
|
+
if (isGfmTableLine(line)) {
|
|
14558
|
+
tableBuffer.push(line);
|
|
14559
|
+
continue;
|
|
14560
|
+
}
|
|
14561
|
+
flushTable();
|
|
14189
14562
|
const candidate = current ? `${current}
|
|
14190
14563
|
${line}` : line;
|
|
14191
14564
|
if (candidate.length > limit && current) {
|
|
@@ -14195,6 +14568,7 @@ ${line}` : line;
|
|
|
14195
14568
|
current = candidate;
|
|
14196
14569
|
}
|
|
14197
14570
|
}
|
|
14571
|
+
flushTable();
|
|
14198
14572
|
if (current) chunks.push(current);
|
|
14199
14573
|
return chunks.length > 0 ? chunks : [text];
|
|
14200
14574
|
},
|
|
@@ -14332,10 +14706,10 @@ function json(data) {
|
|
|
14332
14706
|
details: data
|
|
14333
14707
|
};
|
|
14334
14708
|
}
|
|
14335
|
-
function validatePath(
|
|
14336
|
-
if (!
|
|
14337
|
-
if (
|
|
14338
|
-
if (!/^\/[a-zA-Z0-9\-._~:@!$&'()*+,;=/%]+$/.test(
|
|
14709
|
+
function validatePath(path22) {
|
|
14710
|
+
if (!path22.startsWith("/")) return "path \u5FC5\u987B\u4EE5 / \u5F00\u5934";
|
|
14711
|
+
if (path22.includes("..") || path22.includes("//")) return "path \u4E0D\u5141\u8BB8\u5305\u542B .. \u6216 //";
|
|
14712
|
+
if (!/^\/[a-zA-Z0-9\-._~:@!$&'()*+,;=/%]+$/.test(path22) && path22 !== "/") {
|
|
14339
14713
|
return "path \u5305\u542B\u975E\u6CD5\u5B57\u7B26";
|
|
14340
14714
|
}
|
|
14341
14715
|
return null;
|
|
@@ -14643,7 +15017,7 @@ function verifyRuntimeContract(rt) {
|
|
|
14643
15017
|
for (const r of OPTIONAL) {
|
|
14644
15018
|
if (!r.probe(rt)) degraded.push(r.name);
|
|
14645
15019
|
}
|
|
14646
|
-
log3.
|
|
15020
|
+
log3.debug(`openclaw=${version} required=${REQUIRED.length - missing.length}/${REQUIRED.length} degraded=${degraded.length}/${OPTIONAL.length}`);
|
|
14647
15021
|
if (missing.length) {
|
|
14648
15022
|
log3.error(`BROKEN \u2014 missing: ${missing.join(", ")}`);
|
|
14649
15023
|
}
|