@cxyhhhhh/qqbot-cli 0.1.0-dev.202606011703 → 0.1.0-dev.202606011733
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/bin/cli.js +3028 -6
- package/dist/bin/cli.js.map +1 -1
- package/dist/chunk-OX7GNEPM.js +7656 -0
- package/dist/chunk-OX7GNEPM.js.map +1 -0
- package/dist/chunk-PKY53OCO.js +17414 -0
- package/dist/chunk-PKY53OCO.js.map +1 -0
- package/dist/chunk-PLDDJCW6.js +49 -0
- package/dist/chunk-XV7DJAHN.js +50651 -0
- package/dist/chunk-XV7DJAHN.js.map +1 -0
- package/dist/cli-EI5D6LBL.js +16 -0
- package/dist/cli-EI5D6LBL.js.map +1 -0
- package/dist/dist-PHQEAXWU.js +78 -0
- package/dist/dist-PHQEAXWU.js.map +1 -0
- package/dist/main-OVF3FQYW.js +364 -0
- package/dist/main-OVF3FQYW.js.map +1 -0
- package/dist/src/index.js +3 -1
- package/package.json +4 -5
- package/dist/chunk-WRKDI4MF.js +0 -407
- package/dist/chunk-WRKDI4MF.js.map +0 -1
- package/dist/chunk-XIJ6OSLY.js +0 -3654
- package/dist/chunk-XIJ6OSLY.js.map +0 -1
- package/dist/cli-TUC3HG75.js +0 -14
- /package/dist/{cli-TUC3HG75.js.map → chunk-PLDDJCW6.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/constants.js","../node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/buffer-util.js","../node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/limiter.js","../node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/permessage-deflate.js","../node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/validation.js","../node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/receiver.js","../node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/sender.js","../node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/event-target.js","../node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/extension.js","../node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/websocket.js","../node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/stream.js","../node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/subprotocol.js","../node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/websocket-server.js","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/QQBot.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/middleware/types.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/protocol/types.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/protocol/utils/format.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/protocol/api/api-client.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/protocol/api/media-chunked.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/protocol/api/retry.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/protocol/api/routes.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/protocol/api/media.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/protocol/api/messages.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/protocol/api/token.ts","../node_modules/.pnpm/ws@8.21.0/node_modules/ws/wrapper.mjs","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/protocol/gateway/codec.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/protocol/gateway/constants.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/protocol/gateway/event-dispatcher.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/protocol/gateway/reconnect.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/protocol/gateway/gateway-connection.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/protocol/transport/webhook-verify.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/protocol/transport/webhook-server-node.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/protocol/transport/webhook.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/protocol/utils/file-utils.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/protocol/utils/upload-cache.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/streaming.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/middleware/message-filter.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/middleware/content-sanitizer.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/middleware/rate-limiter.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/middleware/concurrency-guard.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/middleware/access-policy.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/middleware/mention-gate.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/middleware/quote-ref.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/middleware/envelope-formatter.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/middleware/slash-command.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/middleware/history-buffer.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/middleware/typing-indicator.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/middleware/error-handler.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/storage/kv-store.ts","../node_modules/.pnpm/@tencent+qqbot-nodejs@0.0.0-dev.e55b99d7/node_modules/@tencent/qqbot-nodejs/src/storage/session-adapter.ts"],"sourcesContent":["'use strict';\n\nconst BINARY_TYPES = ['nodebuffer', 'arraybuffer', 'fragments'];\nconst hasBlob = typeof Blob !== 'undefined';\n\nif (hasBlob) BINARY_TYPES.push('blob');\n\nmodule.exports = {\n BINARY_TYPES,\n CLOSE_TIMEOUT: 30000,\n EMPTY_BUFFER: Buffer.alloc(0),\n GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',\n hasBlob,\n kForOnEventAttribute: Symbol('kIsForOnEventAttribute'),\n kListener: Symbol('kListener'),\n kStatusCode: Symbol('status-code'),\n kWebSocket: Symbol('websocket'),\n NOOP: () => {}\n};\n","'use strict';\n\nconst { EMPTY_BUFFER } = require('./constants');\n\nconst FastBuffer = Buffer[Symbol.species];\n\n/**\n * Merges an array of buffers into a new buffer.\n *\n * @param {Buffer[]} list The array of buffers to concat\n * @param {Number} totalLength The total length of buffers in the list\n * @return {Buffer} The resulting buffer\n * @public\n */\nfunction concat(list, totalLength) {\n if (list.length === 0) return EMPTY_BUFFER;\n if (list.length === 1) return list[0];\n\n const target = Buffer.allocUnsafe(totalLength);\n let offset = 0;\n\n for (let i = 0; i < list.length; i++) {\n const buf = list[i];\n target.set(buf, offset);\n offset += buf.length;\n }\n\n if (offset < totalLength) {\n return new FastBuffer(target.buffer, target.byteOffset, offset);\n }\n\n return target;\n}\n\n/**\n * Masks a buffer using the given mask.\n *\n * @param {Buffer} source The buffer to mask\n * @param {Buffer} mask The mask to use\n * @param {Buffer} output The buffer where to store the result\n * @param {Number} offset The offset at which to start writing\n * @param {Number} length The number of bytes to mask.\n * @public\n */\nfunction _mask(source, mask, output, offset, length) {\n for (let i = 0; i < length; i++) {\n output[offset + i] = source[i] ^ mask[i & 3];\n }\n}\n\n/**\n * Unmasks a buffer using the given mask.\n *\n * @param {Buffer} buffer The buffer to unmask\n * @param {Buffer} mask The mask to use\n * @public\n */\nfunction _unmask(buffer, mask) {\n for (let i = 0; i < buffer.length; i++) {\n buffer[i] ^= mask[i & 3];\n }\n}\n\n/**\n * Converts a buffer to an `ArrayBuffer`.\n *\n * @param {Buffer} buf The buffer to convert\n * @return {ArrayBuffer} Converted buffer\n * @public\n */\nfunction toArrayBuffer(buf) {\n if (buf.length === buf.buffer.byteLength) {\n return buf.buffer;\n }\n\n return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.length);\n}\n\n/**\n * Converts `data` to a `Buffer`.\n *\n * @param {*} data The data to convert\n * @return {Buffer} The buffer\n * @throws {TypeError}\n * @public\n */\nfunction toBuffer(data) {\n toBuffer.readOnly = true;\n\n if (Buffer.isBuffer(data)) return data;\n\n let buf;\n\n if (data instanceof ArrayBuffer) {\n buf = new FastBuffer(data);\n } else if (ArrayBuffer.isView(data)) {\n buf = new FastBuffer(data.buffer, data.byteOffset, data.byteLength);\n } else {\n buf = Buffer.from(data);\n toBuffer.readOnly = false;\n }\n\n return buf;\n}\n\nmodule.exports = {\n concat,\n mask: _mask,\n toArrayBuffer,\n toBuffer,\n unmask: _unmask\n};\n\n/* istanbul ignore else */\nif (!process.env.WS_NO_BUFFER_UTIL) {\n try {\n const bufferUtil = require('bufferutil');\n\n module.exports.mask = function (source, mask, output, offset, length) {\n if (length < 48) _mask(source, mask, output, offset, length);\n else bufferUtil.mask(source, mask, output, offset, length);\n };\n\n module.exports.unmask = function (buffer, mask) {\n if (buffer.length < 32) _unmask(buffer, mask);\n else bufferUtil.unmask(buffer, mask);\n };\n } catch (e) {\n // Continue regardless of the error.\n }\n}\n","'use strict';\n\nconst kDone = Symbol('kDone');\nconst kRun = Symbol('kRun');\n\n/**\n * A very simple job queue with adjustable concurrency. Adapted from\n * https://github.com/STRML/async-limiter\n */\nclass Limiter {\n /**\n * Creates a new `Limiter`.\n *\n * @param {Number} [concurrency=Infinity] The maximum number of jobs allowed\n * to run concurrently\n */\n constructor(concurrency) {\n this[kDone] = () => {\n this.pending--;\n this[kRun]();\n };\n this.concurrency = concurrency || Infinity;\n this.jobs = [];\n this.pending = 0;\n }\n\n /**\n * Adds a job to the queue.\n *\n * @param {Function} job The job to run\n * @public\n */\n add(job) {\n this.jobs.push(job);\n this[kRun]();\n }\n\n /**\n * Removes a job from the queue and runs it if possible.\n *\n * @private\n */\n [kRun]() {\n if (this.pending === this.concurrency) return;\n\n if (this.jobs.length) {\n const job = this.jobs.shift();\n\n this.pending++;\n job(this[kDone]);\n }\n }\n}\n\nmodule.exports = Limiter;\n","'use strict';\n\nconst zlib = require('zlib');\n\nconst bufferUtil = require('./buffer-util');\nconst Limiter = require('./limiter');\nconst { kStatusCode } = require('./constants');\n\nconst FastBuffer = Buffer[Symbol.species];\nconst TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]);\nconst kPerMessageDeflate = Symbol('permessage-deflate');\nconst kTotalLength = Symbol('total-length');\nconst kCallback = Symbol('callback');\nconst kBuffers = Symbol('buffers');\nconst kError = Symbol('error');\n\n//\n// We limit zlib concurrency, which prevents severe memory fragmentation\n// as documented in https://github.com/nodejs/node/issues/8871#issuecomment-250915913\n// and https://github.com/websockets/ws/issues/1202\n//\n// Intentionally global; it's the global thread pool that's an issue.\n//\nlet zlibLimiter;\n\n/**\n * permessage-deflate implementation.\n */\nclass PerMessageDeflate {\n /**\n * Creates a PerMessageDeflate instance.\n *\n * @param {Object} [options] Configuration options\n * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support\n * for, or request, a custom client window size\n * @param {Boolean} [options.clientNoContextTakeover=false] Advertise/\n * acknowledge disabling of client context takeover\n * @param {Number} [options.concurrencyLimit=10] The number of concurrent\n * calls to zlib\n * @param {Boolean} [options.isServer=false] Create the instance in either\n * server or client mode\n * @param {Number} [options.maxPayload=0] The maximum allowed message length\n * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the\n * use of a custom server window size\n * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept\n * disabling of server context takeover\n * @param {Number} [options.threshold=1024] Size (in bytes) below which\n * messages should not be compressed if context takeover is disabled\n * @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on\n * deflate\n * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on\n * inflate\n */\n constructor(options) {\n this._options = options || {};\n this._threshold =\n this._options.threshold !== undefined ? this._options.threshold : 1024;\n this._maxPayload = this._options.maxPayload | 0;\n this._isServer = !!this._options.isServer;\n this._deflate = null;\n this._inflate = null;\n\n this.params = null;\n\n if (!zlibLimiter) {\n const concurrency =\n this._options.concurrencyLimit !== undefined\n ? this._options.concurrencyLimit\n : 10;\n zlibLimiter = new Limiter(concurrency);\n }\n }\n\n /**\n * @type {String}\n */\n static get extensionName() {\n return 'permessage-deflate';\n }\n\n /**\n * Create an extension negotiation offer.\n *\n * @return {Object} Extension parameters\n * @public\n */\n offer() {\n const params = {};\n\n if (this._options.serverNoContextTakeover) {\n params.server_no_context_takeover = true;\n }\n if (this._options.clientNoContextTakeover) {\n params.client_no_context_takeover = true;\n }\n if (this._options.serverMaxWindowBits) {\n params.server_max_window_bits = this._options.serverMaxWindowBits;\n }\n if (this._options.clientMaxWindowBits) {\n params.client_max_window_bits = this._options.clientMaxWindowBits;\n } else if (this._options.clientMaxWindowBits == null) {\n params.client_max_window_bits = true;\n }\n\n return params;\n }\n\n /**\n * Accept an extension negotiation offer/response.\n *\n * @param {Array} configurations The extension negotiation offers/reponse\n * @return {Object} Accepted configuration\n * @public\n */\n accept(configurations) {\n configurations = this.normalizeParams(configurations);\n\n this.params = this._isServer\n ? this.acceptAsServer(configurations)\n : this.acceptAsClient(configurations);\n\n return this.params;\n }\n\n /**\n * Releases all resources used by the extension.\n *\n * @public\n */\n cleanup() {\n if (this._inflate) {\n this._inflate.close();\n this._inflate = null;\n }\n\n if (this._deflate) {\n const callback = this._deflate[kCallback];\n\n this._deflate.close();\n this._deflate = null;\n\n if (callback) {\n callback(\n new Error(\n 'The deflate stream was closed while data was being processed'\n )\n );\n }\n }\n }\n\n /**\n * Accept an extension negotiation offer.\n *\n * @param {Array} offers The extension negotiation offers\n * @return {Object} Accepted configuration\n * @private\n */\n acceptAsServer(offers) {\n const opts = this._options;\n const accepted = offers.find((params) => {\n if (\n (opts.serverNoContextTakeover === false &&\n params.server_no_context_takeover) ||\n (params.server_max_window_bits &&\n (opts.serverMaxWindowBits === false ||\n (typeof opts.serverMaxWindowBits === 'number' &&\n opts.serverMaxWindowBits > params.server_max_window_bits))) ||\n (typeof opts.clientMaxWindowBits === 'number' &&\n !params.client_max_window_bits)\n ) {\n return false;\n }\n\n return true;\n });\n\n if (!accepted) {\n throw new Error('None of the extension offers can be accepted');\n }\n\n if (opts.serverNoContextTakeover) {\n accepted.server_no_context_takeover = true;\n }\n if (opts.clientNoContextTakeover) {\n accepted.client_no_context_takeover = true;\n }\n if (typeof opts.serverMaxWindowBits === 'number') {\n accepted.server_max_window_bits = opts.serverMaxWindowBits;\n }\n if (typeof opts.clientMaxWindowBits === 'number') {\n accepted.client_max_window_bits = opts.clientMaxWindowBits;\n } else if (\n accepted.client_max_window_bits === true ||\n opts.clientMaxWindowBits === false\n ) {\n delete accepted.client_max_window_bits;\n }\n\n return accepted;\n }\n\n /**\n * Accept the extension negotiation response.\n *\n * @param {Array} response The extension negotiation response\n * @return {Object} Accepted configuration\n * @private\n */\n acceptAsClient(response) {\n const params = response[0];\n\n if (\n this._options.clientNoContextTakeover === false &&\n params.client_no_context_takeover\n ) {\n throw new Error('Unexpected parameter \"client_no_context_takeover\"');\n }\n\n if (!params.client_max_window_bits) {\n if (typeof this._options.clientMaxWindowBits === 'number') {\n params.client_max_window_bits = this._options.clientMaxWindowBits;\n }\n } else if (\n this._options.clientMaxWindowBits === false ||\n (typeof this._options.clientMaxWindowBits === 'number' &&\n params.client_max_window_bits > this._options.clientMaxWindowBits)\n ) {\n throw new Error(\n 'Unexpected or invalid parameter \"client_max_window_bits\"'\n );\n }\n\n return params;\n }\n\n /**\n * Normalize parameters.\n *\n * @param {Array} configurations The extension negotiation offers/reponse\n * @return {Array} The offers/response with normalized parameters\n * @private\n */\n normalizeParams(configurations) {\n configurations.forEach((params) => {\n Object.keys(params).forEach((key) => {\n let value = params[key];\n\n if (value.length > 1) {\n throw new Error(`Parameter \"${key}\" must have only a single value`);\n }\n\n value = value[0];\n\n if (key === 'client_max_window_bits') {\n if (value !== true) {\n const num = +value;\n if (!Number.isInteger(num) || num < 8 || num > 15) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n value = num;\n } else if (!this._isServer) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n } else if (key === 'server_max_window_bits') {\n const num = +value;\n if (!Number.isInteger(num) || num < 8 || num > 15) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n value = num;\n } else if (\n key === 'client_no_context_takeover' ||\n key === 'server_no_context_takeover'\n ) {\n if (value !== true) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n } else {\n throw new Error(`Unknown parameter \"${key}\"`);\n }\n\n params[key] = value;\n });\n });\n\n return configurations;\n }\n\n /**\n * Decompress data. Concurrency limited.\n *\n * @param {Buffer} data Compressed data\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @public\n */\n decompress(data, fin, callback) {\n zlibLimiter.add((done) => {\n this._decompress(data, fin, (err, result) => {\n done();\n callback(err, result);\n });\n });\n }\n\n /**\n * Compress data. Concurrency limited.\n *\n * @param {(Buffer|String)} data Data to compress\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @public\n */\n compress(data, fin, callback) {\n zlibLimiter.add((done) => {\n this._compress(data, fin, (err, result) => {\n done();\n callback(err, result);\n });\n });\n }\n\n /**\n * Decompress data.\n *\n * @param {Buffer} data Compressed data\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @private\n */\n _decompress(data, fin, callback) {\n const endpoint = this._isServer ? 'client' : 'server';\n\n if (!this._inflate) {\n const key = `${endpoint}_max_window_bits`;\n const windowBits =\n typeof this.params[key] !== 'number'\n ? zlib.Z_DEFAULT_WINDOWBITS\n : this.params[key];\n\n this._inflate = zlib.createInflateRaw({\n ...this._options.zlibInflateOptions,\n windowBits\n });\n this._inflate[kPerMessageDeflate] = this;\n this._inflate[kTotalLength] = 0;\n this._inflate[kBuffers] = [];\n this._inflate.on('error', inflateOnError);\n this._inflate.on('data', inflateOnData);\n }\n\n this._inflate[kCallback] = callback;\n\n this._inflate.write(data);\n if (fin) this._inflate.write(TRAILER);\n\n this._inflate.flush(() => {\n const err = this._inflate[kError];\n\n if (err) {\n this._inflate.close();\n this._inflate = null;\n callback(err);\n return;\n }\n\n const data = bufferUtil.concat(\n this._inflate[kBuffers],\n this._inflate[kTotalLength]\n );\n\n if (this._inflate._readableState.endEmitted) {\n this._inflate.close();\n this._inflate = null;\n } else {\n this._inflate[kTotalLength] = 0;\n this._inflate[kBuffers] = [];\n\n if (fin && this.params[`${endpoint}_no_context_takeover`]) {\n this._inflate.reset();\n }\n }\n\n callback(null, data);\n });\n }\n\n /**\n * Compress data.\n *\n * @param {(Buffer|String)} data Data to compress\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @private\n */\n _compress(data, fin, callback) {\n const endpoint = this._isServer ? 'server' : 'client';\n\n if (!this._deflate) {\n const key = `${endpoint}_max_window_bits`;\n const windowBits =\n typeof this.params[key] !== 'number'\n ? zlib.Z_DEFAULT_WINDOWBITS\n : this.params[key];\n\n this._deflate = zlib.createDeflateRaw({\n ...this._options.zlibDeflateOptions,\n windowBits\n });\n\n this._deflate[kTotalLength] = 0;\n this._deflate[kBuffers] = [];\n\n this._deflate.on('data', deflateOnData);\n }\n\n this._deflate[kCallback] = callback;\n\n this._deflate.write(data);\n this._deflate.flush(zlib.Z_SYNC_FLUSH, () => {\n if (!this._deflate) {\n //\n // The deflate stream was closed while data was being processed.\n //\n return;\n }\n\n let data = bufferUtil.concat(\n this._deflate[kBuffers],\n this._deflate[kTotalLength]\n );\n\n if (fin) {\n data = new FastBuffer(data.buffer, data.byteOffset, data.length - 4);\n }\n\n //\n // Ensure that the callback will not be called again in\n // `PerMessageDeflate#cleanup()`.\n //\n this._deflate[kCallback] = null;\n\n this._deflate[kTotalLength] = 0;\n this._deflate[kBuffers] = [];\n\n if (fin && this.params[`${endpoint}_no_context_takeover`]) {\n this._deflate.reset();\n }\n\n callback(null, data);\n });\n }\n}\n\nmodule.exports = PerMessageDeflate;\n\n/**\n * The listener of the `zlib.DeflateRaw` stream `'data'` event.\n *\n * @param {Buffer} chunk A chunk of data\n * @private\n */\nfunction deflateOnData(chunk) {\n this[kBuffers].push(chunk);\n this[kTotalLength] += chunk.length;\n}\n\n/**\n * The listener of the `zlib.InflateRaw` stream `'data'` event.\n *\n * @param {Buffer} chunk A chunk of data\n * @private\n */\nfunction inflateOnData(chunk) {\n this[kTotalLength] += chunk.length;\n\n if (\n this[kPerMessageDeflate]._maxPayload < 1 ||\n this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload\n ) {\n this[kBuffers].push(chunk);\n return;\n }\n\n this[kError] = new RangeError('Max payload size exceeded');\n this[kError].code = 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH';\n this[kError][kStatusCode] = 1009;\n this.removeListener('data', inflateOnData);\n\n //\n // The choice to employ `zlib.reset()` over `zlib.close()` is dictated by the\n // fact that in Node.js versions prior to 13.10.0, the callback for\n // `zlib.flush()` is not called if `zlib.close()` is used. Utilizing\n // `zlib.reset()` ensures that either the callback is invoked or an error is\n // emitted.\n //\n this.reset();\n}\n\n/**\n * The listener of the `zlib.InflateRaw` stream `'error'` event.\n *\n * @param {Error} err The emitted error\n * @private\n */\nfunction inflateOnError(err) {\n //\n // There is no need to call `Zlib#close()` as the handle is automatically\n // closed when an error is emitted.\n //\n this[kPerMessageDeflate]._inflate = null;\n\n if (this[kError]) {\n this[kCallback](this[kError]);\n return;\n }\n\n err[kStatusCode] = 1007;\n this[kCallback](err);\n}\n","'use strict';\n\nconst { isUtf8 } = require('buffer');\n\nconst { hasBlob } = require('./constants');\n\n//\n// Allowed token characters:\n//\n// '!', '#', '$', '%', '&', ''', '*', '+', '-',\n// '.', 0-9, A-Z, '^', '_', '`', a-z, '|', '~'\n//\n// tokenChars[32] === 0 // ' '\n// tokenChars[33] === 1 // '!'\n// tokenChars[34] === 0 // '\"'\n// ...\n//\n// prettier-ignore\nconst tokenChars = [\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31\n 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32 - 47\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63\n 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80 - 95\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 // 112 - 127\n];\n\n/**\n * Checks if a status code is allowed in a close frame.\n *\n * @param {Number} code The status code\n * @return {Boolean} `true` if the status code is valid, else `false`\n * @public\n */\nfunction isValidStatusCode(code) {\n return (\n (code >= 1000 &&\n code <= 1014 &&\n code !== 1004 &&\n code !== 1005 &&\n code !== 1006) ||\n (code >= 3000 && code <= 4999)\n );\n}\n\n/**\n * Checks if a given buffer contains only correct UTF-8.\n * Ported from https://www.cl.cam.ac.uk/%7Emgk25/ucs/utf8_check.c by\n * Markus Kuhn.\n *\n * @param {Buffer} buf The buffer to check\n * @return {Boolean} `true` if `buf` contains only correct UTF-8, else `false`\n * @public\n */\nfunction _isValidUTF8(buf) {\n const len = buf.length;\n let i = 0;\n\n while (i < len) {\n if ((buf[i] & 0x80) === 0) {\n // 0xxxxxxx\n i++;\n } else if ((buf[i] & 0xe0) === 0xc0) {\n // 110xxxxx 10xxxxxx\n if (\n i + 1 === len ||\n (buf[i + 1] & 0xc0) !== 0x80 ||\n (buf[i] & 0xfe) === 0xc0 // Overlong\n ) {\n return false;\n }\n\n i += 2;\n } else if ((buf[i] & 0xf0) === 0xe0) {\n // 1110xxxx 10xxxxxx 10xxxxxx\n if (\n i + 2 >= len ||\n (buf[i + 1] & 0xc0) !== 0x80 ||\n (buf[i + 2] & 0xc0) !== 0x80 ||\n (buf[i] === 0xe0 && (buf[i + 1] & 0xe0) === 0x80) || // Overlong\n (buf[i] === 0xed && (buf[i + 1] & 0xe0) === 0xa0) // Surrogate (U+D800 - U+DFFF)\n ) {\n return false;\n }\n\n i += 3;\n } else if ((buf[i] & 0xf8) === 0xf0) {\n // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx\n if (\n i + 3 >= len ||\n (buf[i + 1] & 0xc0) !== 0x80 ||\n (buf[i + 2] & 0xc0) !== 0x80 ||\n (buf[i + 3] & 0xc0) !== 0x80 ||\n (buf[i] === 0xf0 && (buf[i + 1] & 0xf0) === 0x80) || // Overlong\n (buf[i] === 0xf4 && buf[i + 1] > 0x8f) ||\n buf[i] > 0xf4 // > U+10FFFF\n ) {\n return false;\n }\n\n i += 4;\n } else {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Determines whether a value is a `Blob`.\n *\n * @param {*} value The value to be tested\n * @return {Boolean} `true` if `value` is a `Blob`, else `false`\n * @private\n */\nfunction isBlob(value) {\n return (\n hasBlob &&\n typeof value === 'object' &&\n typeof value.arrayBuffer === 'function' &&\n typeof value.type === 'string' &&\n typeof value.stream === 'function' &&\n (value[Symbol.toStringTag] === 'Blob' ||\n value[Symbol.toStringTag] === 'File')\n );\n}\n\nmodule.exports = {\n isBlob,\n isValidStatusCode,\n isValidUTF8: _isValidUTF8,\n tokenChars\n};\n\nif (isUtf8) {\n module.exports.isValidUTF8 = function (buf) {\n return buf.length < 24 ? _isValidUTF8(buf) : isUtf8(buf);\n };\n} /* istanbul ignore else */ else if (!process.env.WS_NO_UTF_8_VALIDATE) {\n try {\n const isValidUTF8 = require('utf-8-validate');\n\n module.exports.isValidUTF8 = function (buf) {\n return buf.length < 32 ? _isValidUTF8(buf) : isValidUTF8(buf);\n };\n } catch (e) {\n // Continue regardless of the error.\n }\n}\n","'use strict';\n\nconst { Writable } = require('stream');\n\nconst PerMessageDeflate = require('./permessage-deflate');\nconst {\n BINARY_TYPES,\n EMPTY_BUFFER,\n kStatusCode,\n kWebSocket\n} = require('./constants');\nconst { concat, toArrayBuffer, unmask } = require('./buffer-util');\nconst { isValidStatusCode, isValidUTF8 } = require('./validation');\n\nconst FastBuffer = Buffer[Symbol.species];\n\nconst GET_INFO = 0;\nconst GET_PAYLOAD_LENGTH_16 = 1;\nconst GET_PAYLOAD_LENGTH_64 = 2;\nconst GET_MASK = 3;\nconst GET_DATA = 4;\nconst INFLATING = 5;\nconst DEFER_EVENT = 6;\n\n/**\n * HyBi Receiver implementation.\n *\n * @extends Writable\n */\nclass Receiver extends Writable {\n /**\n * Creates a Receiver instance.\n *\n * @param {Object} [options] Options object\n * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether\n * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted\n * multiple times in the same tick\n * @param {String} [options.binaryType=nodebuffer] The type for binary data\n * @param {Object} [options.extensions] An object containing the negotiated\n * extensions\n * @param {Boolean} [options.isServer=false] Specifies whether to operate in\n * client or server mode\n * @param {Number} [options.maxBufferedChunks=0] The maximum number of\n * buffered data chunks\n * @param {Number} [options.maxFragments=0] The maximum number of message\n * fragments\n * @param {Number} [options.maxPayload=0] The maximum allowed message length\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n */\n constructor(options = {}) {\n super();\n\n this._allowSynchronousEvents =\n options.allowSynchronousEvents !== undefined\n ? options.allowSynchronousEvents\n : true;\n this._binaryType = options.binaryType || BINARY_TYPES[0];\n this._extensions = options.extensions || {};\n this._isServer = !!options.isServer;\n this._maxBufferedChunks = options.maxBufferedChunks | 0;\n this._maxFragments = options.maxFragments | 0;\n this._maxPayload = options.maxPayload | 0;\n this._skipUTF8Validation = !!options.skipUTF8Validation;\n this[kWebSocket] = undefined;\n\n this._bufferedBytes = 0;\n this._buffers = [];\n\n this._compressed = false;\n this._payloadLength = 0;\n this._mask = undefined;\n this._fragmented = 0;\n this._masked = false;\n this._fin = false;\n this._opcode = 0;\n\n this._totalPayloadLength = 0;\n this._messageLength = 0;\n this._fragments = [];\n\n this._errored = false;\n this._loop = false;\n this._state = GET_INFO;\n }\n\n /**\n * Implements `Writable.prototype._write()`.\n *\n * @param {Buffer} chunk The chunk of data to write\n * @param {String} encoding The character encoding of `chunk`\n * @param {Function} cb Callback\n * @private\n */\n _write(chunk, encoding, cb) {\n if (this._opcode === 0x08 && this._state == GET_INFO) return cb();\n\n if (\n this._maxBufferedChunks > 0 &&\n this._buffers.length >= this._maxBufferedChunks\n ) {\n cb(\n this.createError(\n RangeError,\n 'Too many buffered chunks',\n false,\n 1008,\n 'WS_ERR_TOO_MANY_BUFFERED_PARTS'\n )\n );\n return;\n }\n\n this._bufferedBytes += chunk.length;\n this._buffers.push(chunk);\n this.startLoop(cb);\n }\n\n /**\n * Consumes `n` bytes from the buffered data.\n *\n * @param {Number} n The number of bytes to consume\n * @return {Buffer} The consumed bytes\n * @private\n */\n consume(n) {\n this._bufferedBytes -= n;\n\n if (n === this._buffers[0].length) return this._buffers.shift();\n\n if (n < this._buffers[0].length) {\n const buf = this._buffers[0];\n this._buffers[0] = new FastBuffer(\n buf.buffer,\n buf.byteOffset + n,\n buf.length - n\n );\n\n return new FastBuffer(buf.buffer, buf.byteOffset, n);\n }\n\n const dst = Buffer.allocUnsafe(n);\n\n do {\n const buf = this._buffers[0];\n const offset = dst.length - n;\n\n if (n >= buf.length) {\n dst.set(this._buffers.shift(), offset);\n } else {\n dst.set(new Uint8Array(buf.buffer, buf.byteOffset, n), offset);\n this._buffers[0] = new FastBuffer(\n buf.buffer,\n buf.byteOffset + n,\n buf.length - n\n );\n }\n\n n -= buf.length;\n } while (n > 0);\n\n return dst;\n }\n\n /**\n * Starts the parsing loop.\n *\n * @param {Function} cb Callback\n * @private\n */\n startLoop(cb) {\n this._loop = true;\n\n do {\n switch (this._state) {\n case GET_INFO:\n this.getInfo(cb);\n break;\n case GET_PAYLOAD_LENGTH_16:\n this.getPayloadLength16(cb);\n break;\n case GET_PAYLOAD_LENGTH_64:\n this.getPayloadLength64(cb);\n break;\n case GET_MASK:\n this.getMask();\n break;\n case GET_DATA:\n this.getData(cb);\n break;\n case INFLATING:\n case DEFER_EVENT:\n this._loop = false;\n return;\n }\n } while (this._loop);\n\n if (!this._errored) cb();\n }\n\n /**\n * Reads the first two bytes of a frame.\n *\n * @param {Function} cb Callback\n * @private\n */\n getInfo(cb) {\n if (this._bufferedBytes < 2) {\n this._loop = false;\n return;\n }\n\n const buf = this.consume(2);\n\n if ((buf[0] & 0x30) !== 0x00) {\n const error = this.createError(\n RangeError,\n 'RSV2 and RSV3 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_2_3'\n );\n\n cb(error);\n return;\n }\n\n const compressed = (buf[0] & 0x40) === 0x40;\n\n if (compressed && !this._extensions[PerMessageDeflate.extensionName]) {\n const error = this.createError(\n RangeError,\n 'RSV1 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_1'\n );\n\n cb(error);\n return;\n }\n\n this._fin = (buf[0] & 0x80) === 0x80;\n this._opcode = buf[0] & 0x0f;\n this._payloadLength = buf[1] & 0x7f;\n\n if (this._opcode === 0x00) {\n if (compressed) {\n const error = this.createError(\n RangeError,\n 'RSV1 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_1'\n );\n\n cb(error);\n return;\n }\n\n if (!this._fragmented) {\n const error = this.createError(\n RangeError,\n 'invalid opcode 0',\n true,\n 1002,\n 'WS_ERR_INVALID_OPCODE'\n );\n\n cb(error);\n return;\n }\n\n this._opcode = this._fragmented;\n } else if (this._opcode === 0x01 || this._opcode === 0x02) {\n if (this._fragmented) {\n const error = this.createError(\n RangeError,\n `invalid opcode ${this._opcode}`,\n true,\n 1002,\n 'WS_ERR_INVALID_OPCODE'\n );\n\n cb(error);\n return;\n }\n\n this._compressed = compressed;\n } else if (this._opcode > 0x07 && this._opcode < 0x0b) {\n if (!this._fin) {\n const error = this.createError(\n RangeError,\n 'FIN must be set',\n true,\n 1002,\n 'WS_ERR_EXPECTED_FIN'\n );\n\n cb(error);\n return;\n }\n\n if (compressed) {\n const error = this.createError(\n RangeError,\n 'RSV1 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_1'\n );\n\n cb(error);\n return;\n }\n\n if (\n this._payloadLength > 0x7d ||\n (this._opcode === 0x08 && this._payloadLength === 1)\n ) {\n const error = this.createError(\n RangeError,\n `invalid payload length ${this._payloadLength}`,\n true,\n 1002,\n 'WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH'\n );\n\n cb(error);\n return;\n }\n } else {\n const error = this.createError(\n RangeError,\n `invalid opcode ${this._opcode}`,\n true,\n 1002,\n 'WS_ERR_INVALID_OPCODE'\n );\n\n cb(error);\n return;\n }\n\n if (!this._fin && !this._fragmented) this._fragmented = this._opcode;\n this._masked = (buf[1] & 0x80) === 0x80;\n\n if (this._isServer) {\n if (!this._masked) {\n const error = this.createError(\n RangeError,\n 'MASK must be set',\n true,\n 1002,\n 'WS_ERR_EXPECTED_MASK'\n );\n\n cb(error);\n return;\n }\n } else if (this._masked) {\n const error = this.createError(\n RangeError,\n 'MASK must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_MASK'\n );\n\n cb(error);\n return;\n }\n\n if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16;\n else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64;\n else this.haveLength(cb);\n }\n\n /**\n * Gets extended payload length (7+16).\n *\n * @param {Function} cb Callback\n * @private\n */\n getPayloadLength16(cb) {\n if (this._bufferedBytes < 2) {\n this._loop = false;\n return;\n }\n\n this._payloadLength = this.consume(2).readUInt16BE(0);\n this.haveLength(cb);\n }\n\n /**\n * Gets extended payload length (7+64).\n *\n * @param {Function} cb Callback\n * @private\n */\n getPayloadLength64(cb) {\n if (this._bufferedBytes < 8) {\n this._loop = false;\n return;\n }\n\n const buf = this.consume(8);\n const num = buf.readUInt32BE(0);\n\n //\n // The maximum safe integer in JavaScript is 2^53 - 1. An error is returned\n // if payload length is greater than this number.\n //\n if (num > Math.pow(2, 53 - 32) - 1) {\n const error = this.createError(\n RangeError,\n 'Unsupported WebSocket frame: payload length > 2^53 - 1',\n false,\n 1009,\n 'WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH'\n );\n\n cb(error);\n return;\n }\n\n this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4);\n this.haveLength(cb);\n }\n\n /**\n * Payload length has been read.\n *\n * @param {Function} cb Callback\n * @private\n */\n haveLength(cb) {\n if (this._payloadLength && this._opcode < 0x08) {\n this._totalPayloadLength += this._payloadLength;\n if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) {\n const error = this.createError(\n RangeError,\n 'Max payload size exceeded',\n false,\n 1009,\n 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'\n );\n\n cb(error);\n return;\n }\n }\n\n if (this._masked) this._state = GET_MASK;\n else this._state = GET_DATA;\n }\n\n /**\n * Reads mask bytes.\n *\n * @private\n */\n getMask() {\n if (this._bufferedBytes < 4) {\n this._loop = false;\n return;\n }\n\n this._mask = this.consume(4);\n this._state = GET_DATA;\n }\n\n /**\n * Reads data bytes.\n *\n * @param {Function} cb Callback\n * @private\n */\n getData(cb) {\n let data = EMPTY_BUFFER;\n\n if (this._payloadLength) {\n if (this._bufferedBytes < this._payloadLength) {\n this._loop = false;\n return;\n }\n\n data = this.consume(this._payloadLength);\n\n if (\n this._masked &&\n (this._mask[0] | this._mask[1] | this._mask[2] | this._mask[3]) !== 0\n ) {\n unmask(data, this._mask);\n }\n }\n\n if (this._opcode > 0x07) {\n this.controlMessage(data, cb);\n return;\n }\n\n if (this._compressed) {\n this._state = INFLATING;\n this.decompress(data, cb);\n return;\n }\n\n if (data.length) {\n if (\n this._maxFragments > 0 &&\n this._fragments.length >= this._maxFragments\n ) {\n const error = this.createError(\n RangeError,\n 'Too many message fragments',\n false,\n 1008,\n 'WS_ERR_TOO_MANY_BUFFERED_PARTS'\n );\n\n cb(error);\n return;\n }\n\n //\n // This message is not compressed so its length is the sum of the payload\n // length of all fragments.\n //\n this._messageLength = this._totalPayloadLength;\n this._fragments.push(data);\n }\n\n this.dataMessage(cb);\n }\n\n /**\n * Decompresses data.\n *\n * @param {Buffer} data Compressed data\n * @param {Function} cb Callback\n * @private\n */\n decompress(data, cb) {\n const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];\n\n perMessageDeflate.decompress(data, this._fin, (err, buf) => {\n if (err) return cb(err);\n\n if (buf.length) {\n this._messageLength += buf.length;\n if (this._messageLength > this._maxPayload && this._maxPayload > 0) {\n const error = this.createError(\n RangeError,\n 'Max payload size exceeded',\n false,\n 1009,\n 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'\n );\n\n cb(error);\n return;\n }\n\n if (\n this._maxFragments > 0 &&\n this._fragments.length >= this._maxFragments\n ) {\n const error = this.createError(\n RangeError,\n 'Too many message fragments',\n false,\n 1008,\n 'WS_ERR_TOO_MANY_BUFFERED_PARTS'\n );\n\n cb(error);\n return;\n }\n\n this._fragments.push(buf);\n }\n\n this.dataMessage(cb);\n if (this._state === GET_INFO) this.startLoop(cb);\n });\n }\n\n /**\n * Handles a data message.\n *\n * @param {Function} cb Callback\n * @private\n */\n dataMessage(cb) {\n if (!this._fin) {\n this._state = GET_INFO;\n return;\n }\n\n const messageLength = this._messageLength;\n const fragments = this._fragments;\n\n this._totalPayloadLength = 0;\n this._messageLength = 0;\n this._fragmented = 0;\n this._fragments = [];\n\n if (this._opcode === 2) {\n let data;\n\n if (this._binaryType === 'nodebuffer') {\n data = concat(fragments, messageLength);\n } else if (this._binaryType === 'arraybuffer') {\n data = toArrayBuffer(concat(fragments, messageLength));\n } else if (this._binaryType === 'blob') {\n data = new Blob(fragments);\n } else {\n data = fragments;\n }\n\n if (this._allowSynchronousEvents) {\n this.emit('message', data, true);\n this._state = GET_INFO;\n } else {\n this._state = DEFER_EVENT;\n setImmediate(() => {\n this.emit('message', data, true);\n this._state = GET_INFO;\n this.startLoop(cb);\n });\n }\n } else {\n const buf = concat(fragments, messageLength);\n\n if (!this._skipUTF8Validation && !isValidUTF8(buf)) {\n const error = this.createError(\n Error,\n 'invalid UTF-8 sequence',\n true,\n 1007,\n 'WS_ERR_INVALID_UTF8'\n );\n\n cb(error);\n return;\n }\n\n if (this._state === INFLATING || this._allowSynchronousEvents) {\n this.emit('message', buf, false);\n this._state = GET_INFO;\n } else {\n this._state = DEFER_EVENT;\n setImmediate(() => {\n this.emit('message', buf, false);\n this._state = GET_INFO;\n this.startLoop(cb);\n });\n }\n }\n }\n\n /**\n * Handles a control message.\n *\n * @param {Buffer} data Data to handle\n * @return {(Error|RangeError|undefined)} A possible error\n * @private\n */\n controlMessage(data, cb) {\n if (this._opcode === 0x08) {\n if (data.length === 0) {\n this._loop = false;\n this.emit('conclude', 1005, EMPTY_BUFFER);\n this.end();\n } else {\n const code = data.readUInt16BE(0);\n\n if (!isValidStatusCode(code)) {\n const error = this.createError(\n RangeError,\n `invalid status code ${code}`,\n true,\n 1002,\n 'WS_ERR_INVALID_CLOSE_CODE'\n );\n\n cb(error);\n return;\n }\n\n const buf = new FastBuffer(\n data.buffer,\n data.byteOffset + 2,\n data.length - 2\n );\n\n if (!this._skipUTF8Validation && !isValidUTF8(buf)) {\n const error = this.createError(\n Error,\n 'invalid UTF-8 sequence',\n true,\n 1007,\n 'WS_ERR_INVALID_UTF8'\n );\n\n cb(error);\n return;\n }\n\n this._loop = false;\n this.emit('conclude', code, buf);\n this.end();\n }\n\n this._state = GET_INFO;\n return;\n }\n\n if (this._allowSynchronousEvents) {\n this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data);\n this._state = GET_INFO;\n } else {\n this._state = DEFER_EVENT;\n setImmediate(() => {\n this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data);\n this._state = GET_INFO;\n this.startLoop(cb);\n });\n }\n }\n\n /**\n * Builds an error object.\n *\n * @param {function(new:Error|RangeError)} ErrorCtor The error constructor\n * @param {String} message The error message\n * @param {Boolean} prefix Specifies whether or not to add a default prefix to\n * `message`\n * @param {Number} statusCode The status code\n * @param {String} errorCode The exposed error code\n * @return {(Error|RangeError)} The error\n * @private\n */\n createError(ErrorCtor, message, prefix, statusCode, errorCode) {\n this._loop = false;\n this._errored = true;\n\n const err = new ErrorCtor(\n prefix ? `Invalid WebSocket frame: ${message}` : message\n );\n\n Error.captureStackTrace(err, this.createError);\n err.code = errorCode;\n err[kStatusCode] = statusCode;\n return err;\n }\n}\n\nmodule.exports = Receiver;\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^Duplex\" }] */\n\n'use strict';\n\nconst { Duplex } = require('stream');\nconst { randomFillSync } = require('crypto');\nconst {\n types: { isUint8Array }\n} = require('util');\n\nconst PerMessageDeflate = require('./permessage-deflate');\nconst { EMPTY_BUFFER, kWebSocket, NOOP } = require('./constants');\nconst { isBlob, isValidStatusCode } = require('./validation');\nconst { mask: applyMask, toBuffer } = require('./buffer-util');\n\nconst kByteLength = Symbol('kByteLength');\nconst maskBuffer = Buffer.alloc(4);\nconst RANDOM_POOL_SIZE = 8 * 1024;\nlet randomPool;\nlet randomPoolPointer = RANDOM_POOL_SIZE;\n\nconst DEFAULT = 0;\nconst DEFLATING = 1;\nconst GET_BLOB_DATA = 2;\n\n/**\n * HyBi Sender implementation.\n */\nclass Sender {\n /**\n * Creates a Sender instance.\n *\n * @param {Duplex} socket The connection socket\n * @param {Object} [extensions] An object containing the negotiated extensions\n * @param {Function} [generateMask] The function used to generate the masking\n * key\n */\n constructor(socket, extensions, generateMask) {\n this._extensions = extensions || {};\n\n if (generateMask) {\n this._generateMask = generateMask;\n this._maskBuffer = Buffer.alloc(4);\n }\n\n this._socket = socket;\n\n this._firstFragment = true;\n this._compress = false;\n\n this._bufferedBytes = 0;\n this._queue = [];\n this._state = DEFAULT;\n this.onerror = NOOP;\n this[kWebSocket] = undefined;\n }\n\n /**\n * Frames a piece of data according to the HyBi WebSocket protocol.\n *\n * @param {(Buffer|String)} data The data to frame\n * @param {Object} options Options object\n * @param {Boolean} [options.fin=false] Specifies whether or not to set the\n * FIN bit\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Buffer} [options.maskBuffer] The buffer used to store the masking\n * key\n * @param {Number} options.opcode The opcode\n * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be\n * modified\n * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the\n * RSV1 bit\n * @return {(Buffer|String)[]} The framed data\n * @public\n */\n static frame(data, options) {\n let mask;\n let merge = false;\n let offset = 2;\n let skipMasking = false;\n\n if (options.mask) {\n mask = options.maskBuffer || maskBuffer;\n\n if (options.generateMask) {\n options.generateMask(mask);\n } else {\n if (randomPoolPointer === RANDOM_POOL_SIZE) {\n /* istanbul ignore else */\n if (randomPool === undefined) {\n //\n // This is lazily initialized because server-sent frames must not\n // be masked so it may never be used.\n //\n randomPool = Buffer.alloc(RANDOM_POOL_SIZE);\n }\n\n randomFillSync(randomPool, 0, RANDOM_POOL_SIZE);\n randomPoolPointer = 0;\n }\n\n mask[0] = randomPool[randomPoolPointer++];\n mask[1] = randomPool[randomPoolPointer++];\n mask[2] = randomPool[randomPoolPointer++];\n mask[3] = randomPool[randomPoolPointer++];\n }\n\n skipMasking = (mask[0] | mask[1] | mask[2] | mask[3]) === 0;\n offset = 6;\n }\n\n let dataLength;\n\n if (typeof data === 'string') {\n if (\n (!options.mask || skipMasking) &&\n options[kByteLength] !== undefined\n ) {\n dataLength = options[kByteLength];\n } else {\n data = Buffer.from(data);\n dataLength = data.length;\n }\n } else {\n dataLength = data.length;\n merge = options.mask && options.readOnly && !skipMasking;\n }\n\n let payloadLength = dataLength;\n\n if (dataLength >= 65536) {\n offset += 8;\n payloadLength = 127;\n } else if (dataLength > 125) {\n offset += 2;\n payloadLength = 126;\n }\n\n const target = Buffer.allocUnsafe(merge ? dataLength + offset : offset);\n\n target[0] = options.fin ? options.opcode | 0x80 : options.opcode;\n if (options.rsv1) target[0] |= 0x40;\n\n target[1] = payloadLength;\n\n if (payloadLength === 126) {\n target.writeUInt16BE(dataLength, 2);\n } else if (payloadLength === 127) {\n target[2] = target[3] = 0;\n target.writeUIntBE(dataLength, 4, 6);\n }\n\n if (!options.mask) return [target, data];\n\n target[1] |= 0x80;\n target[offset - 4] = mask[0];\n target[offset - 3] = mask[1];\n target[offset - 2] = mask[2];\n target[offset - 1] = mask[3];\n\n if (skipMasking) return [target, data];\n\n if (merge) {\n applyMask(data, mask, target, offset, dataLength);\n return [target];\n }\n\n applyMask(data, mask, data, 0, dataLength);\n return [target, data];\n }\n\n /**\n * Sends a close message to the other peer.\n *\n * @param {Number} [code] The status code component of the body\n * @param {(String|Buffer)} [data] The message component of the body\n * @param {Boolean} [mask=false] Specifies whether or not to mask the message\n * @param {Function} [cb] Callback\n * @public\n */\n close(code, data, mask, cb) {\n let buf;\n\n if (code === undefined) {\n buf = EMPTY_BUFFER;\n } else if (typeof code !== 'number' || !isValidStatusCode(code)) {\n throw new TypeError('First argument must be a valid error code number');\n } else if (data === undefined || !data.length) {\n buf = Buffer.allocUnsafe(2);\n buf.writeUInt16BE(code, 0);\n } else {\n const length = Buffer.byteLength(data);\n\n if (length > 123) {\n throw new RangeError('The message must not be greater than 123 bytes');\n }\n\n buf = Buffer.allocUnsafe(2 + length);\n buf.writeUInt16BE(code, 0);\n\n if (typeof data === 'string') {\n buf.write(data, 2);\n } else if (isUint8Array(data)) {\n buf.set(data, 2);\n } else {\n throw new TypeError('Second argument must be a string or a Uint8Array');\n }\n }\n\n const options = {\n [kByteLength]: buf.length,\n fin: true,\n generateMask: this._generateMask,\n mask,\n maskBuffer: this._maskBuffer,\n opcode: 0x08,\n readOnly: false,\n rsv1: false\n };\n\n if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, buf, false, options, cb]);\n } else {\n this.sendFrame(Sender.frame(buf, options), cb);\n }\n }\n\n /**\n * Sends a ping message to the other peer.\n *\n * @param {*} data The message to send\n * @param {Boolean} [mask=false] Specifies whether or not to mask `data`\n * @param {Function} [cb] Callback\n * @public\n */\n ping(data, mask, cb) {\n let byteLength;\n let readOnly;\n\n if (typeof data === 'string') {\n byteLength = Buffer.byteLength(data);\n readOnly = false;\n } else if (isBlob(data)) {\n byteLength = data.size;\n readOnly = false;\n } else {\n data = toBuffer(data);\n byteLength = data.length;\n readOnly = toBuffer.readOnly;\n }\n\n if (byteLength > 125) {\n throw new RangeError('The data size must not be greater than 125 bytes');\n }\n\n const options = {\n [kByteLength]: byteLength,\n fin: true,\n generateMask: this._generateMask,\n mask,\n maskBuffer: this._maskBuffer,\n opcode: 0x09,\n readOnly,\n rsv1: false\n };\n\n if (isBlob(data)) {\n if (this._state !== DEFAULT) {\n this.enqueue([this.getBlobData, data, false, options, cb]);\n } else {\n this.getBlobData(data, false, options, cb);\n }\n } else if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, data, false, options, cb]);\n } else {\n this.sendFrame(Sender.frame(data, options), cb);\n }\n }\n\n /**\n * Sends a pong message to the other peer.\n *\n * @param {*} data The message to send\n * @param {Boolean} [mask=false] Specifies whether or not to mask `data`\n * @param {Function} [cb] Callback\n * @public\n */\n pong(data, mask, cb) {\n let byteLength;\n let readOnly;\n\n if (typeof data === 'string') {\n byteLength = Buffer.byteLength(data);\n readOnly = false;\n } else if (isBlob(data)) {\n byteLength = data.size;\n readOnly = false;\n } else {\n data = toBuffer(data);\n byteLength = data.length;\n readOnly = toBuffer.readOnly;\n }\n\n if (byteLength > 125) {\n throw new RangeError('The data size must not be greater than 125 bytes');\n }\n\n const options = {\n [kByteLength]: byteLength,\n fin: true,\n generateMask: this._generateMask,\n mask,\n maskBuffer: this._maskBuffer,\n opcode: 0x0a,\n readOnly,\n rsv1: false\n };\n\n if (isBlob(data)) {\n if (this._state !== DEFAULT) {\n this.enqueue([this.getBlobData, data, false, options, cb]);\n } else {\n this.getBlobData(data, false, options, cb);\n }\n } else if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, data, false, options, cb]);\n } else {\n this.sendFrame(Sender.frame(data, options), cb);\n }\n }\n\n /**\n * Sends a data message to the other peer.\n *\n * @param {*} data The message to send\n * @param {Object} options Options object\n * @param {Boolean} [options.binary=false] Specifies whether `data` is binary\n * or text\n * @param {Boolean} [options.compress=false] Specifies whether or not to\n * compress `data`\n * @param {Boolean} [options.fin=false] Specifies whether the fragment is the\n * last one\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Function} [cb] Callback\n * @public\n */\n send(data, options, cb) {\n const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];\n let opcode = options.binary ? 2 : 1;\n let rsv1 = options.compress;\n\n let byteLength;\n let readOnly;\n\n if (typeof data === 'string') {\n byteLength = Buffer.byteLength(data);\n readOnly = false;\n } else if (isBlob(data)) {\n byteLength = data.size;\n readOnly = false;\n } else {\n data = toBuffer(data);\n byteLength = data.length;\n readOnly = toBuffer.readOnly;\n }\n\n if (this._firstFragment) {\n this._firstFragment = false;\n if (\n rsv1 &&\n perMessageDeflate &&\n perMessageDeflate.params[\n perMessageDeflate._isServer\n ? 'server_no_context_takeover'\n : 'client_no_context_takeover'\n ]\n ) {\n rsv1 = byteLength >= perMessageDeflate._threshold;\n }\n this._compress = rsv1;\n } else {\n rsv1 = false;\n opcode = 0;\n }\n\n if (options.fin) this._firstFragment = true;\n\n const opts = {\n [kByteLength]: byteLength,\n fin: options.fin,\n generateMask: this._generateMask,\n mask: options.mask,\n maskBuffer: this._maskBuffer,\n opcode,\n readOnly,\n rsv1\n };\n\n if (isBlob(data)) {\n if (this._state !== DEFAULT) {\n this.enqueue([this.getBlobData, data, this._compress, opts, cb]);\n } else {\n this.getBlobData(data, this._compress, opts, cb);\n }\n } else if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, data, this._compress, opts, cb]);\n } else {\n this.dispatch(data, this._compress, opts, cb);\n }\n }\n\n /**\n * Gets the contents of a blob as binary data.\n *\n * @param {Blob} blob The blob\n * @param {Boolean} [compress=false] Specifies whether or not to compress\n * the data\n * @param {Object} options Options object\n * @param {Boolean} [options.fin=false] Specifies whether or not to set the\n * FIN bit\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Buffer} [options.maskBuffer] The buffer used to store the masking\n * key\n * @param {Number} options.opcode The opcode\n * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be\n * modified\n * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the\n * RSV1 bit\n * @param {Function} [cb] Callback\n * @private\n */\n getBlobData(blob, compress, options, cb) {\n this._bufferedBytes += options[kByteLength];\n this._state = GET_BLOB_DATA;\n\n blob\n .arrayBuffer()\n .then((arrayBuffer) => {\n if (this._socket.destroyed) {\n const err = new Error(\n 'The socket was closed while the blob was being read'\n );\n\n //\n // `callCallbacks` is called in the next tick to ensure that errors\n // that might be thrown in the callbacks behave like errors thrown\n // outside the promise chain.\n //\n process.nextTick(callCallbacks, this, err, cb);\n return;\n }\n\n this._bufferedBytes -= options[kByteLength];\n const data = toBuffer(arrayBuffer);\n\n if (!compress) {\n this._state = DEFAULT;\n this.sendFrame(Sender.frame(data, options), cb);\n this.dequeue();\n } else {\n this.dispatch(data, compress, options, cb);\n }\n })\n .catch((err) => {\n //\n // `onError` is called in the next tick for the same reason that\n // `callCallbacks` above is.\n //\n process.nextTick(onError, this, err, cb);\n });\n }\n\n /**\n * Dispatches a message.\n *\n * @param {(Buffer|String)} data The message to send\n * @param {Boolean} [compress=false] Specifies whether or not to compress\n * `data`\n * @param {Object} options Options object\n * @param {Boolean} [options.fin=false] Specifies whether or not to set the\n * FIN bit\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Buffer} [options.maskBuffer] The buffer used to store the masking\n * key\n * @param {Number} options.opcode The opcode\n * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be\n * modified\n * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the\n * RSV1 bit\n * @param {Function} [cb] Callback\n * @private\n */\n dispatch(data, compress, options, cb) {\n if (!compress) {\n this.sendFrame(Sender.frame(data, options), cb);\n return;\n }\n\n const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];\n\n this._bufferedBytes += options[kByteLength];\n this._state = DEFLATING;\n perMessageDeflate.compress(data, options.fin, (_, buf) => {\n if (this._socket.destroyed) {\n const err = new Error(\n 'The socket was closed while data was being compressed'\n );\n\n callCallbacks(this, err, cb);\n return;\n }\n\n this._bufferedBytes -= options[kByteLength];\n this._state = DEFAULT;\n options.readOnly = false;\n this.sendFrame(Sender.frame(buf, options), cb);\n this.dequeue();\n });\n }\n\n /**\n * Executes queued send operations.\n *\n * @private\n */\n dequeue() {\n while (this._state === DEFAULT && this._queue.length) {\n const params = this._queue.shift();\n\n this._bufferedBytes -= params[3][kByteLength];\n Reflect.apply(params[0], this, params.slice(1));\n }\n }\n\n /**\n * Enqueues a send operation.\n *\n * @param {Array} params Send operation parameters.\n * @private\n */\n enqueue(params) {\n this._bufferedBytes += params[3][kByteLength];\n this._queue.push(params);\n }\n\n /**\n * Sends a frame.\n *\n * @param {(Buffer | String)[]} list The frame to send\n * @param {Function} [cb] Callback\n * @private\n */\n sendFrame(list, cb) {\n if (list.length === 2) {\n this._socket.cork();\n this._socket.write(list[0]);\n this._socket.write(list[1], cb);\n this._socket.uncork();\n } else {\n this._socket.write(list[0], cb);\n }\n }\n}\n\nmodule.exports = Sender;\n\n/**\n * Calls queued callbacks with an error.\n *\n * @param {Sender} sender The `Sender` instance\n * @param {Error} err The error to call the callbacks with\n * @param {Function} [cb] The first callback\n * @private\n */\nfunction callCallbacks(sender, err, cb) {\n if (typeof cb === 'function') cb(err);\n\n for (let i = 0; i < sender._queue.length; i++) {\n const params = sender._queue[i];\n const callback = params[params.length - 1];\n\n if (typeof callback === 'function') callback(err);\n }\n}\n\n/**\n * Handles a `Sender` error.\n *\n * @param {Sender} sender The `Sender` instance\n * @param {Error} err The error\n * @param {Function} [cb] The first pending callback\n * @private\n */\nfunction onError(sender, err, cb) {\n callCallbacks(sender, err, cb);\n sender.onerror(err);\n}\n","'use strict';\n\nconst { kForOnEventAttribute, kListener } = require('./constants');\n\nconst kCode = Symbol('kCode');\nconst kData = Symbol('kData');\nconst kError = Symbol('kError');\nconst kMessage = Symbol('kMessage');\nconst kReason = Symbol('kReason');\nconst kTarget = Symbol('kTarget');\nconst kType = Symbol('kType');\nconst kWasClean = Symbol('kWasClean');\n\n/**\n * Class representing an event.\n */\nclass Event {\n /**\n * Create a new `Event`.\n *\n * @param {String} type The name of the event\n * @throws {TypeError} If the `type` argument is not specified\n */\n constructor(type) {\n this[kTarget] = null;\n this[kType] = type;\n }\n\n /**\n * @type {*}\n */\n get target() {\n return this[kTarget];\n }\n\n /**\n * @type {String}\n */\n get type() {\n return this[kType];\n }\n}\n\nObject.defineProperty(Event.prototype, 'target', { enumerable: true });\nObject.defineProperty(Event.prototype, 'type', { enumerable: true });\n\n/**\n * Class representing a close event.\n *\n * @extends Event\n */\nclass CloseEvent extends Event {\n /**\n * Create a new `CloseEvent`.\n *\n * @param {String} type The name of the event\n * @param {Object} [options] A dictionary object that allows for setting\n * attributes via object members of the same name\n * @param {Number} [options.code=0] The status code explaining why the\n * connection was closed\n * @param {String} [options.reason=''] A human-readable string explaining why\n * the connection was closed\n * @param {Boolean} [options.wasClean=false] Indicates whether or not the\n * connection was cleanly closed\n */\n constructor(type, options = {}) {\n super(type);\n\n this[kCode] = options.code === undefined ? 0 : options.code;\n this[kReason] = options.reason === undefined ? '' : options.reason;\n this[kWasClean] = options.wasClean === undefined ? false : options.wasClean;\n }\n\n /**\n * @type {Number}\n */\n get code() {\n return this[kCode];\n }\n\n /**\n * @type {String}\n */\n get reason() {\n return this[kReason];\n }\n\n /**\n * @type {Boolean}\n */\n get wasClean() {\n return this[kWasClean];\n }\n}\n\nObject.defineProperty(CloseEvent.prototype, 'code', { enumerable: true });\nObject.defineProperty(CloseEvent.prototype, 'reason', { enumerable: true });\nObject.defineProperty(CloseEvent.prototype, 'wasClean', { enumerable: true });\n\n/**\n * Class representing an error event.\n *\n * @extends Event\n */\nclass ErrorEvent extends Event {\n /**\n * Create a new `ErrorEvent`.\n *\n * @param {String} type The name of the event\n * @param {Object} [options] A dictionary object that allows for setting\n * attributes via object members of the same name\n * @param {*} [options.error=null] The error that generated this event\n * @param {String} [options.message=''] The error message\n */\n constructor(type, options = {}) {\n super(type);\n\n this[kError] = options.error === undefined ? null : options.error;\n this[kMessage] = options.message === undefined ? '' : options.message;\n }\n\n /**\n * @type {*}\n */\n get error() {\n return this[kError];\n }\n\n /**\n * @type {String}\n */\n get message() {\n return this[kMessage];\n }\n}\n\nObject.defineProperty(ErrorEvent.prototype, 'error', { enumerable: true });\nObject.defineProperty(ErrorEvent.prototype, 'message', { enumerable: true });\n\n/**\n * Class representing a message event.\n *\n * @extends Event\n */\nclass MessageEvent extends Event {\n /**\n * Create a new `MessageEvent`.\n *\n * @param {String} type The name of the event\n * @param {Object} [options] A dictionary object that allows for setting\n * attributes via object members of the same name\n * @param {*} [options.data=null] The message content\n */\n constructor(type, options = {}) {\n super(type);\n\n this[kData] = options.data === undefined ? null : options.data;\n }\n\n /**\n * @type {*}\n */\n get data() {\n return this[kData];\n }\n}\n\nObject.defineProperty(MessageEvent.prototype, 'data', { enumerable: true });\n\n/**\n * This provides methods for emulating the `EventTarget` interface. It's not\n * meant to be used directly.\n *\n * @mixin\n */\nconst EventTarget = {\n /**\n * Register an event listener.\n *\n * @param {String} type A string representing the event type to listen for\n * @param {(Function|Object)} handler The listener to add\n * @param {Object} [options] An options object specifies characteristics about\n * the event listener\n * @param {Boolean} [options.once=false] A `Boolean` indicating that the\n * listener should be invoked at most once after being added. If `true`,\n * the listener would be automatically removed when invoked.\n * @public\n */\n addEventListener(type, handler, options = {}) {\n for (const listener of this.listeners(type)) {\n if (\n !options[kForOnEventAttribute] &&\n listener[kListener] === handler &&\n !listener[kForOnEventAttribute]\n ) {\n return;\n }\n }\n\n let wrapper;\n\n if (type === 'message') {\n wrapper = function onMessage(data, isBinary) {\n const event = new MessageEvent('message', {\n data: isBinary ? data : data.toString()\n });\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else if (type === 'close') {\n wrapper = function onClose(code, message) {\n const event = new CloseEvent('close', {\n code,\n reason: message.toString(),\n wasClean: this._closeFrameReceived && this._closeFrameSent\n });\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else if (type === 'error') {\n wrapper = function onError(error) {\n const event = new ErrorEvent('error', {\n error,\n message: error.message\n });\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else if (type === 'open') {\n wrapper = function onOpen() {\n const event = new Event('open');\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else {\n return;\n }\n\n wrapper[kForOnEventAttribute] = !!options[kForOnEventAttribute];\n wrapper[kListener] = handler;\n\n if (options.once) {\n this.once(type, wrapper);\n } else {\n this.on(type, wrapper);\n }\n },\n\n /**\n * Remove an event listener.\n *\n * @param {String} type A string representing the event type to remove\n * @param {(Function|Object)} handler The listener to remove\n * @public\n */\n removeEventListener(type, handler) {\n for (const listener of this.listeners(type)) {\n if (listener[kListener] === handler && !listener[kForOnEventAttribute]) {\n this.removeListener(type, listener);\n break;\n }\n }\n }\n};\n\nmodule.exports = {\n CloseEvent,\n ErrorEvent,\n Event,\n EventTarget,\n MessageEvent\n};\n\n/**\n * Call an event listener\n *\n * @param {(Function|Object)} listener The listener to call\n * @param {*} thisArg The value to use as `this`` when calling the listener\n * @param {Event} event The event to pass to the listener\n * @private\n */\nfunction callListener(listener, thisArg, event) {\n if (typeof listener === 'object' && listener.handleEvent) {\n listener.handleEvent.call(listener, event);\n } else {\n listener.call(thisArg, event);\n }\n}\n","'use strict';\n\nconst { tokenChars } = require('./validation');\n\n/**\n * Adds an offer to the map of extension offers or a parameter to the map of\n * parameters.\n *\n * @param {Object} dest The map of extension offers or parameters\n * @param {String} name The extension or parameter name\n * @param {(Object|Boolean|String)} elem The extension parameters or the\n * parameter value\n * @private\n */\nfunction push(dest, name, elem) {\n if (dest[name] === undefined) dest[name] = [elem];\n else dest[name].push(elem);\n}\n\n/**\n * Parses the `Sec-WebSocket-Extensions` header into an object.\n *\n * @param {String} header The field value of the header\n * @return {Object} The parsed object\n * @public\n */\nfunction parse(header) {\n const offers = Object.create(null);\n let params = Object.create(null);\n let mustUnescape = false;\n let isEscaping = false;\n let inQuotes = false;\n let extensionName;\n let paramName;\n let start = -1;\n let code = -1;\n let end = -1;\n let i = 0;\n\n for (; i < header.length; i++) {\n code = header.charCodeAt(i);\n\n if (extensionName === undefined) {\n if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (\n i !== 0 &&\n (code === 0x20 /* ' ' */ || code === 0x09) /* '\\t' */\n ) {\n if (end === -1 && start !== -1) end = i;\n } else if (code === 0x3b /* ';' */ || code === 0x2c /* ',' */) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n const name = header.slice(start, end);\n if (code === 0x2c) {\n push(offers, name, params);\n params = Object.create(null);\n } else {\n extensionName = name;\n }\n\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n } else if (paramName === undefined) {\n if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (code === 0x20 || code === 0x09) {\n if (end === -1 && start !== -1) end = i;\n } else if (code === 0x3b || code === 0x2c) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n push(params, header.slice(start, end), true);\n if (code === 0x2c) {\n push(offers, extensionName, params);\n params = Object.create(null);\n extensionName = undefined;\n }\n\n start = end = -1;\n } else if (code === 0x3d /* '=' */ && start !== -1 && end === -1) {\n paramName = header.slice(start, i);\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n } else {\n //\n // The value of a quoted-string after unescaping must conform to the\n // token ABNF, so only token characters are valid.\n // Ref: https://tools.ietf.org/html/rfc6455#section-9.1\n //\n if (isEscaping) {\n if (tokenChars[code] !== 1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n if (start === -1) start = i;\n else if (!mustUnescape) mustUnescape = true;\n isEscaping = false;\n } else if (inQuotes) {\n if (tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (code === 0x22 /* '\"' */ && start !== -1) {\n inQuotes = false;\n end = i;\n } else if (code === 0x5c /* '\\' */) {\n isEscaping = true;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n } else if (code === 0x22 && header.charCodeAt(i - 1) === 0x3d) {\n inQuotes = true;\n } else if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (start !== -1 && (code === 0x20 || code === 0x09)) {\n if (end === -1) end = i;\n } else if (code === 0x3b || code === 0x2c) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n let value = header.slice(start, end);\n if (mustUnescape) {\n value = value.replace(/\\\\/g, '');\n mustUnescape = false;\n }\n push(params, paramName, value);\n if (code === 0x2c) {\n push(offers, extensionName, params);\n params = Object.create(null);\n extensionName = undefined;\n }\n\n paramName = undefined;\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n }\n }\n\n if (start === -1 || inQuotes || code === 0x20 || code === 0x09) {\n throw new SyntaxError('Unexpected end of input');\n }\n\n if (end === -1) end = i;\n const token = header.slice(start, end);\n if (extensionName === undefined) {\n push(offers, token, params);\n } else {\n if (paramName === undefined) {\n push(params, token, true);\n } else if (mustUnescape) {\n push(params, paramName, token.replace(/\\\\/g, ''));\n } else {\n push(params, paramName, token);\n }\n push(offers, extensionName, params);\n }\n\n return offers;\n}\n\n/**\n * Builds the `Sec-WebSocket-Extensions` header field value.\n *\n * @param {Object} extensions The map of extensions and parameters to format\n * @return {String} A string representing the given object\n * @public\n */\nfunction format(extensions) {\n return Object.keys(extensions)\n .map((extension) => {\n let configurations = extensions[extension];\n if (!Array.isArray(configurations)) configurations = [configurations];\n return configurations\n .map((params) => {\n return [extension]\n .concat(\n Object.keys(params).map((k) => {\n let values = params[k];\n if (!Array.isArray(values)) values = [values];\n return values\n .map((v) => (v === true ? k : `${k}=${v}`))\n .join('; ');\n })\n )\n .join('; ');\n })\n .join(', ');\n })\n .join(', ');\n}\n\nmodule.exports = { format, parse };\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^Duplex|Readable$\", \"caughtErrors\": \"none\" }] */\n\n'use strict';\n\nconst EventEmitter = require('events');\nconst https = require('https');\nconst http = require('http');\nconst net = require('net');\nconst tls = require('tls');\nconst { randomBytes, createHash } = require('crypto');\nconst { Duplex, Readable } = require('stream');\nconst { URL } = require('url');\n\nconst PerMessageDeflate = require('./permessage-deflate');\nconst Receiver = require('./receiver');\nconst Sender = require('./sender');\nconst { isBlob } = require('./validation');\n\nconst {\n BINARY_TYPES,\n CLOSE_TIMEOUT,\n EMPTY_BUFFER,\n GUID,\n kForOnEventAttribute,\n kListener,\n kStatusCode,\n kWebSocket,\n NOOP\n} = require('./constants');\nconst {\n EventTarget: { addEventListener, removeEventListener }\n} = require('./event-target');\nconst { format, parse } = require('./extension');\nconst { toBuffer } = require('./buffer-util');\n\nconst kAborted = Symbol('kAborted');\nconst protocolVersions = [8, 13];\nconst readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];\nconst subprotocolRegex = /^[!#$%&'*+\\-.0-9A-Z^_`|a-z~]+$/;\n\n/**\n * Class representing a WebSocket.\n *\n * @extends EventEmitter\n */\nclass WebSocket extends EventEmitter {\n /**\n * Create a new `WebSocket`.\n *\n * @param {(String|URL)} address The URL to which to connect\n * @param {(String|String[])} [protocols] The subprotocols\n * @param {Object} [options] Connection options\n */\n constructor(address, protocols, options) {\n super();\n\n this._binaryType = BINARY_TYPES[0];\n this._closeCode = 1006;\n this._closeFrameReceived = false;\n this._closeFrameSent = false;\n this._closeMessage = EMPTY_BUFFER;\n this._closeTimer = null;\n this._errorEmitted = false;\n this._extensions = {};\n this._paused = false;\n this._protocol = '';\n this._readyState = WebSocket.CONNECTING;\n this._receiver = null;\n this._sender = null;\n this._socket = null;\n\n if (address !== null) {\n this._bufferedAmount = 0;\n this._isServer = false;\n this._redirects = 0;\n\n if (protocols === undefined) {\n protocols = [];\n } else if (!Array.isArray(protocols)) {\n if (typeof protocols === 'object' && protocols !== null) {\n options = protocols;\n protocols = [];\n } else {\n protocols = [protocols];\n }\n }\n\n initAsClient(this, address, protocols, options);\n } else {\n this._autoPong = options.autoPong;\n this._closeTimeout = options.closeTimeout;\n this._isServer = true;\n }\n }\n\n /**\n * For historical reasons, the custom \"nodebuffer\" type is used by the default\n * instead of \"blob\".\n *\n * @type {String}\n */\n get binaryType() {\n return this._binaryType;\n }\n\n set binaryType(type) {\n if (!BINARY_TYPES.includes(type)) return;\n\n this._binaryType = type;\n\n //\n // Allow to change `binaryType` on the fly.\n //\n if (this._receiver) this._receiver._binaryType = type;\n }\n\n /**\n * @type {Number}\n */\n get bufferedAmount() {\n if (!this._socket) return this._bufferedAmount;\n\n return this._socket._writableState.length + this._sender._bufferedBytes;\n }\n\n /**\n * @type {String}\n */\n get extensions() {\n return Object.keys(this._extensions).join();\n }\n\n /**\n * @type {Boolean}\n */\n get isPaused() {\n return this._paused;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onclose() {\n return null;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onerror() {\n return null;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onopen() {\n return null;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onmessage() {\n return null;\n }\n\n /**\n * @type {String}\n */\n get protocol() {\n return this._protocol;\n }\n\n /**\n * @type {Number}\n */\n get readyState() {\n return this._readyState;\n }\n\n /**\n * @type {String}\n */\n get url() {\n return this._url;\n }\n\n /**\n * Set up the socket and the internal resources.\n *\n * @param {Duplex} socket The network socket between the server and client\n * @param {Buffer} head The first packet of the upgraded stream\n * @param {Object} options Options object\n * @param {Boolean} [options.allowSynchronousEvents=false] Specifies whether\n * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted\n * multiple times in the same tick\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Number} [options.maxBufferedChunks=0] The maximum number of\n * buffered data chunks\n * @param {Number} [options.maxFragments=0] The maximum number of message\n * fragments\n * @param {Number} [options.maxPayload=0] The maximum allowed message size\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n * @private\n */\n setSocket(socket, head, options) {\n const receiver = new Receiver({\n allowSynchronousEvents: options.allowSynchronousEvents,\n binaryType: this.binaryType,\n extensions: this._extensions,\n isServer: this._isServer,\n maxBufferedChunks: options.maxBufferedChunks,\n maxFragments: options.maxFragments,\n maxPayload: options.maxPayload,\n skipUTF8Validation: options.skipUTF8Validation\n });\n\n const sender = new Sender(socket, this._extensions, options.generateMask);\n\n this._receiver = receiver;\n this._sender = sender;\n this._socket = socket;\n\n receiver[kWebSocket] = this;\n sender[kWebSocket] = this;\n socket[kWebSocket] = this;\n\n receiver.on('conclude', receiverOnConclude);\n receiver.on('drain', receiverOnDrain);\n receiver.on('error', receiverOnError);\n receiver.on('message', receiverOnMessage);\n receiver.on('ping', receiverOnPing);\n receiver.on('pong', receiverOnPong);\n\n sender.onerror = senderOnError;\n\n //\n // These methods may not be available if `socket` is just a `Duplex`.\n //\n if (socket.setTimeout) socket.setTimeout(0);\n if (socket.setNoDelay) socket.setNoDelay();\n\n if (head.length > 0) socket.unshift(head);\n\n socket.on('close', socketOnClose);\n socket.on('data', socketOnData);\n socket.on('end', socketOnEnd);\n socket.on('error', socketOnError);\n\n this._readyState = WebSocket.OPEN;\n this.emit('open');\n }\n\n /**\n * Emit the `'close'` event.\n *\n * @private\n */\n emitClose() {\n if (!this._socket) {\n this._readyState = WebSocket.CLOSED;\n this.emit('close', this._closeCode, this._closeMessage);\n return;\n }\n\n if (this._extensions[PerMessageDeflate.extensionName]) {\n this._extensions[PerMessageDeflate.extensionName].cleanup();\n }\n\n this._receiver.removeAllListeners();\n this._readyState = WebSocket.CLOSED;\n this.emit('close', this._closeCode, this._closeMessage);\n }\n\n /**\n * Start a closing handshake.\n *\n * +----------+ +-----------+ +----------+\n * - - -|ws.close()|-->|close frame|-->|ws.close()|- - -\n * | +----------+ +-----------+ +----------+ |\n * +----------+ +-----------+ |\n * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING\n * +----------+ +-----------+ |\n * | | | +---+ |\n * +------------------------+-->|fin| - - - -\n * | +---+ | +---+\n * - - - - -|fin|<---------------------+\n * +---+\n *\n * @param {Number} [code] Status code explaining why the connection is closing\n * @param {(String|Buffer)} [data] The reason why the connection is\n * closing\n * @public\n */\n close(code, data) {\n if (this.readyState === WebSocket.CLOSED) return;\n if (this.readyState === WebSocket.CONNECTING) {\n const msg = 'WebSocket was closed before the connection was established';\n abortHandshake(this, this._req, msg);\n return;\n }\n\n if (this.readyState === WebSocket.CLOSING) {\n if (\n this._closeFrameSent &&\n (this._closeFrameReceived || this._receiver._writableState.errorEmitted)\n ) {\n this._socket.end();\n }\n\n return;\n }\n\n this._readyState = WebSocket.CLOSING;\n this._sender.close(code, data, !this._isServer, (err) => {\n //\n // This error is handled by the `'error'` listener on the socket. We only\n // want to know if the close frame has been sent here.\n //\n if (err) return;\n\n this._closeFrameSent = true;\n\n if (\n this._closeFrameReceived ||\n this._receiver._writableState.errorEmitted\n ) {\n this._socket.end();\n }\n });\n\n setCloseTimer(this);\n }\n\n /**\n * Pause the socket.\n *\n * @public\n */\n pause() {\n if (\n this.readyState === WebSocket.CONNECTING ||\n this.readyState === WebSocket.CLOSED\n ) {\n return;\n }\n\n this._paused = true;\n this._socket.pause();\n }\n\n /**\n * Send a ping.\n *\n * @param {*} [data] The data to send\n * @param {Boolean} [mask] Indicates whether or not to mask `data`\n * @param {Function} [cb] Callback which is executed when the ping is sent\n * @public\n */\n ping(data, mask, cb) {\n if (this.readyState === WebSocket.CONNECTING) {\n throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');\n }\n\n if (typeof data === 'function') {\n cb = data;\n data = mask = undefined;\n } else if (typeof mask === 'function') {\n cb = mask;\n mask = undefined;\n }\n\n if (typeof data === 'number') data = data.toString();\n\n if (this.readyState !== WebSocket.OPEN) {\n sendAfterClose(this, data, cb);\n return;\n }\n\n if (mask === undefined) mask = !this._isServer;\n this._sender.ping(data || EMPTY_BUFFER, mask, cb);\n }\n\n /**\n * Send a pong.\n *\n * @param {*} [data] The data to send\n * @param {Boolean} [mask] Indicates whether or not to mask `data`\n * @param {Function} [cb] Callback which is executed when the pong is sent\n * @public\n */\n pong(data, mask, cb) {\n if (this.readyState === WebSocket.CONNECTING) {\n throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');\n }\n\n if (typeof data === 'function') {\n cb = data;\n data = mask = undefined;\n } else if (typeof mask === 'function') {\n cb = mask;\n mask = undefined;\n }\n\n if (typeof data === 'number') data = data.toString();\n\n if (this.readyState !== WebSocket.OPEN) {\n sendAfterClose(this, data, cb);\n return;\n }\n\n if (mask === undefined) mask = !this._isServer;\n this._sender.pong(data || EMPTY_BUFFER, mask, cb);\n }\n\n /**\n * Resume the socket.\n *\n * @public\n */\n resume() {\n if (\n this.readyState === WebSocket.CONNECTING ||\n this.readyState === WebSocket.CLOSED\n ) {\n return;\n }\n\n this._paused = false;\n if (!this._receiver._writableState.needDrain) this._socket.resume();\n }\n\n /**\n * Send a data message.\n *\n * @param {*} data The message to send\n * @param {Object} [options] Options object\n * @param {Boolean} [options.binary] Specifies whether `data` is binary or\n * text\n * @param {Boolean} [options.compress] Specifies whether or not to compress\n * `data`\n * @param {Boolean} [options.fin=true] Specifies whether the fragment is the\n * last one\n * @param {Boolean} [options.mask] Specifies whether or not to mask `data`\n * @param {Function} [cb] Callback which is executed when data is written out\n * @public\n */\n send(data, options, cb) {\n if (this.readyState === WebSocket.CONNECTING) {\n throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');\n }\n\n if (typeof options === 'function') {\n cb = options;\n options = {};\n }\n\n if (typeof data === 'number') data = data.toString();\n\n if (this.readyState !== WebSocket.OPEN) {\n sendAfterClose(this, data, cb);\n return;\n }\n\n const opts = {\n binary: typeof data !== 'string',\n mask: !this._isServer,\n compress: true,\n fin: true,\n ...options\n };\n\n if (!this._extensions[PerMessageDeflate.extensionName]) {\n opts.compress = false;\n }\n\n this._sender.send(data || EMPTY_BUFFER, opts, cb);\n }\n\n /**\n * Forcibly close the connection.\n *\n * @public\n */\n terminate() {\n if (this.readyState === WebSocket.CLOSED) return;\n if (this.readyState === WebSocket.CONNECTING) {\n const msg = 'WebSocket was closed before the connection was established';\n abortHandshake(this, this._req, msg);\n return;\n }\n\n if (this._socket) {\n this._readyState = WebSocket.CLOSING;\n this._socket.destroy();\n }\n }\n}\n\n/**\n * @constant {Number} CONNECTING\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'CONNECTING', {\n enumerable: true,\n value: readyStates.indexOf('CONNECTING')\n});\n\n/**\n * @constant {Number} CONNECTING\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'CONNECTING', {\n enumerable: true,\n value: readyStates.indexOf('CONNECTING')\n});\n\n/**\n * @constant {Number} OPEN\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'OPEN', {\n enumerable: true,\n value: readyStates.indexOf('OPEN')\n});\n\n/**\n * @constant {Number} OPEN\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'OPEN', {\n enumerable: true,\n value: readyStates.indexOf('OPEN')\n});\n\n/**\n * @constant {Number} CLOSING\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'CLOSING', {\n enumerable: true,\n value: readyStates.indexOf('CLOSING')\n});\n\n/**\n * @constant {Number} CLOSING\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'CLOSING', {\n enumerable: true,\n value: readyStates.indexOf('CLOSING')\n});\n\n/**\n * @constant {Number} CLOSED\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'CLOSED', {\n enumerable: true,\n value: readyStates.indexOf('CLOSED')\n});\n\n/**\n * @constant {Number} CLOSED\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'CLOSED', {\n enumerable: true,\n value: readyStates.indexOf('CLOSED')\n});\n\n[\n 'binaryType',\n 'bufferedAmount',\n 'extensions',\n 'isPaused',\n 'protocol',\n 'readyState',\n 'url'\n].forEach((property) => {\n Object.defineProperty(WebSocket.prototype, property, { enumerable: true });\n});\n\n//\n// Add the `onopen`, `onerror`, `onclose`, and `onmessage` attributes.\n// See https://html.spec.whatwg.org/multipage/comms.html#the-websocket-interface\n//\n['open', 'error', 'close', 'message'].forEach((method) => {\n Object.defineProperty(WebSocket.prototype, `on${method}`, {\n enumerable: true,\n get() {\n for (const listener of this.listeners(method)) {\n if (listener[kForOnEventAttribute]) return listener[kListener];\n }\n\n return null;\n },\n set(handler) {\n for (const listener of this.listeners(method)) {\n if (listener[kForOnEventAttribute]) {\n this.removeListener(method, listener);\n break;\n }\n }\n\n if (typeof handler !== 'function') return;\n\n this.addEventListener(method, handler, {\n [kForOnEventAttribute]: true\n });\n }\n });\n});\n\nWebSocket.prototype.addEventListener = addEventListener;\nWebSocket.prototype.removeEventListener = removeEventListener;\n\nmodule.exports = WebSocket;\n\n/**\n * Initialize a WebSocket client.\n *\n * @param {WebSocket} websocket The client to initialize\n * @param {(String|URL)} address The URL to which to connect\n * @param {Array} protocols The subprotocols\n * @param {Object} [options] Connection options\n * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether any\n * of the `'message'`, `'ping'`, and `'pong'` events can be emitted multiple\n * times in the same tick\n * @param {Boolean} [options.autoPong=true] Specifies whether or not to\n * automatically send a pong in response to a ping\n * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to wait\n * for the closing handshake to finish after `websocket.close()` is called\n * @param {Function} [options.finishRequest] A function which can be used to\n * customize the headers of each http request before it is sent\n * @param {Boolean} [options.followRedirects=false] Whether or not to follow\n * redirects\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Number} [options.handshakeTimeout] Timeout in milliseconds for the\n * handshake request\n * @param {Number} [options.maxBufferedChunks=1048576] The maximum number of\n * buffered data chunks\n * @param {Number} [options.maxFragments=131072] The maximum number of message\n * fragments\n * @param {Number} [options.maxPayload=104857600] The maximum allowed message\n * size\n * @param {Number} [options.maxRedirects=10] The maximum number of redirects\n * allowed\n * @param {String} [options.origin] Value of the `Origin` or\n * `Sec-WebSocket-Origin` header\n * @param {(Boolean|Object)} [options.perMessageDeflate=true] Enable/disable\n * permessage-deflate\n * @param {Number} [options.protocolVersion=13] Value of the\n * `Sec-WebSocket-Version` header\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n * @private\n */\nfunction initAsClient(websocket, address, protocols, options) {\n const opts = {\n allowSynchronousEvents: true,\n autoPong: true,\n closeTimeout: CLOSE_TIMEOUT,\n protocolVersion: protocolVersions[1],\n maxBufferedChunks: 1024 * 1024,\n maxFragments: 128 * 1024,\n maxPayload: 100 * 1024 * 1024,\n skipUTF8Validation: false,\n perMessageDeflate: true,\n followRedirects: false,\n maxRedirects: 10,\n ...options,\n socketPath: undefined,\n hostname: undefined,\n protocol: undefined,\n timeout: undefined,\n method: 'GET',\n host: undefined,\n path: undefined,\n port: undefined\n };\n\n websocket._autoPong = opts.autoPong;\n websocket._closeTimeout = opts.closeTimeout;\n\n if (!protocolVersions.includes(opts.protocolVersion)) {\n throw new RangeError(\n `Unsupported protocol version: ${opts.protocolVersion} ` +\n `(supported versions: ${protocolVersions.join(', ')})`\n );\n }\n\n let parsedUrl;\n\n if (address instanceof URL) {\n parsedUrl = address;\n } else {\n try {\n parsedUrl = new URL(address);\n } catch {\n throw new SyntaxError(`Invalid URL: ${address}`);\n }\n }\n\n if (parsedUrl.protocol === 'http:') {\n parsedUrl.protocol = 'ws:';\n } else if (parsedUrl.protocol === 'https:') {\n parsedUrl.protocol = 'wss:';\n }\n\n websocket._url = parsedUrl.href;\n\n const isSecure = parsedUrl.protocol === 'wss:';\n const isIpcUrl = parsedUrl.protocol === 'ws+unix:';\n let invalidUrlMessage;\n\n if (parsedUrl.protocol !== 'ws:' && !isSecure && !isIpcUrl) {\n invalidUrlMessage =\n 'The URL\\'s protocol must be one of \"ws:\", \"wss:\", ' +\n '\"http:\", \"https:\", or \"ws+unix:\"';\n } else if (isIpcUrl && !parsedUrl.pathname) {\n invalidUrlMessage = \"The URL's pathname is empty\";\n } else if (parsedUrl.hash) {\n invalidUrlMessage = 'The URL contains a fragment identifier';\n }\n\n if (invalidUrlMessage) {\n const err = new SyntaxError(invalidUrlMessage);\n\n if (websocket._redirects === 0) {\n throw err;\n } else {\n emitErrorAndClose(websocket, err);\n return;\n }\n }\n\n const defaultPort = isSecure ? 443 : 80;\n const key = randomBytes(16).toString('base64');\n const request = isSecure ? https.request : http.request;\n const protocolSet = new Set();\n let perMessageDeflate;\n\n opts.createConnection =\n opts.createConnection || (isSecure ? tlsConnect : netConnect);\n opts.defaultPort = opts.defaultPort || defaultPort;\n opts.port = parsedUrl.port || defaultPort;\n opts.host = parsedUrl.hostname.startsWith('[')\n ? parsedUrl.hostname.slice(1, -1)\n : parsedUrl.hostname;\n opts.headers = {\n ...opts.headers,\n 'Sec-WebSocket-Version': opts.protocolVersion,\n 'Sec-WebSocket-Key': key,\n Connection: 'Upgrade',\n Upgrade: 'websocket'\n };\n opts.path = parsedUrl.pathname + parsedUrl.search;\n opts.timeout = opts.handshakeTimeout;\n\n if (opts.perMessageDeflate) {\n perMessageDeflate = new PerMessageDeflate({\n ...opts.perMessageDeflate,\n isServer: false,\n maxPayload: opts.maxPayload\n });\n opts.headers['Sec-WebSocket-Extensions'] = format({\n [PerMessageDeflate.extensionName]: perMessageDeflate.offer()\n });\n }\n if (protocols.length) {\n for (const protocol of protocols) {\n if (\n typeof protocol !== 'string' ||\n !subprotocolRegex.test(protocol) ||\n protocolSet.has(protocol)\n ) {\n throw new SyntaxError(\n 'An invalid or duplicated subprotocol was specified'\n );\n }\n\n protocolSet.add(protocol);\n }\n\n opts.headers['Sec-WebSocket-Protocol'] = protocols.join(',');\n }\n if (opts.origin) {\n if (opts.protocolVersion < 13) {\n opts.headers['Sec-WebSocket-Origin'] = opts.origin;\n } else {\n opts.headers.Origin = opts.origin;\n }\n }\n if (parsedUrl.username || parsedUrl.password) {\n opts.auth = `${parsedUrl.username}:${parsedUrl.password}`;\n }\n\n if (isIpcUrl) {\n const parts = opts.path.split(':');\n\n opts.socketPath = parts[0];\n opts.path = parts[1];\n }\n\n let req;\n\n if (opts.followRedirects) {\n if (websocket._redirects === 0) {\n websocket._originalIpc = isIpcUrl;\n websocket._originalSecure = isSecure;\n websocket._originalHostOrSocketPath = isIpcUrl\n ? opts.socketPath\n : parsedUrl.host;\n\n const headers = options && options.headers;\n\n //\n // Shallow copy the user provided options so that headers can be changed\n // without mutating the original object.\n //\n options = { ...options, headers: {} };\n\n if (headers) {\n for (const [key, value] of Object.entries(headers)) {\n options.headers[key.toLowerCase()] = value;\n }\n }\n } else if (websocket.listenerCount('redirect') === 0) {\n const isSameHost = isIpcUrl\n ? websocket._originalIpc\n ? opts.socketPath === websocket._originalHostOrSocketPath\n : false\n : websocket._originalIpc\n ? false\n : parsedUrl.host === websocket._originalHostOrSocketPath;\n\n if (!isSameHost || (websocket._originalSecure && !isSecure)) {\n //\n // Match curl 7.77.0 behavior and drop the following headers. These\n // headers are also dropped when following a redirect to a subdomain.\n //\n delete opts.headers.authorization;\n delete opts.headers.cookie;\n\n if (!isSameHost) delete opts.headers.host;\n\n opts.auth = undefined;\n }\n }\n\n //\n // Match curl 7.77.0 behavior and make the first `Authorization` header win.\n // If the `Authorization` header is set, then there is nothing to do as it\n // will take precedence.\n //\n if (opts.auth && !options.headers.authorization) {\n options.headers.authorization =\n 'Basic ' + Buffer.from(opts.auth).toString('base64');\n }\n\n req = websocket._req = request(opts);\n\n if (websocket._redirects) {\n //\n // Unlike what is done for the `'upgrade'` event, no early exit is\n // triggered here if the user calls `websocket.close()` or\n // `websocket.terminate()` from a listener of the `'redirect'` event. This\n // is because the user can also call `request.destroy()` with an error\n // before calling `websocket.close()` or `websocket.terminate()` and this\n // would result in an error being emitted on the `request` object with no\n // `'error'` event listeners attached.\n //\n websocket.emit('redirect', websocket.url, req);\n }\n } else {\n req = websocket._req = request(opts);\n }\n\n if (opts.timeout) {\n req.on('timeout', () => {\n abortHandshake(websocket, req, 'Opening handshake has timed out');\n });\n }\n\n req.on('error', (err) => {\n if (req === null || req[kAborted]) return;\n\n req = websocket._req = null;\n emitErrorAndClose(websocket, err);\n });\n\n req.on('response', (res) => {\n const location = res.headers.location;\n const statusCode = res.statusCode;\n\n if (\n location &&\n opts.followRedirects &&\n statusCode >= 300 &&\n statusCode < 400\n ) {\n if (++websocket._redirects > opts.maxRedirects) {\n abortHandshake(websocket, req, 'Maximum redirects exceeded');\n return;\n }\n\n req.abort();\n\n let addr;\n\n try {\n addr = new URL(location, address);\n } catch (e) {\n const err = new SyntaxError(`Invalid URL: ${location}`);\n emitErrorAndClose(websocket, err);\n return;\n }\n\n initAsClient(websocket, addr, protocols, options);\n } else if (!websocket.emit('unexpected-response', req, res)) {\n abortHandshake(\n websocket,\n req,\n `Unexpected server response: ${res.statusCode}`\n );\n }\n });\n\n req.on('upgrade', (res, socket, head) => {\n websocket.emit('upgrade', res);\n\n //\n // The user may have closed the connection from a listener of the\n // `'upgrade'` event.\n //\n if (websocket.readyState !== WebSocket.CONNECTING) return;\n\n req = websocket._req = null;\n\n const upgrade = res.headers.upgrade;\n\n if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {\n abortHandshake(websocket, socket, 'Invalid Upgrade header');\n return;\n }\n\n const digest = createHash('sha1')\n .update(key + GUID)\n .digest('base64');\n\n if (res.headers['sec-websocket-accept'] !== digest) {\n abortHandshake(websocket, socket, 'Invalid Sec-WebSocket-Accept header');\n return;\n }\n\n const serverProt = res.headers['sec-websocket-protocol'];\n let protError;\n\n if (serverProt !== undefined) {\n if (!protocolSet.size) {\n protError = 'Server sent a subprotocol but none was requested';\n } else if (!protocolSet.has(serverProt)) {\n protError = 'Server sent an invalid subprotocol';\n }\n } else if (protocolSet.size) {\n protError = 'Server sent no subprotocol';\n }\n\n if (protError) {\n abortHandshake(websocket, socket, protError);\n return;\n }\n\n if (serverProt) websocket._protocol = serverProt;\n\n const secWebSocketExtensions = res.headers['sec-websocket-extensions'];\n\n if (secWebSocketExtensions !== undefined) {\n if (!perMessageDeflate) {\n const message =\n 'Server sent a Sec-WebSocket-Extensions header but no extension ' +\n 'was requested';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n let extensions;\n\n try {\n extensions = parse(secWebSocketExtensions);\n } catch (err) {\n const message = 'Invalid Sec-WebSocket-Extensions header';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n const extensionNames = Object.keys(extensions);\n\n if (\n extensionNames.length !== 1 ||\n extensionNames[0] !== PerMessageDeflate.extensionName\n ) {\n const message = 'Server indicated an extension that was not requested';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n try {\n perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]);\n } catch (err) {\n const message = 'Invalid Sec-WebSocket-Extensions header';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n websocket._extensions[PerMessageDeflate.extensionName] =\n perMessageDeflate;\n }\n\n websocket.setSocket(socket, head, {\n allowSynchronousEvents: opts.allowSynchronousEvents,\n generateMask: opts.generateMask,\n maxBufferedChunks: opts.maxBufferedChunks,\n maxFragments: opts.maxFragments,\n maxPayload: opts.maxPayload,\n skipUTF8Validation: opts.skipUTF8Validation\n });\n });\n\n if (opts.finishRequest) {\n opts.finishRequest(req, websocket);\n } else {\n req.end();\n }\n}\n\n/**\n * Emit the `'error'` and `'close'` events.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @param {Error} The error to emit\n * @private\n */\nfunction emitErrorAndClose(websocket, err) {\n websocket._readyState = WebSocket.CLOSING;\n //\n // The following assignment is practically useless and is done only for\n // consistency.\n //\n websocket._errorEmitted = true;\n websocket.emit('error', err);\n websocket.emitClose();\n}\n\n/**\n * Create a `net.Socket` and initiate a connection.\n *\n * @param {Object} options Connection options\n * @return {net.Socket} The newly created socket used to start the connection\n * @private\n */\nfunction netConnect(options) {\n options.path = options.socketPath;\n return net.connect(options);\n}\n\n/**\n * Create a `tls.TLSSocket` and initiate a connection.\n *\n * @param {Object} options Connection options\n * @return {tls.TLSSocket} The newly created socket used to start the connection\n * @private\n */\nfunction tlsConnect(options) {\n options.path = undefined;\n\n if (!options.servername && options.servername !== '') {\n options.servername = net.isIP(options.host) ? '' : options.host;\n }\n\n return tls.connect(options);\n}\n\n/**\n * Abort the handshake and emit an error.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @param {(http.ClientRequest|net.Socket|tls.Socket)} stream The request to\n * abort or the socket to destroy\n * @param {String} message The error message\n * @private\n */\nfunction abortHandshake(websocket, stream, message) {\n websocket._readyState = WebSocket.CLOSING;\n\n const err = new Error(message);\n Error.captureStackTrace(err, abortHandshake);\n\n if (stream.setHeader) {\n stream[kAborted] = true;\n stream.abort();\n\n if (stream.socket && !stream.socket.destroyed) {\n //\n // On Node.js >= 14.3.0 `request.abort()` does not destroy the socket if\n // called after the request completed. See\n // https://github.com/websockets/ws/issues/1869.\n //\n stream.socket.destroy();\n }\n\n process.nextTick(emitErrorAndClose, websocket, err);\n } else {\n stream.destroy(err);\n stream.once('error', websocket.emit.bind(websocket, 'error'));\n stream.once('close', websocket.emitClose.bind(websocket));\n }\n}\n\n/**\n * Handle cases where the `ping()`, `pong()`, or `send()` methods are called\n * when the `readyState` attribute is `CLOSING` or `CLOSED`.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @param {*} [data] The data to send\n * @param {Function} [cb] Callback\n * @private\n */\nfunction sendAfterClose(websocket, data, cb) {\n if (data) {\n const length = isBlob(data) ? data.size : toBuffer(data).length;\n\n //\n // The `_bufferedAmount` property is used only when the peer is a client and\n // the opening handshake fails. Under these circumstances, in fact, the\n // `setSocket()` method is not called, so the `_socket` and `_sender`\n // properties are set to `null`.\n //\n if (websocket._socket) websocket._sender._bufferedBytes += length;\n else websocket._bufferedAmount += length;\n }\n\n if (cb) {\n const err = new Error(\n `WebSocket is not open: readyState ${websocket.readyState} ` +\n `(${readyStates[websocket.readyState]})`\n );\n process.nextTick(cb, err);\n }\n}\n\n/**\n * The listener of the `Receiver` `'conclude'` event.\n *\n * @param {Number} code The status code\n * @param {Buffer} reason The reason for closing\n * @private\n */\nfunction receiverOnConclude(code, reason) {\n const websocket = this[kWebSocket];\n\n websocket._closeFrameReceived = true;\n websocket._closeMessage = reason;\n websocket._closeCode = code;\n\n if (websocket._socket[kWebSocket] === undefined) return;\n\n websocket._socket.removeListener('data', socketOnData);\n process.nextTick(resume, websocket._socket);\n\n if (code === 1005) websocket.close();\n else websocket.close(code, reason);\n}\n\n/**\n * The listener of the `Receiver` `'drain'` event.\n *\n * @private\n */\nfunction receiverOnDrain() {\n const websocket = this[kWebSocket];\n\n if (!websocket.isPaused) websocket._socket.resume();\n}\n\n/**\n * The listener of the `Receiver` `'error'` event.\n *\n * @param {(RangeError|Error)} err The emitted error\n * @private\n */\nfunction receiverOnError(err) {\n const websocket = this[kWebSocket];\n\n if (websocket._socket[kWebSocket] !== undefined) {\n websocket._socket.removeListener('data', socketOnData);\n\n //\n // On Node.js < 14.0.0 the `'error'` event is emitted synchronously. See\n // https://github.com/websockets/ws/issues/1940.\n //\n process.nextTick(resume, websocket._socket);\n\n websocket.close(err[kStatusCode]);\n }\n\n if (!websocket._errorEmitted) {\n websocket._errorEmitted = true;\n websocket.emit('error', err);\n }\n}\n\n/**\n * The listener of the `Receiver` `'finish'` event.\n *\n * @private\n */\nfunction receiverOnFinish() {\n this[kWebSocket].emitClose();\n}\n\n/**\n * The listener of the `Receiver` `'message'` event.\n *\n * @param {Buffer|ArrayBuffer|Buffer[])} data The message\n * @param {Boolean} isBinary Specifies whether the message is binary or not\n * @private\n */\nfunction receiverOnMessage(data, isBinary) {\n this[kWebSocket].emit('message', data, isBinary);\n}\n\n/**\n * The listener of the `Receiver` `'ping'` event.\n *\n * @param {Buffer} data The data included in the ping frame\n * @private\n */\nfunction receiverOnPing(data) {\n const websocket = this[kWebSocket];\n\n if (websocket._autoPong) websocket.pong(data, !this._isServer, NOOP);\n websocket.emit('ping', data);\n}\n\n/**\n * The listener of the `Receiver` `'pong'` event.\n *\n * @param {Buffer} data The data included in the pong frame\n * @private\n */\nfunction receiverOnPong(data) {\n this[kWebSocket].emit('pong', data);\n}\n\n/**\n * Resume a readable stream\n *\n * @param {Readable} stream The readable stream\n * @private\n */\nfunction resume(stream) {\n stream.resume();\n}\n\n/**\n * The `Sender` error event handler.\n *\n * @param {Error} The error\n * @private\n */\nfunction senderOnError(err) {\n const websocket = this[kWebSocket];\n\n if (websocket.readyState === WebSocket.CLOSED) return;\n if (websocket.readyState === WebSocket.OPEN) {\n websocket._readyState = WebSocket.CLOSING;\n setCloseTimer(websocket);\n }\n\n //\n // `socket.end()` is used instead of `socket.destroy()` to allow the other\n // peer to finish sending queued data. There is no need to set a timer here\n // because `CLOSING` means that it is already set or not needed.\n //\n this._socket.end();\n\n if (!websocket._errorEmitted) {\n websocket._errorEmitted = true;\n websocket.emit('error', err);\n }\n}\n\n/**\n * Set a timer to destroy the underlying raw socket of a WebSocket.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @private\n */\nfunction setCloseTimer(websocket) {\n websocket._closeTimer = setTimeout(\n websocket._socket.destroy.bind(websocket._socket),\n websocket._closeTimeout\n );\n}\n\n/**\n * The listener of the socket `'close'` event.\n *\n * @private\n */\nfunction socketOnClose() {\n const websocket = this[kWebSocket];\n\n this.removeListener('close', socketOnClose);\n this.removeListener('data', socketOnData);\n this.removeListener('end', socketOnEnd);\n\n websocket._readyState = WebSocket.CLOSING;\n\n //\n // The close frame might not have been received or the `'end'` event emitted,\n // for example, if the socket was destroyed due to an error. Ensure that the\n // `receiver` stream is closed after writing any remaining buffered data to\n // it. If the readable side of the socket is in flowing mode then there is no\n // buffered data as everything has been already written. If instead, the\n // socket is paused, any possible buffered data will be read as a single\n // chunk.\n //\n if (\n !this._readableState.endEmitted &&\n !websocket._closeFrameReceived &&\n !websocket._receiver._writableState.errorEmitted &&\n this._readableState.length !== 0\n ) {\n const chunk = this.read(this._readableState.length);\n\n websocket._receiver.write(chunk);\n }\n\n websocket._receiver.end();\n\n this[kWebSocket] = undefined;\n\n clearTimeout(websocket._closeTimer);\n\n if (\n websocket._receiver._writableState.finished ||\n websocket._receiver._writableState.errorEmitted\n ) {\n websocket.emitClose();\n } else {\n websocket._receiver.on('error', receiverOnFinish);\n websocket._receiver.on('finish', receiverOnFinish);\n }\n}\n\n/**\n * The listener of the socket `'data'` event.\n *\n * @param {Buffer} chunk A chunk of data\n * @private\n */\nfunction socketOnData(chunk) {\n if (!this[kWebSocket]._receiver.write(chunk)) {\n this.pause();\n }\n}\n\n/**\n * The listener of the socket `'end'` event.\n *\n * @private\n */\nfunction socketOnEnd() {\n const websocket = this[kWebSocket];\n\n websocket._readyState = WebSocket.CLOSING;\n websocket._receiver.end();\n this.end();\n}\n\n/**\n * The listener of the socket `'error'` event.\n *\n * @private\n */\nfunction socketOnError() {\n const websocket = this[kWebSocket];\n\n this.removeListener('error', socketOnError);\n this.on('error', NOOP);\n\n if (websocket) {\n websocket._readyState = WebSocket.CLOSING;\n this.destroy();\n }\n}\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^WebSocket$\" }] */\n'use strict';\n\nconst WebSocket = require('./websocket');\nconst { Duplex } = require('stream');\n\n/**\n * Emits the `'close'` event on a stream.\n *\n * @param {Duplex} stream The stream.\n * @private\n */\nfunction emitClose(stream) {\n stream.emit('close');\n}\n\n/**\n * The listener of the `'end'` event.\n *\n * @private\n */\nfunction duplexOnEnd() {\n if (!this.destroyed && this._writableState.finished) {\n this.destroy();\n }\n}\n\n/**\n * The listener of the `'error'` event.\n *\n * @param {Error} err The error\n * @private\n */\nfunction duplexOnError(err) {\n this.removeListener('error', duplexOnError);\n this.destroy();\n if (this.listenerCount('error') === 0) {\n // Do not suppress the throwing behavior.\n this.emit('error', err);\n }\n}\n\n/**\n * Wraps a `WebSocket` in a duplex stream.\n *\n * @param {WebSocket} ws The `WebSocket` to wrap\n * @param {Object} [options] The options for the `Duplex` constructor\n * @return {Duplex} The duplex stream\n * @public\n */\nfunction createWebSocketStream(ws, options) {\n let terminateOnDestroy = true;\n\n const duplex = new Duplex({\n ...options,\n autoDestroy: false,\n emitClose: false,\n objectMode: false,\n writableObjectMode: false\n });\n\n ws.on('message', function message(msg, isBinary) {\n const data =\n !isBinary && duplex._readableState.objectMode ? msg.toString() : msg;\n\n if (!duplex.push(data)) ws.pause();\n });\n\n ws.once('error', function error(err) {\n if (duplex.destroyed) return;\n\n // Prevent `ws.terminate()` from being called by `duplex._destroy()`.\n //\n // - If the `'error'` event is emitted before the `'open'` event, then\n // `ws.terminate()` is a noop as no socket is assigned.\n // - Otherwise, the error is re-emitted by the listener of the `'error'`\n // event of the `Receiver` object. The listener already closes the\n // connection by calling `ws.close()`. This allows a close frame to be\n // sent to the other peer. If `ws.terminate()` is called right after this,\n // then the close frame might not be sent.\n terminateOnDestroy = false;\n duplex.destroy(err);\n });\n\n ws.once('close', function close() {\n if (duplex.destroyed) return;\n\n duplex.push(null);\n });\n\n duplex._destroy = function (err, callback) {\n if (ws.readyState === ws.CLOSED) {\n callback(err);\n process.nextTick(emitClose, duplex);\n return;\n }\n\n let called = false;\n\n ws.once('error', function error(err) {\n called = true;\n callback(err);\n });\n\n ws.once('close', function close() {\n if (!called) callback(err);\n process.nextTick(emitClose, duplex);\n });\n\n if (terminateOnDestroy) ws.terminate();\n };\n\n duplex._final = function (callback) {\n if (ws.readyState === ws.CONNECTING) {\n ws.once('open', function open() {\n duplex._final(callback);\n });\n return;\n }\n\n // If the value of the `_socket` property is `null` it means that `ws` is a\n // client websocket and the handshake failed. In fact, when this happens, a\n // socket is never assigned to the websocket. Wait for the `'error'` event\n // that will be emitted by the websocket.\n if (ws._socket === null) return;\n\n if (ws._socket._writableState.finished) {\n callback();\n if (duplex._readableState.endEmitted) duplex.destroy();\n } else {\n ws._socket.once('finish', function finish() {\n // `duplex` is not destroyed here because the `'end'` event will be\n // emitted on `duplex` after this `'finish'` event. The EOF signaling\n // `null` chunk is, in fact, pushed when the websocket emits `'close'`.\n callback();\n });\n ws.close();\n }\n };\n\n duplex._read = function () {\n if (ws.isPaused) ws.resume();\n };\n\n duplex._write = function (chunk, encoding, callback) {\n if (ws.readyState === ws.CONNECTING) {\n ws.once('open', function open() {\n duplex._write(chunk, encoding, callback);\n });\n return;\n }\n\n ws.send(chunk, callback);\n };\n\n duplex.on('end', duplexOnEnd);\n duplex.on('error', duplexOnError);\n return duplex;\n}\n\nmodule.exports = createWebSocketStream;\n","'use strict';\n\nconst { tokenChars } = require('./validation');\n\n/**\n * Parses the `Sec-WebSocket-Protocol` header into a set of subprotocol names.\n *\n * @param {String} header The field value of the header\n * @return {Set} The subprotocol names\n * @public\n */\nfunction parse(header) {\n const protocols = new Set();\n let start = -1;\n let end = -1;\n let i = 0;\n\n for (i; i < header.length; i++) {\n const code = header.charCodeAt(i);\n\n if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (\n i !== 0 &&\n (code === 0x20 /* ' ' */ || code === 0x09) /* '\\t' */\n ) {\n if (end === -1 && start !== -1) end = i;\n } else if (code === 0x2c /* ',' */) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n\n const protocol = header.slice(start, end);\n\n if (protocols.has(protocol)) {\n throw new SyntaxError(`The \"${protocol}\" subprotocol is duplicated`);\n }\n\n protocols.add(protocol);\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n }\n\n if (start === -1 || end !== -1) {\n throw new SyntaxError('Unexpected end of input');\n }\n\n const protocol = header.slice(start, i);\n\n if (protocols.has(protocol)) {\n throw new SyntaxError(`The \"${protocol}\" subprotocol is duplicated`);\n }\n\n protocols.add(protocol);\n return protocols;\n}\n\nmodule.exports = { parse };\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^Duplex$\", \"caughtErrors\": \"none\" }] */\n\n'use strict';\n\nconst EventEmitter = require('events');\nconst http = require('http');\nconst { Duplex } = require('stream');\nconst { createHash } = require('crypto');\n\nconst extension = require('./extension');\nconst PerMessageDeflate = require('./permessage-deflate');\nconst subprotocol = require('./subprotocol');\nconst WebSocket = require('./websocket');\nconst { CLOSE_TIMEOUT, GUID, kWebSocket } = require('./constants');\n\nconst keyRegex = /^[+/0-9A-Za-z]{22}==$/;\n\nconst RUNNING = 0;\nconst CLOSING = 1;\nconst CLOSED = 2;\n\n/**\n * Class representing a WebSocket server.\n *\n * @extends EventEmitter\n */\nclass WebSocketServer extends EventEmitter {\n /**\n * Create a `WebSocketServer` instance.\n *\n * @param {Object} options Configuration options\n * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether\n * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted\n * multiple times in the same tick\n * @param {Boolean} [options.autoPong=true] Specifies whether or not to\n * automatically send a pong in response to a ping\n * @param {Number} [options.backlog=511] The maximum length of the queue of\n * pending connections\n * @param {Boolean} [options.clientTracking=true] Specifies whether or not to\n * track clients\n * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to\n * wait for the closing handshake to finish after `websocket.close()` is\n * called\n * @param {Function} [options.handleProtocols] A hook to handle protocols\n * @param {String} [options.host] The hostname where to bind the server\n * @param {Number} [options.maxBufferedChunks=1048576] The maximum number of\n * buffered data chunks\n * @param {Number} [options.maxFragments=131072] The maximum number of message\n * fragments\n * @param {Number} [options.maxPayload=104857600] The maximum allowed message\n * size\n * @param {Boolean} [options.noServer=false] Enable no server mode\n * @param {String} [options.path] Accept only connections matching this path\n * @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable\n * permessage-deflate\n * @param {Number} [options.port] The port where to bind the server\n * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S\n * server to use\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n * @param {Function} [options.verifyClient] A hook to reject connections\n * @param {Function} [options.WebSocket=WebSocket] Specifies the `WebSocket`\n * class to use. It must be the `WebSocket` class or class that extends it\n * @param {Function} [callback] A listener for the `listening` event\n */\n constructor(options, callback) {\n super();\n\n options = {\n allowSynchronousEvents: true,\n autoPong: true,\n maxBufferedChunks: 1024 * 1024,\n maxFragments: 128 * 1024,\n maxPayload: 100 * 1024 * 1024,\n skipUTF8Validation: false,\n perMessageDeflate: false,\n handleProtocols: null,\n clientTracking: true,\n closeTimeout: CLOSE_TIMEOUT,\n verifyClient: null,\n noServer: false,\n backlog: null, // use default (511 as implemented in net.js)\n server: null,\n host: null,\n path: null,\n port: null,\n WebSocket,\n ...options\n };\n\n if (\n (options.port == null && !options.server && !options.noServer) ||\n (options.port != null && (options.server || options.noServer)) ||\n (options.server && options.noServer)\n ) {\n throw new TypeError(\n 'One and only one of the \"port\", \"server\", or \"noServer\" options ' +\n 'must be specified'\n );\n }\n\n if (options.port != null) {\n this._server = http.createServer((req, res) => {\n const body = http.STATUS_CODES[426];\n\n res.writeHead(426, {\n 'Content-Length': body.length,\n 'Content-Type': 'text/plain'\n });\n res.end(body);\n });\n this._server.listen(\n options.port,\n options.host,\n options.backlog,\n callback\n );\n } else if (options.server) {\n this._server = options.server;\n }\n\n if (this._server) {\n const emitConnection = this.emit.bind(this, 'connection');\n\n this._removeListeners = addListeners(this._server, {\n listening: this.emit.bind(this, 'listening'),\n error: this.emit.bind(this, 'error'),\n upgrade: (req, socket, head) => {\n this.handleUpgrade(req, socket, head, emitConnection);\n }\n });\n }\n\n if (options.perMessageDeflate === true) options.perMessageDeflate = {};\n if (options.clientTracking) {\n this.clients = new Set();\n this._shouldEmitClose = false;\n }\n\n this.options = options;\n this._state = RUNNING;\n }\n\n /**\n * Returns the bound address, the address family name, and port of the server\n * as reported by the operating system if listening on an IP socket.\n * If the server is listening on a pipe or UNIX domain socket, the name is\n * returned as a string.\n *\n * @return {(Object|String|null)} The address of the server\n * @public\n */\n address() {\n if (this.options.noServer) {\n throw new Error('The server is operating in \"noServer\" mode');\n }\n\n if (!this._server) return null;\n return this._server.address();\n }\n\n /**\n * Stop the server from accepting new connections and emit the `'close'` event\n * when all existing connections are closed.\n *\n * @param {Function} [cb] A one-time listener for the `'close'` event\n * @public\n */\n close(cb) {\n if (this._state === CLOSED) {\n if (cb) {\n this.once('close', () => {\n cb(new Error('The server is not running'));\n });\n }\n\n process.nextTick(emitClose, this);\n return;\n }\n\n if (cb) this.once('close', cb);\n\n if (this._state === CLOSING) return;\n this._state = CLOSING;\n\n if (this.options.noServer || this.options.server) {\n if (this._server) {\n this._removeListeners();\n this._removeListeners = this._server = null;\n }\n\n if (this.clients) {\n if (!this.clients.size) {\n process.nextTick(emitClose, this);\n } else {\n this._shouldEmitClose = true;\n }\n } else {\n process.nextTick(emitClose, this);\n }\n } else {\n const server = this._server;\n\n this._removeListeners();\n this._removeListeners = this._server = null;\n\n //\n // The HTTP/S server was created internally. Close it, and rely on its\n // `'close'` event.\n //\n server.close(() => {\n emitClose(this);\n });\n }\n }\n\n /**\n * See if a given request should be handled by this server instance.\n *\n * @param {http.IncomingMessage} req Request object to inspect\n * @return {Boolean} `true` if the request is valid, else `false`\n * @public\n */\n shouldHandle(req) {\n if (this.options.path) {\n const index = req.url.indexOf('?');\n const pathname = index !== -1 ? req.url.slice(0, index) : req.url;\n\n if (pathname !== this.options.path) return false;\n }\n\n return true;\n }\n\n /**\n * Handle a HTTP Upgrade request.\n *\n * @param {http.IncomingMessage} req The request object\n * @param {Duplex} socket The network socket between the server and client\n * @param {Buffer} head The first packet of the upgraded stream\n * @param {Function} cb Callback\n * @public\n */\n handleUpgrade(req, socket, head, cb) {\n socket.on('error', socketOnError);\n\n const key = req.headers['sec-websocket-key'];\n const upgrade = req.headers.upgrade;\n const version = +req.headers['sec-websocket-version'];\n\n if (req.method !== 'GET') {\n const message = 'Invalid HTTP method';\n abortHandshakeOrEmitwsClientError(this, req, socket, 405, message);\n return;\n }\n\n if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {\n const message = 'Invalid Upgrade header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n\n if (key === undefined || !keyRegex.test(key)) {\n const message = 'Missing or invalid Sec-WebSocket-Key header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n\n if (version !== 13 && version !== 8) {\n const message = 'Missing or invalid Sec-WebSocket-Version header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message, {\n 'Sec-WebSocket-Version': '13, 8'\n });\n return;\n }\n\n if (!this.shouldHandle(req)) {\n abortHandshake(socket, 400);\n return;\n }\n\n const secWebSocketProtocol = req.headers['sec-websocket-protocol'];\n let protocols = new Set();\n\n if (secWebSocketProtocol !== undefined) {\n try {\n protocols = subprotocol.parse(secWebSocketProtocol);\n } catch (err) {\n const message = 'Invalid Sec-WebSocket-Protocol header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n }\n\n const secWebSocketExtensions = req.headers['sec-websocket-extensions'];\n const extensions = {};\n\n if (\n this.options.perMessageDeflate &&\n secWebSocketExtensions !== undefined\n ) {\n const perMessageDeflate = new PerMessageDeflate({\n ...this.options.perMessageDeflate,\n isServer: true,\n maxPayload: this.options.maxPayload\n });\n\n try {\n const offers = extension.parse(secWebSocketExtensions);\n\n if (offers[PerMessageDeflate.extensionName]) {\n perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]);\n extensions[PerMessageDeflate.extensionName] = perMessageDeflate;\n }\n } catch (err) {\n const message =\n 'Invalid or unacceptable Sec-WebSocket-Extensions header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n }\n\n //\n // Optionally call external client verification handler.\n //\n if (this.options.verifyClient) {\n const info = {\n origin:\n req.headers[`${version === 8 ? 'sec-websocket-origin' : 'origin'}`],\n secure: !!(req.socket.authorized || req.socket.encrypted),\n req\n };\n\n if (this.options.verifyClient.length === 2) {\n this.options.verifyClient(info, (verified, code, message, headers) => {\n if (!verified) {\n return abortHandshake(socket, code || 401, message, headers);\n }\n\n this.completeUpgrade(\n extensions,\n key,\n protocols,\n req,\n socket,\n head,\n cb\n );\n });\n return;\n }\n\n if (!this.options.verifyClient(info)) return abortHandshake(socket, 401);\n }\n\n this.completeUpgrade(extensions, key, protocols, req, socket, head, cb);\n }\n\n /**\n * Upgrade the connection to WebSocket.\n *\n * @param {Object} extensions The accepted extensions\n * @param {String} key The value of the `Sec-WebSocket-Key` header\n * @param {Set} protocols The subprotocols\n * @param {http.IncomingMessage} req The request object\n * @param {Duplex} socket The network socket between the server and client\n * @param {Buffer} head The first packet of the upgraded stream\n * @param {Function} cb Callback\n * @throws {Error} If called more than once with the same socket\n * @private\n */\n completeUpgrade(extensions, key, protocols, req, socket, head, cb) {\n //\n // Destroy the socket if the client has already sent a FIN packet.\n //\n if (!socket.readable || !socket.writable) return socket.destroy();\n\n if (socket[kWebSocket]) {\n throw new Error(\n 'server.handleUpgrade() was called more than once with the same ' +\n 'socket, possibly due to a misconfiguration'\n );\n }\n\n if (this._state > RUNNING) return abortHandshake(socket, 503);\n\n const digest = createHash('sha1')\n .update(key + GUID)\n .digest('base64');\n\n const headers = [\n 'HTTP/1.1 101 Switching Protocols',\n 'Upgrade: websocket',\n 'Connection: Upgrade',\n `Sec-WebSocket-Accept: ${digest}`\n ];\n\n const ws = new this.options.WebSocket(null, undefined, this.options);\n\n if (protocols.size) {\n //\n // Optionally call external protocol selection handler.\n //\n const protocol = this.options.handleProtocols\n ? this.options.handleProtocols(protocols, req)\n : protocols.values().next().value;\n\n if (protocol) {\n headers.push(`Sec-WebSocket-Protocol: ${protocol}`);\n ws._protocol = protocol;\n }\n }\n\n if (extensions[PerMessageDeflate.extensionName]) {\n const params = extensions[PerMessageDeflate.extensionName].params;\n const value = extension.format({\n [PerMessageDeflate.extensionName]: [params]\n });\n headers.push(`Sec-WebSocket-Extensions: ${value}`);\n ws._extensions = extensions;\n }\n\n //\n // Allow external modification/inspection of handshake headers.\n //\n this.emit('headers', headers, req);\n\n socket.write(headers.concat('\\r\\n').join('\\r\\n'));\n socket.removeListener('error', socketOnError);\n\n ws.setSocket(socket, head, {\n allowSynchronousEvents: this.options.allowSynchronousEvents,\n maxBufferedChunks: this.options.maxBufferedChunks,\n maxFragments: this.options.maxFragments,\n maxPayload: this.options.maxPayload,\n skipUTF8Validation: this.options.skipUTF8Validation\n });\n\n if (this.clients) {\n this.clients.add(ws);\n ws.on('close', () => {\n this.clients.delete(ws);\n\n if (this._shouldEmitClose && !this.clients.size) {\n process.nextTick(emitClose, this);\n }\n });\n }\n\n cb(ws, req);\n }\n}\n\nmodule.exports = WebSocketServer;\n\n/**\n * Add event listeners on an `EventEmitter` using a map of <event, listener>\n * pairs.\n *\n * @param {EventEmitter} server The event emitter\n * @param {Object.<String, Function>} map The listeners to add\n * @return {Function} A function that will remove the added listeners when\n * called\n * @private\n */\nfunction addListeners(server, map) {\n for (const event of Object.keys(map)) server.on(event, map[event]);\n\n return function removeListeners() {\n for (const event of Object.keys(map)) {\n server.removeListener(event, map[event]);\n }\n };\n}\n\n/**\n * Emit a `'close'` event on an `EventEmitter`.\n *\n * @param {EventEmitter} server The event emitter\n * @private\n */\nfunction emitClose(server) {\n server._state = CLOSED;\n server.emit('close');\n}\n\n/**\n * Handle socket errors.\n *\n * @private\n */\nfunction socketOnError() {\n this.destroy();\n}\n\n/**\n * Close the connection when preconditions are not fulfilled.\n *\n * @param {Duplex} socket The socket of the upgrade request\n * @param {Number} code The HTTP response status code\n * @param {String} [message] The HTTP response body\n * @param {Object} [headers] Additional HTTP response headers\n * @private\n */\nfunction abortHandshake(socket, code, message, headers) {\n //\n // The socket is writable unless the user destroyed or ended it before calling\n // `server.handleUpgrade()` or in the `verifyClient` function, which is a user\n // error. Handling this does not make much sense as the worst that can happen\n // is that some of the data written by the user might be discarded due to the\n // call to `socket.end()` below, which triggers an `'error'` event that in\n // turn causes the socket to be destroyed.\n //\n message = message || http.STATUS_CODES[code];\n headers = {\n Connection: 'close',\n 'Content-Type': 'text/html',\n 'Content-Length': Buffer.byteLength(message),\n ...headers\n };\n\n socket.once('finish', socket.destroy);\n\n socket.end(\n `HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\\r\\n` +\n Object.keys(headers)\n .map((h) => `${h}: ${headers[h]}`)\n .join('\\r\\n') +\n '\\r\\n\\r\\n' +\n message\n );\n}\n\n/**\n * Emit a `'wsClientError'` event on a `WebSocketServer` if there is at least\n * one listener for it, otherwise call `abortHandshake()`.\n *\n * @param {WebSocketServer} server The WebSocket server\n * @param {http.IncomingMessage} req The request object\n * @param {Duplex} socket The socket of the upgrade request\n * @param {Number} code The HTTP response status code\n * @param {String} message The HTTP response body\n * @param {Object} [headers] The HTTP response headers\n * @private\n */\nfunction abortHandshakeOrEmitwsClientError(\n server,\n req,\n socket,\n code,\n message,\n headers\n) {\n if (server.listenerCount('wsClientError')) {\n const err = new Error(message);\n Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError);\n\n server.emit('wsClientError', err, socket, req);\n } else {\n abortHandshake(socket, code, message, headers);\n }\n}\n","/**\n * High-level facade for the QQ Open Platform Node.js SDK.\n *\n * 这是大部分用户的主要入口。它把协议层(HTTP / WebSocket / 媒体上传 / 流式\n * 消息)组合成一个清晰的「机器人客户端」对象,类似 `@line/bot-sdk` 或\n * `@larksuiteoapi/node-sdk` 在其他平台上的角色。\n *\n * Example:\n * ```ts\n * import { QQBot } from \"@tencent-connect/qqbot-nodejs\";\n *\n * const bot = new QQBot({\n * appId: process.env.QQBOT_APP_ID!,\n * appSecret: process.env.QQBOT_APP_SECRET!,\n * });\n *\n * bot.on(\"message\", async (ctx, msg) => {\n * await bot.sendText(msg.replyTarget, `Echo: ${msg.content}`);\n * });\n *\n * await bot.start();\n * ```\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport {\n createMiddlewareContext,\n runMiddlewareChain,\n type Middleware,\n type MiddlewareContext,\n} from \"./middleware/types.js\";\nimport { ApiClient } from \"./protocol/api/api-client.js\";\nimport { ChunkedMediaApi } from \"./protocol/api/media-chunked.js\";\nimport { MediaApi } from \"./protocol/api/media.js\";\nimport { MessageApi } from \"./protocol/api/messages.js\";\nimport { TokenManager } from \"./protocol/api/token.js\";\nimport { GatewayConnection, type SessionPersistencePort } from \"./protocol/gateway/gateway-connection.js\";\nimport type { InboundMessage } from \"./protocol/gateway/event-dispatcher.js\";\nimport { WebhookTransport } from \"./protocol/transport/webhook.js\";\nimport type { EventTransport, WebhookServerAdapter } from \"./protocol/transport/types.js\";\nimport {\n MediaFileType,\n type ChatScope,\n type Credentials,\n type GatewayAccount,\n type InlineKeyboard,\n type InteractionEvent,\n type Logger,\n type MessageResponse,\n type UploadMediaResponse,\n} from \"./protocol/types.js\";\nimport { LARGE_FILE_THRESHOLD, sanitizeFileName } from \"./protocol/utils/file-utils.js\";\nimport { UploadCache } from \"./protocol/utils/upload-cache.js\";\nimport { StreamSession, type StreamSessionOptions } from \"./streaming.js\";\n\n// ============ Public types ============\n\n/** QQ Open Platform message type codes (msg_type). */\nexport const MsgType = {\n /** Plain text. */\n TEXT: 0,\n /** Markdown. */\n MARKDOWN: 2,\n /** Ark template message. */\n ARK: 3,\n /** Embed message. */\n EMBED: 4,\n /** Rich media (image/video/voice/file). */\n MEDIA: 7,\n} as const;\nexport type MsgType = (typeof MsgType)[keyof typeof MsgType];\n\n/** Universal message send options — supports all QQ platform message types. */\nexport interface SendMessageOptions {\n /** Target peer. When `msgId` is present → reply; otherwise → proactive. */\n target: ReplyTarget;\n /** Message type (auto-detected if omitted). */\n msgType?: MsgType;\n /** Plain text content. */\n content?: string;\n /** Markdown payload (msg_type=2). */\n markdown?: { content: string; custom_template_id?: string; params?: Array<{ key: string; values: string[] }> };\n /** Ark template payload (msg_type=3). */\n ark?: { template_id: number; kv: Array<{ key: string; value?: string; obj?: unknown[] }> };\n /** Embed payload (msg_type=4). */\n embed?: Record<string, unknown>;\n /** Rich media reference (msg_type=7, from uploadMedia response). */\n media?: { file_info: string };\n /** Inline keyboard (buttons). */\n keyboard?: InlineKeyboard;\n /** Message reference (quote/reply). */\n messageReference?: { message_id: string };\n /** Pass-through extra fields (for new platform features not yet typed). */\n extra?: Record<string, unknown>;\n}\n\n/** API Gateway interface — call any QQ Open Platform REST API. */\nexport interface ApiGateway {\n /**\n * Authenticated GET request.\n * @param query — values are auto-stringified (numbers accepted).\n */\n get<T = unknown>(path: string, query?: Record<string, string | number | boolean>): Promise<T>;\n /** Authenticated POST request. */\n post<T = unknown>(path: string, body?: unknown): Promise<T>;\n /** Authenticated PUT request. */\n put<T = unknown>(path: string, body?: unknown): Promise<T>;\n /** Authenticated PATCH request. */\n patch<T = unknown>(path: string, body?: unknown): Promise<T>;\n /** Authenticated DELETE request. */\n delete<T = unknown>(path: string): Promise<T>;\n /** Get the current valid access token (for advanced/custom usage). */\n getToken(): Promise<string>;\n}\n\n/** Resolved peer for outbound messages. */\nexport interface ReplyTarget {\n /** \"c2c\" for private chat, \"group\" for group chat. */\n scope: ChatScope;\n /** User openid (c2c) or group openid (group). */\n targetId: string;\n /** Inbound message id — used to associate the reply with the trigger. */\n msgId?: string;\n}\n\nexport interface QQBotOptions {\n /** QQ Open Platform AppID. */\n appId: string;\n /** QQ Open Platform AppSecret. */\n appSecret: string;\n /** Stable account identifier used for logging / session persistence. */\n accountId?: string;\n /** Whether the bot has markdown permission. Defaults to false. */\n markdownSupport?: boolean;\n /** Logger. Defaults to a no-op logger. */\n logger?: Logger;\n /** User-Agent header. Defaults to `qqbot-nodejs/<version>`. */\n userAgent?: string;\n /** Override the QQ Open Platform API base URL (mostly for tests). */\n baseUrl?: string;\n /** Override the token endpoint base URL. Defaults to `https://bots.qq.com`. */\n tokenBaseUrl?: string;\n /** Optional session persistence (e.g. file-backed). */\n sessionPersistence?: SessionPersistencePort;\n /** Custom intent mask. Defaults to FULL_INTENTS (group + c2c + interaction). */\n intents?: number;\n /** Override the upload cache. Defaults to a private in-memory cache. */\n uploadCache?: UploadCache;\n\n /**\n * Event transport mode.\n * - `\"websocket\"` (default): long-lived WS connection with heartbeat/RESUME.\n * - `\"webhook\"`: QQ POSTs events to your HTTPS endpoint.\n * - Custom `EventTransport` instance for advanced use.\n */\n transport?: \"websocket\" | \"webhook\" | EventTransport;\n\n /**\n * Token prefetch strategy at startup.\n * - `\"sync\"` (default): Await token fetch before accepting traffic.\n * Provides fail-fast semantics — credential errors surface immediately.\n * - `\"async\"`: Start accepting traffic immediately; token is fetched in\n * the background. Faster startup but first requests may fail if token\n * is not yet available.\n */\n tokenPrefetch?: \"sync\" | \"async\";\n\n /** Webhook-specific options (only used when `transport: \"webhook\"`). */\n webhook?: {\n /** Port to listen on. Defaults to 8080. */\n port?: number;\n /** Path to listen on. Defaults to \"/\". */\n path?: string;\n /** Bring your own HTTP server adapter (Express/Fastify/Koa). */\n server?: WebhookServerAdapter;\n };\n}\n\n/** Lightweight context for interaction events (pre-reserved for future middleware). */\nexport interface InteractionContext {\n /** The QQBot instance. */\n readonly bot: QQBot;\n /** The interaction event. */\n readonly event: InteractionEvent;\n /** Per-request state slot (for future middleware to share data). */\n state: Record<string, unknown>;\n /** Timestamp when the SDK received this event. */\n readonly receivedAt: number;\n}\n\n/** Lightweight context for raw gateway events (pre-reserved for future middleware). */\nexport interface RawEventContext {\n /** The QQBot instance. */\n readonly bot: QQBot;\n /** Gateway event type string (e.g. \"GUILD_CREATE\", \"FRIEND_ADD\"). */\n readonly eventType: string;\n /** Raw event data from the platform. */\n readonly data: unknown;\n /** Per-request state slot (for future middleware to share data). */\n state: Record<string, unknown>;\n /** Timestamp when the SDK received this event. */\n readonly receivedAt: number;\n}\n\n/** Built-in event names. */\nexport type QQBotEventMap = {\n ready: (data: unknown) => void;\n resumed: (data: unknown) => void;\n error: (err: Error) => void;\n message: (ctx: MiddlewareContext, msg: QQBotInboundMessage) => void | Promise<void>;\n interaction: (ctx: InteractionContext, event: InteractionEvent) => void | Promise<void>;\n /**\n * Raw gateway event pass-through for any event not handled by SDK internals.\n *\n * Covers all platform events (guild/group/friend lifecycle, reactions, etc.)\n * without SDK needing explicit support. New platform events are immediately\n * available here with zero SDK changes.\n *\n * @example\n * ```ts\n * bot.on('rawEvent', (ctx) => {\n * if (ctx.eventType === 'FRIEND_ADD') {\n * const e = ctx.data as { openid: string; timestamp: string };\n * console.log('New friend:', e.openid);\n * }\n * });\n * ```\n */\n rawEvent: (ctx: RawEventContext) => void | Promise<void>;\n};\n\n/**\n * Augmented inbound message with a ready-to-use `replyTarget`.\n */\nexport interface QQBotInboundMessage extends InboundMessage {\n /** The peer this message originated from — pass to `bot.sendText`/`bot.sendFile`. */\n replyTarget: ReplyTarget;\n}\n\n// ============ QQBot class ============\n\nconst noopLogger: Logger = {\n info: () => {},\n error: () => {},\n warn: () => {},\n debug: () => {},\n};\n\n/**\n * High-level QQ Open Platform client.\n *\n * Owns an isolated stack of low-level primitives (token manager, HTTP\n * client, message API, media APIs, gateway connection) per bot instance,\n * so multiple bots can run concurrently without sharing global state.\n */\nexport class QQBot {\n // Public protocol primitives — exposed for advanced users.\n readonly tokenManager: TokenManager;\n readonly apiClient: ApiClient;\n readonly messageApi: MessageApi;\n readonly mediaApi: MediaApi;\n readonly chunkedMediaApi: ChunkedMediaApi;\n\n private readonly opts: QQBotOptions;\n private readonly logger: Logger;\n private readonly creds: Credentials;\n private readonly account: GatewayAccount;\n private readonly userAgent: string;\n private readonly uploadCache: UploadCache;\n private readonly middlewares: Middleware[] = [];\n private readonly handlers: { [K in keyof QQBotEventMap]: Set<QQBotEventMap[K]> } = {\n ready: new Set(),\n resumed: new Set(),\n error: new Set(),\n message: new Set(),\n interaction: new Set(),\n rawEvent: new Set(),\n };\n\n private gateway: GatewayConnection | null = null;\n private abortController: AbortController | null = null;\n private _apiGateway: ApiGateway | null = null;\n\n constructor(options: QQBotOptions) {\n if (!options.appId) {\n throw new Error(\"QQBot: appId is required\");\n }\n if (!options.appSecret) {\n throw new Error(\"QQBot: appSecret is required\");\n }\n this.opts = options;\n this.logger = options.logger ?? noopLogger;\n this.userAgent = options.userAgent ?? `qqbot-nodejs/0.1.0 (Node/${process.versions.node})`;\n this.creds = {\n appId: options.appId,\n clientSecret: options.appSecret,\n };\n this.account = {\n accountId: options.accountId ?? options.appId,\n appId: options.appId,\n clientSecret: options.appSecret,\n markdownSupport: options.markdownSupport === true,\n };\n\n this.uploadCache = options.uploadCache ?? new UploadCache({ logger: this.logger });\n\n this.apiClient = new ApiClient({\n logger: this.logger,\n userAgent: this.userAgent,\n baseUrl: options.baseUrl,\n });\n this.tokenManager = new TokenManager({\n logger: this.logger,\n userAgent: this.userAgent,\n baseUrl: options.tokenBaseUrl,\n });\n this.messageApi = new MessageApi(this.apiClient, this.tokenManager, {\n markdownSupport: options.markdownSupport === true,\n logger: this.logger,\n });\n\n const cacheAdapter = {\n computeHash: (data: string) => this.uploadCache.computeHash(data),\n get: (hash: string, scope: string, targetId: string, fileType: number) =>\n this.uploadCache.get(hash, scope as ChatScope, targetId, fileType),\n set: (\n hash: string,\n scope: string,\n targetId: string,\n fileType: number,\n fileInfo: string,\n fileUuid: string,\n ttl: number,\n ) =>\n this.uploadCache.set(\n hash,\n scope as ChatScope,\n targetId,\n fileType,\n fileInfo,\n fileUuid,\n ttl,\n ),\n };\n\n this.mediaApi = new MediaApi(this.apiClient, this.tokenManager, {\n logger: this.logger,\n uploadCache: cacheAdapter,\n sanitizeFileName,\n });\n this.chunkedMediaApi = new ChunkedMediaApi(this.apiClient, this.tokenManager, {\n logger: this.logger,\n uploadCache: cacheAdapter,\n sanitizeFileName,\n });\n }\n\n // ============ Public getters ============\n\n /** The QQ Open Platform AppID this bot is bound to. */\n get appId(): string {\n return this.creds.appId;\n }\n\n /** The stable account id (defaults to appId). */\n get accountId(): string {\n return this.account.accountId;\n }\n\n // ============ Event listeners ============\n\n on<K extends keyof QQBotEventMap>(event: K, handler: QQBotEventMap[K]): this {\n this.handlers[event].add(handler);\n return this;\n }\n\n off<K extends keyof QQBotEventMap>(event: K, handler: QQBotEventMap[K]): this {\n this.handlers[event].delete(handler);\n return this;\n }\n\n // ============ Middleware ============\n\n /**\n * Register an inbound middleware. Middlewares run in registration order\n * before the `message` event listeners; calling `ctx.stop()` (or simply\n * not calling `next()`) short-circuits the chain — including the final\n * `message` listener.\n *\n * @example\n * ```ts\n * import { accessPolicy, mentionGate } from \"@tencent-connect/qqbot-nodejs\";\n * bot.use(accessPolicy({ group: { mode: \"allowlist\", allow: [...] } }));\n * bot.use(mentionGate());\n * bot.on(\"message\", async (ctx, msg) => { ... });\n * ```\n */\n use(...middleware: Middleware[]): this {\n for (const mw of middleware) {\n if (typeof mw !== \"function\") {\n throw new Error(\"QQBot.use: middleware must be a function\");\n }\n this.middlewares.push(mw);\n }\n return this;\n }\n\n /** Read the registered middleware chain (for diagnostics). */\n getMiddlewares(): readonly Middleware[] {\n return this.middlewares;\n }\n\n private async emit<K extends keyof QQBotEventMap>(\n event: K,\n ...args: Parameters<QQBotEventMap[K]>\n ): Promise<void> {\n for (const handler of this.handlers[event]) {\n try {\n await Promise.resolve((handler as (...a: unknown[]) => unknown)(...args));\n } catch (err) {\n this.logger.error?.(\n `[qqbot] handler for \"${String(event)}\" threw: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n }\n\n // ============ Lifecycle ============\n\n /**\n * Start receiving events from QQ Open Platform.\n *\n * - **WebSocket mode** (default): connects to the WS gateway with heartbeat/RESUME.\n * - **Webhook mode**: starts an HTTP server to receive POST callbacks.\n *\n * Resolves when {@link stop} or the abort signal terminates the connection.\n */\n async start(externalSignal?: AbortSignal): Promise<void> {\n if (this.gateway) {\n throw new Error(\"QQBot: already started\");\n }\n this.abortController = new AbortController();\n if (externalSignal) {\n if (externalSignal.aborted) {\n this.abortController.abort();\n } else {\n externalSignal.addEventListener(\"abort\", () => this.abortController?.abort(), {\n once: true,\n });\n }\n }\n\n const transportMode = this.opts.transport ?? \"websocket\";\n\n if (transportMode === \"webhook\") {\n await this.startWebhook();\n } else if (transportMode === \"websocket\") {\n await this.startWebSocket();\n } else {\n // Custom EventTransport instance\n const custom = transportMode as EventTransport;\n await custom.start();\n }\n\n // Cleanup\n this.tokenManager.stopBackgroundRefresh(this.creds.appId);\n this.gateway = null;\n this.abortController = null;\n }\n\n /** Stop the transport and background refreshers. */\n stop(): void {\n this.abortController?.abort();\n this.tokenManager.stopBackgroundRefresh(this.creds.appId);\n this.gateway = null;\n this.abortController = null;\n }\n\n // ============ Token initialization ============\n\n /**\n * Initialize token based on the configured prefetch strategy.\n *\n * - `\"sync\"` (default): awaits the first token fetch, providing fail-fast\n * semantics so credential errors surface at startup.\n * - `\"async\"`: fires the token fetch in the background and starts the\n * background refresher immediately — trades fail-fast for faster startup.\n */\n private async initToken(): Promise<void> {\n const mode = this.opts.tokenPrefetch ?? \"sync\";\n\n if (mode === \"sync\") {\n await this.tokenManager.getAccessToken(this.creds.appId, this.creds.clientSecret);\n } else {\n // Fire-and-forget: fetch token in background, log errors but don't block startup.\n this.tokenManager.getAccessToken(this.creds.appId, this.creds.clientSecret).catch((err) => {\n this.logger.error?.(`[qqbot] async token prefetch failed: ${err}`);\n void this.emit(\"error\", err instanceof Error ? err : new Error(String(err)));\n });\n }\n\n this.tokenManager.startBackgroundRefresh(this.creds.appId, this.creds.clientSecret);\n }\n\n // ============ Transport: WebSocket ============\n\n private async startWebSocket(): Promise<void> {\n await this.initToken();\n\n this.gateway = new GatewayConnection({\n account: this.account,\n abortSignal: this.abortController!.signal,\n log: this.logger,\n userAgent: this.userAgent,\n intents: this.opts.intents,\n session: this.opts.sessionPersistence,\n getAccessToken: () =>\n this.tokenManager.getAccessToken(this.creds.appId, this.creds.clientSecret),\n clearTokenCache: () => this.tokenManager.clearCache(this.creds.appId),\n getGatewayUrl: () => this.messageApi.getGatewayUrl(this.creds),\n onReady: (data) => {\n this.logger.info?.(`[qqbot] gateway READY`);\n void this.emit(\"ready\", data);\n },\n onResumed: (data) => {\n this.logger.info?.(`[qqbot] gateway RESUMED`);\n void this.emit(\"resumed\", data);\n },\n onError: (err) => {\n void this.emit(\"error\", err);\n },\n onMessage: (raw) => this.handleInboundMessage(raw),\n onInteraction: (event) => {\n const ctx: InteractionContext = { bot: this, event, state: {}, receivedAt: Date.now() };\n void this.emit(\"interaction\", ctx, event);\n },\n onRawEvent: (type, data) => {\n const ctx: RawEventContext = { bot: this, eventType: type, data, state: {}, receivedAt: Date.now() };\n void this.emit(\"rawEvent\", ctx);\n },\n });\n\n await this.gateway.start();\n }\n\n // ============ Transport: Webhook ============\n\n private async startWebhook(): Promise<void> {\n await this.initToken();\n\n const webhook = new WebhookTransport(\n {\n appId: this.creds.appId,\n appSecret: this.creds.clientSecret,\n port: this.opts.webhook?.port,\n path: this.opts.webhook?.path,\n server: this.opts.webhook?.server,\n accountId: this.account.accountId,\n log: this.logger,\n abortSignal: this.abortController!.signal,\n },\n {\n onReady: (data) => {\n this.logger.info?.(`[qqbot] webhook READY`);\n void this.emit(\"ready\", data);\n },\n onResumed: (data) => {\n void this.emit(\"resumed\", data);\n },\n onError: (err) => {\n void this.emit(\"error\", err);\n },\n onMessage: (raw) => this.handleInboundMessage(raw),\n onInteraction: (event) => {\n const ctx: InteractionContext = { bot: this, event, state: {}, receivedAt: Date.now() };\n void this.emit(\"interaction\", ctx, event);\n },\n },\n );\n\n await webhook.start();\n }\n\n // ============ Shared inbound message handler ============\n\n private async handleInboundMessage(raw: InboundMessage): Promise<void> {\n const replyTarget = this.deriveReplyTarget(raw);\n if (!replyTarget) {\n this.logger.debug?.(`[qqbot] inbound message has no reply target — skipping`);\n return;\n }\n const augmented: QQBotInboundMessage = { ...raw, replyTarget };\n\n const ctx = createMiddlewareContext({\n bot: this,\n message: augmented,\n log: this.logger,\n });\n\n // Koa-style: compose middleware chain with emit as the final downstream.\n const downstream: Middleware = async () => {\n await this.emit(\"message\", ctx, ctx.message);\n };\n const chain: Middleware[] = [...this.middlewares, downstream];\n\n try {\n await runMiddlewareChain(chain, ctx);\n } catch (err) {\n this.logger.error?.(\n `[qqbot] middleware chain threw: ${err instanceof Error ? err.message : String(err)}`,\n );\n void this.emit(\"error\", err instanceof Error ? err : new Error(String(err)));\n }\n }\n\n // ============ Message sending ============\n\n /**\n * Universal message send — supports all QQ Open Platform message types.\n *\n * This is the most flexible sending method. It accepts the full parameter\n * set of POST `/v2/users/{openid}/messages` or `/v2/groups/{group_openid}/messages`.\n * Use it when the convenience helpers (sendText, sendMarkdown, etc.) don't\n * cover your use case.\n *\n * `msg_type` is auto-detected if not specified:\n * - markdown field present → 2 (Markdown)\n * - ark field present → 3 (Ark)\n * - embed field present → 4 (Embed)\n * - media field present → 7 (Rich media)\n * - otherwise → 0 (Text)\n *\n * @example Send a keyboard message\n * ```ts\n * await bot.send({\n * target: msg.replyTarget,\n * msgType: MsgType.MARKDOWN,\n * markdown: { content: '# Hello' },\n * keyboard: { content: { rows: [...] } },\n * });\n * ```\n *\n * @example Send a proactive message (no msgId)\n * ```ts\n * await bot.send({\n * target: { scope: 'c2c', targetId: openid },\n * content: 'Hello from bot!',\n * });\n * ```\n */\n async send(opts: SendMessageOptions): Promise<MessageResponse> {\n const body: Record<string, unknown> = {};\n if (opts.target.msgId) body.msg_id = opts.target.msgId;\n if (opts.msgType !== undefined) body.msg_type = opts.msgType;\n if (opts.content !== undefined) body.content = opts.content;\n if (opts.markdown) body.markdown = opts.markdown;\n if (opts.ark) body.ark = opts.ark;\n if (opts.embed) body.embed = opts.embed;\n if (opts.media) body.media = opts.media;\n if (opts.keyboard) body.keyboard = opts.keyboard;\n if (opts.messageReference) body.message_reference = opts.messageReference;\n if (opts.extra) Object.assign(body, opts.extra);\n return this.messageApi.sendRaw(opts.target.scope, opts.target.targetId, this.creds, body);\n }\n\n /**\n * Send a text message to a C2C user or group (smart mode).\n *\n * **Difference from `send()`**:\n * - `sendText` auto-selects msg_type based on `markdownSupport` config\n * (markdown bots automatically send as msg_type=2).\n * - `send()` is explicit mode — you control msg_type directly.\n *\n * When `target.msgId` is present the message is treated as a reply\n * (tied to the inbound message lifecycle); otherwise it is treated as\n * a proactive push.\n */\n async sendText(target: ReplyTarget, content: string): Promise<MessageResponse> {\n if (target.msgId) {\n return this.messageApi.sendMessage(target.scope, target.targetId, content, this.creds, {\n msgId: target.msgId,\n });\n }\n return this.messageApi.sendProactiveMessage(\n target.scope,\n target.targetId,\n content,\n this.creds,\n );\n }\n\n /** Send a text message with an inline keyboard. */\n async sendTextWithKeyboard(\n target: ReplyTarget,\n content: string,\n inlineKeyboard: InlineKeyboard,\n ): Promise<MessageResponse> {\n return this.messageApi.sendMessage(target.scope, target.targetId, content, this.creds, {\n msgId: target.msgId,\n inlineKeyboard,\n });\n }\n\n /**\n * Send a Markdown message (msg_type=2).\n *\n * @example\n * ```ts\n * await bot.sendMarkdown(msg.replyTarget, '# Hello **world**');\n * await bot.sendMarkdown(msg.replyTarget, '# Click below', {\n * keyboard: { content: { rows: [...] } },\n * });\n * ```\n */\n async sendMarkdown(\n target: ReplyTarget,\n content: string,\n opts?: { keyboard?: InlineKeyboard },\n ): Promise<MessageResponse> {\n return this.send({\n target,\n msgType: MsgType.MARKDOWN,\n markdown: { content },\n keyboard: opts?.keyboard,\n });\n }\n\n /**\n * Recall (delete) a previously sent message.\n *\n * @example\n * ```ts\n * const sent = await bot.sendText(target, 'oops');\n * await bot.recallMessage(target, sent.id);\n * ```\n */\n async recallMessage(target: ReplyTarget, messageId: string): Promise<void> {\n return this.messageApi.recallMessage(target.scope, target.targetId, messageId, this.creds);\n }\n\n /**\n * Send a wakeup/recall message (C2C only, 30-day window).\n *\n * After a user initiates a conversation, the bot can send periodic\n * recall messages within 30 days using `is_wakeup: true`.\n * Platform enforces frequency limits.\n *\n * @example\n * ```ts\n * await bot.sendWakeup({ scope: 'c2c', targetId: openid }, '你有新消息!');\n * ```\n */\n async sendWakeup(target: ReplyTarget, content: string): Promise<MessageResponse> {\n if (target.scope !== \"c2c\") {\n throw new Error(\"sendWakeup is only supported for C2C targets\");\n }\n return this.send({ target, content, extra: { is_wakeup: true } });\n }\n\n /**\n * Send a message to a guild text channel.\n *\n * @example\n * ```ts\n * await bot.sendChannelMessage(channelId, '频道消息', { msgId });\n * ```\n */\n async sendChannelMessage(\n channelId: string,\n content: string,\n opts?: { msgId?: string; keyboard?: InlineKeyboard; messageReference?: string },\n ): Promise<MessageResponse> {\n const body: Record<string, unknown> = { content };\n if (opts?.msgId) body.msg_id = opts.msgId;\n if (opts?.keyboard) body.keyboard = opts.keyboard;\n if (opts?.messageReference) body.message_reference = { message_id: opts.messageReference };\n return this.messageApi.sendChannelMessageRaw(channelId, this.creds, body);\n }\n\n /**\n * Send a direct message (DM) in a guild.\n *\n * @example\n * ```ts\n * await bot.sendDmMessage(guildId, '私信内容', { msgId });\n * ```\n */\n async sendDmMessage(\n guildId: string,\n content: string,\n opts?: { msgId?: string },\n ): Promise<MessageResponse> {\n const body: Record<string, unknown> = { content };\n if (opts?.msgId) body.msg_id = opts.msgId;\n return this.messageApi.sendDmMessageRaw(guildId, this.creds, body);\n }\n\n /** Send a typing indicator (C2C only). */\n async sendTyping(target: ReplyTarget, durationSec = 30): Promise<{ refIdx?: string }> {\n if (target.scope !== \"c2c\") {\n throw new Error(\"sendTyping is only supported for C2C targets\");\n }\n return this.messageApi.sendInputNotify({\n openid: target.targetId,\n creds: this.creds,\n msgId: target.msgId,\n inputSecond: durationSec,\n });\n }\n\n /** Acknowledge an INTERACTION_CREATE event. */\n async acknowledgeInteraction(\n interactionId: string,\n code: 0 | 1 | 2 | 3 | 4 | 5 = 0,\n ): Promise<void> {\n return this.messageApi.acknowledgeInteraction(interactionId, this.creds, code);\n }\n\n // ============ API Gateway ============\n\n /**\n * Open Platform API Gateway — call any QQ Open Platform REST API with\n * automatic token injection and refresh.\n *\n * This is the \"escape hatch\" for any API not wrapped by a dedicated method.\n * All requests are authenticated, rate-limit aware, and return structured errors.\n *\n * @example List guilds\n * ```ts\n * const guilds = await bot.api.get('/users/@me/guilds');\n * ```\n *\n * @example Create an announcement\n * ```ts\n * await bot.api.post(`/guilds/${guildId}/announces`, {\n * message_id: msgId, channel_id: channelId,\n * });\n * ```\n *\n * @example Get a raw access token\n * ```ts\n * const token = await bot.api.getToken();\n * ```\n */\n get api(): ApiGateway {\n if (this._apiGateway) return this._apiGateway;\n this._apiGateway = {\n get: <T = unknown>(path: string, query?: Record<string, string | number | boolean>) =>\n this.apiRequest<T>(\"GET\", path, undefined, query),\n post: <T = unknown>(path: string, body?: unknown) =>\n this.apiRequest<T>(\"POST\", path, body),\n put: <T = unknown>(path: string, body?: unknown) =>\n this.apiRequest<T>(\"PUT\", path, body),\n patch: <T = unknown>(path: string, body?: unknown) =>\n this.apiRequest<T>(\"PATCH\", path, body),\n delete: <T = unknown>(path: string) =>\n this.apiRequest<T>(\"DELETE\", path),\n getToken: () =>\n this.tokenManager.getAccessToken(this.creds.appId, this.creds.clientSecret),\n };\n return this._apiGateway;\n }\n\n private async apiRequest<T>(\n method: string,\n path: string,\n body?: unknown,\n query?: Record<string, string | number | boolean>,\n ): Promise<T> {\n const token = await this.tokenManager.getAccessToken(\n this.creds.appId,\n this.creds.clientSecret,\n );\n let fullPath = path;\n if (query && Object.keys(query).length > 0) {\n const params = new URLSearchParams();\n for (const [k, v] of Object.entries(query)) {\n if (v !== undefined && v !== null) params.set(k, String(v));\n }\n fullPath = `${path}?${params.toString()}`;\n }\n return this.apiClient.request<T>(token, method, fullPath, body ?? undefined);\n }\n\n // ============ Streaming ============\n\n /**\n * Open a C2C stream session for incremental output.\n *\n * @returns A {@link StreamSession} — call `update(fullText)` repeatedly,\n * then `complete()` when finished.\n */\n openStream(opts: {\n target: ReplyTarget;\n eventId?: string;\n throttleMs?: number;\n }): StreamSession {\n if (opts.target.scope !== \"c2c\") {\n throw new Error(\"Streaming is only supported for C2C targets\");\n }\n if (!opts.target.msgId) {\n throw new Error(\"Streaming requires target.msgId from the inbound message\");\n }\n const sessionOptions: StreamSessionOptions = {\n openid: opts.target.targetId,\n msgId: opts.target.msgId,\n creds: this.creds,\n eventId: opts.eventId,\n throttleMs: opts.throttleMs,\n logger: this.logger,\n };\n return new StreamSession(this.messageApi, sessionOptions);\n }\n\n // ============ Media ============\n\n /**\n * Upload media (image / voice / video / file) to a target. Automatically\n * dispatches to the chunked-upload path when the source exceeds\n * {@link LARGE_FILE_THRESHOLD} bytes.\n */\n async uploadMedia(opts: {\n target: ReplyTarget;\n fileType: MediaFileType;\n /** Mutually exclusive: pass exactly one source. */\n url?: string;\n fileData?: string;\n buffer?: Buffer;\n localPath?: string;\n fileName?: string;\n /** Whether to let the server send the message immediately. */\n srvSendMsg?: boolean;\n onProgress?: (uploaded: number, total: number) => void;\n }): Promise<UploadMediaResponse> {\n const sources = [opts.url, opts.fileData, opts.buffer, opts.localPath].filter(\n (v) => v !== undefined,\n );\n if (sources.length === 0) {\n throw new Error(\"uploadMedia: one of url/fileData/buffer/localPath is required\");\n }\n if (sources.length > 1) {\n throw new Error(\"uploadMedia: provide exactly one source\");\n }\n\n const size = await this.computeSourceSize(opts);\n const useChunked = size !== null && size >= LARGE_FILE_THRESHOLD;\n\n // Auto-fill fileName from localPath or URL when not explicitly provided\n const fileName = opts.fileName\n ?? (opts.localPath ? path.basename(opts.localPath) : undefined)\n ?? (opts.url ? decodeURIComponent(path.basename(new URL(opts.url).pathname)) || undefined : undefined);\n\n if (useChunked && (opts.localPath || opts.buffer)) {\n const source = opts.localPath\n ? { kind: \"localPath\" as const, path: opts.localPath, size: size! }\n : {\n kind: \"buffer\" as const,\n buffer: opts.buffer!,\n fileName,\n };\n return this.chunkedMediaApi.uploadChunked({\n scope: opts.target.scope,\n targetId: opts.target.targetId,\n fileType: opts.fileType,\n source,\n creds: this.creds,\n fileName,\n onProgress: opts.onProgress\n ? (p) => opts.onProgress!(p.uploadedBytes, p.totalBytes)\n : undefined,\n });\n }\n\n return this.mediaApi.uploadMedia(\n opts.target.scope,\n opts.target.targetId,\n opts.fileType,\n this.creds,\n {\n url: opts.url,\n fileData: opts.fileData,\n buffer: opts.buffer,\n localPath: opts.localPath,\n srvSendMsg: opts.srvSendMsg,\n fileName,\n },\n );\n }\n\n /**\n * Upload + send a media message to a C2C user or group.\n */\n async sendMedia(opts: {\n target: ReplyTarget;\n fileType: MediaFileType;\n url?: string;\n fileData?: string;\n buffer?: Buffer;\n localPath?: string;\n fileName?: string;\n /** Optional caption (sent as the `content` field). */\n content?: string;\n onProgress?: (uploaded: number, total: number) => void;\n }): Promise<{ upload: UploadMediaResponse; message: MessageResponse | undefined }> {\n const upload = await this.uploadMedia({ ...opts, srvSendMsg: false });\n const message = await this.mediaApi.sendMediaMessage(\n opts.target.scope,\n opts.target.targetId,\n upload.file_info,\n this.creds,\n {\n msgId: opts.target.msgId,\n content: opts.content,\n },\n );\n return { upload, message };\n }\n\n /** Convenience: upload + send an image. */\n async sendImage(\n target: ReplyTarget,\n source: { url?: string; buffer?: Buffer; localPath?: string },\n opts?: { content?: string; onProgress?: (uploaded: number, total: number) => void },\n ): Promise<{ upload: UploadMediaResponse; message: MessageResponse | undefined }> {\n return this.sendMedia({\n target,\n fileType: MediaFileType.IMAGE,\n ...source,\n content: opts?.content,\n onProgress: opts?.onProgress,\n });\n }\n\n /** Convenience: upload + send a video. */\n async sendVideo(\n target: ReplyTarget,\n source: { url?: string; buffer?: Buffer; localPath?: string },\n opts?: { content?: string; onProgress?: (uploaded: number, total: number) => void },\n ): Promise<{ upload: UploadMediaResponse; message: MessageResponse | undefined }> {\n return this.sendMedia({\n target,\n fileType: MediaFileType.VIDEO,\n ...source,\n content: opts?.content,\n onProgress: opts?.onProgress,\n });\n }\n\n /** Convenience: upload + send a voice message. */\n async sendVoice(\n target: ReplyTarget,\n source: { url?: string; buffer?: Buffer; localPath?: string },\n opts?: { onProgress?: (uploaded: number, total: number) => void },\n ): Promise<{ upload: UploadMediaResponse; message: MessageResponse | undefined }> {\n return this.sendMedia({\n target,\n fileType: MediaFileType.VOICE,\n ...source,\n onProgress: opts?.onProgress,\n });\n }\n\n /** Convenience: upload + send a generic file (for users with file-message permission). */\n async sendFile(\n target: ReplyTarget,\n source: { url?: string; buffer?: Buffer; localPath?: string },\n opts?: {\n fileName?: string;\n content?: string;\n onProgress?: (uploaded: number, total: number) => void;\n },\n ): Promise<{ upload: UploadMediaResponse; message: MessageResponse | undefined }> {\n return this.sendMedia({\n target,\n fileType: MediaFileType.FILE,\n ...source,\n fileName: opts?.fileName,\n content: opts?.content,\n onProgress: opts?.onProgress,\n });\n }\n\n // ============ Internal ============\n\n private deriveReplyTarget(raw: InboundMessage): ReplyTarget | null {\n if (raw.kind === \"c2c\") {\n return { scope: \"c2c\", targetId: raw.senderId, msgId: raw.messageId };\n }\n if (raw.kind === \"group\" && raw.groupOpenid) {\n return { scope: \"group\", targetId: raw.groupOpenid, msgId: raw.messageId };\n }\n // Guild / DM 暂时没有 channel-level 的 c2c/group 等价。SDK 选择忽略\n // 这两类消息(业务侧仍然可以通过 raw 字段自己处理)。\n return null;\n }\n\n private async computeSourceSize(opts: {\n url?: string;\n fileData?: string;\n buffer?: Buffer;\n localPath?: string;\n }): Promise<number | null> {\n if (opts.buffer) {\n return opts.buffer.length;\n }\n if (opts.localPath) {\n try {\n const stat = await fs.promises.stat(opts.localPath);\n return stat.size;\n } catch {\n return null;\n }\n }\n if (opts.fileData) {\n // base64 length → byte length estimate.\n return Math.floor((opts.fileData.length * 3) / 4);\n }\n // url upload — server-side size, can't know up-front.\n return null;\n }\n}\n","/**\n * Middleware chain — pluggable inbound message processing pipeline.\n *\n * Inspired by Koa / Express middleware: each middleware receives a context\n * object and a `next()` function, and may run arbitrary logic before / after\n * downstream middleware. Calling `ctx.stop()` (or simply not calling `next()`)\n * short-circuits the chain.\n *\n * The SDK ships several **built-in middleware** in `./middleware/*` that cover\n * common needs (access policy, mention gating, command dispatch). Users can\n * compose them, replace them, or add their own.\n *\n * @example\n * ```ts\n * import { QQBot, accessPolicy, mentionGate } from \"@tencent-connect/qqbot-nodejs\";\n *\n * const bot = new QQBot({ appId, appSecret });\n *\n * bot.use(accessPolicy({ allowFrom: [\"*\"] }));\n * bot.use(mentionGate({ requireMentionInGroup: true }));\n * bot.use(async (ctx, next) => {\n * // Custom logic before\n * await next();\n * // Custom logic after\n * });\n *\n * bot.on(\"message\", async (msg) => {\n * await bot.sendText(msg.replyTarget, `Echo: ${msg.content}`);\n * });\n * ```\n */\n\nimport type { QQBot, QQBotInboundMessage, ReplyTarget } from \"../QQBot.js\";\nimport type { Logger } from \"../protocol/types.js\";\n\n// ============ Types ============\n\n/**\n * Free-form per-request state slot, augmentable via TS module augmentation.\n * Built-in middleware fills well-known keys (see `middleware/index.ts`).\n */\nexport interface MiddlewareState {\n [key: string]: unknown;\n}\n\n/**\n * Context passed to each middleware.\n *\n * Mutating `ctx.message` or `ctx.replyTarget` propagates to downstream\n * middleware and to the final `bot.on(\"message\")` listener.\n */\nexport interface MiddlewareContext {\n /** The QQBot instance — middlewares can call `bot.sendText` etc. */\n readonly bot: QQBot;\n /** The inbound message being processed. Mutable — middlewares can rewrite. */\n message: QQBotInboundMessage;\n /** The derived reply target. Same object reference as `message.replyTarget`. */\n readonly replyTarget: ReplyTarget;\n /**\n * Free-form per-request state slot. Use this to share data between\n * middlewares (e.g. a parsed command struct, an authentication result).\n *\n * Built-in middleware writes well-known keys here:\n * - `command`: parsed slash-command (set by `slashCommand` middleware)\n * - `mention`: mention-gate decision (set by `mentionGate` middleware)\n * - `history`: buffered history entries (set by `historyBuffer` middleware)\n *\n * Users may also add arbitrary keys.\n */\n state: MiddlewareState;\n /** Logger. */\n readonly log: Logger;\n /**\n * Stop the chain immediately. Equivalent to not calling `next()` and\n * preventing any downstream middleware (or the `message` event listener)\n * from running.\n */\n stop(reason?: string): void;\n /** Whether `stop()` has been called (or some upstream short-circuited). */\n readonly stopped: boolean;\n /** Reason passed to `stop()`, if any. */\n readonly stopReason: string | undefined;\n /**\n * AbortSignal for this request. Aborted when `ctx.abort()` is called.\n *\n * Use this to cancel in-flight async work (e.g. streaming, LLM calls)\n * when a middleware (like `concurrencyGuard`) decides to interrupt\n * the current processing.\n *\n * @example\n * ```ts\n * bot.on(\"message\", async (ctx, msg) => {\n * for await (const chunk of llmStream) {\n * if (ctx.signal.aborted) break;\n * await stream.update(chunk);\n * }\n * });\n * ```\n */\n readonly signal: AbortSignal;\n /**\n * Abort the current request processing. Triggers `signal` and calls\n * `stop()`. Use from middleware to interrupt an in-flight handler.\n */\n abort(reason?: string): void;\n /** Whether `abort()` has been called. */\n readonly aborted: boolean;\n /**\n * Timestamp (`Date.now()`) when the SDK created this context.\n * Use to measure end-to-end latency from event arrival to handler completion.\n */\n readonly receivedAt: number;\n}\n\n/** Middleware function — `next` advances the chain. */\nexport type Middleware = (\n ctx: MiddlewareContext,\n next: () => Promise<void>,\n) => void | Promise<void>;\n\n// ============ Implementation ============\n\n/**\n * Run a middleware chain.\n *\n * Returns `true` if the chain ran to completion (no `stop()`); `false` if\n * any middleware short-circuited.\n *\n * Errors thrown by middleware propagate up — the caller decides whether to\n * surface them via `bot.emit(\"error\")` or swallow them.\n */\nexport async function runMiddlewareChain(\n middlewares: Middleware[],\n ctx: MiddlewareContext,\n): Promise<boolean> {\n let index = -1;\n\n const dispatch = async (i: number): Promise<void> => {\n if (i <= index) {\n throw new Error(\"next() called multiple times\");\n }\n index = i;\n if (ctx.stopped) {\n return;\n }\n if (i >= middlewares.length) {\n return;\n }\n const fn = middlewares[i];\n if (!fn) {\n return;\n }\n await fn(ctx, () => dispatch(i + 1));\n };\n\n await dispatch(0);\n return !ctx.stopped;\n}\n\n/**\n * Build a fresh middleware context for one inbound message.\n *\n * Internal helper — used by {@link QQBot} when dispatching inbound events.\n */\nexport function createMiddlewareContext(params: {\n bot: QQBot;\n message: QQBotInboundMessage;\n log: Logger;\n}): MiddlewareContext {\n const receivedAt = Date.now();\n let stopped = false;\n let stopReason: string | undefined;\n const ac = new AbortController();\n\n const ctx: MiddlewareContext = {\n bot: params.bot,\n message: params.message,\n replyTarget: params.message.replyTarget,\n state: {},\n log: params.log,\n stop(reason?: string) {\n stopped = true;\n stopReason = reason;\n },\n get stopped() {\n return stopped;\n },\n get stopReason() {\n return stopReason;\n },\n get signal() {\n return ac.signal;\n },\n abort(reason?: string) {\n ac.abort(reason);\n stopped = true;\n stopReason = reason ?? \"aborted\";\n },\n get aborted() {\n return ac.signal.aborted;\n },\n receivedAt,\n };\n\n return ctx;\n}\n","/**\n * Protocol-level public types for the QQ Open Platform.\n *\n * 这一层只关心与 QQ 官方 API 协议相关的数据结构(HTTP 请求/响应、\n * WebSocket Gateway 事件、消息体、媒体类型等),不包含任何上层框架\n * 业务概念(路由、ACP、access policy 等)。\n *\n * 上层应用通过 `QQBot` facade 与这些类型交互;高级用户也可以从\n * `@tencent-connect/qqbot-nodejs/protocol` 直接消费这些低层类型。\n */\n\n// ============ Structured API Error ============\n\n/**\n * QQ 开放平台 HTTP 调用失败时抛出的结构化错误。\n *\n * 携带 HTTP 状态码、API 路径以及业务错误码,供上层重试/降级判断使用。\n */\nexport class ApiError extends Error {\n override readonly name = \"ApiError\";\n\n constructor(\n message: string,\n /** HTTP status code returned by the QQ Open Platform. */\n public readonly httpStatus: number,\n /** API path that produced the error (e.g. `/v2/users/{id}/messages`). */\n public readonly path: string,\n /** Business error code from the response body (`code` or `err_code`). */\n public readonly bizCode?: number,\n /** Original error message from the response body. */\n public readonly bizMessage?: string,\n ) {\n super(message);\n }\n}\n\n// ============ Logger ============\n\n/**\n * Logger interface used across all protocol modules.\n *\n * `info` and `error` are required; `warn` and `debug` are optional.\n */\nexport interface Logger {\n info: (msg: string, meta?: Record<string, unknown>) => void;\n error: (msg: string, meta?: Record<string, unknown>) => void;\n warn?: (msg: string, meta?: Record<string, unknown>) => void;\n debug?: (msg: string, meta?: Record<string, unknown>) => void;\n}\n\n/** @deprecated Use {@link Logger}. */\nexport type EngineLogger = Logger;\n\n// ============ Chat Scope ============\n\n/** Chat scope used to unify C2C/Group path construction. */\nexport type ChatScope = \"c2c\" | \"group\";\n\n// ============ Credentials ============\n\n/** Credentials needed to authenticate API requests. */\nexport interface Credentials {\n appId: string;\n clientSecret: string;\n}\n\n// ============ Message Response ============\n\n/** Standard message send response from the QQ Open Platform. */\nexport interface MessageResponse {\n id: string;\n timestamp: number | string;\n /** Reference index for future quoting. */\n ext_info?: {\n ref_idx?: string;\n };\n}\n\n// ============ Media Types ============\n\n/** QQ Open Platform media file type codes. */\nexport enum MediaFileType {\n IMAGE = 1,\n VIDEO = 2,\n VOICE = 3,\n FILE = 4,\n}\n\n/** Media upload response from the QQ Open Platform. */\nexport interface UploadMediaResponse {\n file_uuid: string;\n file_info: string;\n ttl: number;\n id?: string;\n}\n\n/** Structured metadata recorded for outbound messages. */\nexport interface OutboundMeta {\n text?: string;\n mediaType?: \"image\" | \"voice\" | \"video\" | \"file\";\n mediaUrl?: string;\n mediaLocalPath?: string;\n ttsText?: string;\n}\n\n// ============ API Client Config ============\n\n/** Configuration for the core HTTP client. */\nexport interface ApiClientConfig {\n baseUrl?: string;\n defaultTimeoutMs?: number;\n fileUploadTimeoutMs?: number;\n logger?: Logger;\n userAgent?: string | (() => string);\n}\n\n// ============ Chunked Upload Types ============\n\nexport interface UploadPart {\n index: number;\n presigned_url: string;\n}\n\nexport interface UploadPrepareResponse {\n upload_id: string;\n block_size: number;\n parts: UploadPart[];\n concurrency?: number;\n retry_timeout?: number;\n}\n\nexport interface UploadPrepareHashes {\n md5: string;\n sha1: string;\n md5_10m: string;\n}\n\n// ============ Stream Message Types ============\n\nexport const StreamInputMode = {\n REPLACE: \"replace\",\n} as const;\nexport type StreamInputMode = (typeof StreamInputMode)[keyof typeof StreamInputMode];\n\nexport const StreamInputState = {\n GENERATING: 1,\n DONE: 10,\n} as const;\nexport type StreamInputState = (typeof StreamInputState)[keyof typeof StreamInputState];\n\nexport const StreamContentType = {\n MARKDOWN: \"markdown\",\n} as const;\nexport type StreamContentType = (typeof StreamContentType)[keyof typeof StreamContentType];\n\nexport interface StreamMessageRequest {\n input_mode: StreamInputMode;\n input_state: StreamInputState;\n content_type: StreamContentType;\n content_raw: string;\n event_id: string;\n msg_id: string;\n stream_msg_id?: string;\n msg_seq: number;\n index: number;\n}\n\n// ============ Inline Keyboard ============\n\nexport interface KeyboardButton {\n id: string;\n render_data: {\n label: string;\n visited_label: string;\n style: number;\n };\n action: {\n type: number;\n permission: { type: number };\n data: string;\n click_limit?: number;\n };\n group_id?: string;\n}\n\nexport interface InlineKeyboard {\n content: {\n rows: Array<{ buttons: KeyboardButton[] }>;\n };\n}\n\n// ============ Interaction Event ============\n\nexport interface InteractionEvent {\n id: string;\n type: number;\n scene?: string;\n chat_type?: number;\n timestamp?: string;\n guild_id?: string;\n channel_id?: string;\n user_openid?: string;\n group_openid?: string;\n group_member_openid?: string;\n version: number;\n data: {\n type: number;\n resolved: {\n button_data?: string;\n button_id?: string;\n user_id?: string;\n feature_id?: string;\n message_id?: string;\n };\n };\n}\n\n// ============ Gateway WebSocket Types ============\n\nexport interface WSPayload {\n op: number;\n d: unknown;\n s?: number;\n t?: string;\n}\n\nexport interface RawMessageAttachment {\n content_type: string;\n url: string;\n filename?: string;\n voice_wav_url?: string;\n asr_refer_text?: string;\n}\n\nexport interface RawMsgElement {\n msg_idx?: string;\n content?: string;\n attachments?: Array<\n RawMessageAttachment & {\n height?: number;\n width?: number;\n size?: number;\n }\n >;\n}\n\nexport interface C2CMessageEvent {\n id: string;\n content: string;\n timestamp: string;\n author: { user_openid: string };\n attachments?: RawMessageAttachment[];\n message_scene?: { ext?: string[] };\n message_type?: number;\n msg_elements?: RawMsgElement[];\n}\n\nexport interface GuildMessageEvent {\n id: string;\n content: string;\n timestamp: string;\n author: { id: string; username?: string };\n channel_id: string;\n guild_id: string;\n attachments?: RawMessageAttachment[];\n message_scene?: { ext?: string[] };\n}\n\nexport interface GroupMessageEvent {\n id: string;\n content: string;\n timestamp: string;\n author: {\n member_openid: string;\n username?: string;\n bot?: boolean;\n };\n group_openid: string;\n attachments?: RawMessageAttachment[];\n mentions?: Array<{\n scope?: \"all\" | \"single\";\n id?: string;\n user_openid?: string;\n member_openid?: string;\n nickname?: string;\n username?: string;\n bot?: boolean;\n is_you?: boolean;\n }>;\n message_scene?: { source?: string; ext?: string[] };\n message_type?: number;\n msg_elements?: RawMsgElement[];\n}\n\n// ============ Account ============\n\n/** Lightweight account record consumed by GatewayConnection. */\nexport interface GatewayAccount {\n /** Stable account identifier (used for logging / session persistence). */\n accountId: string;\n appId: string;\n clientSecret: string;\n /** Whether this bot has markdown permission. */\n markdownSupport?: boolean;\n}\n","/**\n * General formatting utilities. Pure helpers with zero external dependencies.\n */\n\n/** Format any error object into a readable string, traversing the `.cause` chain. */\nexport function formatErrorMessage(err: unknown): string {\n if (err instanceof Error) {\n let formatted = err.message || err.name || \"Error\";\n let cause: unknown = err.cause;\n const seen = new Set<unknown>([err]);\n while (cause && !seen.has(cause)) {\n seen.add(cause);\n if (cause instanceof Error) {\n if (cause.message) {\n formatted += ` | ${cause.message}`;\n }\n cause = cause.cause;\n } else if (typeof cause === \"string\") {\n formatted += ` | ${cause}`;\n break;\n } else {\n break;\n }\n }\n return formatted;\n }\n if (typeof err === \"string\") {\n return err;\n }\n if (\n err === null ||\n err === undefined ||\n typeof err === \"number\" ||\n typeof err === \"boolean\" ||\n typeof err === \"bigint\"\n ) {\n return String(err);\n }\n try {\n return JSON.stringify(err);\n } catch {\n return Object.prototype.toString.call(err);\n }\n}\n\n/** Format a millisecond duration into a human-readable string (e.g. \"5m 30s\"). */\nexport function formatDuration(durationMs: number): string {\n const seconds = Math.round(durationMs / 1000);\n if (seconds < 60) {\n return `${seconds}s`;\n }\n const minutes = Math.floor(seconds / 60);\n const remainSeconds = seconds % 60;\n return remainSeconds > 0 ? `${minutes}m ${remainSeconds}s` : `${minutes}m`;\n}\n\n/** Format a byte count into a human-readable string (e.g. \"1.23 MB\"). */\nexport function formatFileSize(bytes: number): string {\n if (bytes < 1024) {\n return `${bytes} B`;\n }\n if (bytes < 1024 * 1024) {\n return `${(bytes / 1024).toFixed(2)} KB`;\n }\n if (bytes < 1024 * 1024 * 1024) {\n return `${(bytes / 1024 / 1024).toFixed(2)} MB`;\n }\n return `${(bytes / 1024 / 1024 / 1024).toFixed(2)} GB`;\n}\n","/**\n * Core HTTP client for the QQ Open Platform REST API.\n *\n * - `ApiClient` is an instance — config (baseUrl, timeout, logger, UA)\n * is injected via the constructor, eliminating module-level globals.\n * - Throws structured `ApiError` with httpStatus, bizCode, and path fields.\n * - Detects HTML error pages from CDN/gateway and returns user-friendly messages.\n */\n\nimport { ApiError, type ApiClientConfig, type Logger } from \"../types.js\";\nimport { formatErrorMessage } from \"../utils/format.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.sgroup.qq.com\";\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst FILE_UPLOAD_TIMEOUT_MS = 120_000;\n\nexport interface RequestOptions {\n timeoutMs?: number;\n redactBodyKeys?: string[];\n uploadRequest?: boolean;\n}\n\n/**\n * Stateful HTTP client for the QQ Open Platform.\n */\nexport class ApiClient {\n private readonly baseUrl: string;\n private readonly defaultTimeoutMs: number;\n private readonly fileUploadTimeoutMs: number;\n private readonly logger?: Logger;\n private readonly resolveUserAgent: () => string;\n\n constructor(config: ApiClientConfig = {}) {\n this.baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;\n this.defaultTimeoutMs = config.defaultTimeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.fileUploadTimeoutMs = config.fileUploadTimeoutMs ?? FILE_UPLOAD_TIMEOUT_MS;\n this.logger = config.logger;\n const ua = config.userAgent ?? \"qqbot-nodejs/unknown\";\n this.resolveUserAgent = typeof ua === \"function\" ? ua : () => ua;\n }\n\n async request<T = unknown>(\n accessToken: string,\n method: string,\n path: string,\n body?: unknown,\n options?: RequestOptions,\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n\n const headers: Record<string, string> = {\n Authorization: `QQBot ${accessToken}`,\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.resolveUserAgent(),\n };\n\n const isFileUpload =\n options?.uploadRequest === true ||\n path.includes(\"/files\") ||\n path.includes(\"/upload_prepare\") ||\n path.includes(\"/upload_part_finish\");\n const timeout =\n options?.timeoutMs ?? (isFileUpload ? this.fileUploadTimeoutMs : this.defaultTimeoutMs);\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n const fetchInit: RequestInit = { method, headers, signal: controller.signal };\n if (body) {\n fetchInit.body = JSON.stringify(body);\n }\n\n this.logger?.debug?.(`[qqbot:api] >>> ${method} ${url} (timeout: ${timeout}ms)`);\n if (body && this.logger?.debug) {\n const logBody = { ...(body as Record<string, unknown>) };\n for (const key of options?.redactBodyKeys ?? [\"file_data\"]) {\n if (typeof logBody[key] === \"string\") {\n logBody[key] = `<redacted ${logBody[key].length} chars>`;\n }\n }\n this.logger.debug(`[qqbot:api] >>> Body: ${JSON.stringify(logBody)}`);\n }\n\n let res: Response;\n try {\n res = await fetch(url, fetchInit);\n } catch (err) {\n clearTimeout(timeoutId);\n if (err instanceof Error && err.name === \"AbortError\") {\n this.logger?.error?.(`[qqbot:api] <<< Timeout after ${timeout}ms`);\n throw new ApiError(`Request timeout [${path}]: exceeded ${timeout}ms`, 0, path);\n }\n this.logger?.error?.(`[qqbot:api] <<< Network error: ${formatErrorMessage(err)}`);\n throw new ApiError(`Network error [${path}]: ${formatErrorMessage(err)}`, 0, path);\n } finally {\n clearTimeout(timeoutId);\n }\n\n const traceId = res.headers.get(\"x-tps-trace-id\") ?? \"\";\n this.logger?.info?.(\n `[qqbot:api] <<< Status: ${res.status} ${res.statusText}${traceId ? ` | TraceId: ${traceId}` : \"\"}`,\n );\n\n let rawBody: string;\n try {\n rawBody = await res.text();\n } catch (err) {\n throw new ApiError(\n `Failed to read response [${path}]: ${formatErrorMessage(err)}`,\n res.status,\n path,\n );\n }\n this.logger?.debug?.(`[qqbot:api] <<< Body: ${rawBody}`);\n\n const contentType = res.headers.get(\"content-type\") ?? \"\";\n const isHtmlResponse = contentType.includes(\"text/html\") || rawBody.trimStart().startsWith(\"<\");\n\n if (!res.ok) {\n if (isHtmlResponse) {\n const statusHint =\n res.status === 502 || res.status === 503 || res.status === 504\n ? \"调用发生异常,请稍候重试\"\n : res.status === 429\n ? \"请求过于频繁,已被限流\"\n : `开放平台返回 HTTP ${res.status}`;\n throw new ApiError(`${statusHint}(${path}),请稍后重试`, res.status, path);\n }\n\n try {\n const error = JSON.parse(rawBody) as {\n message?: string;\n code?: number;\n err_code?: number;\n };\n const bizCode = error.code ?? error.err_code;\n throw new ApiError(\n `API Error [${path}]: ${error.message ?? rawBody}`,\n res.status,\n path,\n bizCode,\n error.message,\n );\n } catch (parseErr) {\n if (parseErr instanceof ApiError) {\n throw parseErr;\n }\n throw new ApiError(\n `API Error [${path}] HTTP ${res.status}: ${rawBody.slice(0, 200)}`,\n res.status,\n path,\n );\n }\n }\n\n if (isHtmlResponse) {\n throw new ApiError(\n `QQ 服务端返回了非 JSON 响应(${path}),可能是临时故障,请稍后重试`,\n res.status,\n path,\n );\n }\n\n try {\n return JSON.parse(rawBody) as T;\n } catch {\n throw new ApiError(`开放平台响应格式异常(${path}),请稍后重试`, res.status, path);\n }\n }\n}\n","/**\n * Chunked media upload for the QQ Open Platform (large files > 5MB).\n *\n * Flow:\n * 1. `upload_prepare` — submit file metadata + (md5/sha1/md5_10m) hashes,\n * receive `{ upload_id, block_size, parts[], concurrency? }`.\n * 2. For every part:\n * a. PUT bytes to the pre-signed COS URL.\n * b. POST `upload_part_finish` with persistent retry.\n * 3. POST `complete_upload` — returns `{ file_uuid, file_info, ttl }`.\n */\n\nimport * as crypto from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport {\n ApiError,\n MediaFileType,\n type ChatScope,\n type Credentials,\n type Logger,\n type UploadMediaResponse,\n type UploadPart,\n type UploadPrepareHashes,\n type UploadPrepareResponse,\n} from \"../types.js\";\nimport { formatFileSize } from \"../utils/format.js\";\nimport type { ApiClient } from \"./api-client.js\";\nimport type { SanitizeFileNameFn, UploadCacheAdapter } from \"./media.js\";\nimport {\n buildPartFinishPersistentPolicy,\n COMPLETE_UPLOAD_RETRY_POLICY,\n PART_FINISH_RETRY_POLICY,\n UPLOAD_PREPARE_FALLBACK_CODE,\n withRetry,\n} from \"./retry.js\";\nimport { uploadCompletePath, uploadPartFinishPath, uploadPreparePath } from \"./routes.js\";\nimport type { TokenManager } from \"./token.js\";\n\n/**\n * Raised when `upload_prepare` returns {@link UPLOAD_PREPARE_FALLBACK_CODE}.\n */\nexport class UploadDailyLimitExceededError extends Error {\n override readonly name = \"UploadDailyLimitExceededError\";\n\n constructor(\n public readonly filePath: string,\n public readonly fileSize: number,\n originalMessage: string,\n ) {\n super(originalMessage);\n }\n}\n\nexport interface ChunkedUploadProgress {\n completedParts: number;\n totalParts: number;\n uploadedBytes: number;\n totalBytes: number;\n}\n\n/** Source of bytes for a chunked upload. */\nexport type ChunkedMediaSource =\n | { kind: \"localPath\"; path: string; size: number }\n | { kind: \"buffer\"; buffer: Buffer; fileName?: string };\n\nexport interface UploadChunkedOptions {\n scope: ChatScope;\n targetId: string;\n fileType: MediaFileType;\n source: ChunkedMediaSource;\n creds: Credentials;\n fileName?: string;\n onProgress?: (progress: ChunkedUploadProgress) => void;\n logPrefix?: string;\n}\n\nexport interface ChunkedMediaApiConfig {\n logger?: Logger;\n uploadCache?: UploadCacheAdapter;\n sanitizeFileName?: SanitizeFileNameFn;\n}\n\nconst DEFAULT_CONCURRENT_PARTS = 1;\nconst MAX_CONCURRENT_PARTS = 10;\nconst MAX_PART_FINISH_RETRY_TIMEOUT_MS = 10 * 60 * 1000;\nconst PART_UPLOAD_TIMEOUT_MS = 300_000;\nconst MD5_10M_SIZE = 10_002_432;\n\nexport class ChunkedMediaApi {\n private readonly client: ApiClient;\n private readonly tokenManager: TokenManager;\n private readonly logger?: Logger;\n private readonly cache?: UploadCacheAdapter;\n private readonly sanitize: SanitizeFileNameFn;\n\n constructor(client: ApiClient, tokenManager: TokenManager, config: ChunkedMediaApiConfig = {}) {\n this.client = client;\n this.tokenManager = tokenManager;\n this.logger = config.logger;\n this.cache = config.uploadCache;\n this.sanitize = config.sanitizeFileName ?? ((n) => n);\n }\n\n async uploadChunked(opts: UploadChunkedOptions): Promise<UploadMediaResponse> {\n const prefix = opts.logPrefix ?? \"[qqbot:chunked-upload]\";\n const input = resolveSource(opts.source, opts.fileName);\n\n const displayName = input.fileName;\n const fileSize = input.size;\n const pathLabel = input.kind === \"localPath\" ? input.path : \"<buffer>\";\n\n this.logger?.info?.(\n `${prefix} Start: file=${displayName} size=${formatFileSize(fileSize)} type=${opts.fileType}`,\n );\n\n const hashes = await computeHashes(input);\n this.logger?.debug?.(\n `${prefix} hashes: md5=${hashes.md5} sha1=${hashes.sha1} md5_10m=${hashes.md5_10m}`,\n );\n\n if (this.cache) {\n const cached = this.cache.get(hashes.md5, opts.scope, opts.targetId, opts.fileType);\n if (cached) {\n this.logger?.info?.(\n `${prefix} cache HIT (md5=${hashes.md5.slice(0, 8)}) — skipping chunked upload`,\n );\n return { file_uuid: \"\", file_info: cached, ttl: 0 };\n }\n }\n\n const fileNameForPrepare =\n opts.fileType === MediaFileType.FILE ? this.sanitize(displayName) : displayName;\n const prepareResp = await this.callUploadPrepare(\n opts,\n fileNameForPrepare,\n fileSize,\n hashes,\n pathLabel,\n );\n\n const { upload_id, parts } = prepareResp;\n const block_size = prepareResp.block_size;\n const maxConcurrent = Math.min(\n prepareResp.concurrency ? prepareResp.concurrency : DEFAULT_CONCURRENT_PARTS,\n MAX_CONCURRENT_PARTS,\n );\n const retryTimeoutMs = prepareResp.retry_timeout\n ? Math.min(prepareResp.retry_timeout * 1000, MAX_PART_FINISH_RETRY_TIMEOUT_MS)\n : undefined;\n\n this.logger?.info?.(\n `${prefix} prepared: upload_id=${upload_id} block=${formatFileSize(block_size)} parts=${parts.length} concurrency=${maxConcurrent}`,\n );\n\n let completedParts = 0;\n let uploadedBytes = 0;\n\n const uploadPart = async (part: UploadPart): Promise<void> => {\n const partIndex = part.index;\n const offset = (partIndex - 1) * block_size;\n const length = Math.min(block_size, fileSize - offset);\n\n const partBuffer = await readPart(input, offset, length);\n const md5Hex = crypto.createHash(\"md5\").update(partBuffer).digest(\"hex\");\n\n this.logger?.debug?.(\n `${prefix} part ${partIndex}/${parts.length}: ${formatFileSize(length)} offset=${offset} md5=${md5Hex}`,\n );\n\n await putToPresignedUrl(\n part.presigned_url,\n partBuffer,\n partIndex,\n parts.length,\n this.logger,\n prefix,\n );\n\n await this.callUploadPartFinish(opts, upload_id, partIndex, length, md5Hex, retryTimeoutMs);\n\n completedParts++;\n uploadedBytes += length;\n this.logger?.info?.(\n `${prefix} part ${partIndex}/${parts.length} done (${completedParts}/${parts.length})`,\n );\n\n opts.onProgress?.({\n completedParts,\n totalParts: parts.length,\n uploadedBytes,\n totalBytes: fileSize,\n });\n };\n\n await runWithConcurrency(\n parts.map((part) => () => uploadPart(part)),\n maxConcurrent,\n );\n\n this.logger?.info?.(`${prefix} all parts uploaded, completing...`);\n\n const result = await this.callCompleteUpload(opts, upload_id);\n this.logger?.info?.(`${prefix} completed: file_uuid=${result.file_uuid} ttl=${result.ttl}s`);\n\n if (this.cache && result.file_info && result.ttl > 0) {\n this.cache.set(\n hashes.md5,\n opts.scope,\n opts.targetId,\n opts.fileType,\n result.file_info,\n result.file_uuid,\n result.ttl,\n );\n }\n\n return result;\n }\n\n private async callUploadPrepare(\n opts: UploadChunkedOptions,\n fileName: string,\n fileSize: number,\n hashes: UploadPrepareHashes,\n pathLabel: string,\n ): Promise<UploadPrepareResponse> {\n const token = await this.tokenManager.getAccessToken(opts.creds.appId, opts.creds.clientSecret);\n const path = uploadPreparePath(opts.scope, opts.targetId);\n try {\n return await this.client.request<UploadPrepareResponse>(\n token,\n \"POST\",\n path,\n {\n file_type: opts.fileType,\n file_name: fileName,\n file_size: fileSize,\n md5: hashes.md5,\n sha1: hashes.sha1,\n md5_10m: hashes.md5_10m,\n },\n { uploadRequest: true },\n );\n } catch (err) {\n if (err instanceof ApiError && err.bizCode === UPLOAD_PREPARE_FALLBACK_CODE) {\n throw new UploadDailyLimitExceededError(pathLabel, fileSize, err.message);\n }\n throw err;\n }\n }\n\n private async callUploadPartFinish(\n opts: UploadChunkedOptions,\n uploadId: string,\n partIndex: number,\n blockSize: number,\n md5: string,\n retryTimeoutMs?: number,\n ): Promise<void> {\n const persistentPolicy = buildPartFinishPersistentPolicy(retryTimeoutMs);\n const path = uploadPartFinishPath(opts.scope, opts.targetId);\n await withRetry(\n async () => {\n const token = await this.tokenManager.getAccessToken(\n opts.creds.appId,\n opts.creds.clientSecret,\n );\n return this.client.request(\n token,\n \"POST\",\n path,\n {\n upload_id: uploadId,\n part_index: partIndex,\n block_size: blockSize,\n md5,\n },\n { uploadRequest: true },\n );\n },\n PART_FINISH_RETRY_POLICY,\n persistentPolicy,\n this.logger,\n );\n }\n\n private async callCompleteUpload(\n opts: UploadChunkedOptions,\n uploadId: string,\n ): Promise<UploadMediaResponse> {\n const path = uploadCompletePath(opts.scope, opts.targetId);\n return withRetry(\n async () => {\n const token = await this.tokenManager.getAccessToken(\n opts.creds.appId,\n opts.creds.clientSecret,\n );\n return this.client.request<UploadMediaResponse>(\n token,\n \"POST\",\n path,\n { upload_id: uploadId },\n { uploadRequest: true },\n );\n },\n COMPLETE_UPLOAD_RETRY_POLICY,\n undefined,\n this.logger,\n );\n }\n}\n\n// ============ Source resolution ============\n\ntype ChunkedInput =\n | { kind: \"localPath\"; path: string; size: number; fileName: string }\n | { kind: \"buffer\"; buffer: Buffer; size: number; fileName: string };\n\nfunction resolveSource(source: ChunkedMediaSource, fileNameOverride?: string): ChunkedInput {\n if (source.kind === \"localPath\") {\n const inferredName = source.path.split(/[/\\\\]/).pop() || \"file\";\n return {\n kind: \"localPath\",\n path: source.path,\n size: source.size,\n fileName: fileNameOverride ?? inferredName,\n };\n }\n return {\n kind: \"buffer\",\n buffer: source.buffer,\n size: source.buffer.length,\n fileName: fileNameOverride ?? source.fileName ?? \"file\",\n };\n}\n\nasync function readPart(input: ChunkedInput, offset: number, length: number): Promise<Buffer> {\n if (input.kind === \"buffer\") {\n return input.buffer.subarray(offset, offset + length);\n }\n const handle = await fs.promises.open(input.path, \"r\");\n try {\n const buf = Buffer.alloc(length);\n const { bytesRead } = await handle.read(buf, 0, length, offset);\n return bytesRead < length ? buf.subarray(0, bytesRead) : buf;\n } finally {\n await handle.close();\n }\n}\n\nasync function computeHashes(input: ChunkedInput): Promise<UploadPrepareHashes> {\n if (input.kind === \"buffer\") {\n const md5 = crypto.createHash(\"md5\").update(input.buffer).digest(\"hex\");\n const sha1 = crypto.createHash(\"sha1\").update(input.buffer).digest(\"hex\");\n const md5_10m =\n input.size > MD5_10M_SIZE\n ? crypto.createHash(\"md5\").update(input.buffer.subarray(0, MD5_10M_SIZE)).digest(\"hex\")\n : md5;\n return { md5, sha1, md5_10m };\n }\n\n return new Promise((resolve, reject) => {\n const md5 = crypto.createHash(\"md5\");\n const sha1 = crypto.createHash(\"sha1\");\n const md5_10m = crypto.createHash(\"md5\");\n let consumed = 0;\n const needsMd5_10m = input.size > MD5_10M_SIZE;\n\n const stream = fs.createReadStream(input.path);\n stream.on(\"data\", (chunk: Buffer | string) => {\n const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n md5.update(buf);\n sha1.update(buf);\n if (needsMd5_10m) {\n const remaining = MD5_10M_SIZE - consumed;\n if (remaining > 0) {\n md5_10m.update(remaining >= buf.length ? buf : buf.subarray(0, remaining));\n }\n }\n consumed += buf.length;\n });\n stream.on(\"end\", () => {\n const md5Hex = md5.digest(\"hex\");\n const sha1Hex = sha1.digest(\"hex\");\n resolve({\n md5: md5Hex,\n sha1: sha1Hex,\n md5_10m: needsMd5_10m ? md5_10m.digest(\"hex\") : md5Hex,\n });\n });\n stream.on(\"error\", reject);\n });\n}\n\n// ============ COS PUT ============\n\nconst PART_UPLOAD_MAX_RETRIES = 2;\n\nasync function putToPresignedUrl(\n presignedUrl: string,\n data: Buffer,\n partIndex: number,\n totalParts: number,\n logger: Logger | undefined,\n prefix: string,\n): Promise<void> {\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= PART_UPLOAD_MAX_RETRIES; attempt++) {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), PART_UPLOAD_TIMEOUT_MS);\n\n try {\n const ab = data.buffer.slice(\n data.byteOffset,\n data.byteOffset + data.byteLength,\n ) as ArrayBuffer;\n\n const startTime = Date.now();\n const response = await fetch(presignedUrl, {\n method: \"PUT\",\n body: new Blob([ab]),\n headers: { \"Content-Length\": String(data.length) },\n signal: controller.signal,\n });\n const elapsed = Date.now() - startTime;\n const requestId = response.headers.get(\"x-cos-request-id\") ?? \"-\";\n const etag = response.headers.get(\"ETag\") ?? \"-\";\n\n if (!response.ok) {\n const body = await response.text().catch(() => \"\");\n logger?.error?.(\n `${prefix} PUT part ${partIndex}/${totalParts}: HTTP ${response.status} ${response.statusText} (${elapsed}ms, requestId=${requestId}) body=${body.slice(0, 160)}`,\n );\n throw new Error(\n `COS PUT failed: ${response.status} ${response.statusText} - ${body.slice(0, 120)}`,\n );\n }\n\n logger?.debug?.(\n `${prefix} PUT part ${partIndex}/${totalParts} OK (${elapsed}ms ETag=${etag} requestId=${requestId})`,\n );\n return;\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n if (lastError.name === \"AbortError\") {\n lastError = new Error(\n `Part ${partIndex}/${totalParts} upload timeout after ${PART_UPLOAD_TIMEOUT_MS}ms`,\n );\n }\n if (attempt < PART_UPLOAD_MAX_RETRIES) {\n const delay = 1000 * 2 ** attempt;\n (logger?.warn ?? logger?.error)?.(\n `${prefix} PUT part ${partIndex}/${totalParts} attempt ${attempt + 1} failed (${lastError.message.slice(0, 120)}), retrying in ${delay}ms`,\n );\n await sleep(delay);\n }\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n throw lastError ?? new Error(`Part ${partIndex}/${totalParts} upload failed`);\n}\n\nasync function runWithConcurrency(\n tasks: Array<() => Promise<void>>,\n maxConcurrent: number,\n): Promise<void> {\n for (let i = 0; i < tasks.length; i += maxConcurrent) {\n const batch = tasks.slice(i, i + maxConcurrent);\n await Promise.all(batch.map((task) => task()));\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","/**\n * Generic retry engine for QQ Bot API requests.\n */\n\nimport type { Logger } from \"../types.js\";\nimport { formatErrorMessage } from \"../utils/format.js\";\n\nexport interface RetryPolicy {\n maxRetries: number;\n baseDelayMs: number;\n backoff: \"exponential\" | \"fixed\";\n shouldRetry?: (error: Error, attempt: number) => boolean;\n}\n\nexport interface PersistentRetryPolicy {\n timeoutMs: number;\n intervalMs: number;\n shouldPersistRetry: (error: Error) => boolean;\n}\n\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n policy: RetryPolicy,\n persistentPolicy?: PersistentRetryPolicy,\n logger?: Logger,\n): Promise<T> {\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= policy.maxRetries; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(formatErrorMessage(err));\n\n if (persistentPolicy?.shouldPersistRetry(lastError)) {\n (logger?.warn ?? logger?.error)?.(\n `[qqbot:retry] Hit persistent-retry trigger, entering persistent loop (timeout=${persistentPolicy.timeoutMs / 1000}s)`,\n );\n return await persistentRetryLoop(fn, persistentPolicy, logger);\n }\n\n if (policy.shouldRetry?.(lastError, attempt) === false) {\n throw lastError;\n }\n\n if (attempt < policy.maxRetries) {\n const delay =\n policy.backoff === \"exponential\" ? policy.baseDelayMs * 2 ** attempt : policy.baseDelayMs;\n\n logger?.debug?.(\n `[qqbot:retry] Attempt ${attempt + 1} failed, retrying in ${delay}ms: ${lastError.message.slice(0, 100)}`,\n );\n await sleep(delay);\n }\n }\n }\n\n throw lastError!;\n}\n\nasync function persistentRetryLoop<T>(\n fn: () => Promise<T>,\n policy: PersistentRetryPolicy,\n logger?: Logger,\n): Promise<T> {\n const deadline = Date.now() + policy.timeoutMs;\n let attempt = 0;\n let lastError: Error | null = null;\n\n while (Date.now() < deadline) {\n try {\n const result = await fn();\n logger?.debug?.(`[qqbot:retry] Persistent retry succeeded after ${attempt} retries`);\n return result;\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(formatErrorMessage(err));\n\n if (!policy.shouldPersistRetry(lastError)) {\n logger?.error?.(`[qqbot:retry] Persistent retry: error is no longer retryable, aborting`);\n throw lastError;\n }\n\n attempt++;\n const remaining = deadline - Date.now();\n if (remaining <= 0) {\n break;\n }\n\n const actualDelay = Math.min(policy.intervalMs, remaining);\n (logger?.warn ?? logger?.error)?.(\n `[qqbot:retry] Persistent retry #${attempt}: retrying in ${actualDelay}ms (remaining=${Math.round(remaining / 1000)}s)`,\n );\n await sleep(actualDelay);\n }\n }\n\n logger?.error?.(\n `[qqbot:retry] Persistent retry timed out after ${policy.timeoutMs / 1000}s (${attempt} attempts)`,\n );\n throw lastError ?? new Error(`Persistent retry timed out (${policy.timeoutMs / 1000}s)`);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n// ============ Pre-built Retry Policies ============\n\nexport const UPLOAD_RETRY_POLICY: RetryPolicy = {\n maxRetries: 2,\n baseDelayMs: 1000,\n backoff: \"exponential\",\n shouldRetry: (error) => {\n const msg = error.message;\n return !(\n msg.includes(\"400\") ||\n msg.includes(\"401\") ||\n msg.includes(\"Invalid\") ||\n msg.includes(\"timeout\") ||\n msg.includes(\"Timeout\")\n );\n },\n};\n\nexport const COMPLETE_UPLOAD_RETRY_POLICY: RetryPolicy = {\n maxRetries: 2,\n baseDelayMs: 2000,\n backoff: \"exponential\",\n};\n\nexport const PART_FINISH_RETRY_POLICY: RetryPolicy = {\n maxRetries: 2,\n baseDelayMs: 1000,\n backoff: \"exponential\",\n};\n\nexport function buildPartFinishPersistentPolicy(\n retryTimeoutMs?: number,\n retryableCodes: Set<number> = PART_FINISH_RETRYABLE_CODES,\n): PersistentRetryPolicy {\n return {\n timeoutMs: retryTimeoutMs ?? 2 * 60 * 1000,\n intervalMs: 1000,\n shouldPersistRetry: (error) => {\n if (retryableCodes.size === 0) {\n return false;\n }\n if (\"bizCode\" in error && typeof (error as { bizCode?: number }).bizCode === \"number\") {\n return retryableCodes.has((error as { bizCode: number }).bizCode);\n }\n return false;\n },\n };\n}\n\nexport const PART_FINISH_RETRYABLE_CODES: Set<number> = new Set([40093001]);\nexport const UPLOAD_PREPARE_FALLBACK_CODE = 40093002;\n","/**\n * Centralized API route templates for the QQ Open Platform.\n *\n * Eliminates C2C/Group path duplication by parameterizing on `ChatScope`.\n */\n\nimport type { ChatScope } from \"../types.js\";\n\nexport function messagePath(scope: ChatScope, targetId: string): string {\n return scope === \"c2c\" ? `/v2/users/${targetId}/messages` : `/v2/groups/${targetId}/messages`;\n}\n\nexport function channelMessagePath(channelId: string): string {\n return `/channels/${channelId}/messages`;\n}\n\nexport function dmMessagePath(guildId: string): string {\n return `/dms/${guildId}/messages`;\n}\n\nexport function mediaUploadPath(scope: ChatScope, targetId: string): string {\n return scope === \"c2c\" ? `/v2/users/${targetId}/files` : `/v2/groups/${targetId}/files`;\n}\n\nexport function uploadPreparePath(scope: ChatScope, targetId: string): string {\n return scope === \"c2c\"\n ? `/v2/users/${targetId}/upload_prepare`\n : `/v2/groups/${targetId}/upload_prepare`;\n}\n\nexport function uploadPartFinishPath(scope: ChatScope, targetId: string): string {\n return scope === \"c2c\"\n ? `/v2/users/${targetId}/upload_part_finish`\n : `/v2/groups/${targetId}/upload_part_finish`;\n}\n\nexport function uploadCompletePath(scope: ChatScope, targetId: string): string {\n return mediaUploadPath(scope, targetId);\n}\n\nexport function streamMessagePath(openid: string): string {\n return `/v2/users/${openid}/stream_messages`;\n}\n\nexport function gatewayPath(): string {\n return \"/gateway\";\n}\n\nexport function interactionPath(interactionId: string): string {\n return `/interactions/${interactionId}`;\n}\n\n/**\n * Generate a message sequence number in the 0..65535 range.\n *\n * Used by both `messages.ts` and `media.ts` to avoid duplicate definitions.\n */\nexport function getNextMsgSeq(_msgId: string): number {\n const timePart = Date.now() % 100_000_000;\n const random = Math.floor(Math.random() * 65536);\n return (timePart ^ random) % 65536;\n}\n","/**\n * Small-file media upload API for the QQ Open Platform.\n */\n\nimport * as fs from \"node:fs\";\nimport {\n MediaFileType,\n type ChatScope,\n type Credentials,\n type Logger,\n type MessageResponse,\n type UploadMediaResponse,\n} from \"../types.js\";\nimport { ApiClient } from \"./api-client.js\";\nimport { UPLOAD_RETRY_POLICY, withRetry } from \"./retry.js\";\nimport { getNextMsgSeq, mediaUploadPath, messagePath } from \"./routes.js\";\nimport { TokenManager } from \"./token.js\";\n\n/** Upload cache adapter. The caller provides the implementation. */\nexport interface UploadCacheAdapter {\n computeHash: (data: string) => string;\n get: (hash: string, scope: string, targetId: string, fileType: number) => string | null;\n set: (\n hash: string,\n scope: string,\n targetId: string,\n fileType: number,\n fileInfo: string,\n fileUuid: string,\n ttl: number,\n ) => void;\n}\n\nexport type SanitizeFileNameFn = (name: string) => string;\n\nexport interface MediaApiConfig {\n logger?: Logger;\n uploadCache?: UploadCacheAdapter;\n sanitizeFileName?: SanitizeFileNameFn;\n}\n\n/** Small-file media upload module. */\nexport class MediaApi {\n private readonly client: ApiClient;\n private readonly tokenManager: TokenManager;\n private readonly logger?: Logger;\n private readonly cache?: UploadCacheAdapter;\n private readonly sanitize: SanitizeFileNameFn;\n\n constructor(client: ApiClient, tokenManager: TokenManager, config: MediaApiConfig = {}) {\n this.client = client;\n this.tokenManager = tokenManager;\n this.logger = config.logger;\n this.cache = config.uploadCache;\n this.sanitize = config.sanitizeFileName ?? ((n) => n);\n }\n\n /**\n * Upload media via base64, URL, buffer, or local file path to a C2C or Group target.\n */\n async uploadMedia(\n scope: ChatScope,\n targetId: string,\n fileType: MediaFileType,\n creds: Credentials,\n opts: {\n url?: string;\n fileData?: string;\n buffer?: Buffer;\n localPath?: string;\n srvSendMsg?: boolean;\n fileName?: string;\n },\n ): Promise<UploadMediaResponse> {\n const sources = [opts.url, opts.fileData, opts.buffer, opts.localPath].filter(\n (v) => v !== undefined,\n );\n if (sources.length === 0) {\n throw new Error(`uploadMedia: one of url/fileData/buffer/localPath is required`);\n }\n if (sources.length > 1) {\n throw new Error(\n `uploadMedia: url/fileData/buffer/localPath are mutually exclusive (got ${sources.length})`,\n );\n }\n\n let fileData = opts.fileData;\n if (opts.buffer) {\n fileData = opts.buffer.toString(\"base64\");\n } else if (opts.localPath) {\n const buf = await fs.promises.readFile(opts.localPath);\n fileData = buf.toString(\"base64\");\n }\n\n if (fileData && this.cache) {\n const hash = this.cache.computeHash(fileData);\n const cached = this.cache.get(hash, scope, targetId, fileType);\n if (cached) {\n return { file_uuid: \"\", file_info: cached, ttl: 0 };\n }\n }\n\n const body: Record<string, unknown> = {\n file_type: fileType,\n srv_send_msg: opts.srvSendMsg ?? false,\n };\n if (opts.url) {\n body.url = opts.url;\n } else if (fileData) {\n body.file_data = fileData;\n }\n if (fileType === MediaFileType.FILE && opts.fileName) {\n body.file_name = this.sanitize(opts.fileName);\n }\n\n const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);\n const path = mediaUploadPath(scope, targetId);\n\n const result = await withRetry(\n () =>\n this.client.request<UploadMediaResponse>(token, \"POST\", path, body, {\n redactBodyKeys: [\"file_data\"],\n uploadRequest: true,\n }),\n UPLOAD_RETRY_POLICY,\n undefined,\n this.logger,\n );\n\n if (fileData && result.file_info && result.ttl > 0 && this.cache) {\n const hash = this.cache.computeHash(fileData);\n this.cache.set(\n hash,\n scope,\n targetId,\n fileType,\n result.file_info,\n result.file_uuid,\n result.ttl,\n );\n }\n\n return result;\n }\n\n /**\n * Send a media message (post upload) to a C2C or Group target.\n */\n async sendMediaMessage(\n scope: ChatScope,\n targetId: string,\n fileInfo: string,\n creds: Credentials,\n opts?: {\n msgId?: string;\n content?: string;\n },\n ): Promise<MessageResponse> {\n const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);\n const msgSeq = opts?.msgId ? getNextMsgSeq(opts.msgId) : 1;\n const path = messagePath(scope, targetId);\n\n return this.client.request<MessageResponse>(token, \"POST\", path, {\n msg_type: 7,\n media: { file_info: fileInfo },\n msg_seq: msgSeq,\n ...(opts?.content ? { content: opts.content } : {}),\n ...(opts?.msgId ? { msg_id: opts.msgId } : {}),\n });\n }\n}\n","/**\n * Message-sending API for the QQ Open Platform.\n */\n\nimport type {\n ChatScope,\n Credentials,\n InlineKeyboard,\n Logger,\n MessageResponse,\n OutboundMeta,\n StreamMessageRequest,\n} from \"../types.js\";\nimport { formatErrorMessage } from \"../utils/format.js\";\nimport { ApiClient } from \"./api-client.js\";\nimport {\n channelMessagePath,\n dmMessagePath,\n gatewayPath,\n getNextMsgSeq,\n interactionPath,\n messagePath,\n streamMessagePath,\n} from \"./routes.js\";\nimport { TokenManager } from \"./token.js\";\n\nexport interface MessageApiConfig {\n /** Whether the QQ Bot has markdown permission. */\n markdownSupport: boolean;\n logger?: Logger;\n}\n\ntype OnMessageSentCallback = (refIdx: string, meta: OutboundMeta) => void;\n\nexport class MessageApi {\n private readonly client: ApiClient;\n private readonly tokenManager: TokenManager;\n private readonly markdownSupport: boolean;\n private readonly logger?: Logger;\n private messageSentHook: OnMessageSentCallback | null = null;\n\n constructor(client: ApiClient, tokenManager: TokenManager, config: MessageApiConfig) {\n this.client = client;\n this.tokenManager = tokenManager;\n this.markdownSupport = config.markdownSupport;\n this.logger = config.logger;\n }\n\n onMessageSent(callback: OnMessageSentCallback): void {\n this.messageSentHook = callback;\n }\n\n notifyMessageSent(refIdx: string, meta: OutboundMeta): void {\n if (this.messageSentHook) {\n try {\n this.messageSentHook(refIdx, meta);\n } catch (err) {\n this.logger?.error?.(\n `[qqbot:messages] onMessageSent hook error: ${formatErrorMessage(err)}`,\n );\n }\n }\n }\n\n async sendMessage(\n scope: ChatScope,\n targetId: string,\n content: string,\n creds: Credentials,\n opts?: {\n msgId?: string;\n messageReference?: string;\n inlineKeyboard?: InlineKeyboard;\n },\n ): Promise<MessageResponse> {\n const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);\n const msgSeq = opts?.msgId ? getNextMsgSeq(opts.msgId) : 1;\n const body = this.buildMessageBody(\n content,\n opts?.msgId,\n msgSeq,\n opts?.messageReference,\n opts?.inlineKeyboard,\n );\n const path = messagePath(scope, targetId);\n return this.sendAndNotify(creds.appId, token, \"POST\", path, body, { text: content });\n }\n\n async sendProactiveMessage(\n scope: ChatScope,\n targetId: string,\n content: string,\n creds: Credentials,\n ): Promise<MessageResponse> {\n if (!content?.trim()) {\n throw new Error(\"Proactive message content must not be empty\");\n }\n const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);\n const body = this.buildProactiveBody(content);\n const path = messagePath(scope, targetId);\n return this.sendAndNotify(creds.appId, token, \"POST\", path, body, { text: content });\n }\n\n async sendChannelMessage(opts: {\n channelId: string;\n content: string;\n creds: Credentials;\n msgId?: string;\n }): Promise<MessageResponse> {\n const token = await this.tokenManager.getAccessToken(opts.creds.appId, opts.creds.clientSecret);\n return this.client.request<MessageResponse>(token, \"POST\", channelMessagePath(opts.channelId), {\n content: opts.content,\n ...(opts.msgId ? { msg_id: opts.msgId } : {}),\n });\n }\n\n async sendDmMessage(opts: {\n guildId: string;\n content: string;\n creds: Credentials;\n msgId?: string;\n }): Promise<MessageResponse> {\n const token = await this.tokenManager.getAccessToken(opts.creds.appId, opts.creds.clientSecret);\n return this.client.request<MessageResponse>(token, \"POST\", dmMessagePath(opts.guildId), {\n content: opts.content,\n ...(opts.msgId ? { msg_id: opts.msgId } : {}),\n });\n }\n\n /** Send a typing indicator to a C2C user. */\n async sendInputNotify(opts: {\n openid: string;\n creds: Credentials;\n msgId?: string;\n inputSecond?: number;\n }): Promise<{ refIdx?: string }> {\n const inputSecond = opts.inputSecond ?? 60;\n const token = await this.tokenManager.getAccessToken(opts.creds.appId, opts.creds.clientSecret);\n const msgSeq = opts.msgId ? getNextMsgSeq(opts.msgId) : 1;\n const response = await this.client.request<{ ext_info?: { ref_idx?: string } }>(\n token,\n \"POST\",\n messagePath(\"c2c\", opts.openid),\n {\n msg_type: 6,\n input_notify: { input_type: 1, input_second: inputSecond },\n msg_seq: msgSeq,\n ...(opts.msgId ? { msg_id: opts.msgId } : {}),\n },\n );\n return { refIdx: response.ext_info?.ref_idx };\n }\n\n async acknowledgeInteraction(\n interactionId: string,\n creds: Credentials,\n code: 0 | 1 | 2 | 3 | 4 | 5 = 0,\n ): Promise<void> {\n const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);\n await this.client.request(token, \"PUT\", interactionPath(interactionId), { code });\n }\n\n /** Get the WebSocket gateway URL for the bot. */\n async getGatewayUrl(creds: Credentials): Promise<string> {\n const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);\n const data = await this.client.request<{ url: string }>(token, \"GET\", gatewayPath());\n return data.url;\n }\n\n /**\n * Send a C2C stream message chunk (`/v2/users/{openid}/stream_messages`).\n * Only supported for one-to-one chats.\n */\n async sendC2CStreamMessage(\n creds: Credentials,\n openid: string,\n req: StreamMessageRequest,\n ): Promise<MessageResponse> {\n const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);\n const path = streamMessagePath(openid);\n const body: Record<string, unknown> = {\n input_mode: req.input_mode,\n input_state: req.input_state,\n content_type: req.content_type,\n content_raw: req.content_raw,\n event_id: req.event_id,\n msg_id: req.msg_id,\n msg_seq: req.msg_seq,\n index: req.index,\n };\n if (req.stream_msg_id) {\n body.stream_msg_id = req.stream_msg_id;\n }\n return this.client.request<MessageResponse>(token, \"POST\", path, body);\n }\n\n /**\n * Raw message send — transparently forwards all fields to the QQ Open Platform API.\n *\n * This is the \"escape hatch\" for any message type not covered by the\n * higher-level helpers. Fields like `msg_type`, `markdown`, `ark`, `embed`,\n * `keyboard`, `media`, `message_reference`, `is_wakeup` etc. are passed through\n * as-is to `/v2/users/{openid}/messages` or `/v2/groups/{group_openid}/messages`.\n *\n * Auto-injects `msg_seq` if not provided.\n */\n async sendRaw(\n scope: ChatScope,\n targetId: string,\n creds: Credentials,\n body: Record<string, unknown>,\n ): Promise<MessageResponse> {\n const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);\n const path = messagePath(scope, targetId);\n\n // Auto-inject msg_seq if missing\n if (body.msg_seq === undefined) {\n body.msg_seq = body.msg_id ? getNextMsgSeq(body.msg_id as string) : 1;\n }\n // Auto-detect msg_type if missing\n if (body.msg_type === undefined) {\n if (body.markdown) body.msg_type = 2;\n else if (body.ark) body.msg_type = 3;\n else if (body.embed) body.msg_type = 4;\n else if (body.media) body.msg_type = 7;\n else body.msg_type = 0;\n }\n\n // Remove undefined values\n const cleaned = Object.fromEntries(\n Object.entries(body).filter(([, v]) => v !== undefined),\n );\n\n return this.sendAndNotify(\n creds.appId,\n token,\n \"POST\",\n path,\n cleaned,\n { text: (cleaned.content as string) ?? (cleaned.markdown as any)?.content },\n );\n }\n\n /**\n * Send a message to a guild text channel.\n * Supports content, keyboard, message_reference, and arbitrary extra fields.\n */\n async sendChannelMessageRaw(\n channelId: string,\n creds: Credentials,\n body: Record<string, unknown>,\n ): Promise<MessageResponse> {\n const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);\n const cleaned = Object.fromEntries(\n Object.entries(body).filter(([, v]) => v !== undefined),\n );\n return this.client.request<MessageResponse>(\n token, \"POST\", channelMessagePath(channelId), cleaned,\n );\n }\n\n /**\n * Send a DM (direct message) in a guild.\n */\n async sendDmMessageRaw(\n guildId: string,\n creds: Credentials,\n body: Record<string, unknown>,\n ): Promise<MessageResponse> {\n const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);\n const cleaned = Object.fromEntries(\n Object.entries(body).filter(([, v]) => v !== undefined),\n );\n return this.client.request<MessageResponse>(\n token, \"POST\", dmMessagePath(guildId), cleaned,\n );\n }\n\n /**\n * Recall (delete) a message.\n */\n async recallMessage(\n scope: ChatScope,\n targetId: string,\n messageId: string,\n creds: Credentials,\n ): Promise<void> {\n const token = await this.tokenManager.getAccessToken(creds.appId, creds.clientSecret);\n const path = `${messagePath(scope, targetId)}/${messageId}`;\n await this.client.request(token, \"DELETE\", path);\n }\n\n private async sendAndNotify(\n _appId: string,\n accessToken: string,\n method: string,\n path: string,\n body: unknown,\n meta: OutboundMeta,\n ): Promise<MessageResponse> {\n const result = await this.client.request<MessageResponse>(accessToken, method, path, body);\n if (result.ext_info?.ref_idx && this.messageSentHook) {\n try {\n this.messageSentHook(result.ext_info.ref_idx, meta);\n } catch (err) {\n this.logger?.error?.(\n `[qqbot:messages] onMessageSent hook error: ${formatErrorMessage(err)}`,\n );\n }\n }\n return result;\n }\n\n private buildMessageBody(\n content: string,\n msgId: string | undefined,\n msgSeq: number,\n messageReference?: string,\n inlineKeyboard?: InlineKeyboard,\n ): Record<string, unknown> {\n const body: Record<string, unknown> = this.markdownSupport\n ? { markdown: { content }, msg_type: 2, msg_seq: msgSeq }\n : { content, msg_type: 0, msg_seq: msgSeq };\n\n if (msgId) {\n body.msg_id = msgId;\n }\n if (messageReference && !this.markdownSupport) {\n body.message_reference = { message_id: messageReference };\n }\n if (inlineKeyboard) {\n body.keyboard = inlineKeyboard;\n }\n return body;\n }\n\n private buildProactiveBody(content: string): Record<string, unknown> {\n return this.markdownSupport ? { markdown: { content }, msg_type: 2 } : { content, msg_type: 0 };\n }\n}\n\nexport { getNextMsgSeq } from \"./routes.js\";\n","/**\n * Token management for the QQ Open Platform.\n *\n * Per-appId token manager with caching, singleflight, and background refresh.\n * All state encapsulated in the class — no module-level globals.\n */\n\nimport type { Logger } from \"../types.js\";\nimport { formatErrorMessage } from \"../utils/format.js\";\n\nconst DEFAULT_TOKEN_BASE_URL = \"https://bots.qq.com\";\nconst TOKEN_PATH = \"/app/getAppAccessToken\";\n\ninterface CachedToken {\n token: string;\n expiresAt: number;\n appId: string;\n}\n\nexport interface BackgroundRefreshOptions {\n refreshAheadMs?: number;\n randomOffsetMs?: number;\n minRefreshIntervalMs?: number;\n retryDelayMs?: number;\n}\n\nexport class TokenManager {\n private readonly cache = new Map<string, CachedToken>();\n private readonly fetchPromises = new Map<string, Promise<string>>();\n private readonly refreshControllers = new Map<string, AbortController>();\n private readonly logger?: Logger;\n private readonly resolveUserAgent: () => string;\n private readonly baseUrl: string;\n\n constructor(config?: { logger?: Logger; userAgent?: string | (() => string); baseUrl?: string }) {\n this.logger = config?.logger;\n const ua = config?.userAgent ?? \"qqbot-nodejs/unknown\";\n this.resolveUserAgent = typeof ua === \"function\" ? ua : () => ua;\n this.baseUrl = config?.baseUrl ?? DEFAULT_TOKEN_BASE_URL;\n }\n\n async getAccessToken(appId: string, clientSecret: string): Promise<string> {\n const normalizedId = appId.trim();\n const cached = this.cache.get(normalizedId);\n\n const refreshAheadMs = cached\n ? Math.min(5 * 60 * 1000, (cached.expiresAt - Date.now()) / 3)\n : 0;\n\n if (cached && Date.now() < cached.expiresAt - refreshAheadMs) {\n return cached.token;\n }\n\n let pending = this.fetchPromises.get(normalizedId);\n if (pending) {\n this.logger?.debug?.(`[qqbot:token:${normalizedId}] Fetch in progress, reusing promise`);\n return pending;\n }\n\n pending = (async () => {\n try {\n return await this.doFetchToken(normalizedId, clientSecret);\n } finally {\n this.fetchPromises.delete(normalizedId);\n }\n })();\n\n this.fetchPromises.set(normalizedId, pending);\n return pending;\n }\n\n clearCache(appId?: string): void {\n if (appId) {\n this.cache.delete(appId.trim());\n this.logger?.debug?.(`[qqbot:token:${appId}] Cache cleared`);\n } else {\n this.cache.clear();\n this.logger?.debug?.(`[token] All caches cleared`);\n }\n }\n\n getStatus(appId: string): {\n status: \"valid\" | \"expired\" | \"refreshing\" | \"none\";\n expiresAt: number | null;\n } {\n if (this.fetchPromises.has(appId)) {\n return { status: \"refreshing\", expiresAt: this.cache.get(appId)?.expiresAt ?? null };\n }\n const cached = this.cache.get(appId);\n if (!cached) {\n return { status: \"none\", expiresAt: null };\n }\n const remaining = cached.expiresAt - Date.now();\n const isValid = remaining > Math.min(5 * 60 * 1000, remaining / 3);\n return { status: isValid ? \"valid\" : \"expired\", expiresAt: cached.expiresAt };\n }\n\n startBackgroundRefresh(\n appId: string,\n clientSecret: string,\n options?: BackgroundRefreshOptions,\n ): void {\n if (this.refreshControllers.has(appId)) {\n this.logger?.info?.(`[qqbot:token:${appId}] Background refresh already running`);\n return;\n }\n\n const {\n refreshAheadMs = 5 * 60 * 1000,\n randomOffsetMs = 30 * 1000,\n minRefreshIntervalMs = 60 * 1000,\n retryDelayMs = 5 * 1000,\n } = options ?? {};\n\n const controller = new AbortController();\n this.refreshControllers.set(appId, controller);\n const { signal } = controller;\n\n const loop = async () => {\n this.logger?.info?.(`[qqbot:token:${appId}] Background refresh started`);\n\n while (!signal.aborted) {\n try {\n await this.getAccessToken(appId, clientSecret);\n const cached = this.cache.get(appId);\n\n if (cached) {\n const expiresIn = cached.expiresAt - Date.now();\n const randomOffset = Math.random() * randomOffsetMs;\n const refreshIn = Math.max(\n expiresIn - refreshAheadMs - randomOffset,\n minRefreshIntervalMs,\n );\n this.logger?.debug?.(\n `[qqbot:token:${appId}] Next refresh in ${Math.round(refreshIn / 1000)}s`,\n );\n await this.abortableSleep(refreshIn, signal);\n } else {\n await this.abortableSleep(minRefreshIntervalMs, signal);\n }\n } catch (err) {\n if (signal.aborted) {\n break;\n }\n this.logger?.error?.(\n `[qqbot:token:${appId}] Background refresh failed: ${formatErrorMessage(err)}`,\n );\n await this.abortableSleep(retryDelayMs, signal);\n }\n }\n\n this.refreshControllers.delete(appId);\n this.logger?.info?.(`[qqbot:token:${appId}] Background refresh stopped`);\n };\n\n loop().catch((err) => {\n this.refreshControllers.delete(appId);\n this.logger?.error?.(`[qqbot:token:${appId}] Background refresh crashed: ${err}`);\n });\n }\n\n stopBackgroundRefresh(appId?: string): void {\n if (appId) {\n const ctrl = this.refreshControllers.get(appId);\n if (ctrl) {\n ctrl.abort();\n this.refreshControllers.delete(appId);\n }\n } else {\n for (const ctrl of this.refreshControllers.values()) {\n ctrl.abort();\n }\n this.refreshControllers.clear();\n }\n }\n\n isBackgroundRefreshRunning(appId?: string): boolean {\n if (appId) {\n return this.refreshControllers.has(appId);\n }\n return this.refreshControllers.size > 0;\n }\n\n private async doFetchToken(appId: string, clientSecret: string): Promise<string> {\n const url = `${this.baseUrl}${TOKEN_PATH}`;\n this.logger?.debug?.(`[qqbot:token:${appId}] >>> POST ${url}`);\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.resolveUserAgent(),\n },\n body: JSON.stringify({ appId, clientSecret }),\n });\n } catch (err) {\n this.logger?.error?.(`[qqbot:token:${appId}] Network error: ${formatErrorMessage(err)}`);\n throw new Error(`Network error getting access_token: ${formatErrorMessage(err)}`, {\n cause: err,\n });\n }\n\n const traceId = response.headers.get(\"x-tps-trace-id\") ?? \"\";\n this.logger?.debug?.(\n `[qqbot:token:${appId}] <<< ${response.status}${traceId ? ` | TraceId: ${traceId}` : \"\"}`,\n );\n\n let data: { access_token?: string; expires_in?: number };\n try {\n const rawBody = await response.text();\n const logBody = rawBody.replace(/\"access_token\"\\s*:\\s*\"[^\"]+\"/g, '\"access_token\": \"***\"');\n this.logger?.debug?.(`[qqbot:token:${appId}] <<< Body: ${logBody}`);\n data = JSON.parse(rawBody);\n } catch (err) {\n throw new Error(`Failed to parse access_token response: ${formatErrorMessage(err)}`, {\n cause: err,\n });\n }\n\n if (!data.access_token) {\n throw new Error(`Failed to get access_token: ${JSON.stringify(data)}`);\n }\n\n const expiresAt = Date.now() + (data.expires_in ?? 7200) * 1000;\n this.cache.set(appId, { token: data.access_token, expiresAt, appId });\n this.logger?.debug?.(\n `[qqbot:token:${appId}] Cached, expires at: ${new Date(expiresAt).toISOString()}`,\n );\n\n return data.access_token;\n }\n\n private abortableSleep(ms: number, signal: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n const timer = setTimeout(resolve, ms);\n if (signal.aborted) {\n clearTimeout(timer);\n reject(new Error(\"Aborted\"));\n return;\n }\n const onAbort = () => {\n clearTimeout(timer);\n reject(new Error(\"Aborted\"));\n };\n signal.addEventListener(\"abort\", onAbort, { once: true });\n });\n }\n}\n","import createWebSocketStream from './lib/stream.js';\nimport extension from './lib/extension.js';\nimport PerMessageDeflate from './lib/permessage-deflate.js';\nimport Receiver from './lib/receiver.js';\nimport Sender from './lib/sender.js';\nimport subprotocol from './lib/subprotocol.js';\nimport WebSocket from './lib/websocket.js';\nimport WebSocketServer from './lib/websocket-server.js';\n\nexport {\n createWebSocketStream,\n extension,\n PerMessageDeflate,\n Receiver,\n Sender,\n subprotocol,\n WebSocket,\n WebSocketServer\n};\n\nexport default WebSocket;\n","/**\n * Gateway message decoding utilities.\n *\n * Handles the various data formats that the QQ Bot WebSocket can deliver\n * (string, Buffer, Buffer[], ArrayBuffer).\n */\n\nexport function decodeGatewayMessageData(data: unknown): string {\n if (typeof data === \"string\") {\n return data;\n }\n if (Buffer.isBuffer(data)) {\n return data.toString(\"utf8\");\n }\n if (Array.isArray(data) && data.every((chunk) => Buffer.isBuffer(chunk))) {\n return Buffer.concat(data).toString(\"utf8\");\n }\n if (data instanceof ArrayBuffer) {\n return Buffer.from(data).toString(\"utf8\");\n }\n if (ArrayBuffer.isView(data)) {\n return Buffer.from(data.buffer, data.byteOffset, data.byteLength).toString(\"utf8\");\n }\n return \"\";\n}\n\nexport function readOptionalMessageSceneExt(event: Record<string, unknown>): string[] | undefined {\n if (!(\"message_scene\" in event)) {\n return undefined;\n }\n const scene = event.message_scene as { ext?: string[] } | undefined;\n return scene?.ext;\n}\n","/**\n * QQ Bot WebSocket Gateway protocol constants.\n *\n * Pure protocol-layer constants. Zero external dependencies.\n */\n\n/** QQ Bot WebSocket intents grouped by permission level. */\nconst INTENTS = {\n GUILDS: 1 << 0,\n GUILD_MEMBERS: 1 << 1,\n PUBLIC_GUILD_MESSAGES: 1 << 30,\n DIRECT_MESSAGE: 1 << 12,\n GROUP_AND_C2C: 1 << 25,\n /** Button interaction callbacks (INTERACTION_CREATE). */\n INTERACTION: 1 << 26,\n} as const;\n\nexport const FULL_INTENTS =\n INTENTS.GUILDS |\n INTENTS.GUILD_MEMBERS |\n INTENTS.PUBLIC_GUILD_MESSAGES |\n INTENTS.DIRECT_MESSAGE |\n INTENTS.GROUP_AND_C2C |\n INTENTS.INTERACTION;\n\nexport const RECONNECT_DELAYS = [1000, 2000, 5000, 10000, 30000, 60000] as const;\nexport const RATE_LIMIT_DELAY = 60000;\nexport const MAX_RECONNECT_ATTEMPTS = 100;\nexport const MAX_QUICK_DISCONNECT_COUNT = 3;\nexport const QUICK_DISCONNECT_THRESHOLD = 5000;\n\n/** Gateway opcodes used by the QQ Bot WebSocket protocol. */\nexport const GatewayOp = {\n DISPATCH: 0,\n HEARTBEAT: 1,\n IDENTIFY: 2,\n RESUME: 6,\n RECONNECT: 7,\n INVALID_SESSION: 9,\n HELLO: 10,\n HEARTBEAT_ACK: 11,\n} as const;\n\n/** WebSocket close codes used by the QQ Gateway. */\nexport const GatewayCloseCode = {\n NORMAL: 1000,\n AUTH_FAILED: 4004,\n INVALID_SESSION: 4006,\n SEQ_OUT_OF_RANGE: 4007,\n RATE_LIMITED: 4008,\n SESSION_TIMEOUT: 4009,\n SERVER_ERROR_START: 4900,\n SERVER_ERROR_END: 4913,\n INSUFFICIENT_INTENTS: 4914,\n DISALLOWED_INTENTS: 4915,\n} as const;\n\n/** Event type strings dispatched under opcode 0 (DISPATCH). */\nexport const GatewayEvent = {\n READY: \"READY\",\n RESUMED: \"RESUMED\",\n // ── Message events ──\n C2C_MESSAGE_CREATE: \"C2C_MESSAGE_CREATE\",\n AT_MESSAGE_CREATE: \"AT_MESSAGE_CREATE\",\n DIRECT_MESSAGE_CREATE: \"DIRECT_MESSAGE_CREATE\",\n GROUP_AT_MESSAGE_CREATE: \"GROUP_AT_MESSAGE_CREATE\",\n GROUP_MESSAGE_CREATE: \"GROUP_MESSAGE_CREATE\",\n // ── Interaction ──\n INTERACTION_CREATE: \"INTERACTION_CREATE\",\n // ── Guild events (P1) ──\n GUILD_CREATE: \"GUILD_CREATE\",\n GUILD_UPDATE: \"GUILD_UPDATE\",\n GUILD_DELETE: \"GUILD_DELETE\",\n GUILD_MEMBER_ADD: \"GUILD_MEMBER_ADD\",\n GUILD_MEMBER_UPDATE: \"GUILD_MEMBER_UPDATE\",\n GUILD_MEMBER_REMOVE: \"GUILD_MEMBER_REMOVE\",\n CHANNEL_CREATE: \"CHANNEL_CREATE\",\n CHANNEL_UPDATE: \"CHANNEL_UPDATE\",\n CHANNEL_DELETE: \"CHANNEL_DELETE\",\n // ── Group/C2C lifecycle events (P1) ──\n GROUP_ADD_ROBOT: \"GROUP_ADD_ROBOT\",\n GROUP_DEL_ROBOT: \"GROUP_DEL_ROBOT\",\n GROUP_MSG_REJECT: \"GROUP_MSG_REJECT\",\n GROUP_MSG_RECEIVE: \"GROUP_MSG_RECEIVE\",\n FRIEND_ADD: \"FRIEND_ADD\",\n FRIEND_DEL: \"FRIEND_DEL\",\n C2C_MSG_REJECT: \"C2C_MSG_REJECT\",\n C2C_MSG_RECEIVE: \"C2C_MSG_RECEIVE\",\n // ── Reaction events ──\n MESSAGE_REACTION_ADD: \"MESSAGE_REACTION_ADD\",\n MESSAGE_REACTION_REMOVE: \"MESSAGE_REACTION_REMOVE\",\n} as const;\n\n/** Interaction sub-types carried in `InteractionEvent.data.type`. */\nexport const InteractionType = {\n CONFIG_QUERY: 2001,\n CONFIG_UPDATE: 2002,\n} as const;\n","/**\n * Event dispatcher — convert raw WebSocket op=0 events into typed events.\n *\n * Pure mapping logic with zero side effects.\n */\n\nimport type {\n C2CMessageEvent,\n GroupMessageEvent,\n GuildMessageEvent,\n InteractionEvent,\n Logger,\n} from \"../types.js\";\nimport { readOptionalMessageSceneExt } from \"./codec.js\";\nimport { GatewayEvent } from \"./constants.js\";\n\n// ============ Inbound sub-structures ============\n\n/** A media attachment on an inbound message. */\nexport interface InboundAttachment {\n content_type: string;\n url: string;\n filename?: string;\n height?: number;\n width?: number;\n size?: number;\n /** WAV URL for voice messages (QQ server-side conversion). */\n voice_wav_url?: string;\n /** ASR transcription text for voice messages (QQ built-in speech recognition). */\n asr_refer_text?: string;\n}\n\n/** One element from the `msg_elements` array pushed by QQ. */\nexport interface InboundMsgElement {\n /** Sequential message index (used for quote resolution). */\n msg_idx?: string;\n /** Text content of this element. */\n content?: string;\n /** Attachments carried by this element. */\n attachments?: InboundAttachment[];\n}\n\n// ============ Inbound message ============\n\n/** Inbound message envelope normalised across C2C / Group / Guild scopes. */\nexport interface InboundMessage {\n /** Raw event type from the gateway. */\n rawEventType: string;\n /** Conversation kind. */\n kind: \"c2c\" | \"group\" | \"guild\" | \"dm\";\n senderId: string;\n senderName?: string;\n senderIsBot?: boolean;\n content: string;\n messageId: string;\n timestamp: string;\n channelId?: string;\n guildId?: string;\n groupOpenid?: string;\n attachments?: InboundAttachment[];\n refMsgIdx?: string;\n msgIdx?: string;\n msgType?: number;\n /** @mentions list (group events only). */\n mentions?: GroupMessageEvent[\"mentions\"];\n /** Raw message scene info. */\n messageScene?: { source?: string; ext?: string[] };\n /**\n * Raw msg_elements from the QQ push event.\n *\n * When a user quotes/replies to a message, `msg_elements[0]` contains the\n * quoted message's content and attachments. This is the **only** source of\n * truth when the quoted message is not in our RefIndexStore (cache miss).\n */\n msgElements?: InboundMsgElement[];\n /**\n * The original platform event object, transparently forwarded.\n *\n * Use this when you need fields not yet mapped to the normalized interface.\n * The shape depends on `kind`:\n * - `\"c2c\"` → `C2CMessageEvent`\n * - `\"group\"` → `GroupMessageEvent`\n * - `\"guild\"` / `\"dm\"` → `GuildMessageEvent`\n *\n * New platform fields are immediately accessible here without SDK updates.\n */\n raw: C2CMessageEvent | GroupMessageEvent | GuildMessageEvent;\n}\n\nexport type DispatchResult =\n | { action: \"ready\"; data: unknown; sessionId: string }\n | { action: \"resumed\"; data: unknown }\n | { action: \"message\"; msg: InboundMessage }\n | { action: \"interaction\"; event: InteractionEvent }\n | { action: \"raw\"; type: string; data: unknown }\n | { action: \"ignore\" };\n\ninterface Refs {\n refMsgIdx?: string;\n msgIdx?: string;\n}\n\nconst REF_INDEX_KEY = \"msg_idx\";\n\n/**\n * Parse `ref_idx` and `msg_idx` from message_scene.ext + msg_elements.\n */\nfunction parseRefIndices(\n ext: string[] | undefined,\n msgType?: number,\n msgElements?: Array<{ msg_idx?: string }>,\n): Refs {\n let refMsgIdx: string | undefined;\n let msgIdx: string | undefined;\n\n if (Array.isArray(ext)) {\n for (const entry of ext) {\n if (typeof entry !== \"string\") {\n continue;\n }\n const eq = entry.indexOf(\"=\");\n if (eq < 0) {\n continue;\n }\n const key = entry.slice(0, eq).trim();\n const val = entry.slice(eq + 1).trim();\n if (!val) {\n continue;\n }\n if (key === REF_INDEX_KEY) {\n msgIdx = val;\n } else if (key === \"ref_msg_idx\") {\n refMsgIdx = val;\n }\n }\n }\n\n if (msgType === 103 && Array.isArray(msgElements)) {\n for (const el of msgElements) {\n if (el?.msg_idx) {\n refMsgIdx = el.msg_idx;\n break;\n }\n }\n }\n\n return { refMsgIdx, msgIdx };\n}\n\nexport function dispatchEvent(\n eventType: string,\n data: unknown,\n _accountId: string,\n _log?: Logger,\n): DispatchResult {\n if (eventType === GatewayEvent.READY) {\n const d = data as { session_id: string };\n return { action: \"ready\", data, sessionId: d.session_id };\n }\n\n if (eventType === GatewayEvent.RESUMED) {\n return { action: \"resumed\", data };\n }\n\n if (eventType === GatewayEvent.C2C_MESSAGE_CREATE) {\n const ev = data as C2CMessageEvent;\n const refs = parseRefIndices(ev.message_scene?.ext, ev.message_type, ev.msg_elements);\n return {\n action: \"message\",\n msg: {\n rawEventType: eventType,\n kind: \"c2c\",\n senderId: ev.author.user_openid,\n content: ev.content,\n messageId: ev.id,\n timestamp: ev.timestamp,\n attachments: ev.attachments,\n refMsgIdx: refs.refMsgIdx,\n msgIdx: refs.msgIdx,\n msgType: ev.message_type,\n messageScene: ev.message_scene,\n msgElements: ev.msg_elements,\n raw: ev,\n },\n };\n }\n\n if (eventType === GatewayEvent.AT_MESSAGE_CREATE) {\n const ev = data as GuildMessageEvent;\n const refs = parseRefIndices(\n readOptionalMessageSceneExt(ev as unknown as Record<string, unknown>),\n );\n return {\n action: \"message\",\n msg: {\n rawEventType: eventType,\n kind: \"guild\",\n senderId: ev.author.id,\n senderName: ev.author.username,\n content: ev.content,\n messageId: ev.id,\n timestamp: ev.timestamp,\n channelId: ev.channel_id,\n guildId: ev.guild_id,\n attachments: ev.attachments,\n refMsgIdx: refs.refMsgIdx,\n msgIdx: refs.msgIdx,\n raw: ev,\n },\n };\n }\n\n if (eventType === GatewayEvent.DIRECT_MESSAGE_CREATE) {\n const ev = data as GuildMessageEvent;\n const refs = parseRefIndices(\n readOptionalMessageSceneExt(ev as unknown as Record<string, unknown>),\n );\n return {\n action: \"message\",\n msg: {\n rawEventType: eventType,\n kind: \"dm\",\n senderId: ev.author.id,\n senderName: ev.author.username,\n content: ev.content,\n messageId: ev.id,\n timestamp: ev.timestamp,\n guildId: ev.guild_id,\n attachments: ev.attachments,\n refMsgIdx: refs.refMsgIdx,\n msgIdx: refs.msgIdx,\n raw: ev,\n },\n };\n }\n\n if (\n eventType === GatewayEvent.GROUP_AT_MESSAGE_CREATE ||\n eventType === GatewayEvent.GROUP_MESSAGE_CREATE\n ) {\n const ev = data as GroupMessageEvent;\n const refs = parseRefIndices(ev.message_scene?.ext, ev.message_type, ev.msg_elements);\n return {\n action: \"message\",\n msg: {\n rawEventType: eventType,\n kind: \"group\",\n senderId: ev.author.member_openid,\n senderName: ev.author.username,\n senderIsBot: ev.author.bot,\n content: ev.content,\n messageId: ev.id,\n timestamp: ev.timestamp,\n groupOpenid: ev.group_openid,\n attachments: ev.attachments,\n refMsgIdx: refs.refMsgIdx,\n msgIdx: refs.msgIdx,\n msgType: ev.message_type,\n mentions: ev.mentions,\n messageScene: ev.message_scene,\n msgElements: ev.msg_elements,\n raw: ev,\n },\n };\n }\n\n if (eventType === GatewayEvent.INTERACTION_CREATE) {\n return { action: \"interaction\", event: data as InteractionEvent };\n }\n\n // All other gateway events are forwarded as raw events.\n // This covers guild/group/friend lifecycle, reactions, and any future\n // platform events — zero SDK changes required for new event types.\n return { action: \"raw\", type: eventType, data };\n}\n","/**\n * WebSocket reconnection state machine and close-code handler.\n */\n\nimport type { Logger } from \"../types.js\";\nimport {\n GatewayCloseCode,\n MAX_QUICK_DISCONNECT_COUNT,\n MAX_RECONNECT_ATTEMPTS,\n QUICK_DISCONNECT_THRESHOLD,\n RATE_LIMIT_DELAY,\n RECONNECT_DELAYS,\n} from \"./constants.js\";\n\nexport interface CloseAction {\n shouldReconnect: boolean;\n reconnectDelay?: number;\n clearSession: boolean;\n refreshToken: boolean;\n fatal: boolean;\n reason: string;\n}\n\nexport class ReconnectState {\n private attempts = 0;\n private lastConnectTime = 0;\n private quickDisconnectCount = 0;\n\n constructor(\n private readonly accountId: string,\n private readonly log?: Logger,\n ) {}\n\n onConnected(): void {\n this.attempts = 0;\n this.lastConnectTime = Date.now();\n }\n\n isExhausted(): boolean {\n return this.attempts >= MAX_RECONNECT_ATTEMPTS;\n }\n\n getNextDelay(customDelay?: number): number {\n const delay =\n customDelay ?? RECONNECT_DELAYS[Math.min(this.attempts, RECONNECT_DELAYS.length - 1)];\n this.attempts++;\n this.log?.debug?.(`[${this.accountId}] Reconnecting in ${delay}ms (attempt ${this.attempts})`);\n return delay;\n }\n\n handleClose(code: number, isAborted: boolean): CloseAction {\n if (\n code === GatewayCloseCode.INSUFFICIENT_INTENTS ||\n code === GatewayCloseCode.DISALLOWED_INTENTS\n ) {\n const reason =\n code === GatewayCloseCode.INSUFFICIENT_INTENTS ? \"offline/sandbox-only\" : \"banned\";\n this.log?.error(`[${this.accountId}] Bot is ${reason}. Please contact QQ platform.`);\n return {\n shouldReconnect: false,\n clearSession: false,\n refreshToken: false,\n fatal: true,\n reason,\n };\n }\n\n if (code === GatewayCloseCode.AUTH_FAILED) {\n this.log?.info(`[${this.accountId}] Invalid token (4004), will refresh token and reconnect`);\n return {\n shouldReconnect: !isAborted,\n clearSession: false,\n refreshToken: true,\n fatal: false,\n reason: \"invalid token (4004)\",\n };\n }\n\n if (code === GatewayCloseCode.RATE_LIMITED) {\n this.log?.info(`[${this.accountId}] Rate limited (4008), waiting ${RATE_LIMIT_DELAY}ms`);\n return {\n shouldReconnect: !isAborted,\n reconnectDelay: RATE_LIMIT_DELAY,\n clearSession: false,\n refreshToken: false,\n fatal: false,\n reason: \"rate limited (4008)\",\n };\n }\n\n if (\n code === GatewayCloseCode.INVALID_SESSION ||\n code === GatewayCloseCode.SEQ_OUT_OF_RANGE ||\n code === GatewayCloseCode.SESSION_TIMEOUT\n ) {\n const codeDesc: Record<number, string> = {\n [GatewayCloseCode.INVALID_SESSION]: \"session no longer valid\",\n [GatewayCloseCode.SEQ_OUT_OF_RANGE]: \"invalid seq on resume\",\n [GatewayCloseCode.SESSION_TIMEOUT]: \"session timed out\",\n };\n this.log?.info(`[${this.accountId}] Error ${code} (${codeDesc[code]}), will re-identify`);\n return {\n shouldReconnect: !isAborted,\n clearSession: true,\n refreshToken: true,\n fatal: false,\n reason: codeDesc[code],\n };\n }\n\n if (code >= GatewayCloseCode.SERVER_ERROR_START && code <= GatewayCloseCode.SERVER_ERROR_END) {\n this.log?.info(`[${this.accountId}] Internal error (${code}), will re-identify`);\n return {\n shouldReconnect: !isAborted && code !== GatewayCloseCode.NORMAL,\n clearSession: true,\n refreshToken: true,\n fatal: false,\n reason: `internal error (${code})`,\n };\n }\n\n const connectionDuration = Date.now() - this.lastConnectTime;\n if (connectionDuration < QUICK_DISCONNECT_THRESHOLD && this.lastConnectTime > 0) {\n this.quickDisconnectCount++;\n this.log?.debug?.(\n `[${this.accountId}] Quick disconnect detected (${connectionDuration}ms), count: ${this.quickDisconnectCount}`,\n );\n\n if (this.quickDisconnectCount >= MAX_QUICK_DISCONNECT_COUNT) {\n this.log?.error(\n `[${this.accountId}] Too many quick disconnects. This may indicate a permission issue.`,\n );\n this.quickDisconnectCount = 0;\n return {\n shouldReconnect: !isAborted && code !== 1000,\n reconnectDelay: RATE_LIMIT_DELAY,\n clearSession: false,\n refreshToken: false,\n fatal: false,\n reason: \"too many quick disconnects\",\n };\n }\n } else {\n this.quickDisconnectCount = 0;\n }\n\n return {\n shouldReconnect: !isAborted && code !== GatewayCloseCode.NORMAL,\n clearSession: false,\n refreshToken: false,\n fatal: false,\n reason: `close code ${code}`,\n };\n }\n}\n","/**\n * GatewayConnection — pure protocol-layer WebSocket lifecycle.\n *\n * Owns: WebSocket connection, heartbeat, reconnect, IDENTIFY/RESUME, event\n * dispatch.\n *\n * Does NOT own: token caching (delegated via callbacks), session persistence\n * (delegated via callbacks), business policies, message queueing.\n *\n * All state injected through the constructor — no module-level globals.\n */\n\nimport WebSocket from \"ws\";\nimport type { GatewayAccount, InteractionEvent, Logger, WSPayload } from \"../types.js\";\nimport { decodeGatewayMessageData } from \"./codec.js\";\nimport { FULL_INTENTS, GatewayOp, RATE_LIMIT_DELAY } from \"./constants.js\";\nimport { dispatchEvent, type InboundMessage } from \"./event-dispatcher.js\";\nimport { ReconnectState } from \"./reconnect.js\";\n\n/** Persisted session info for RESUME after reconnection. */\nexport interface PersistedSession {\n sessionId: string;\n lastSeq: number | null;\n}\n\n/** Hooks for session persistence (optional). */\nexport interface SessionPersistencePort {\n load: () => PersistedSession | null;\n save: (session: PersistedSession) => void;\n clear: () => void;\n}\n\nexport interface GatewayConnectionOptions {\n account: GatewayAccount;\n abortSignal: AbortSignal;\n log?: Logger;\n\n /** User-Agent header sent on the WebSocket upgrade request. */\n userAgent?: string | (() => string);\n\n /** Resolve a fresh access_token for IDENTIFY / RESUME. */\n getAccessToken: () => Promise<string>;\n /** Force-clear any cached token (called when 4004 invalid token). */\n clearTokenCache?: () => void;\n /** Request the WebSocket gateway URL from the QQ Open Platform. */\n getGatewayUrl: (accessToken: string) => Promise<string>;\n\n /** Optional: persist session id + last seq across process restarts. */\n session?: SessionPersistencePort;\n\n /** Custom intent mask. Defaults to FULL_INTENTS. */\n intents?: number;\n\n // ---- Event handlers ----\n onReady?: (data: unknown) => void;\n onResumed?: (data: unknown) => void;\n onError?: (error: Error) => void;\n onMessage: (msg: InboundMessage) => void | Promise<void>;\n onInteraction?: (event: InteractionEvent) => void | Promise<void>;\n onRawEvent?: (type: string, data: unknown) => void | Promise<void>;\n}\n\n/** Pure-protocol gateway connection. */\nexport class GatewayConnection {\n private isAborted = false;\n private currentWs: WebSocket | null = null;\n private heartbeatInterval: ReturnType<typeof setInterval> | null = null;\n private sessionId: string | null = null;\n private lastSeq: number | null = null;\n private isConnecting = false;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private shouldRefreshToken = false;\n\n private readonly reconnect: ReconnectState;\n private readonly opts: GatewayConnectionOptions;\n private readonly resolveUserAgent: () => string;\n\n constructor(opts: GatewayConnectionOptions) {\n this.opts = opts;\n this.reconnect = new ReconnectState(opts.account.accountId, opts.log);\n const ua = opts.userAgent ?? \"qqbot-nodejs/unknown\";\n this.resolveUserAgent = typeof ua === \"function\" ? ua : () => ua;\n }\n\n /** Start the connection loop. Resolves when abortSignal fires. */\n async start(): Promise<void> {\n this.restoreSession();\n this.registerAbortHandler();\n await this.connect();\n return new Promise<void>((resolve) => {\n this.opts.abortSignal.addEventListener(\"abort\", () => resolve());\n });\n }\n\n // ============ Session persistence ============\n\n private restoreSession(): void {\n const saved = this.opts.session?.load();\n if (saved) {\n this.sessionId = saved.sessionId;\n this.lastSeq = saved.lastSeq;\n this.opts.log?.info?.(\n `[${this.opts.account.accountId}] Restored session: sessionId=${saved.sessionId}, lastSeq=${saved.lastSeq}`,\n );\n }\n }\n\n private saveCurrentSession(): void {\n if (!this.sessionId || !this.opts.session) {\n return;\n }\n this.opts.session.save({\n sessionId: this.sessionId,\n lastSeq: this.lastSeq,\n });\n }\n\n // ============ Abort + cleanup ============\n\n private registerAbortHandler(): void {\n this.opts.abortSignal.addEventListener(\"abort\", () => {\n this.isAborted = true;\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n this.cleanup();\n });\n }\n\n private cleanup(): void {\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n this.heartbeatInterval = null;\n }\n if (\n this.currentWs &&\n (this.currentWs.readyState === WebSocket.OPEN ||\n this.currentWs.readyState === WebSocket.CONNECTING)\n ) {\n this.currentWs.close();\n }\n this.currentWs = null;\n }\n\n // ============ Reconnect ============\n\n private scheduleReconnect(customDelay?: number): void {\n if (this.isAborted || this.reconnect.isExhausted()) {\n this.opts.log?.error(\n `[${this.opts.account.accountId}] Max reconnect attempts reached or aborted`,\n );\n return;\n }\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n const delay = this.reconnect.getNextDelay(customDelay);\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n if (!this.isAborted) {\n void this.connect();\n }\n }, delay);\n }\n\n // ============ Connect ============\n\n private async connect(): Promise<void> {\n const { log, account } = this.opts;\n\n if (this.isConnecting) {\n log?.debug?.(`[${account.accountId}] Already connecting, skip`);\n return;\n }\n this.isConnecting = true;\n\n try {\n this.cleanup();\n if (this.shouldRefreshToken) {\n log?.debug?.(`[${account.accountId}] Refreshing token...`);\n this.opts.clearTokenCache?.();\n this.shouldRefreshToken = false;\n }\n\n const accessToken = await this.opts.getAccessToken();\n log?.info(`[${account.accountId}] ✅ Access token obtained`);\n const gatewayUrl = await this.opts.getGatewayUrl(accessToken);\n log?.info(`[${account.accountId}] Connecting to ${gatewayUrl}`);\n\n const ws = new WebSocket(gatewayUrl, {\n headers: { \"User-Agent\": this.resolveUserAgent() },\n });\n this.currentWs = ws;\n\n ws.on(\"open\", () => {\n log?.info(`[${account.accountId}] WebSocket connected`);\n this.isConnecting = false;\n this.reconnect.onConnected();\n });\n\n ws.on(\"message\", async (data) => {\n try {\n const rawData = decodeGatewayMessageData(data);\n const payload = JSON.parse(rawData) as WSPayload;\n const { op, d, s, t } = payload;\n\n if (s) {\n this.lastSeq = s;\n this.saveCurrentSession();\n }\n\n switch (op) {\n case GatewayOp.HELLO:\n this.handleHello(ws, d, accessToken);\n break;\n\n case GatewayOp.DISPATCH: {\n log?.debug?.(\n `[${account.accountId}] Dispatch event: t=${t} payload=${previewPayload(d)}`,\n );\n const result = dispatchEvent(t ?? \"\", d, account.accountId, log);\n if (result.action === \"ready\") {\n this.sessionId = result.sessionId;\n this.saveCurrentSession();\n this.opts.onReady?.(result.data);\n } else if (result.action === \"resumed\") {\n (this.opts.onResumed ?? this.opts.onReady)?.(result.data);\n this.saveCurrentSession();\n } else if (result.action === \"interaction\") {\n // Interaction 有 handler → 调用;否则 fallback 到 rawEvent\n if (this.opts.onInteraction) {\n void Promise.resolve(this.opts.onInteraction(result.event));\n } else if (this.opts.onRawEvent) {\n void Promise.resolve(this.opts.onRawEvent(payload.t!, payload.d));\n }\n } else if (result.action === \"message\") {\n void Promise.resolve(this.opts.onMessage(result.msg));\n } else if (result.action === \"raw\") {\n if (this.opts.onRawEvent) {\n void Promise.resolve(this.opts.onRawEvent(result.type, result.data));\n }\n }\n break;\n }\n\n case GatewayOp.HEARTBEAT_ACK:\n break;\n\n case GatewayOp.RECONNECT:\n this.cleanup();\n this.scheduleReconnect();\n break;\n\n case GatewayOp.INVALID_SESSION: {\n const canResume = d as boolean;\n if (!canResume) {\n this.sessionId = null;\n this.lastSeq = null;\n this.opts.session?.clear();\n this.shouldRefreshToken = true;\n }\n this.cleanup();\n this.scheduleReconnect(3000);\n break;\n }\n }\n } catch (err) {\n log?.error(\n `[${account.accountId}] Message parse error: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n });\n\n ws.on(\"close\", (code, reason) => {\n log?.info(`[${account.accountId}] WebSocket closed: ${code} ${reason.toString()}`);\n this.isConnecting = false;\n this.handleClose(code);\n });\n\n ws.on(\"error\", (err) => {\n log?.error(`[${account.accountId}] WebSocket error: ${err.message}`);\n this.opts.onError?.(err);\n });\n } catch (err) {\n this.isConnecting = false;\n const errMsg = err instanceof Error ? err.message : String(err);\n log?.error(`[${account.accountId}] Connection failed: ${errMsg}`);\n if (errMsg.includes(\"Too many requests\") || errMsg.includes(\"100001\")) {\n this.scheduleReconnect(RATE_LIMIT_DELAY);\n } else {\n this.scheduleReconnect();\n }\n }\n }\n\n // ============ Protocol handlers ============\n\n private handleHello(ws: WebSocket, d: unknown, accessToken: string): void {\n const intents = this.opts.intents ?? FULL_INTENTS;\n if (this.sessionId && this.lastSeq !== null) {\n ws.send(\n JSON.stringify({\n op: GatewayOp.RESUME,\n d: {\n token: `QQBot ${accessToken}`,\n session_id: this.sessionId,\n seq: this.lastSeq,\n },\n }),\n );\n } else {\n ws.send(\n JSON.stringify({\n op: GatewayOp.IDENTIFY,\n d: {\n token: `QQBot ${accessToken}`,\n intents,\n shard: [0, 1],\n },\n }),\n );\n }\n\n const interval = (d as { heartbeat_interval: number }).heartbeat_interval;\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n }\n this.heartbeatInterval = setInterval(() => {\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify({ op: GatewayOp.HEARTBEAT, d: this.lastSeq }));\n }\n }, interval);\n }\n\n private handleClose(code: number): void {\n const action = this.reconnect.handleClose(code, this.isAborted);\n\n if (action.clearSession) {\n this.sessionId = null;\n this.lastSeq = null;\n this.opts.session?.clear();\n }\n if (action.refreshToken) {\n this.shouldRefreshToken = true;\n }\n\n this.cleanup();\n\n if (action.fatal) {\n return;\n }\n if (action.shouldReconnect) {\n this.scheduleReconnect(action.reconnectDelay);\n }\n }\n}\n\n/**\n * Serialize a gateway event payload for debug logging.\n *\n * JSON-stringifies the payload; returns `\"(non-serializable)\"` for cyclic\n * or otherwise unserializable values so logging never throws.\n */\nfunction previewPayload(data: unknown): string {\n if (data === undefined) return \"undefined\";\n if (data === null) return \"null\";\n try {\n const s = JSON.stringify(data);\n return s === undefined ? \"(non-serializable)\" : s;\n } catch {\n return \"(non-serializable)\";\n }\n}\n","/**\n * Webhook signature verification — Ed25519.\n *\n * QQ Open Platform uses Ed25519 for webhook callback verification:\n * 1. Bot secret is padded/truncated to 32 bytes as the Ed25519 seed.\n * 2. The private key signs `timestamp + body` for request verification.\n * 3. For callback URL validation (op:13), signs `event_ts + plain_token`.\n *\n * Reference: https://bot.q.qq.com/wiki/develop/api-v2/dev-prepare/interface-framework/event-emit.html\n */\n\nimport * as crypto from \"node:crypto\";\n\n// ============ Seed derivation ============\n\n/**\n * Derive an Ed25519 seed (32 bytes) from the bot secret.\n * QQ's spec: repeat the secret until >= 32 chars, then truncate to 32.\n */\nfunction deriveSeed(botSecret: string): Buffer {\n let seed = botSecret;\n while (seed.length < 32) {\n seed = seed + seed;\n }\n return Buffer.from(seed.slice(0, 32), \"utf-8\");\n}\n\n/**\n * Generate Ed25519 key pair from bot secret.\n */\nfunction getKeyPair(botSecret: string): { privateKey: crypto.KeyObject; publicKey: crypto.KeyObject } {\n const seed = deriveSeed(botSecret);\n // Node.js Ed25519: create private key from raw 32-byte seed\n const privateKey = crypto.createPrivateKey({\n key: Buffer.concat([\n // Ed25519 PKCS8 DER prefix for 32-byte seed\n Buffer.from(\"302e020100300506032b657004220420\", \"hex\"),\n seed,\n ]),\n format: \"der\",\n type: \"pkcs8\",\n });\n const publicKey = crypto.createPublicKey(privateKey);\n return { privateKey, publicKey };\n}\n\n// ============ Signature generation ============\n\n/**\n * Sign a message using the bot's Ed25519 private key.\n * Returns hex-encoded signature.\n */\nexport function ed25519Sign(botSecret: string, message: Buffer): string {\n const { privateKey } = getKeyPair(botSecret);\n const signature = crypto.sign(null, message, privateKey);\n return signature.toString(\"hex\");\n}\n\n// ============ Signature verification ============\n\n/**\n * Verify an Ed25519 signature from a QQ webhook callback request.\n *\n * @param params.body - Raw request body (Buffer)\n * @param params.timestamp - Value of `X-Signature-Timestamp` header\n * @param params.signature - Value of `X-Signature-Ed25519` header (hex string)\n * @param params.botSecret - The bot's AppSecret\n * @returns `true` if signature is valid\n */\nexport function verifyWebhookSignature(params: {\n body: Buffer;\n timestamp: string;\n signature: string;\n botSecret: string;\n}): boolean {\n const { body, timestamp, signature, botSecret } = params;\n\n try {\n const { publicKey } = getKeyPair(botSecret);\n const message = Buffer.concat([\n Buffer.from(timestamp, \"utf-8\"),\n body,\n ]);\n const sigBuffer = Buffer.from(signature, \"hex\");\n return crypto.verify(null, message, publicKey, sigBuffer);\n } catch {\n return false;\n }\n}\n\n// ============ Callback URL validation (op:13) ============\n\n/**\n * Generate the response for callback URL validation (op:13).\n *\n * QQ sends `{ op: 13, d: { plain_token, event_ts } }` to verify\n * the callback URL. We must return `{ plain_token, signature }`.\n *\n * @param params.plainToken - The `plain_token` from the validation request\n * @param params.eventTs - The `event_ts` from the validation request\n * @param params.botSecret - The bot's AppSecret\n */\nexport function signValidationResponse(params: {\n plainToken: string;\n eventTs: string;\n botSecret: string;\n}): { plain_token: string; signature: string } {\n const { plainToken, eventTs, botSecret } = params;\n\n // Sign: event_ts + plain_token\n const message = Buffer.from(eventTs + plainToken, \"utf-8\");\n const signature = ed25519Sign(botSecret, message);\n\n return {\n plain_token: plainToken,\n signature,\n };\n}\n","/**\n * Built-in node:http webhook server adapter.\n *\n * A minimal HTTP server that receives QQ webhook callbacks. If you prefer\n * Express/Fastify/Koa, implement `WebhookServerAdapter` and pass it as\n * `webhook.server` in QQBotOptions.\n */\n\nimport * as http from \"node:http\";\nimport type { WebhookRequestHandler, WebhookServerAdapter } from \"./types.js\";\n\nexport class NodeHttpWebhookServer implements WebhookServerAdapter {\n private server: http.Server | null = null;\n\n async listen(port: number, path: string, handler: WebhookRequestHandler): Promise<void> {\n return new Promise((resolve, reject) => {\n const server = http.createServer(async (req, res) => {\n // Only accept POST to the configured path\n if (req.method !== \"POST\" || req.url !== path) {\n res.writeHead(404, { \"Content-Type\": \"text/plain\" });\n res.end(\"Not Found\");\n return;\n }\n\n // Collect body\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n req.on(\"end\", async () => {\n try {\n const body = Buffer.concat(chunks);\n const headers: Record<string, string | string[] | undefined> = {};\n for (const [key, value] of Object.entries(req.headers)) {\n headers[key.toLowerCase()] = value;\n }\n\n const response = await handler({ body, headers });\n\n res.writeHead(response.status, {\n \"Content-Type\": \"application/json\",\n ...(response.headers ?? {}),\n });\n res.end(response.body);\n } catch (_err) {\n res.writeHead(500, { \"Content-Type\": \"text/plain\" });\n res.end(\"Internal Server Error\");\n }\n });\n });\n\n server.on(\"error\", reject);\n server.listen(port, () => {\n this.server = server;\n resolve();\n });\n });\n }\n\n close(): void {\n if (this.server) {\n this.server.close();\n this.server = null;\n }\n }\n}\n","/**\n * WebhookTransport — receive QQ Bot events via HTTP POST callbacks.\n *\n * This transport implements the QQ Open Platform Webhook mode:\n * 1. Starts an HTTP server (built-in or user-provided adapter)\n * 2. Verifies Ed25519 signatures on every request\n * 3. Handles callback URL validation (op:13)\n * 4. Dispatches op:0 events through the same `dispatchEvent` as WebSocket\n * 5. Returns op:12 ACK to QQ platform\n *\n * Usage:\n * ```ts\n * const bot = new QQBot({\n * appId, appSecret,\n * transport: \"webhook\",\n * webhook: { port: 8443, path: \"/callback\" },\n * });\n * await bot.start();\n * ```\n */\n\nimport { dispatchEvent } from \"../gateway/event-dispatcher.js\";\nimport type { Logger } from \"../types.js\";\nimport type {\n EventTransport,\n EventTransportCallbacks,\n WebhookRequest,\n WebhookResponse,\n WebhookServerAdapter,\n WebhookTransportOptions,\n} from \"./types.js\";\nimport { signValidationResponse, verifyWebhookSignature } from \"./webhook-verify.js\";\nimport { NodeHttpWebhookServer } from \"./webhook-server-node.js\";\n\n// OpCodes relevant to webhook\nconst OP_DISPATCH = 0;\nconst OP_HTTP_CALLBACK_ACK = 12;\nconst OP_VALIDATION = 13;\n\ninterface WebhookPayload {\n id?: string;\n op: number;\n d?: unknown;\n s?: number;\n t?: string;\n}\n\nexport class WebhookTransport implements EventTransport {\n private readonly opts: WebhookTransportOptions;\n private readonly callbacks: EventTransportCallbacks;\n private readonly log: Logger | undefined;\n private readonly server: WebhookServerAdapter;\n private readonly accountId: string;\n private stopped = false;\n private stopResolve: (() => void) | null = null;\n\n constructor(opts: WebhookTransportOptions, callbacks: EventTransportCallbacks) {\n this.opts = opts;\n this.callbacks = callbacks;\n this.log = opts.log;\n this.server = opts.server ?? new NodeHttpWebhookServer();\n this.accountId = opts.accountId ?? opts.appId;\n }\n\n async start(): Promise<void> {\n const port = this.opts.port ?? 8080;\n const path = this.opts.path ?? \"/\";\n\n this.log?.info?.(`[webhook] starting on port ${port}, path ${path}`);\n\n await this.server.listen(port, path, (req) => this.handleRequest(req));\n\n this.log?.info?.(`[webhook] listening on :${port}${path}`);\n\n // Notify ready\n this.callbacks.onReady?.({ transport: \"webhook\", port, path });\n\n // Wait until stopped\n if (this.opts.abortSignal) {\n await new Promise<void>((resolve) => {\n if (this.opts.abortSignal!.aborted) {\n resolve();\n return;\n }\n this.stopResolve = resolve;\n this.opts.abortSignal!.addEventListener(\"abort\", () => this.stop(), { once: true });\n });\n } else {\n // Wait until stop() is called externally\n await new Promise<void>((resolve) => {\n this.stopResolve = resolve;\n });\n }\n }\n\n stop(): void {\n if (this.stopped) return;\n this.stopped = true;\n this.server.close();\n this.log?.info?.(`[webhook] stopped`);\n this.stopResolve?.();\n }\n\n // ============ Request handler ============\n\n private async handleRequest(req: WebhookRequest): Promise<WebhookResponse> {\n // Parse body\n let payload: WebhookPayload;\n try {\n payload = JSON.parse(req.body.toString(\"utf-8\")) as WebhookPayload;\n } catch {\n this.log?.warn?.(`[webhook] invalid JSON body`);\n return { status: 400, body: JSON.stringify({ error: \"invalid json\" }) };\n }\n\n // ── op:13 — Callback URL validation (no signature check needed) ──\n if (payload.op === OP_VALIDATION) {\n return this.handleValidation(payload);\n }\n\n // ── Signature verification ──\n const timestamp = getHeader(req.headers, \"x-signature-timestamp\") ?? \"\";\n const signature = getHeader(req.headers, \"x-signature-ed25519\") ?? \"\";\n\n if (!timestamp || !signature) {\n this.log?.warn?.(`[webhook] missing signature headers`);\n return { status: 401, body: JSON.stringify({ error: \"missing signature\" }) };\n }\n\n const valid = verifyWebhookSignature({\n body: req.body,\n timestamp,\n signature,\n botSecret: this.opts.appSecret,\n });\n\n if (!valid) {\n this.log?.warn?.(`[webhook] signature verification failed`);\n return { status: 401, body: JSON.stringify({ error: \"invalid signature\" }) };\n }\n\n // ── op:0 — Dispatch event (async, fire-and-forget) ──\n // Return ACK immediately, process message in background.\n // Otherwise long-running handlers (AI inference) block the HTTP response,\n // causing the QQ platform to timeout and re-deliver the event.\n if (payload.op === OP_DISPATCH) {\n this.handleDispatch(payload).catch((err) => {\n this.log?.error?.(\n `[webhook] dispatch error: ${err instanceof Error ? err.message : String(err)}`,\n );\n });\n }\n\n // Return ACK (op:12) for all valid requests\n return {\n status: 200,\n body: JSON.stringify({ op: OP_HTTP_CALLBACK_ACK, d: 0 }),\n };\n }\n\n // ============ Validation handler (op:13) ============\n\n private handleValidation(payload: WebhookPayload): WebhookResponse {\n const d = payload.d as { plain_token?: string; event_ts?: string } | undefined;\n\n if (!d?.plain_token || !d?.event_ts) {\n this.log?.warn?.(`[webhook] validation missing plain_token or event_ts`);\n return { status: 400, body: JSON.stringify({ error: \"invalid validation\" }) };\n }\n\n this.log?.info?.(`[webhook] handling callback URL validation`);\n\n const response = signValidationResponse({\n plainToken: d.plain_token,\n eventTs: d.event_ts,\n botSecret: this.opts.appSecret,\n });\n\n return {\n status: 200,\n body: JSON.stringify(response),\n };\n }\n\n // ============ Dispatch handler (op:0) ============\n\n private async handleDispatch(payload: WebhookPayload): Promise<void> {\n const eventType = payload.t ?? \"\";\n const data = payload.d;\n\n this.log?.debug?.(\n `[webhook] dispatch event: t=${eventType} payload=${JSON.stringify(data)}`,\n );\n\n const result = dispatchEvent(eventType, data, this.accountId, this.log);\n\n switch (result.action) {\n case \"ready\":\n this.callbacks.onReady?.(result.data);\n break;\n case \"resumed\":\n this.callbacks.onResumed?.(result.data);\n break;\n case \"message\":\n try {\n await this.callbacks.onMessage(result.msg);\n } catch (err) {\n this.callbacks.onError?.(\n err instanceof Error ? err : new Error(String(err)),\n );\n }\n break;\n case \"interaction\":\n try {\n await this.callbacks.onInteraction?.(result.event);\n } catch (err) {\n this.callbacks.onError?.(\n err instanceof Error ? err : new Error(String(err)),\n );\n }\n break;\n case \"ignore\":\n break;\n }\n }\n}\n\n// ============ Helpers ============\n\nfunction getHeader(\n headers: Record<string, string | string[] | undefined>,\n key: string,\n): string | undefined {\n const val = headers[key];\n if (Array.isArray(val)) return val[0];\n return val;\n}\n","/**\n * File-related helpers for the QQ Open Platform SDK.\n *\n * Pure helpers: filename sanitization, size constants, file size formatting.\n * The SDK does NOT bundle SSRF / remote-fetch logic — those are concerns\n * of the host application (e.g. an OpenClaw plugin) and should be\n * implemented at the integration layer.\n */\n\nimport { MediaFileType } from \"../types.js\";\n\n/** Maximum file size accepted by the QQ Bot one-shot upload API (base64 direct). */\nexport const MAX_UPLOAD_SIZE = 20 * 1024 * 1024;\n\n/** Absolute upper bound enforced on the chunked upload path. */\nexport const CHUNKED_UPLOAD_MAX_SIZE = 100 * 1024 * 1024;\n\n/** Threshold above which uploads are dispatched to the chunked path. */\nexport const LARGE_FILE_THRESHOLD = 5 * 1024 * 1024;\n\n/** Per-{@link MediaFileType} upload metadata. */\nexport const MEDIA_FILE_TYPE_INFO: Record<MediaFileType, { maxSize: number; name: string }> = {\n [MediaFileType.IMAGE]: { maxSize: 30 * 1024 * 1024, name: \"image\" },\n [MediaFileType.VIDEO]: { maxSize: 100 * 1024 * 1024, name: \"video\" },\n [MediaFileType.VOICE]: { maxSize: 20 * 1024 * 1024, name: \"voice\" },\n [MediaFileType.FILE]: { maxSize: 100 * 1024 * 1024, name: \"file\" },\n};\n\nexport function getFileTypeName(fileType: number): string {\n return MEDIA_FILE_TYPE_INFO[fileType as MediaFileType]?.name ?? \"file\";\n}\n\nexport function getMaxUploadSize(fileType: number): number {\n return MEDIA_FILE_TYPE_INFO[fileType as MediaFileType]?.maxSize ?? CHUNKED_UPLOAD_MAX_SIZE;\n}\n\n/** Canonical ext → MIME table. Single source of truth. */\nconst MIME_TYPES: Record<string, string> = {\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".png\": \"image/png\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n \".bmp\": \"image/bmp\",\n \".mp4\": \"video/mp4\",\n \".mov\": \"video/quicktime\",\n \".avi\": \"video/x-msvideo\",\n \".mkv\": \"video/x-matroska\",\n \".webm\": \"video/webm\",\n \".pdf\": \"application/pdf\",\n \".doc\": \"application/msword\",\n \".docx\": \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n \".xls\": \"application/vnd.ms-excel\",\n \".xlsx\": \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n \".zip\": \"application/zip\",\n \".tar\": \"application/x-tar\",\n \".gz\": \"application/gzip\",\n \".txt\": \"text/plain\",\n};\n\n/** Extensions accepted as image uploads by the QQ Bot media pipeline. */\nconst IMAGE_EXTENSIONS = new Set([\".jpg\", \".jpeg\", \".png\", \".gif\", \".webp\", \".bmp\"]);\n\n/**\n * Extract the lowercase extension (`\".png\"`) from a path-like string.\n *\n * Inlined from the lookup helpers so this module stays free of `node:path`\n * imports — works the same for `/abs/foo.PNG`, `relative/foo.PNG`,\n * `bare.PNG`, and accepts both forward and backward slashes.\n */\nfunction lowercaseExt(filePath: string): string {\n const sepIdx = Math.max(filePath.lastIndexOf(\"/\"), filePath.lastIndexOf(\"\\\\\"));\n const base = sepIdx === -1 ? filePath : filePath.slice(sepIdx + 1);\n const dotIdx = base.lastIndexOf(\".\");\n if (dotIdx <= 0) {\n return \"\";\n }\n return base.slice(dotIdx).toLowerCase();\n}\n\n/** Infer a MIME type from a file path's extension. */\nexport function getMimeType(filePath: string): string {\n return MIME_TYPES[lowercaseExt(filePath)] ?? \"application/octet-stream\";\n}\n\n/**\n * Return the image MIME type for a local file path, or `null` if the\n * extension is not in the supported image whitelist.\n *\n * Use this instead of {@link getMimeType} when the caller must enforce\n * \"image formats only\" as a business rule (e.g. constructing a\n * `data:image/...;base64,` URL).\n */\nexport function getImageMimeType(filePath: string): string | null {\n const ext = lowercaseExt(filePath);\n if (!IMAGE_EXTENSIONS.has(ext)) {\n return null;\n }\n return MIME_TYPES[ext] ?? null;\n}\n\n/**\n * Sanitize a filename for safe transmission to the QQ Open Platform.\n *\n * - Strips path separators / control characters.\n * - Collapses repeated whitespace.\n * - Falls back to `\"file\"` when the result is empty.\n */\nexport function sanitizeFileName(name: string): string {\n if (!name) {\n return \"file\";\n }\n \n const cleaned = name\n .replace(/[\\\\/:*?\"<>|]/g, \"_\")\n // eslint-disable-next-line no-control-regex\n .replace(/[\\u0000-\\u001f\\u007f]/g, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n return cleaned || \"file\";\n}\n","/**\n * Cache `file_info` values returned by the QQ Bot API so identical uploads\n * can be reused before the server-side TTL expires.\n */\n\nimport * as crypto from \"node:crypto\";\nimport type { ChatScope, Logger } from \"../types.js\";\n\ninterface CacheEntry {\n fileInfo: string;\n fileUuid: string;\n expiresAt: number;\n}\n\nconst MAX_CACHE_SIZE = 500;\n\n/** Compute an MD5 hash used as part of the cache key. */\nexport function computeFileHash(data: string | Buffer): string {\n return crypto.createHash(\"md5\").update(data).digest(\"hex\");\n}\n\nfunction buildCacheKey(\n contentHash: string,\n scope: string,\n targetId: string,\n fileType: number,\n): string {\n return `${contentHash}:${scope}:${targetId}:${fileType}`;\n}\n\n/**\n * In-memory upload cache. Each {@link QQBot} instance owns its own\n * cache so multiple concurrent bots do not compete for the same map.\n */\nexport class UploadCache {\n private readonly cache = new Map<string, CacheEntry>();\n private readonly logger?: Logger;\n\n constructor(options?: { logger?: Logger }) {\n this.logger = options?.logger;\n }\n\n computeHash(data: string | Buffer): string {\n return computeFileHash(data);\n }\n\n get(contentHash: string, scope: ChatScope, targetId: string, fileType: number): string | null {\n const key = buildCacheKey(contentHash, scope, targetId, fileType);\n const entry = this.cache.get(key);\n if (!entry) {\n return null;\n }\n if (Date.now() >= entry.expiresAt) {\n this.cache.delete(key);\n return null;\n }\n this.logger?.debug?.(\n `[upload-cache] HIT key=${key.slice(0, 40)}... uuid=${entry.fileUuid}`,\n );\n return entry.fileInfo;\n }\n\n set(\n contentHash: string,\n scope: ChatScope,\n targetId: string,\n fileType: number,\n fileInfo: string,\n fileUuid: string,\n ttl: number,\n ): void {\n if (this.cache.size >= MAX_CACHE_SIZE) {\n const now = Date.now();\n for (const [k, v] of this.cache) {\n if (now >= v.expiresAt) {\n this.cache.delete(k);\n }\n }\n if (this.cache.size >= MAX_CACHE_SIZE) {\n const keys = Array.from(this.cache.keys());\n for (let i = 0; i < keys.length / 2; i++) {\n this.cache.delete(keys[i]);\n }\n }\n }\n const key = buildCacheKey(contentHash, scope, targetId, fileType);\n const safetyMargin = 60;\n const effectiveTtl = Math.max(ttl - safetyMargin, 10);\n this.cache.set(key, {\n fileInfo,\n fileUuid,\n expiresAt: Date.now() + effectiveTtl * 1000,\n });\n this.logger?.debug?.(\n `[upload-cache] SET key=${key.slice(0, 40)}... ttl=${effectiveTtl}s uuid=${fileUuid}`,\n );\n }\n\n stats(): { size: number; maxSize: number } {\n return { size: this.cache.size, maxSize: MAX_CACHE_SIZE };\n }\n\n clear(): void {\n this.cache.clear();\n this.logger?.debug?.(`[upload-cache] cleared`);\n }\n}\n","/**\n * High-level helpers for QQ Bot C2C stream messages.\n *\n * QQ 开放平台只对 C2C(私聊)开放 stream_messages API。本模块提供一个\n * 简单的 sequencer,把上层应用的「逐字/逐 token 输出」适配为 QQ 协议\n * 要求的 `index + msg_seq` 序列。\n */\n\nimport { MessageApi } from \"./protocol/api/messages.js\";\nimport { getNextMsgSeq } from \"./protocol/api/routes.js\";\nimport {\n StreamContentType,\n StreamInputMode,\n StreamInputState,\n type Credentials,\n type Logger,\n type MessageResponse,\n type StreamMessageRequest,\n} from \"./protocol/types.js\";\nimport { formatErrorMessage } from \"./protocol/utils/format.js\";\n\n/** Throttle constants — match QQ open platform best practice. */\nconst DEFAULT_THROTTLE_MS = 500;\nconst MIN_THROTTLE_MS = 300;\n\nexport interface StreamSessionOptions {\n /** Target user openid. */\n openid: string;\n /** Inbound message id used to anchor the reply. */\n msgId: string;\n /** Credentials. */\n creds: Credentials;\n /**\n * Optional event id passed to QQ open platform `stream_messages`. Defaults\n * to the inbound `msgId` — matches QQ's expectation that this field carries\n * the originating message id, not a freshly-generated UUID.\n */\n eventId?: string;\n /** Throttle interval between flushes (ms). Default 500ms, min 300ms. */\n throttleMs?: number;\n /** Logger. */\n logger?: Logger;\n}\n\n/**\n * Lightweight controller for QQ C2C stream messages.\n *\n * Usage:\n * ```ts\n * const stream = bot.openStream({ openid, msgId });\n * for (const chunk of chunks) {\n * await stream.update(currentText); // currentText is the full text so far\n * }\n * await stream.complete(); // marks input_state = DONE\n * ```\n *\n * Important: `update()` expects the *full* current message text, not the\n * delta. The QQ API uses `input_mode=replace` semantics — each frame\n * replaces the previous one in place.\n */\n/** Maximum number of retries on rate-limit (429 / 50002). */\nconst MAX_FLUSH_RETRIES = 3;\n/** Base delay for exponential backoff on rate-limit (ms). */\nconst RATE_LIMIT_BASE_DELAY_MS = 1000;\n\nexport class StreamSession {\n private readonly api: MessageApi;\n private readonly opts: StreamSessionOptions;\n private readonly throttleMs: number;\n private readonly eventId: string;\n\n private streamMsgId: string | undefined;\n private index = 0;\n /**\n * `msg_seq` for the current stream session. QQ open platform expects all\n * frames in one stream to share the same `msg_seq` (only `index` advances).\n */\n private msgSeq: number | null = null;\n private lastFlushAt = 0;\n private lastSentText = \"\";\n private pendingText = \"\";\n private pendingTimer: ReturnType<typeof setTimeout> | null = null;\n private flushInProgress = false;\n private flushPromise: Promise<MessageResponse | undefined> | null = null;\n private isCompleted = false;\n\n constructor(api: MessageApi, opts: StreamSessionOptions) {\n this.api = api;\n this.opts = opts;\n this.throttleMs = Math.max(opts.throttleMs ?? DEFAULT_THROTTLE_MS, MIN_THROTTLE_MS);\n this.eventId = opts.eventId ?? opts.msgId;\n }\n\n /**\n * Update the current full message text. Will be sent at most once per\n * throttle window.\n */\n async update(fullText: string): Promise<void> {\n if (this.isCompleted) {\n return;\n }\n this.pendingText = fullText;\n const now = Date.now();\n const elapsed = now - this.lastFlushAt;\n\n if (this.flushInProgress) {\n // A flush is in flight — leave pendingText for the trailing flush.\n return;\n }\n\n if (elapsed >= this.throttleMs) {\n await this.flush(StreamInputState.GENERATING);\n return;\n }\n\n if (!this.pendingTimer) {\n const wait = this.throttleMs - elapsed;\n this.pendingTimer = setTimeout(() => {\n this.pendingTimer = null;\n if (!this.isCompleted) {\n this.flush(StreamInputState.GENERATING).catch((err) => {\n this.opts.logger?.error?.(\n `[qqbot:stream] throttle flush error: ${formatErrorMessage(err)}`,\n );\n });\n }\n }, wait);\n }\n }\n\n /** Mark the stream as DONE. Sends a final frame with the latest text. */\n async complete(): Promise<MessageResponse | undefined> {\n if (this.isCompleted) {\n return undefined;\n }\n this.isCompleted = true;\n if (this.pendingTimer) {\n clearTimeout(this.pendingTimer);\n this.pendingTimer = null;\n }\n // 等待当前正在进行的 flush 完成,避免 DONE 帧被跳过\n if (this.flushPromise) {\n await this.flushPromise.catch(() => {});\n }\n return this.flush(StreamInputState.DONE);\n }\n\n /** Force-cancel without sending a DONE frame (caller must clean up). */\n cancel(): void {\n this.isCompleted = true;\n if (this.pendingTimer) {\n clearTimeout(this.pendingTimer);\n this.pendingTimer = null;\n }\n }\n\n // ============ Internal ============\n\n private async flush(state: StreamInputState): Promise<MessageResponse | undefined> {\n if (this.flushInProgress) {\n return undefined;\n }\n if (this.pendingText === this.lastSentText && state !== StreamInputState.DONE) {\n return undefined;\n }\n this.flushInProgress = true;\n const promise = this.doFlush(state);\n this.flushPromise = promise;\n return promise;\n }\n\n private async doFlush(state: StreamInputState): Promise<MessageResponse | undefined> {\n let flushFailed = false;\n try {\n const text = this.pendingText;\n if (this.msgSeq === null) {\n this.msgSeq = getNextMsgSeq(this.opts.msgId);\n }\n const currentIndex = this.index++;\n const req: StreamMessageRequest = {\n input_mode: StreamInputMode.REPLACE,\n input_state: state,\n content_type: StreamContentType.MARKDOWN,\n content_raw: text,\n event_id: this.eventId,\n msg_id: this.opts.msgId,\n msg_seq: this.msgSeq,\n index: currentIndex,\n };\n if (this.streamMsgId) {\n req.stream_msg_id = this.streamMsgId;\n }\n\n const resp = await this.sendWithRetry(req);\n if (resp?.id && !this.streamMsgId) {\n this.streamMsgId = resp.id;\n }\n this.lastSentText = text;\n this.lastFlushAt = Date.now();\n return resp;\n } catch (err) {\n flushFailed = true;\n this.opts.logger?.error?.(\n `[qqbot:stream] flush failed (state=${state}): ${formatErrorMessage(err)}`,\n );\n throw err;\n } finally {\n this.flushInProgress = false;\n // Trailing flush if more text arrived during the in-flight call.\n // Skip trailing flush on failure to avoid retry storm.\n if (\n !flushFailed &&\n !this.isCompleted &&\n this.pendingText !== this.lastSentText &&\n !this.pendingTimer &&\n state !== StreamInputState.DONE\n ) {\n await this.flush(StreamInputState.GENERATING);\n }\n }\n }\n\n /**\n * Send a stream message with exponential backoff on rate-limit errors.\n * QQ returns err_code 50002 or HTTP 429 when rate-limited.\n */\n private async sendWithRetry(req: StreamMessageRequest): Promise<MessageResponse | undefined> {\n for (let attempt = 0; attempt <= MAX_FLUSH_RETRIES; attempt++) {\n try {\n return await this.api.sendC2CStreamMessage(this.opts.creds, this.opts.openid, req);\n } catch (err: unknown) {\n if (!this.isRateLimitError(err) || attempt >= MAX_FLUSH_RETRIES) {\n throw err;\n }\n const delay = RATE_LIMIT_BASE_DELAY_MS * Math.pow(2, attempt);\n this.opts.logger?.debug?.(\n `[qqbot:stream] rate limited, retry ${attempt + 1}/${MAX_FLUSH_RETRIES} after ${delay}ms`,\n );\n await new Promise((r) => setTimeout(r, delay));\n // Advance index for the retry to avoid stale index conflict\n req.index = this.index++;\n }\n }\n return undefined;\n }\n\n /** Check if an error is a rate-limit error (QQ err_code 50002 or HTTP 429). */\n private isRateLimitError(err: unknown): boolean {\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes(\"rate limit\")) return true;\n const code = (err as Record<string, unknown>)?.code ?? (err as Record<string, unknown>)?.err_code;\n if (code === 50002 || code === 429) return true;\n return false;\n }\n}\n","/**\n * Message filter middleware — drop invalid/duplicate/self-echo messages.\n *\n * Combines two common filtering needs into a single middleware:\n * 1. **Self-echo**: QQ may deliver the bot's own outbound messages back\n * as inbound events (especially in group chats).\n * 2. **Deduplication**: QQ occasionally pushes the same event more than\n * once (network retries, reconnect overlap, etc.).\n *\n * Both are enabled by default. Disable either via options.\n *\n * @example\n * ```ts\n * bot.use(messageFilter()); // both enabled\n * bot.use(messageFilter({ skipSelfEcho: false })); // only dedup\n * bot.use(messageFilter({ dedup: { windowMs: 10_000 }})); // custom window\n * ```\n */\n\nimport type { Middleware } from \"./types.js\";\n\nexport interface MessageFilterOptions {\n /**\n * Drop messages where `senderIsBot === true`.\n * Defaults to `true`.\n */\n skipSelfEcho?: boolean;\n /**\n * Deduplication settings. Set to `false` to disable entirely.\n * Defaults to `{ windowMs: 5000, maxSize: 1000 }`.\n */\n dedup?: false | {\n /** Time window (ms) to keep messageIds. Defaults to `5000`. */\n windowMs?: number;\n /** Max tracked ids. Defaults to `1000`. */\n maxSize?: number;\n };\n}\n\nexport function messageFilter(options: MessageFilterOptions = {}): Middleware {\n const skipSelfEcho = options.skipSelfEcho ?? true;\n const dedupOpts = options.dedup !== false\n ? { windowMs: 5000, maxSize: 1000, ...(options.dedup ?? {}) }\n : null;\n\n const seen = dedupOpts ? new Map<string, number>() : null;\n\n function evict(now: number): void {\n if (!seen || !dedupOpts) return;\n if (seen.size <= dedupOpts.maxSize) return;\n for (const [key, ts] of seen) {\n if (now - ts > dedupOpts.windowMs || seen.size > dedupOpts.maxSize) {\n seen.delete(key);\n } else {\n break;\n }\n }\n }\n\n return async (ctx, next) => {\n // 1. Self-echo check\n if (skipSelfEcho && ctx.message.senderIsBot) {\n ctx.stop(\"self-echo\");\n return;\n }\n\n // 2. Deduplication check\n if (seen && dedupOpts) {\n const id = ctx.message.messageId;\n const now = Date.now();\n if (seen.has(id)) {\n ctx.log.debug?.(`[message-filter] dropping duplicate messageId=${id}`);\n ctx.stop(\"deduplication\");\n return;\n }\n seen.set(id, now);\n evict(now);\n }\n\n await next();\n };\n}\n","/**\n * Content-sanitizer middleware — clean up raw message text.\n *\n * QQ delivers messages with `<@!{appId}>` mention markers, extra whitespace,\n * and sometimes face-tag markup. This middleware strips those artifacts so\n * downstream middleware (and the user's `onMessage` handler) receives clean\n * human-readable text.\n *\n * Operates on `ctx.message.content` in-place — downstream sees the\n * sanitized version.\n */\n\nimport type { Middleware, MiddlewareContext } from \"./types.js\";\n\nexport interface ContentSanitizerOptions {\n /**\n * Whether to strip `<@!{appId}>` / `<@{appId}>` mention markers.\n * Defaults to `true`.\n */\n stripBotMention?: boolean;\n /**\n * Whether to strip all `<@!{id}>` markers (not just the bot's).\n * Defaults to `false`.\n */\n stripAllMentions?: boolean;\n /**\n * Whether to collapse multiple consecutive whitespace / newlines into\n * a single space. Defaults to `false`.\n */\n collapseWhitespace?: boolean;\n /**\n * Whether to parse QQ face tags `[<face,id=xx/>]` into emoji text.\n * Defaults to `false` (just strip them).\n */\n parseFaceTags?: boolean;\n /**\n * Custom transform applied after all built-in sanitization.\n */\n transform?: (content: string, ctx: MiddlewareContext) => string;\n}\n\n/**\n * @example\n * ```ts\n * bot.use(contentSanitizer()); // Default: strip bot mention + trim\n * bot.use(contentSanitizer({ stripAllMentions: true, collapseWhitespace: true }));\n * ```\n */\nexport function contentSanitizer(options: ContentSanitizerOptions = {}): Middleware {\n const {\n stripBotMention = true,\n stripAllMentions = false,\n collapseWhitespace = false,\n parseFaceTags = false,\n transform,\n } = options;\n\n return async (ctx, next) => {\n let content = ctx.message.content ?? \"\";\n\n // Strip mention markers\n if (stripAllMentions) {\n content = content.replace(/<@!?\\d+>\\s*/g, \"\");\n } else if (stripBotMention) {\n const appId = ctx.bot.appId;\n if (appId) {\n const re = new RegExp(`<@!?${appId.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")}>\\\\s*`, \"g\");\n content = re[Symbol.replace](content, \"\");\n }\n }\n\n // Face tags\n if (parseFaceTags) {\n // Map common face ids to emoji (simplified subset)\n content = content.replace(/\\[<face,id=(\\d+)\\/?>]/g, (_m, id) => faceToEmoji(id) ?? \"\");\n } else {\n // Strip face tags entirely\n content = content.replace(/\\[<face,id=\\d+\\/?>]/g, \"\");\n }\n\n // Collapse whitespace\n if (collapseWhitespace) {\n content = content.replace(/\\s+/g, \" \");\n }\n\n // Trim\n content = content.trim();\n\n // Custom transform\n if (transform) {\n content = transform(content, ctx);\n }\n\n ctx.message.content = content;\n await next();\n };\n}\n\n/** Simplified face-id → emoji mapping (QQ common faces). */\nfunction faceToEmoji(id: string): string | undefined {\n const map: Record<string, string> = {\n \"0\": \"😊\", \"1\": \"😣\", \"2\": \"😍\", \"4\": \"😎\", \"5\": \"😭\",\n \"6\": \"😳\", \"7\": \"🤐\", \"8\": \"😴\", \"9\": \"😢\", \"10\": \"😰\",\n \"11\": \"😡\", \"12\": \"🤗\", \"13\": \"⭐\", \"14\": \"🌟\", \"15\": \"🌙\",\n \"16\": \"👍\", \"18\": \"✊\", \"21\": \"😊\", \"23\": \"😢\", \"25\": \"🤔\",\n \"26\": \"😱\", \"27\": \"😅\", \"28\": \"😁\", \"29\": \"🤮\", \"30\": \"💪\",\n \"32\": \"🎉\", \"33\": \"😤\", \"34\": \"😏\", \"35\": \"🥺\", \"49\": \"🐷\",\n \"53\": \"🎂\", \"60\": \"☕\", \"63\": \"🌹\", \"66\": \"❤️\", \"74\": \"🌞\",\n \"75\": \"🌛\", \"76\": \"👏\", \"78\": \"🤝\", \"79\": \"✌️\", \"85\": \"🎅\",\n \"89\": \"🍉\", \"96\": \"😓\", \"97\": \"😲\", \"100\": \"😂\", \"101\": \"😊\",\n \"104\": \"😭\", \"106\": \"😱\", \"109\": \"😘\", \"111\": \"🥰\",\n };\n return map[id];\n}\n","/**\n * Rate-limiter middleware — configurable multi-tier rate limiting.\n *\n * Supports three tiers: per-sender, per-group, and global. Uses a\n * sliding-window counter algorithm. When a message exceeds the limit,\n * the chain is short-circuited; an optional `onLimit` hook lets users\n * send a friendly rejection or log the event.\n */\n\nimport type { Middleware, MiddlewareContext } from \"./types.js\";\n\nexport interface RateLimitTier {\n /** Max requests within the window. */\n max: number;\n /** Window duration in milliseconds. */\n windowMs: number;\n}\n\nexport interface RateLimiterOptions {\n /** Per-sender limit. Keyed by `senderId`. */\n perSender?: RateLimitTier;\n /** Per-group limit. Keyed by `groupOpenid` (group only; C2C uses senderId). */\n perGroup?: RateLimitTier;\n /** Global limit across all messages. */\n global?: RateLimitTier;\n /**\n * Hook invoked when a message is rate-limited. Use to send a reply or\n * log. Return value is ignored.\n */\n onLimit?: (ctx: MiddlewareContext, tier: \"perSender\" | \"perGroup\" | \"global\") => void | Promise<void>;\n}\n\n// ============ Sliding window counter ============\n\nclass SlidingWindow {\n private readonly buckets = new Map<string, number[]>();\n private readonly max: number;\n private readonly windowMs: number;\n\n constructor(tier: RateLimitTier) {\n this.max = tier.max;\n this.windowMs = tier.windowMs;\n }\n\n /** Returns `true` if allowed, `false` if rate-limited. */\n check(key: string): boolean {\n const now = Date.now();\n let arr = this.buckets.get(key);\n if (!arr) {\n arr = [];\n this.buckets.set(key, arr);\n }\n\n // Evict expired entries\n while (arr.length > 0 && now - arr[0]! > this.windowMs) {\n arr.shift();\n }\n\n if (arr.length >= this.max) {\n return false;\n }\n\n arr.push(now);\n return true;\n }\n}\n\n/**\n * @example\n * ```ts\n * bot.use(rateLimiter({\n * perSender: { max: 5, windowMs: 60_000 }, // 5 msg/min per user\n * perGroup: { max: 30, windowMs: 60_000 }, // 30 msg/min per group\n * global: { max: 100, windowMs: 60_000 }, // 100 msg/min total\n * onLimit: async (ctx, tier) => {\n * await ctx.bot.sendText(ctx.replyTarget, `请稍后再试(${tier}限流)`);\n * },\n * }));\n * ```\n */\nexport function rateLimiter(options: RateLimiterOptions = {}): Middleware {\n const { onLimit } = options;\n const perSender = options.perSender ? new SlidingWindow(options.perSender) : undefined;\n const perGroup = options.perGroup ? new SlidingWindow(options.perGroup) : undefined;\n const global = options.global ? new SlidingWindow(options.global) : undefined;\n\n return async (ctx, next) => {\n const senderId = ctx.message.senderId;\n const groupKey = ctx.message.groupOpenid ?? senderId;\n\n // Check global first (cheapest to short-circuit)\n if (global && !global.check(\"__global__\")) {\n await onLimit?.(ctx, \"global\");\n ctx.stop(\"rate-limit:global\");\n return;\n }\n\n if (perGroup && !perGroup.check(groupKey)) {\n await onLimit?.(ctx, \"perGroup\");\n ctx.stop(\"rate-limit:perGroup\");\n return;\n }\n\n if (perSender && !perSender.check(senderId)) {\n await onLimit?.(ctx, \"perSender\");\n ctx.stop(\"rate-limit:perSender\");\n return;\n }\n\n await next();\n };\n}\n","/**\n * Concurrency-guard middleware — per-target serial message processing.\n *\n * Ensures only one message is being processed at a time for each\n * target (user or group). Prevents concurrent stream_messages calls\n * to the same QQ user/group which causes platform 500 errors.\n *\n * Strategy:\n * - \"queue\": New messages wait until the current one finishes.\n * - \"drop\": New messages are silently dropped while busy.\n * - \"abort\": Cancel the current processing, start the new one.\n * - \"merge\": Buffer new messages; after current finishes, merge all\n * buffered messages into one combined context and process once.\n *\n * The concurrency key is `${scope}:${targetId}` (e.g. \"c2c:OPENID\"\n * or \"group:GROUPID\").\n *\n * @example\n * ```ts\n * bot.use(concurrencyGuard({ strategy: \"queue\", maxQueue: 3 }));\n * bot.use(concurrencyGuard({\n * strategy: \"merge\",\n * maxQueue: 50,\n * onMerge: (buffered) => mergeContexts(buffered),\n * onDispatch: (merged) => handleMessage(merged),\n * }));\n * ```\n */\n\nimport type { Middleware, MiddlewareContext } from \"./types.js\";\n\nexport type ConcurrencyStrategy = \"queue\" | \"drop\" | \"abort\" | \"merge\";\n\nexport interface ConcurrencyGuardOptions {\n /**\n * How to handle a new message when the target is busy.\n * - \"queue\": Wait for the current message to finish (default).\n * - \"drop\": Silently skip the new message.\n * - \"abort\": Abort current processing via AbortController, then process new.\n * - \"merge\": Buffer new messages; after current finishes, merge all buffered\n * into a single context and dispatch via `onDispatch`.\n */\n strategy?: ConcurrencyStrategy;\n /** Max queued messages per target (only for \"queue\" and \"merge\" strategies). Default: 3. */\n maxQueue?: number;\n /** Called when a message is dropped (strategy=drop or queue overflow). */\n onDrop?: (ctx: MiddlewareContext) => void | Promise<void>;\n /**\n * Merge function for \"merge\" strategy. Receives the array of buffered contexts\n * (in arrival order) and must return a single merged context to be dispatched.\n *\n * If not provided, the last context is used and all buffered message contents\n * are concatenated with newline separators into `ctx.message.content`.\n */\n onMerge?: (buffered: MiddlewareContext[]) => MiddlewareContext;\n /**\n * Dispatch function for \"merge\" strategy. Called with the merged context\n * after buffered messages are combined.\n *\n * This is the **only** way merged messages get processed — the middleware\n * does not call `next()` or access bot internals. The caller decides how\n * to handle the merged context (e.g. call the message handler directly).\n *\n * Required when strategy is \"merge\".\n */\n onDispatch?: (merged: MiddlewareContext) => Promise<void>;\n}\n\ninterface QueueEntry {\n run: () => void;\n /** Associated ctx — used by abort strategy to cancel queued waiters. */\n ctx?: MiddlewareContext;\n}\n\nexport function concurrencyGuard(options: ConcurrencyGuardOptions = {}): Middleware {\n const strategy = options.strategy ?? \"queue\";\n const maxQueue = options.maxQueue ?? 3;\n const { onDrop, onMerge, onDispatch } = options;\n\n // Per-target state\n const locks = new Map<string, {\n busy: boolean;\n queue: QueueEntry[];\n /** The currently active ctx — abort() it to interrupt processing. */\n activeCtx?: MiddlewareContext;\n /** Buffered contexts for \"merge\" strategy. */\n mergeBuffer?: MiddlewareContext[];\n }>();\n\n function getState(key: string) {\n let s = locks.get(key);\n if (!s) {\n s = { busy: false, queue: [] };\n locks.set(key, s);\n }\n return s;\n }\n\n function targetKey(ctx: MiddlewareContext): string {\n const t = ctx.message.replyTarget;\n return `${t.scope}:${t.targetId}`;\n }\n\n return async (ctx, next) => {\n const key = targetKey(ctx);\n const state = getState(key);\n\n if (!state.busy) {\n // No active processing — proceed immediately\n state.busy = true;\n state.activeCtx = ctx;\n try {\n await next();\n } finally {\n state.busy = false;\n state.activeCtx = undefined;\n if (strategy === \"merge\") {\n await drainMergeBuffer(key);\n } else {\n drainQueue(key);\n }\n }\n return;\n }\n\n // Target is busy — apply strategy\n switch (strategy) {\n case \"merge\": {\n if (!state.mergeBuffer) {\n state.mergeBuffer = [];\n }\n if (state.mergeBuffer.length >= maxQueue) {\n ctx.log.debug?.(`[concurrency] merge buffer full (${maxQueue}), drop for ${key}`);\n await onDrop?.(ctx);\n ctx.stop(\"concurrency:merge-full\");\n return;\n }\n ctx.log.debug?.(`[concurrency] buffered for merge: ${key} (pos=${state.mergeBuffer.length + 1})`);\n state.mergeBuffer.push(ctx);\n return;\n }\n\n case \"drop\": {\n ctx.log.debug?.(`[concurrency] drop message for busy target ${key}`);\n await onDrop?.(ctx);\n ctx.stop(\"concurrency:drop\");\n return;\n }\n\n case \"abort\": {\n ctx.log.debug?.(`[concurrency] abort previous for ${key}`);\n\n // 1. Abort the currently active processing\n state.activeCtx?.abort(\"concurrency:abort\");\n\n // 2. Abort and evict all queued waiters — only the latest wins\n for (const entry of state.queue) {\n entry.ctx?.abort(\"concurrency:superseded\");\n entry.run(); // unblock the awaiting promise so it can exit\n }\n state.queue.length = 0;\n\n // 3. Wait for the active processing to release the lock\n await waitForRelease(state, ctx);\n\n // 4. If we were superseded while waiting, bail out\n if (ctx.signal.aborted) {\n ctx.log.debug?.(`[concurrency] superseded while waiting for ${key}`);\n return;\n }\n\n // Now proceed\n state.busy = true;\n state.activeCtx = ctx;\n try {\n await next();\n } finally {\n state.busy = false;\n state.activeCtx = undefined;\n drainQueue(key);\n }\n return;\n }\n\n case \"queue\":\n default: {\n if (state.queue.length >= maxQueue) {\n ctx.log.debug?.(`[concurrency] queue full (${maxQueue}), drop for ${key}`);\n await onDrop?.(ctx);\n ctx.stop(\"concurrency:queue-full\");\n return;\n }\n\n // Enqueue and wait\n ctx.log.debug?.(`[concurrency] queued message for ${key} (pos=${state.queue.length + 1})`);\n await new Promise<void>((resolve) => {\n state.queue.push({ run: resolve });\n });\n\n // Our turn\n state.busy = true;\n state.activeCtx = ctx;\n try {\n await next();\n } finally {\n state.busy = false;\n state.activeCtx = undefined;\n drainQueue(key);\n }\n return;\n }\n }\n };\n\n function drainQueue(key: string) {\n const state = locks.get(key);\n if (!state) return;\n const entry = state.queue.shift();\n if (entry) {\n entry.run();\n } else if (!state.busy) {\n locks.delete(key);\n }\n }\n\n /**\n * Drain the merge buffer: take all buffered contexts, merge into one,\n * and dispatch via the injected `onDispatch` callback.\n * Repeats until buffer is empty (new messages may arrive during dispatch).\n */\n async function drainMergeBuffer(key: string): Promise<void> {\n const state = locks.get(key);\n if (!state || !onDispatch) return;\n\n while (state.mergeBuffer && state.mergeBuffer.length > 0) {\n const buffered = state.mergeBuffer.splice(0);\n const merged = onMerge\n ? onMerge(buffered)\n : defaultMerge(buffered);\n\n state.busy = true;\n state.activeCtx = merged;\n try {\n await onDispatch(merged);\n } catch (err) {\n merged.log.error?.(\n `[concurrency:merge] dispatch error: ${err instanceof Error ? err.message : String(err)}`,\n );\n } finally {\n state.busy = false;\n state.activeCtx = undefined;\n }\n }\n\n // Clean up\n if (!state.busy && (!state.mergeBuffer || state.mergeBuffer.length === 0)) {\n locks.delete(key);\n }\n }\n\n /**\n * Default merge: concatenate contents, use last ctx (freshest msgId).\n */\n function defaultMerge(buffered: MiddlewareContext[]): MiddlewareContext {\n const last = buffered[buffered.length - 1]!;\n if (buffered.length === 1) return last;\n\n const contents = buffered\n .map((ctx) => ctx.message.content ?? \"\")\n .filter(Boolean);\n last.message.content = contents.join(\"\\n\");\n\n const envelopes = buffered\n .map((ctx) => ctx.state.envelope as string | undefined)\n .filter(Boolean);\n if (envelopes.length > 0) {\n last.state.envelope = envelopes.join(\"\\n\\n\");\n }\n\n const allAttachments = buffered.flatMap((ctx) => ctx.message.attachments ?? []);\n if (allAttachments.length > 0) {\n last.message.attachments = allAttachments;\n }\n\n return last;\n }\n\n function waitForRelease(\n state: { busy: boolean; queue: QueueEntry[] },\n ctx?: MiddlewareContext,\n ): Promise<void> {\n if (!state.busy) return Promise.resolve();\n return new Promise<void>((resolve) => {\n state.queue.unshift({ run: resolve, ctx });\n });\n }\n}\n","/**\n * Access policy middleware — gate inbound messages by sender / group allow-list.\n *\n * QQ Bot has no native concept of \"allow-list\"; this is a SDK-side mechanism\n * commonly required by production deployments (allow only specific group ids,\n * specific QQ openids, etc).\n *\n * The middleware is **purely declarative** — it simply evaluates the policy\n * against `ctx.message` and short-circuits the chain when blocked.\n */\n\nimport type { Middleware, MiddlewareContext } from \"./types.js\";\n\n// ============ Policy Types ============\n\n/** Match rules for `allowFrom` / `denyFrom`. */\nexport type AccessMatcher =\n | \"*\" // Match anything\n | string // Exact id (groupId / senderId)\n | RegExp // Regex match\n | ((ctx: MiddlewareContext) => boolean);\n\n/** Policy applied to one chat scope. */\nexport interface ScopePolicy {\n /** \"open\": allow all; \"allowlist\": only allow listed; \"disabled\": block all. */\n mode?: \"open\" | \"allowlist\" | \"disabled\";\n /** Patterns whose match → allow. Used with mode=allowlist. */\n allow?: AccessMatcher[];\n /** Patterns whose match → block. Evaluated before allow. */\n deny?: AccessMatcher[];\n}\n\n/** Full access policy. */\nexport interface AccessPolicy {\n /** Default policy for direct messages (C2C / DM). Defaults to `open`. */\n c2c?: ScopePolicy;\n /** Policy for group messages. Defaults to `open`. */\n group?: ScopePolicy;\n /** Policy for guild channel messages. Defaults to `open`. */\n guild?: ScopePolicy;\n /**\n * Optional callback when a message is blocked. Use for telemetry.\n */\n onBlock?: (ctx: MiddlewareContext, reason: string) => void;\n}\n\n// ============ Helpers ============\n\nfunction matcherMatches(matcher: AccessMatcher, value: string, ctx: MiddlewareContext): boolean {\n if (matcher === \"*\") return true;\n if (typeof matcher === \"string\") return matcher === value;\n if (matcher instanceof RegExp) return matcher.test(value);\n if (typeof matcher === \"function\") return matcher(ctx);\n return false;\n}\n\nfunction evaluateScope(\n policy: ScopePolicy | undefined,\n identifier: string,\n ctx: MiddlewareContext,\n): { allowed: boolean; reason: string } {\n const mode = policy?.mode ?? \"open\";\n\n // Deny list always evaluated first\n if (policy?.deny) {\n for (const m of policy.deny) {\n if (matcherMatches(m, identifier, ctx)) {\n return { allowed: false, reason: `denied by deny-list (${identifier})` };\n }\n }\n }\n\n if (mode === \"disabled\") {\n return { allowed: false, reason: \"scope disabled by policy\" };\n }\n\n if (mode === \"open\") {\n return { allowed: true, reason: \"\" };\n }\n\n // mode === \"allowlist\"\n if (!policy?.allow || policy.allow.length === 0) {\n return { allowed: false, reason: \"allowlist is empty\" };\n }\n for (const m of policy.allow) {\n if (matcherMatches(m, identifier, ctx)) {\n return { allowed: true, reason: \"\" };\n }\n }\n return { allowed: false, reason: `not in allowlist (${identifier})` };\n}\n\n// ============ Middleware ============\n\n/**\n * Build an access-policy middleware.\n *\n * Identifier used for matching:\n * - `c2c` / `dm` → senderId (user openid)\n * - `group` → groupOpenid\n * - `guild` → channelId\n *\n * @example\n * ```ts\n * bot.use(accessPolicy({\n * c2c: { mode: \"open\" },\n * group: { mode: \"allowlist\", allow: [\"group-openid-1\", \"group-openid-2\"] },\n * onBlock: (ctx, reason) => console.warn(\"blocked\", reason),\n * }));\n * ```\n */\nexport function accessPolicy(policy: AccessPolicy = {}): Middleware {\n return async (ctx, next) => {\n const { kind, senderId, groupOpenid, channelId } = ctx.message;\n\n let result: { allowed: boolean; reason: string };\n\n if (kind === \"c2c\" || kind === \"dm\") {\n result = evaluateScope(policy.c2c, senderId, ctx);\n } else if (kind === \"group\") {\n result = evaluateScope(policy.group, groupOpenid ?? \"\", ctx);\n } else if (kind === \"guild\") {\n result = evaluateScope(policy.guild, channelId ?? \"\", ctx);\n } else {\n result = { allowed: true, reason: \"\" };\n }\n\n if (!result.allowed) {\n ctx.log.debug?.(\n `[access] blocked ${kind} message from ${senderId}: ${result.reason}`,\n );\n policy.onBlock?.(ctx, result.reason);\n ctx.stop(`access:${result.reason}`);\n return;\n }\n\n await next();\n };\n}\n","/**\n * Mention-gate middleware — decide whether a group message should be answered.\n *\n * QQ Bot group messages may or may not contain an `@bot` mention. Many\n * production bots want to **only respond to mentions** in group chats while\n * still listening to all C2C messages. This middleware encapsulates that\n * common decision.\n *\n * The decision is exposed in `ctx.state.mention` for downstream middleware\n * to inspect (e.g. a history-buffer middleware may still record non-mention\n * messages without triggering a reply).\n */\n\nimport type { Middleware, MiddlewareContext } from \"./types.js\";\n\n// ============ Types ============\n\nexport interface MentionDecision {\n /** True if the bot was explicitly @-mentioned. */\n wasMentioned: boolean;\n /**\n * True if the message satisfies an *implicit* mention rule (e.g. it is a\n * direct reply to a previous bot message — set by upstream middleware).\n */\n implicit: boolean;\n /** Effective answer: `wasMentioned || implicit`. */\n shouldAnswer: boolean;\n /** When `shouldAnswer === false`, the gate's reason for skipping. */\n reason: \"no_mention\" | \"passthrough\";\n}\n\nexport interface MentionGateOptions {\n /**\n * Require an `@bot` mention in group messages. Defaults to `true`.\n * When `false`, every group message is treated as addressed to the bot.\n */\n requireMentionInGroup?: boolean;\n\n /**\n * Treat C2C messages as always addressed to the bot. Defaults to `true`.\n */\n alwaysAnswerC2C?: boolean;\n\n /**\n * Optional implicit-mention probe — return true to bypass the\n * `requireMentionInGroup` check (e.g. when the message quotes a prior\n * bot message).\n */\n isImplicitMention?: (ctx: MiddlewareContext) => boolean;\n\n /**\n * Hook invoked when the gate skips a message. Use for telemetry or to\n * record the message into a history buffer despite skipping.\n */\n onSkip?: (ctx: MiddlewareContext, decision: MentionDecision) => void;\n\n /**\n * If `true`, do **not** stop the middleware chain when the message should\n * not be answered — only annotate `ctx.state.mention`. Useful when other\n * middleware (e.g. history buffering) still needs to run.\n *\n * Defaults to `false` (stop the chain on skip).\n */\n passthrough?: boolean;\n}\n\n// ============ Helpers ============\n\n/** Heuristic: detect `<@!{appId}>` or `<@{appId}>` mention markers in content. */\nfunction detectMentionInContent(content: string, appId: string): boolean {\n if (!content || !appId) return false;\n const re = new RegExp(`<@!?${appId.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")}>`);\n return re.test(content);\n}\n\n// ============ Middleware ============\n\n/**\n * Build a mention-gate middleware.\n *\n * @example\n * ```ts\n * bot.use(mentionGate({\n * requireMentionInGroup: true,\n * isImplicitMention: (ctx) => ctx.message.refMsgIdx !== undefined,\n * }));\n *\n * bot.on(\"message\", async (msg) => {\n * // Only fires for messages that passed the gate.\n * await bot.sendText(msg.replyTarget, `Hi!`);\n * });\n * ```\n */\nexport function mentionGate(options: MentionGateOptions = {}): Middleware {\n const {\n requireMentionInGroup = true,\n alwaysAnswerC2C = true,\n isImplicitMention,\n onSkip,\n passthrough = false,\n } = options;\n\n return async (ctx, next) => {\n const msg = ctx.message;\n const appId = ctx.bot.appId;\n\n // Only group messages need gating\n if (msg.kind !== \"group\") {\n const decision: MentionDecision = {\n wasMentioned: true,\n implicit: false,\n shouldAnswer: alwaysAnswerC2C || msg.kind !== \"c2c\" && msg.kind !== \"dm\",\n reason: \"passthrough\",\n };\n ctx.state.mention = decision;\n await next();\n return;\n }\n\n // ---- Group: decide ----\n //\n // Priority order for \"was mentioned\":\n // 1. rawEventType === GROUP_AT_MESSAGE_CREATE\n // The event itself is QQ's authoritative signal — the Open Platform\n // only delivers this event when the user actually @-ed the bot.\n // Public-domain bots only ever receive this event type for groups.\n // 2. mentions[].is_you === true\n // Server-marked structured mention list (present on some payloads).\n // 3. Content contains `<@!{appId}>` or `<@{appId}>`\n // Fallback scan for self-hosted / private-domain bots that also\n // receive GROUP_MESSAGE_CREATE (every group message, not just @).\n const wasMentioned =\n msg.rawEventType === \"GROUP_AT_MESSAGE_CREATE\" ||\n (Array.isArray(msg.mentions) && msg.mentions.some((m) => m?.is_you === true)) ||\n detectMentionInContent(msg.content, appId);\n\n const implicit = isImplicitMention?.(ctx) ?? false;\n\n const shouldAnswer = !requireMentionInGroup || wasMentioned || implicit;\n\n const decision: MentionDecision = {\n wasMentioned,\n implicit,\n shouldAnswer,\n reason: shouldAnswer ? \"passthrough\" : \"no_mention\",\n };\n\n ctx.state.mention = decision;\n\n if (!shouldAnswer) {\n onSkip?.(ctx, decision);\n ctx.log.debug?.(\n `[mention-gate] skip group message: wasMentioned=${wasMentioned}, implicit=${implicit}`,\n );\n if (!passthrough) {\n ctx.stop(\"mention-gate:no_mention\");\n return;\n }\n }\n\n await next();\n };\n}\n","/**\n * Quote & Ref-Index middleware — record messages + resolve quoted references.\n *\n * A single middleware that does two things in one pass:\n * 1. **Record** — captures a compact summary of the current message into\n * a pluggable store (default: in-memory LRU), keyed by `msgIdx` or `messageId`.\n * 2. **Resolve** — if the current message quotes/replies to a previous one\n * (`refMsgIdx` set), looks it up from the store or falls back to QQ's\n * `msg_elements[0]` push data.\n *\n * The resolved quote is attached to `ctx.state.quote`.\n *\n * @example\n * ```ts\n * import { quoteRef } from \"@tencent-connect/qqbot-nodejs\";\n *\n * bot.use(quoteRef()); // zero-config\n * bot.use(quoteRef({ maxSize: 1000 })); // custom LRU size\n * bot.use(quoteRef({ store: myRedisStore })); // custom backend\n * ```\n */\n\nimport type { Middleware } from \"./types.js\";\n\n// ============ Types ============\n\n/** Compact summary stored per message. */\nexport interface RefEntry {\n messageId: string;\n senderId: string;\n senderName?: string;\n content: string;\n timestamp: string;\n}\n\n/** Pluggable store interface for ref-index. */\nexport interface RefIndexStore {\n get(key: string): RefEntry | undefined | Promise<RefEntry | undefined>;\n set(key: string, entry: RefEntry): void | Promise<void>;\n}\n\n/** Attachment summary from the quoted message (from msg_elements). */\nexport interface QuotedAttachment {\n contentType: string;\n url: string;\n filename?: string;\n /** ASR text for voice messages (QQ built-in speech recognition). */\n asrText?: string;\n}\n\n/** Resolved quote attached to `ctx.state.quote`. */\nexport interface ResolvedQuote {\n /** The ref key that was looked up. */\n refKey: string;\n /** Source of the resolution. */\n source: \"store\" | \"msg_elements\" | \"none\";\n /** The resolved entry from store (cache hit). */\n entry?: RefEntry;\n /** Raw content from msg_elements[0] (cache miss fallback). */\n rawContent?: string;\n /** Attachments from the quoted message (from msg_elements[0]). */\n attachments?: QuotedAttachment[];\n /**\n * Combined text representation of the quoted message.\n * Prefers store entry content; falls back to msg_elements content.\n */\n text: string;\n}\n\nexport interface QuoteRefOptions {\n /** Backing store. Defaults to an in-memory LRU. */\n store?: RefIndexStore;\n /** Max entries in the default in-memory LRU. Defaults to 500. */\n maxSize?: number;\n /** Max content chars stored per entry. Defaults to 200. */\n contentLimit?: number;\n}\n\n// ============ Default in-memory LRU ============\n\n/**\n * Default in-memory ref-index store (LRU eviction).\n *\n * Suitable for single-process bots. For multi-instance deployments,\n * implement `RefIndexStore` with Redis / SQL / etc.\n */\nexport class MemoryRefIndexStore implements RefIndexStore {\n private readonly map = new Map<string, RefEntry>();\n private readonly maxSize: number;\n\n constructor(maxSize = 500) {\n this.maxSize = maxSize;\n }\n\n get(key: string): RefEntry | undefined {\n return this.map.get(key);\n }\n\n set(key: string, entry: RefEntry): void {\n if (this.map.size >= this.maxSize) {\n const first = this.map.keys().next().value;\n if (first !== undefined) this.map.delete(first);\n }\n this.map.set(key, entry);\n }\n}\n\n// ============ Middleware ============\n\n/**\n * Combined quote & ref-index middleware.\n *\n * One middleware does both: records the current message into the store\n * **and** resolves any quoted message reference.\n *\n * @example\n * ```ts\n * bot.use(quoteRef()); // that's it — zero config\n *\n * bot.on(\"message\", (msg) => {\n * // Access resolved quote via middleware state\n * // (ctx.state.quote is typed as ResolvedQuote)\n * });\n * ```\n */\nexport function quoteRef(options: QuoteRefOptions = {}): Middleware {\n const contentLimit = options.contentLimit ?? 200;\n const store = options.store ?? new MemoryRefIndexStore(options.maxSize ?? 500);\n\n return async (ctx, next) => {\n const msg = ctx.message;\n\n // ── 1. Record current message ──\n const key = msg.msgIdx ?? msg.messageId;\n if (key) {\n const entry: RefEntry = {\n messageId: msg.messageId,\n senderId: msg.senderId,\n senderName: msg.senderName,\n content: (msg.content ?? \"\").slice(0, contentLimit),\n timestamp: msg.timestamp,\n };\n await store.set(key, entry);\n }\n\n // ── 2. Resolve quoted message (if any) ──\n const refKey = msg.refMsgIdx;\n if (refKey) {\n const entry = await store.get(refKey);\n\n if (entry) {\n // Cache hit\n ctx.state.quote = {\n refKey,\n source: \"store\",\n entry,\n text: entry.content || \"[empty message]\",\n };\n ctx.log.debug?.(\n `[quote-ref] hit refKey=${refKey} sender=${entry.senderId}`,\n );\n } else {\n // Cache miss — fallback to msg_elements[0]\n const el = msg.msgElements?.[0];\n if (el && (el.content || el.attachments?.length)) {\n const rawContent = el.content ?? \"\";\n const attachments = parseAttachments(el.attachments);\n const text = buildText(rawContent, attachments);\n ctx.state.quote = { refKey, source: \"msg_elements\", rawContent, attachments, text };\n ctx.log.debug?.(\n `[quote-ref] fallback refKey=${refKey} content=\"${rawContent.slice(0, 30)}...\"`,\n );\n } else {\n ctx.state.quote = { refKey, source: \"none\", text: \"\" };\n ctx.log.debug?.(`[quote-ref] miss refKey=${refKey} (no store, no msg_elements)`);\n }\n }\n }\n\n await next();\n };\n}\n\n// ============ Helpers ============\n\nfunction parseAttachments(\n raw: Array<{ content_type: string; url: string; filename?: string; asr_refer_text?: string }> | undefined,\n): QuotedAttachment[] {\n if (!raw || raw.length === 0) return [];\n return raw.map((a) => ({\n contentType: a.content_type,\n url: a.url,\n filename: a.filename,\n asrText: a.asr_refer_text,\n }));\n}\n\nfunction buildText(content: string, attachments: QuotedAttachment[]): string {\n const parts: string[] = [];\n if (content.trim()) parts.push(content.trim());\n for (const att of attachments) {\n const t = att.contentType.toLowerCase();\n if (t.startsWith(\"audio/\")) {\n parts.push(att.asrText ? `[voice: ${att.asrText}]` : \"[voice]\");\n } else if (t.startsWith(\"image/\")) {\n parts.push(att.filename ? `[image: ${att.filename}]` : \"[image]\");\n } else if (t.startsWith(\"video/\")) {\n parts.push(att.filename ? `[video: ${att.filename}]` : \"[video]\");\n } else {\n parts.push(`[file: ${att.filename ?? \"untitled\"}]`);\n }\n }\n return parts.join(\"\\n\") || \"[empty message]\";\n}\n","/**\n * Envelope-formatter middleware — assemble LLM prompt context.\n *\n * Gathers information from upstream middleware (history, quote, mention\n * state, sender info) and formats it into a structured context string\n * attached to `ctx.state.envelope`. This is the \"last mile\" before the\n * user's LLM call — providing a ready-to-use prompt prefix.\n *\n * This middleware is **optional** — users who prefer to build their own\n * prompt can skip it and read `ctx.state.history` / `ctx.state.quote`\n * directly.\n */\n\nimport type { Middleware, MiddlewareContext } from \"./types.js\";\nimport type { HistoryEntry } from \"./history-buffer.js\";\nimport type { ResolvedQuote } from \"./quote-ref.js\";\n\nexport interface EnvelopeFormatterOptions {\n /**\n * Maximum number of history entries to include.\n * Defaults to `5`.\n */\n historyLimit?: number;\n /**\n * Whether to include the resolved quote in the envelope.\n * Defaults to `true`.\n */\n includeQuote?: boolean;\n /**\n * Whether to include sender name / id as context.\n * Defaults to `true`.\n */\n includeSender?: boolean;\n /**\n * Custom formatter override. If provided, replaces the default logic\n * entirely. Receives the same ctx and should return the formatted string.\n */\n format?: (ctx: MiddlewareContext) => string;\n}\n\n/**\n * @example\n * ```ts\n * bot.use(historyBuffer({ limit: 10 }));\n * bot.use(quoteResolver({ store: refStore }));\n * bot.use(envelopeFormatter({ historyLimit: 5 }));\n *\n * bot.on(\"message\", async (msg) => {\n * const envelope = msg._ctx?.state.envelope as string;\n * const response = await llm.chat(envelope + \"\\n\" + msg.content);\n * await bot.sendText(msg.replyTarget, response);\n * });\n * ```\n */\nexport function envelopeFormatter(options: EnvelopeFormatterOptions = {}): Middleware {\n const {\n historyLimit = 5,\n includeQuote = true,\n includeSender = true,\n format,\n } = options;\n\n return async (ctx, next) => {\n if (format) {\n ctx.state.envelope = format(ctx);\n } else {\n ctx.state.envelope = buildEnvelope(ctx, { historyLimit, includeQuote, includeSender });\n }\n\n ctx.log.debug?.(\n `[envelope] built ${(ctx.state.envelope as string).length} chars` +\n ` (sender=${includeSender}, quote=${includeQuote}, history=${(ctx.state.history as unknown[] | undefined)?.length ?? 0}/${historyLimit})`,\n );\n\n await next();\n };\n}\n\nfunction buildEnvelope(\n ctx: MiddlewareContext,\n opts: { historyLimit: number; includeQuote: boolean; includeSender: boolean },\n): string {\n const sections: string[] = [];\n\n // ── Context meta ──\n if (opts.includeSender) {\n const name = ctx.message.senderName || ctx.message.senderId;\n const scope = ctx.message.kind === \"group\"\n ? `group(${ctx.message.groupOpenid ?? \"unknown\"})`\n : ctx.message.kind;\n sections.push(`<from>\\nuser: ${name}\\nscope: ${scope}\\n</from>`);\n }\n\n // ── Quoted message (reply-to) ──\n if (opts.includeQuote) {\n const quote = ctx.state.quote as ResolvedQuote | undefined;\n if (quote && quote.text) {\n const sender = quote.entry?.senderName || quote.entry?.senderId;\n const line = sender ? `${sender}: ${quote.text}` : quote.text;\n sections.push(`<reply_to>\\n${line}\\n</reply_to>`);\n }\n }\n\n // ── Conversation history ──\n const history = ctx.state.history as HistoryEntry[] | undefined;\n if (history && history.length > 0) {\n const recent = history.slice(-opts.historyLimit);\n const lines = recent.map((h) => {\n const name = h.senderName || h.senderId;\n return `${name}: ${h.content.slice(0, 200)}`;\n });\n sections.push(`<history>\\n${lines.join(\"\\n\")}\\n</history>`);\n }\n\n // ── Current message ──\n const content = (ctx.message.content ?? \"\").trim();\n const attachments = ctx.message.attachments;\n const hasAttachments = attachments && attachments.length > 0;\n\n if (content || hasAttachments) {\n const parts: string[] = [];\n if (content) {\n parts.push(content);\n }\n if (hasAttachments) {\n for (const att of attachments) {\n const t = att.content_type.toLowerCase();\n if (t.startsWith(\"image/\")) parts.push(`[image: ${att.filename ?? \"image\"}]`);\n else if (t.startsWith(\"audio/\") || t === \"voice\") {\n parts.push(att.asr_refer_text ? `[voice: ${att.asr_refer_text}]` : \"[voice]\");\n }\n else if (t.startsWith(\"video/\")) parts.push(\"[video]\");\n else parts.push(`[file: ${att.filename ?? \"file\"}]`);\n }\n }\n sections.push(`<message>\\n${parts.join(\"\\n\")}\\n</message>`);\n }\n\n return sections.join(\"\\n\\n\");\n}\n","/**\n * Slash-command middleware — register `/cmd` style commands.\n *\n * Pattern: any message whose content starts with a configured prefix\n * (default `/`) is intercepted; the matched command's `handler` runs, and\n * the chain is short-circuited so the `bot.on(\"message\")` listener does\n * not fire.\n *\n * Commands are **explicitly registered** on the middleware instance so the\n * SDK does not enforce any specific business commands — users define what\n * makes sense for their bot.\n */\n\nimport type { ReplyTarget } from \"../QQBot.js\";\nimport type { Middleware, MiddlewareContext } from \"./types.js\";\n\n// ============ Types ============\n\n/** Parsed command struct exposed via `ctx.state.command`. */\nexport interface ParsedCommand {\n /** The command name (without leading prefix). */\n name: string;\n /** Whitespace-separated arguments after the command name. */\n args: string[];\n /** Raw arguments string (everything after the command name). */\n raw: string;\n}\n\n/** Result returned by a slash-command handler. */\nexport type SlashCommandResult =\n | string // Text reply\n | { kind: \"text\"; content: string } // Explicit text\n | { kind: \"noop\" } // Silently consume\n | void; // = noop\n\nexport interface SlashCommandHandlerContext extends MiddlewareContext {\n /** Parsed command struct. */\n command: ParsedCommand;\n}\n\n/** Spec for one registered command. */\nexport interface SlashCommand {\n /** Command name(s). The first is canonical; the rest are aliases. */\n name: string | string[];\n /** Brief description (used by `/help`). */\n description?: string;\n /** Optional usage hint (used by `/help`). */\n usage?: string;\n /** Whether this command is hidden from `/help`. Defaults to false. */\n hidden?: boolean;\n /** Scope restriction: \"c2c\" = only private chat, \"group\" = only group, \"all\" = both (default). */\n scope?: \"c2c\" | \"group\" | \"all\";\n /**\n * Handler. Return a string to send a text reply, or `{ kind: \"noop\" }`\n * to silently consume.\n */\n handler: (ctx: SlashCommandHandlerContext) => Promise<SlashCommandResult> | SlashCommandResult;\n}\n\nexport interface SlashCommandOptions {\n /** Command prefix(es). Defaults to `[\"/\"]`. */\n prefixes?: string[];\n /** Pre-registered commands. */\n commands?: SlashCommand[];\n /**\n * If `true`, when a command throws, the error is caught and\n * `{ kind: \"text\", content: errorMessage }` is sent as a reply.\n * Defaults to `true`.\n */\n catchErrors?: boolean;\n /**\n * Auto-register a `/help` command listing all visible commands.\n * Defaults to `true`.\n */\n autoHelp?: boolean;\n /**\n * Global allowlist of user OpenIDs permitted to use slash commands.\n * If empty or not set, all users can use commands.\n * Non-allowlisted users' command-like messages pass through to `next()`\n * as regular messages.\n */\n allowFrom?: string[];\n}\n\n// ============ Implementation ============\n\n/**\n * Slash-command middleware factory.\n *\n * Returns a middleware **and** a registry — the registry lets you keep\n * adding commands after the middleware is registered with the bot.\n *\n * @example\n * ```ts\n * const slash = slashCommand({ prefixes: [\"/\", \"!\"] });\n * slash.register({\n * name: \"ping\",\n * description: \"Reply with pong\",\n * handler: () => \"pong\",\n * });\n *\n * slash.register({\n * name: [\"whoami\", \"me\"],\n * handler: (ctx) => `You are ${ctx.message.senderId}`,\n * });\n *\n * bot.use(slash.middleware);\n * ```\n */\nexport function slashCommand(options: SlashCommandOptions = {}): {\n middleware: Middleware;\n register: (cmd: SlashCommand) => void;\n unregister: (name: string) => void;\n list: () => SlashCommand[];\n} {\n const prefixes = options.prefixes ?? [\"/\"];\n const catchErrors = options.catchErrors ?? true;\n const autoHelp = options.autoHelp ?? true;\n const allowFrom = options.allowFrom ?? [];\n\n const registry = new Map<string, SlashCommand>();\n\n const register = (cmd: SlashCommand): void => {\n const names = Array.isArray(cmd.name) ? cmd.name : [cmd.name];\n if (names.length === 0) {\n throw new Error(\"slash-command: name must not be empty\");\n }\n for (const n of names) {\n const key = n.toLowerCase();\n if (registry.has(key)) {\n throw new Error(`slash-command: duplicate name \"${n}\"`);\n }\n registry.set(key, cmd);\n }\n };\n\n const unregister = (name: string): void => {\n registry.delete(name.toLowerCase());\n };\n\n const list = (): SlashCommand[] => {\n const seen = new Set<SlashCommand>();\n const out: SlashCommand[] = [];\n for (const cmd of registry.values()) {\n if (!seen.has(cmd)) {\n seen.add(cmd);\n out.push(cmd);\n }\n }\n return out;\n };\n\n // Pre-register commands\n for (const cmd of options.commands ?? []) {\n register(cmd);\n }\n\n // Auto /help\n if (autoHelp && !registry.has(\"help\")) {\n register({\n name: \"help\",\n description: \"List all available commands\",\n handler: () => {\n const lines: string[] = [\"Available commands:\"];\n for (const cmd of list()) {\n if (cmd.hidden) continue;\n const names = Array.isArray(cmd.name) ? cmd.name.join(\", \") : cmd.name;\n const desc = cmd.description ?? \"\";\n const usage = cmd.usage ? ` — ${cmd.usage}` : \"\";\n lines.push(`/${names}${usage}${desc ? ` — ${desc}` : \"\"}`);\n }\n return lines.join(\"\\n\");\n },\n });\n }\n\n const middleware: Middleware = async (ctx, next) => {\n const content = (ctx.message.content ?? \"\").trim();\n if (!content) {\n await next();\n return;\n }\n\n // Strip server-side `<@bot>` mention markers from content for matching.\n const cleaned = content.replace(/<@!?\\d+>\\s*/g, \"\").trim();\n\n // Find matching prefix\n const prefix = prefixes.find((p) => cleaned.startsWith(p));\n if (!prefix) {\n await next();\n return;\n }\n\n const body = cleaned.slice(prefix.length);\n const match = /^(\\S+)(?:\\s+(.*))?$/.exec(body);\n if (!match) {\n await next();\n return;\n }\n\n const [, name, rest = \"\"] = match;\n const cmd = registry.get(name!.toLowerCase());\n if (!cmd) {\n await next();\n return;\n }\n\n // AllowFrom check: non-allowlisted users bypass commands as regular messages\n if (allowFrom.length > 0 && !allowFrom.includes(ctx.message.senderId)) {\n await next();\n return;\n }\n\n const parsed: ParsedCommand = {\n name: name!.toLowerCase(),\n args: rest ? rest.split(/\\s+/) : [],\n raw: rest,\n };\n ctx.state.command = parsed;\n\n // Scope check: reject if command is restricted to a different scope\n const cmdScope = cmd.scope ?? \"all\";\n if (cmdScope !== \"all\") {\n const msgKind = ctx.message.kind;\n const isC2C = msgKind === \"c2c\" || msgKind === \"dm\";\n const isGroup = msgKind === \"group\";\n if ((cmdScope === \"c2c\" && !isC2C) || (cmdScope === \"group\" && !isGroup)) {\n const hint = cmdScope === \"c2c\" ? \"该指令仅限私聊使用\" : \"该指令仅限群聊使用\";\n await sendCommandResult(ctx, hint);\n ctx.stop(`command:scope-denied:${parsed.name}`);\n return;\n }\n }\n\n const handlerCtx = ctx as SlashCommandHandlerContext;\n handlerCtx.command = parsed;\n\n try {\n const result = await cmd.handler(handlerCtx);\n await sendCommandResult(ctx, result);\n } catch (err) {\n if (catchErrors) {\n const msg = err instanceof Error ? err.message : String(err);\n ctx.log.error?.(`[slash-command] handler \"${parsed.name}\" threw: ${msg}`);\n await sendCommandResult(ctx, { kind: \"text\", content: `Error: ${msg}` });\n } else {\n ctx.stop(`command:error:${parsed.name}`);\n throw err;\n }\n }\n\n // Commands always short-circuit the chain.\n ctx.stop(`command:matched:${parsed.name}`);\n };\n\n return { middleware, register, unregister, list };\n}\n\nasync function sendCommandResult(\n ctx: MiddlewareContext,\n result: SlashCommandResult,\n): Promise<void> {\n if (result === undefined || result === null) return;\n if (typeof result === \"string\") {\n if (result) await ctx.bot.sendText(ctx.replyTarget as ReplyTarget, result);\n return;\n }\n if (typeof result === \"object\") {\n if (result.kind === \"text\" && result.content) {\n await ctx.bot.sendText(ctx.replyTarget as ReplyTarget, result.content);\n }\n // kind === \"noop\" → no-op\n }\n}\n","/**\n * History-buffer middleware — keep recent group messages around.\n *\n * Many bots want to feed the LLM a few rounds of recent context, even for\n * messages that did not directly @-mention the bot. This middleware\n * silently records every group message into a per-group ring buffer, then\n * exposes the buffered list via `ctx.state.history`.\n *\n * **Pluggable storage** — the actual store is whatever object the user\n * passes in. The SDK ships an in-memory implementation; users can drop in\n * Redis / SQL / file-backed stores via the `HistoryStore` interface.\n */\n\nimport type { Middleware, MiddlewareContext } from \"./types.js\";\n\n// ============ Types ============\n\n/** One buffered message. */\nexport interface HistoryEntry {\n senderId: string;\n senderName?: string;\n content: string;\n timestamp: number;\n /** Original message id (for de-duplication). */\n messageId: string;\n}\n\n/** Pluggable storage backend. */\nexport interface HistoryStore {\n /** Append one entry into a group's buffer. Caller-provided ordering. */\n append(groupKey: string, entry: HistoryEntry, limit: number): void | Promise<void>;\n /** Return the most-recent entries for a group (oldest → newest). */\n list(groupKey: string, limit: number): HistoryEntry[] | Promise<HistoryEntry[]>;\n /** Optional: clear a group's buffer. */\n clear?(groupKey: string): void | Promise<void>;\n}\n\nexport interface HistoryBufferOptions {\n /** Max entries kept per group. Defaults to 10. */\n limit?: number;\n /** Storage backend. Defaults to {@link MemoryHistoryStore}. */\n store?: HistoryStore;\n /**\n * Whether to record the message even when an upstream middleware called\n * `ctx.stop()` (e.g. mention-gate skipped a no-mention group message).\n * Defaults to `true` — history exists precisely to capture the chatter\n * we did not respond to.\n */\n recordOnSkip?: boolean;\n /** Group-key derivation. Defaults to `groupOpenid`. */\n groupKey?: (ctx: MiddlewareContext) => string | undefined;\n}\n\n// ============ In-memory store ============\n\n/**\n * Default in-memory history store. Keeps a ring buffer per group key.\n *\n * Suitable for single-process bots; for multi-instance deployments use\n * a Redis / SQL backed implementation.\n */\nexport class MemoryHistoryStore implements HistoryStore {\n private readonly buffers = new Map<string, HistoryEntry[]>();\n\n append(groupKey: string, entry: HistoryEntry, limit: number): void {\n let buf = this.buffers.get(groupKey);\n if (!buf) {\n buf = [];\n this.buffers.set(groupKey, buf);\n }\n // De-dup by messageId.\n if (buf.some((e) => e.messageId === entry.messageId)) {\n return;\n }\n buf.push(entry);\n if (buf.length > limit) {\n buf.splice(0, buf.length - limit);\n }\n }\n\n list(groupKey: string, limit: number): HistoryEntry[] {\n const buf = this.buffers.get(groupKey);\n if (!buf) return [];\n return buf.slice(-limit);\n }\n\n clear(groupKey: string): void {\n this.buffers.delete(groupKey);\n }\n\n /** Diagnostic: number of groups with buffered history. */\n size(): number {\n return this.buffers.size;\n }\n}\n\n// ============ Middleware ============\n\n/**\n * Build a history-buffer middleware.\n *\n * The middleware:\n * 1. Records the current group message into the store (before downstream).\n * 2. Exposes `ctx.state.history: HistoryEntry[]` to downstream middleware\n * and to the final `bot.on(\"message\")` listener (oldest → newest,\n * excluding the current message).\n *\n * @example\n * ```ts\n * const history = historyBuffer({ limit: 5 });\n * bot.use(mentionGate({ passthrough: true })); // record even on no-mention\n * bot.use(history);\n *\n * bot.on(\"message\", async (msg) => {\n * const buf = msg.history ?? [];\n * const prompt = buf.map(h => `${h.senderName}: ${h.content}`).join(\"\\n\");\n * // ...\n * });\n * ```\n */\nexport function historyBuffer(options: HistoryBufferOptions = {}): Middleware {\n const limit = options.limit ?? 10;\n const store = options.store ?? new MemoryHistoryStore();\n const recordOnSkip = options.recordOnSkip ?? true;\n const getKey =\n options.groupKey ??\n ((ctx) => (ctx.message.kind === \"group\" ? ctx.message.groupOpenid : undefined));\n\n const m: Middleware = async (ctx, next) => {\n const key = getKey(ctx);\n if (!key) {\n await next();\n return;\n }\n\n // 1. List buffered (excluding current message)\n const buffered = await store.list(key, limit);\n ctx.state.history = buffered;\n\n // 2. Record the current message (after exposing previous buffer)\n const entry: HistoryEntry = {\n senderId: ctx.message.senderId,\n senderName: ctx.message.senderName,\n content: ctx.message.content,\n timestamp: Date.parse(ctx.message.timestamp) || Date.now(),\n messageId: ctx.message.messageId,\n };\n\n try {\n await store.append(key, entry, limit);\n } catch (err) {\n ctx.log.error?.(\n `[history-buffer] append failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n if (ctx.stopped && !recordOnSkip) {\n return;\n }\n\n await next();\n };\n\n return m;\n}\n","/**\n * Typing-indicator middleware — auto-send a `typing` notification for C2C\n * messages so the user sees a visual hint while the bot is processing.\n *\n * Supports keepalive mode: periodically re-send typing every `intervalSec`\n * to cover long-running AI inference (QQ platform typing window is ~60s).\n *\n * QQ Open Platform restriction: `sendInputNotify` only works for C2C\n * (private chat) targets. Group / Guild messages are silently skipped.\n */\n\nimport type { Middleware } from \"./types.js\";\n\n// ============ Options ============\n\nexport interface TypingIndicatorOptions {\n /** Indicator duration per send, in seconds. Defaults to 60. */\n durationSec?: number;\n /**\n * Only send typing for messages that pass `predicate(ctx)`. Defaults to\n * always (returns true).\n */\n predicate?: (ctx: import(\"./types.js\").MiddlewareContext) => boolean;\n /**\n * If `true`, the typing call is awaited before continuing the chain.\n * Defaults to `false` (fire-and-forget).\n */\n awaitTyping?: boolean;\n /**\n * Enable keepalive: re-send typing every `keepAliveIntervalMs` until\n * the downstream middleware chain completes. Defaults to `true`.\n */\n keepAlive?: boolean;\n /**\n * Keepalive interval in milliseconds. Defaults to 50_000 (50s).\n * Should be less than the platform's typing window (~60s).\n */\n keepAliveIntervalMs?: number;\n}\n\n// ============ Constants ============\n\nconst DEFAULT_DURATION_SEC = 60;\nconst DEFAULT_KEEPALIVE_INTERVAL_MS = 50_000;\n\n// ============ Middleware ============\n\n/**\n * Auto-send `typing` notification for inbound C2C messages.\n *\n * With keepalive enabled (default), typing is refreshed periodically\n * throughout the entire middleware chain + message handler execution,\n * covering long-running AI inference that may take 30s+.\n *\n * @example\n * ```ts\n * bot.use(typingIndicator()); // keepalive enabled by default\n * bot.on(\"message\", async (msg) => {\n * // User sees \"typing…\" continuously while the LLM is generating\n * const reply = await llm.chat(msg.content);\n * await bot.sendText(msg.replyTarget, reply);\n * });\n * ```\n */\nexport function typingIndicator(options: TypingIndicatorOptions = {}): Middleware {\n const durationSec = options.durationSec ?? DEFAULT_DURATION_SEC;\n const predicate = options.predicate ?? (() => true);\n const awaitTyping = options.awaitTyping ?? false;\n const keepAlive = options.keepAlive ?? true;\n const keepAliveIntervalMs = options.keepAliveIntervalMs ?? DEFAULT_KEEPALIVE_INTERVAL_MS;\n\n return async (ctx, next) => {\n if (ctx.message.kind !== \"c2c\" || !predicate(ctx)) {\n await next();\n return;\n }\n\n const sendTyping = () =>\n ctx.bot.sendTyping(ctx.replyTarget, durationSec).catch((err) => {\n ctx.log.debug?.(\n `[typing] failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n });\n\n // Send initial typing\n const promise = sendTyping();\n if (awaitTyping) {\n await promise;\n }\n\n // Setup keepalive timer\n let timer: ReturnType<typeof setInterval> | null = null;\n if (keepAlive) {\n timer = setInterval(() => {\n sendTyping();\n }, keepAliveIntervalMs);\n }\n\n try {\n await next();\n } finally {\n if (timer) {\n clearInterval(timer);\n }\n }\n };\n}\n","/**\n * Error-handler middleware — catch downstream errors and send a friendly reply.\n *\n * Add this **first** in the chain (before any other middleware) so it sees\n * errors from all downstream stages.\n *\n * @example\n * ```ts\n * bot.use(errorHandler({\n * format: (err) => `抱歉,处理消息时出错:${err.message}`,\n * }));\n * bot.use(slashCommand(...));\n * ```\n */\n\nimport { ApiError } from \"../protocol/types.js\";\nimport type { Middleware, MiddlewareContext } from \"./types.js\";\n\nexport interface ErrorHandlerOptions {\n /** Build a user-facing reply from the caught error. */\n format?: (err: Error, ctx: MiddlewareContext) => string;\n /**\n * If true, also re-throw the error so `bot.on(\"error\")` listeners fire.\n * Defaults to `false` (consume the error after replying).\n */\n rethrow?: boolean;\n /**\n * Filter — only handle errors that match. Defaults to all `Error`\n * instances. Useful to skip e.g. ApiError 4xx (let the user see them).\n */\n filter?: (err: Error) => boolean;\n}\n\nconst DEFAULT_FORMAT = (err: Error): string => {\n if (err instanceof ApiError) {\n if (err.bizMessage) return `[QQ ${err.bizCode ?? err.httpStatus}] ${err.bizMessage}`;\n return `[QQ ${err.httpStatus}] ${err.message}`;\n }\n return err.message || \"Unknown error\";\n};\n\n/**\n * Build an error-handler middleware. The middleware **wraps** the rest of\n * the chain — if any downstream middleware (or the `message` listener)\n * throws, it catches the error, sends a reply, and optionally re-emits.\n */\nexport function errorHandler(options: ErrorHandlerOptions = {}): Middleware {\n const format = options.format ?? DEFAULT_FORMAT;\n const rethrow = options.rethrow ?? false;\n const filter = options.filter ?? (() => true);\n\n return async (ctx, next) => {\n try {\n await next();\n } catch (err) {\n const e = err instanceof Error ? err : new Error(String(err));\n if (!filter(e)) {\n if (rethrow) throw e;\n return;\n }\n ctx.log.error?.(`[error-handler] caught: ${e.message}`);\n\n try {\n const reply = format(e, ctx);\n if (reply) {\n await ctx.bot.sendText(ctx.replyTarget, reply);\n }\n } catch (sendErr) {\n ctx.log.error?.(\n `[error-handler] failed to send error reply: ${sendErr instanceof Error ? sendErr.message : String(sendErr)}`,\n );\n }\n\n if (rethrow) throw e;\n }\n };\n}\n","/**\n * Generic key-value store interface — used by built-in pluggable backends.\n *\n * The SDK ships:\n * - {@link MemoryKVStore}: in-memory (default for tests / simple deployments)\n * - {@link FileKVStore}: JSON-file backed (single-process, simple deployments)\n *\n * Users can plug in Redis / SQL / cloud KV by implementing this same\n * interface. See `examples/storage-redis/` for a Redis adapter sketch.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\n// ============ Interface ============\n\n/**\n * Generic async KV store with optional TTL support.\n *\n * All methods may be sync or async; callers always `await` them.\n */\nexport interface KVStore {\n /** Get a value. Returns `undefined` if missing or expired. */\n get<T = unknown>(key: string): Promise<T | undefined> | T | undefined;\n /** Set a value with optional TTL (milliseconds). */\n set<T = unknown>(key: string, value: T, ttlMs?: number): Promise<void> | void;\n /** Delete a value. Returns true if it existed. */\n delete(key: string): Promise<boolean> | boolean;\n /** Check key existence (cheaper than `get` on some backends). */\n has?(key: string): Promise<boolean> | boolean;\n /** Iterate keys matching a prefix. Optional. */\n keys?(prefix?: string): Promise<string[]> | string[];\n /** Clear all keys (or those matching a prefix). Optional. */\n clear?(prefix?: string): Promise<void> | void;\n}\n\n// ============ Memory ============\n\ninterface MemoryEntry {\n value: unknown;\n expireAt?: number;\n}\n\n/**\n * In-memory KV store. Suitable for single-process deployments and tests.\n */\nexport class MemoryKVStore implements KVStore {\n private readonly map = new Map<string, MemoryEntry>();\n\n get<T = unknown>(key: string): T | undefined {\n const entry = this.map.get(key);\n if (!entry) return undefined;\n if (entry.expireAt && entry.expireAt <= Date.now()) {\n this.map.delete(key);\n return undefined;\n }\n return entry.value as T;\n }\n\n set<T = unknown>(key: string, value: T, ttlMs?: number): void {\n this.map.set(key, {\n value,\n expireAt: ttlMs && ttlMs > 0 ? Date.now() + ttlMs : undefined,\n });\n }\n\n delete(key: string): boolean {\n return this.map.delete(key);\n }\n\n has(key: string): boolean {\n const entry = this.map.get(key);\n if (!entry) return false;\n if (entry.expireAt && entry.expireAt <= Date.now()) {\n this.map.delete(key);\n return false;\n }\n return true;\n }\n\n keys(prefix?: string): string[] {\n const all = [...this.map.keys()];\n return prefix ? all.filter((k) => k.startsWith(prefix)) : all;\n }\n\n clear(prefix?: string): void {\n if (!prefix) {\n this.map.clear();\n return;\n }\n for (const k of this.map.keys()) {\n if (k.startsWith(prefix)) this.map.delete(k);\n }\n }\n\n /** Diagnostic: number of keys (incl. expired-but-not-yet-cleaned). */\n size(): number {\n return this.map.size;\n }\n}\n\n// ============ File-backed ============\n\nexport interface FileKVStoreOptions {\n /** Directory holding the JSON file. */\n dir: string;\n /** File name. Defaults to `kv-store.json`. */\n fileName?: string;\n /** Save throttle window, ms. Defaults to 1000. */\n saveThrottleMs?: number;\n /** Optional logger. */\n logger?: { error?: (msg: string) => void };\n}\n\ninterface FileEntry {\n value: unknown;\n expireAt?: number;\n}\n\n/**\n * JSON-file backed KV store.\n *\n * Loads on construct, throttles writes. Suitable for single-process bots\n * with light persistence needs (e.g. session id, refIdx).\n *\n * Not safe for multi-process / multi-instance use — use a real KV\n * (Redis, SQLite, ...) for that.\n */\nexport class FileKVStore implements KVStore {\n private readonly map = new Map<string, FileEntry>();\n private readonly filePath: string;\n private readonly saveThrottleMs: number;\n private saveTimer: ReturnType<typeof setTimeout> | null = null;\n private dirty = false;\n private readonly logger: NonNullable<FileKVStoreOptions[\"logger\"]>;\n\n constructor(opts: FileKVStoreOptions) {\n this.filePath = path.join(opts.dir, opts.fileName ?? \"kv-store.json\");\n this.saveThrottleMs = opts.saveThrottleMs ?? 1000;\n this.logger = opts.logger ?? {};\n this.load();\n }\n\n get<T = unknown>(key: string): T | undefined {\n const entry = this.map.get(key);\n if (!entry) return undefined;\n if (entry.expireAt && entry.expireAt <= Date.now()) {\n this.map.delete(key);\n this.scheduleSave();\n return undefined;\n }\n return entry.value as T;\n }\n\n set<T = unknown>(key: string, value: T, ttlMs?: number): void {\n this.map.set(key, {\n value,\n expireAt: ttlMs && ttlMs > 0 ? Date.now() + ttlMs : undefined,\n });\n this.scheduleSave();\n }\n\n delete(key: string): boolean {\n const removed = this.map.delete(key);\n if (removed) this.scheduleSave();\n return removed;\n }\n\n has(key: string): boolean {\n return this.get(key) !== undefined;\n }\n\n keys(prefix?: string): string[] {\n const all = [...this.map.keys()];\n return prefix ? all.filter((k) => k.startsWith(prefix)) : all;\n }\n\n clear(prefix?: string): void {\n if (!prefix) {\n this.map.clear();\n } else {\n for (const k of this.map.keys()) {\n if (k.startsWith(prefix)) this.map.delete(k);\n }\n }\n this.scheduleSave();\n }\n\n /** Force flush pending writes. Call before process exit. */\n flush(): void {\n if (this.saveTimer) {\n clearTimeout(this.saveTimer);\n this.saveTimer = null;\n }\n if (this.dirty) {\n this.doSave();\n }\n }\n\n // ============ Internal ============\n\n private load(): void {\n try {\n if (!fs.existsSync(this.filePath)) return;\n const raw = fs.readFileSync(this.filePath, \"utf-8\");\n const data = JSON.parse(raw) as Record<string, FileEntry>;\n const now = Date.now();\n for (const [k, e] of Object.entries(data)) {\n if (e.expireAt && e.expireAt <= now) continue;\n this.map.set(k, e);\n }\n } catch (err) {\n this.logger.error?.(\n `[file-kv-store] load failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n private scheduleSave(): void {\n this.dirty = true;\n if (this.saveTimer) return;\n this.saveTimer = setTimeout(() => {\n this.saveTimer = null;\n this.doSave();\n }, this.saveThrottleMs);\n }\n\n private doSave(): void {\n try {\n fs.mkdirSync(path.dirname(this.filePath), { recursive: true });\n const obj: Record<string, FileEntry> = {};\n for (const [k, e] of this.map) obj[k] = e;\n const tmp = this.filePath + \".tmp\";\n fs.writeFileSync(tmp, JSON.stringify(obj, null, 2), \"utf-8\");\n fs.renameSync(tmp, this.filePath);\n this.dirty = false;\n } catch (err) {\n this.logger.error?.(\n `[file-kv-store] save failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n}\n","/**\n * Bridge `KVStore` → `SessionPersistencePort`.\n *\n * Lets users plug any KV backend (Memory / File / Redis / ...) into the\n * gateway session persistence slot via a single line:\n *\n * ```ts\n * import { QQBot, kvSessionPersistence, FileKVStore } from \"@tencent-connect/qqbot-nodejs\";\n *\n * const bot = new QQBot({\n * appId, appSecret,\n * sessionPersistence: kvSessionPersistence({\n * store: new FileKVStore({ dir: \"./data\" }),\n * accountId: \"my-bot\",\n * }),\n * });\n * ```\n */\n\nimport type {\n PersistedSession,\n SessionPersistencePort,\n} from \"../protocol/gateway/gateway-connection.js\";\nimport type { KVStore } from \"./kv-store.js\";\n\nexport interface KVSessionPersistenceOptions {\n /** Underlying KV store. */\n store: KVStore;\n /** Stable account id used as the storage key. */\n accountId: string;\n /** Optional key prefix. Defaults to `qqbot:session:`. */\n prefix?: string;\n /** Optional TTL for the entry, ms. Defaults to 5 min (matches QQ session expiry). */\n ttlMs?: number;\n}\n\n/**\n * Build a {@link SessionPersistencePort} backed by any {@link KVStore}.\n */\nexport function kvSessionPersistence(opts: KVSessionPersistenceOptions): SessionPersistencePort {\n const prefix = opts.prefix ?? \"qqbot:session:\";\n const key = `${prefix}${opts.accountId}`;\n const ttlMs = opts.ttlMs ?? 5 * 60 * 1000;\n\n return {\n load() {\n const v = opts.store.get<PersistedSession>(key);\n // Note: KVStore.get may return Promise<>. The gateway port expects\n // a sync result, so callers using async stores should await\n // separately during startup (or use `awaitable` adapter, see TODO).\n if (v && typeof (v as Promise<PersistedSession>).then === \"function\") {\n // Async store — we can't synchronously resolve here; warn and\n // return null. Users should provide a sync store or warm-up\n // the session via `await kvWarmup(...)` before `bot.start()`.\n return null;\n }\n return (v as PersistedSession) ?? null;\n },\n save(session) {\n void opts.store.set(key, session, ttlMs);\n },\n clear() {\n void opts.store.delete(key);\n },\n };\n}\n"],"mappings":"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","names":["PerMessageDeflate","data","PerMessageDeflate","Receiver","PerMessageDeflate","Sender","extension","http","createHash","URL","PerMessageDeflate","Receiver","Sender","WebSocket","key","WebSocket","createWebSocketStream","err","protocol","http","createHash","extension","PerMessageDeflate","subprotocol","WebSocket","WebSocketServer","fs","path","MediaFileType","path","path","sleep","fs","path","path","WebSocket","crypto","path","path","crypto","path","decision","fs","path"]}
|