mqtt-crypto-client 0.2.1 → 0.2.3
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/README.md +32 -7
- package/dist/index.browser.js +9 -0
- package/dist/index.browser.js.map +7 -0
- package/dist/index.cjs +66 -1
- package/dist/index.cjs.map +3 -3
- package/dist/index.iife.js +6 -6
- package/dist/index.iife.js.map +4 -4
- package/package.json +6 -2
- package/src/config-string.js +117 -0
- package/src/index.js +2 -0
- package/src/options.js +6 -1
- package/types/index.d.ts +33 -4
package/dist/index.cjs
CHANGED
|
@@ -58,8 +58,10 @@ __export(index_exports, {
|
|
|
58
58
|
isEncryptedPayload: () => isEncryptedPayload,
|
|
59
59
|
isOwnMessage: () => isOwnMessage,
|
|
60
60
|
isResponseCommand: () => isResponseCommand,
|
|
61
|
+
parseConfigString: () => parseConfigString,
|
|
61
62
|
parseEnvelope: () => parseEnvelope,
|
|
62
63
|
resolveOptions: () => resolveOptions,
|
|
64
|
+
serializeConfigString: () => serializeConfigString,
|
|
63
65
|
tryDecrypt: () => tryDecrypt,
|
|
64
66
|
validateTopic: () => validateTopic
|
|
65
67
|
});
|
|
@@ -408,6 +410,64 @@ function buildTopic(...segments) {
|
|
|
408
410
|
return validateTopic(parts.join("/"));
|
|
409
411
|
}
|
|
410
412
|
|
|
413
|
+
// src/config-string.js
|
|
414
|
+
var KNOWN_KEYS = /* @__PURE__ */ new Set(["name", "broker", "topic", "password"]);
|
|
415
|
+
function parseConfigString(str) {
|
|
416
|
+
if (typeof str !== "string" || str.trim().length === 0) {
|
|
417
|
+
throw new InvalidConfigError("\u914D\u7F6E\u5B57\u7B26\u4E32\u4E3A\u7A7A");
|
|
418
|
+
}
|
|
419
|
+
const raw = {};
|
|
420
|
+
for (const pair of str.trim().split("&")) {
|
|
421
|
+
if (pair.length === 0) continue;
|
|
422
|
+
const idx = pair.indexOf("=");
|
|
423
|
+
if (idx < 0) continue;
|
|
424
|
+
const k = pair.slice(0, idx).trim();
|
|
425
|
+
if (k.length === 0) continue;
|
|
426
|
+
const v = decodeURIComponent(pair.slice(idx + 1));
|
|
427
|
+
raw[k] = v;
|
|
428
|
+
}
|
|
429
|
+
const broker = raw.broker;
|
|
430
|
+
const topic = raw.topic;
|
|
431
|
+
if (!broker || !topic) {
|
|
432
|
+
throw new InvalidConfigError("\u914D\u7F6E\u5B57\u7B26\u4E32\u7F3A\u5C11\u5FC5\u586B\u5B57\u6BB5 broker \u6216 topic");
|
|
433
|
+
}
|
|
434
|
+
const password = raw.password || "";
|
|
435
|
+
const result = {
|
|
436
|
+
broker,
|
|
437
|
+
topic,
|
|
438
|
+
// 库的 secret 对应字符串的 password
|
|
439
|
+
secret: password,
|
|
440
|
+
// 口令非空即视为加密;空口令 = 不加密
|
|
441
|
+
encrypt: password.length > 0
|
|
442
|
+
};
|
|
443
|
+
if (raw.name !== void 0) result.name = raw.name;
|
|
444
|
+
for (const k of Object.keys(raw)) {
|
|
445
|
+
if (KNOWN_KEYS.has(k)) continue;
|
|
446
|
+
result[k] = raw[k];
|
|
447
|
+
}
|
|
448
|
+
return result;
|
|
449
|
+
}
|
|
450
|
+
function serializeConfigString(opts) {
|
|
451
|
+
if (!opts || typeof opts !== "object" || Array.isArray(opts)) {
|
|
452
|
+
throw new InvalidConfigError("serializeConfigString \u9700\u8981\u914D\u7F6E\u5BF9\u8C61");
|
|
453
|
+
}
|
|
454
|
+
const entries = [];
|
|
455
|
+
const push = (k, v) => {
|
|
456
|
+
if (v === void 0 || v === null) return;
|
|
457
|
+
entries.push(`${k}=${encodeURIComponent(String(v))}`);
|
|
458
|
+
};
|
|
459
|
+
if (opts.name !== void 0) push("name", opts.name);
|
|
460
|
+
push("broker", opts.broker);
|
|
461
|
+
push("topic", opts.topic);
|
|
462
|
+
const password = opts.encrypt === false ? "" : opts.secret ?? "";
|
|
463
|
+
push("password", password);
|
|
464
|
+
for (const k of Object.keys(opts)) {
|
|
465
|
+
if (["broker", "topic", "secret", "encrypt", "name"].includes(k)) continue;
|
|
466
|
+
push(k, opts[k]);
|
|
467
|
+
}
|
|
468
|
+
return entries.join("&");
|
|
469
|
+
}
|
|
470
|
+
|
|
411
471
|
// src/options.js
|
|
412
472
|
var SUPPORTED_PROTOCOLS = /* @__PURE__ */ new Set(["ws:", "wss:", "mqtt:", "mqtts:", "tcp:", "tls:"]);
|
|
413
473
|
var DEFAULT_OPTIONS = Object.freeze({
|
|
@@ -460,8 +520,11 @@ function validateBroker(broker) {
|
|
|
460
520
|
return broker;
|
|
461
521
|
}
|
|
462
522
|
function resolveOptions(input = {}) {
|
|
523
|
+
if (typeof input === "string") {
|
|
524
|
+
input = parseConfigString(input);
|
|
525
|
+
}
|
|
463
526
|
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
464
|
-
throw new InvalidConfigError("options \u5FC5\u987B\u662F\u5BF9\u8C61");
|
|
527
|
+
throw new InvalidConfigError("options \u5FC5\u987B\u662F\u5BF9\u8C61\u6216\u914D\u7F6E\u5B57\u7B26\u4E32");
|
|
465
528
|
}
|
|
466
529
|
const options = { ...DEFAULT_OPTIONS, ...input };
|
|
467
530
|
options.broker = validateBroker(options.broker);
|
|
@@ -1079,8 +1142,10 @@ function createClient(options = {}) {
|
|
|
1079
1142
|
isEncryptedPayload,
|
|
1080
1143
|
isOwnMessage,
|
|
1081
1144
|
isResponseCommand,
|
|
1145
|
+
parseConfigString,
|
|
1082
1146
|
parseEnvelope,
|
|
1083
1147
|
resolveOptions,
|
|
1148
|
+
serializeConfigString,
|
|
1084
1149
|
tryDecrypt,
|
|
1085
1150
|
validateTopic
|
|
1086
1151
|
});
|
package/dist/index.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/index.js", "../src/client.js", "../src/crypto.js", "../src/errors.js", "../src/envelope.js", "../src/message.js", "../src/topic.js", "../src/options.js"],
|
|
4
|
-
"sourcesContent": ["/**\n * mqtt-crypto-client\n * MQTT over WebSocket + CryptoJS \u517C\u5BB9 AES \u4FE1\u5C01\u52A0\u5BC6\u7684 Node.js \u5BA2\u6237\u7AEF\u3002\n */\nexport { MqttCryptoClient, createClient } from './client.js';\n\nexport {\n decryptPayload,\n deriveKeyAndIv,\n encryptPayload,\n isEncryptedPayload,\n tryDecrypt,\n} from './crypto.js';\n\nexport {\n DEFAULT_CLIENT_ID_PREFIX,\n DEFAULT_USER,\n buildEnvelope,\n createClientId,\n generateMsgId,\n isOwnMessage,\n isResponseCommand,\n parseEnvelope,\n} from './envelope.js';\n\nexport { decodeIncoming } from './message.js';\n\nexport {\n DEFAULT_OPTIONS,\n buildMqttOptions,\n resolveOptions,\n} from './options.js';\n\nexport { DEFAULT_TOPIC, PRESET_BROKERS, buildTopic, validateTopic } from './topic.js';\n\nexport {\n ConnectTimeoutError,\n CryptoError,\n EnvelopeError,\n InvalidConfigError,\n MqttCryptoError,\n NotConnectedError,\n RequestTimeoutError,\n TopicError,\n} from './errors.js';\n", "/**\n * MQTT over WebSocket \u5BA2\u6237\u7AEF\uFF1A\u52A0\u5BC6\u4FE1\u5C01\u6536\u53D1\u3001\u5FC3\u8DF3\u3001\u53BB\u91CD\u3001\u8BF7\u6C42/\u54CD\u5E94\u914D\u5BF9\u3002\n *\n * \u4E8B\u4EF6\uFF1A\n * connect \u9996\u6B21/\u6BCF\u6B21\u8FDE\u63A5\u6210\u529F\uFF08\u5DF2\u53D1\u8D77\u8BA2\u9605\uFF09\n * reconnect \u5E95\u5C42\u6B63\u5728\u91CD\u8FDE\n * close / offline \u8FDE\u63A5\u5173\u95ED / \u79BB\u7EBF\n * error Error\uFF08\u4EC5\u5728\u5B58\u5728 error \u76D1\u542C\u5668\u65F6\u629B\u51FA\uFF0C\u907F\u514D\u672A\u5904\u7406\u5F02\u5E38\uFF09\n * message { envelope, command, topic, decrypted }\n * response { envelope, command, topic }\n * agentStatus boolean\uFF08\u6536\u5230 pong = true\uFF1B\u4EC5\u5F53\u914D\u7F6E pongTimeout > 0 \u65F6\u624D\u53EF\u80FD\u4E3A false\uFF09\n * status { connected, agentOnline }\n * messageError Error\uFF08\u4FE1\u5C01/\u547D\u4EE4 JSON \u89E3\u6790\u5931\u8D25\uFF09\n */\nimport { EventEmitter } from 'node:events';\nimport mqtt from 'mqtt';\nimport { encryptPayload } from './crypto.js';\nimport {\n buildEnvelope,\n generateMsgId,\n isOwnMessage,\n isResponseCommand,\n parseEnvelope,\n} from './envelope.js';\nimport { ConnectTimeoutError, NotConnectedError, RequestTimeoutError } from './errors.js';\nimport { decodeIncoming } from './message.js';\nimport { buildMqttOptions, resolveOptions } from './options.js';\n\n/**\n * @typedef {{ command: Record<string, any> | null, envelope: Record<string, any>, topic: string }} IncomingMessage\n * @typedef {{\n * resolve: (value: IncomingMessage) => void,\n * reject: (reason?: any) => void,\n * timer: NodeJS.Timeout\n * }} PendingRequest\n */\n\nexport class MqttCryptoClient extends EventEmitter {\n /**\n * @param {Parameters<typeof resolveOptions>[0]} [options]\n */\n constructor(options = {}) {\n super();\n /** @type {ReturnType<typeof resolveOptions>} */\n this.options = resolveOptions(options);\n this.broker = this.options.broker;\n this.topic = this.options.topic;\n this.clientId = this.options.clientId;\n this.qos = this.options.qos;\n this.secret = this.options.secret;\n this.encrypt = this.options.encrypt;\n\n /** @type {import('mqtt').MqttClient | null} */\n this._client = null;\n this._connected = false;\n this._agentOnline = false;\n /** @type {Map<string, NodeJS.Timeout>} \u5DF2\u53D1\u9001 msgId -> \u53BB\u91CD\u8BA1\u65F6\u5668 */\n this._pendingMessages = new Map();\n /** @type {Map<string, PendingRequest>} */\n this._pendingRequests = new Map();\n /** @type {NodeJS.Timeout | null} */\n this._heartbeatTimer = null;\n /** @type {NodeJS.Timeout | null} */\n this._pongTimer = null;\n /** @type {Error | null} \u6700\u8FD1\u4E00\u6B21\u8FDE\u63A5\u9519\u8BEF\uFF08\u65E0 error \u76D1\u542C\u5668\u65F6\u4E5F\u4FBF\u4E8E\u6392\u67E5\uFF09 */\n this.lastError = null;\n }\n\n /** \u5E95\u5C42 mqtt \u5BA2\u6237\u7AEF\uFF08\u9AD8\u7EA7\u7528\u6CD5\uFF1B\u8FDE\u63A5\u524D\u4E3A null\uFF09 */\n get mqttClient() {\n return this._client;\n }\n\n /** \u662F\u5426\u5DF2\u8FDE\u63A5\u5E76\u5B8C\u6210\u8BA2\u9605 */\n isConnected() {\n return this._connected;\n }\n\n /** \u5BF9\u7AEF agent \u662F\u5426\u5728\u7EBF\uFF08\u6536\u5230 pong\uFF09 */\n isAgentOnline() {\n return this._agentOnline;\n }\n\n /**\n * \u5EFA\u7ACB\u8FDE\u63A5\u3002\u5E95\u5C42\u4F1A\u6309 reconnectPeriod \u6301\u7EED\u91CD\u8BD5\uFF1B\n * \u8BE5 Promise \u5728\u9996\u6B21\u8FDE\u63A5\u6210\u529F\u65F6 resolve\uFF0C\u8D85\u8FC7 timeout \u4ECD\u672A\u8FDE\u63A5\u5219 reject\uFF08\u4F46\u91CD\u8BD5\u7EE7\u7EED\uFF09\u3002\n * @param {number} [timeout]\n * @returns {Promise<MqttCryptoClient>}\n */\n connect(timeout = this.options.connectTimeout) {\n if (this._connected) return Promise.resolve(this);\n\n try {\n if (!this._client) this._createClient();\n } catch (error) {\n return Promise.reject(error);\n }\n\n return new Promise((resolve, reject) => {\n let settled = false;\n /** @param {Error} error */\n const onError = (error) => {\n // \u8FDE\u63A5\u9636\u6BB5\u7684\u9996\u4E2A\u9519\u8BEF\u4E0D\u7ACB\u5373 reject\uFF1A\u5E95\u5C42\u4F1A\u81EA\u52A8\u91CD\u8BD5\uFF0C\u7531\u8D85\u65F6\u515C\u5E95\u3002\n this.lastError = error;\n };\n const timer = setTimeout(() => {\n if (settled) return;\n settled = true;\n this.off('connect', onConnect);\n this.off('error', onError);\n reject(new ConnectTimeoutError(timeout));\n }, timeout);\n // \u4FDD\u6301\u5F15\u7528\uFF1A\u786E\u4FDD await connect() \u5728\u8FDB\u7A0B\u9000\u51FA\u524D\u80FD\u6B63\u5E38\u7ED3\u7B97\n\n const onConnect = () => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n this.off('error', onError);\n resolve(this);\n };\n\n this.once('connect', onConnect);\n this.on('error', onError);\n });\n }\n\n /**\n * \u65AD\u5F00\u8FDE\u63A5\u5E76\u6E05\u7406\u6240\u6709\u8BA1\u65F6\u5668\u4E0E\u672A\u5B8C\u6210\u7684\u8BF7\u6C42\u3002\n * @param {{ force?: boolean }} [options]\n * @returns {Promise<void>}\n */\n async disconnect(options = {}) {\n const { force = true } = options;\n this._stopHeartbeat();\n this._clearPendingMessages();\n this._rejectPendingRequests(new NotConnectedError('\u5BA2\u6237\u7AEF\u5DF2\u65AD\u5F00'));\n this._connected = false;\n this._agentOnline = false;\n\n const client = this._client;\n this._client = null;\n if (!client) {\n this._emitStatus();\n return;\n }\n\n await /** @type {Promise<void>} */ (new Promise((resolve) => {\n let settled = false;\n const done = () => {\n if (settled) return;\n settled = true;\n resolve();\n };\n // \u9632\u5FA1\uFF1Aend \u56DE\u8C03\u5728\u4E2A\u522B broker \u5F02\u5E38\u65F6\u4E0D\u89E6\u53D1\n const guard = setTimeout(done, 1000);\n guard.unref?.();\n try {\n client.end(force, {}, done);\n } catch {\n done();\n }\n }));\n\n client.removeAllListeners();\n this._emitStatus();\n }\n\n /**\n * \u8BA2\u9605 topic\uFF08\u9ED8\u8BA4\u4F7F\u7528\u914D\u7F6E\u4E2D\u7684 topic\uFF09\u3002\n * @param {string} [topic]\n * @param {{ qos?: number }} [options]\n * @returns {Promise<unknown>}\n */\n async subscribe(topic = this.topic, options = {}) {\n const qos = options.qos ?? this.qos;\n const client = this._client;\n if (!client || !this._connected) throw new NotConnectedError();\n return new Promise((resolve, reject) => {\n client.subscribe(topic, { qos }, (error, granted) => {\n if (error) reject(error);\n else resolve(granted);\n });\n });\n }\n\n /**\n * \u53D1\u5E03\u4E00\u4E2A\u4FE1\u5C01\uFF08\u81EA\u52A8\u8865\u9F50 id/user/time/msgId\uFF0C\u5E76\u6309\u914D\u7F6E\u52A0\u5BC6\uFF09\u3002\n * @param {Record<string, any>} envelope\n * @param {{ qos?: number, track?: boolean }} [options]\n * @returns {Promise<string>} msgId\n */\n async publish(envelope, options = {}) {\n const client = this._requireConnected();\n const { qos = this.qos, track = true } = options;\n const built = this._completeEnvelope(envelope);\n const payload = this._encode(built);\n\n if (track) this._trackMessage(built.msgId);\n\n await new Promise((resolve, reject) => {\n client.publish(this.topic, payload, { qos }, (error) => {\n if (error) {\n if (track) this._untrackMessage(built.msgId);\n this._emitError(error);\n reject(error);\n return;\n }\n resolve(undefined);\n });\n });\n\n return built.msgId;\n }\n\n /**\n * \u53D1\u9001\u547D\u4EE4\uFF1Amsg = JSON.stringify({ action, data })\u3002\n * @param {string} action\n * @param {Record<string, any>} [data]\n * @param {{ qos?: number, msgId?: string, track?: boolean }} [options]\n * @returns {Promise<string>} msgId\n */\n async sendCommand(action, data = {}, options = {}) {\n if (typeof action !== 'string' || action.length === 0) {\n throw new TypeError('action \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32');\n }\n const { qos = this.qos, msgId, track = true } = options;\n return this.publish(\n buildEnvelope({\n id: this.clientId,\n user: this.options.user,\n userSuffix: this.options.userSuffix,\n msg: JSON.stringify({ action, data }),\n msgId,\n }),\n { qos, track },\n );\n }\n\n /**\n * \u56DE\u590D\u8BF7\u6C42\uFF1A\u56DE\u663E\u8BF7\u6C42\u7684 msgId\uFF08\u539F\u5B9E\u73B0\u7684 msgId \u5173\u8054\u89C4\u5219\uFF09\u3002\n * @param {Record<string, any>} requestEnvelope \u8BF7\u6C42\u4FE1\u5C01\uFF08\u4E5F\u53EF\u4EE5\u662F JSON \u5B57\u7B26\u4E32\uFF09\n * @param {string} action\n * @param {Record<string, any>} [data]\n * @param {{ qos?: number, track?: boolean }} [options]\n * @returns {Promise<string>} msgId\n */\n async reply(requestEnvelope, action, data = {}, options = {}) {\n const request = this._normalizeEnvelopeInput(requestEnvelope);\n const msgId = request.msgId;\n const { qos = this.qos, track = Boolean(msgId) } = options;\n\n return this.publish(\n buildEnvelope({\n id: this.clientId,\n user: this.options.user,\n userSuffix: this.options.userSuffix,\n msg: JSON.stringify({ action, data }),\n msgId,\n }),\n { qos, track },\n );\n }\n\n /**\n * \u53D1\u9001\u547D\u4EE4\u5E76\u7B49\u5F85\u540C msgId \u7684\u54CD\u5E94\uFF08\u54CD\u5E94\u8D85\u65F6 reject\uFF09\u3002\n * \u7528\u4E8E\u53D6\u4EF7\u7B49\"\u8BF7\u6C42-\u54CD\u5E94\"\u573A\u666F\uFF0C\u539F\u811A\u672C\u6309 msgId \u914D\u5BF9\u3002\n * @param {string} action\n * @param {Record<string, any>} [data]\n * @param {{ qos?: number, timeout?: number }} [options]\n * @returns {Promise<IncomingMessage>}\n */\n async request(action, data = {}, options = {}) {\n this._requireConnected();\n const { qos = this.qos, timeout = this.options.requestTimeout } = options;\n const msgId = generateMsgId();\n\n /** @type {Promise<IncomingMessage>} */\n const response = new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this._pendingRequests.delete(msgId);\n reject(new RequestTimeoutError(msgId, timeout));\n }, timeout);\n this._pendingRequests.set(msgId, { resolve, reject, timer });\n });\n\n try {\n await this.publish(\n buildEnvelope({\n id: this.clientId,\n user: this.options.user,\n userSuffix: this.options.userSuffix,\n msg: JSON.stringify({ action, data }),\n msgId,\n }),\n { qos, track: false },\n );\n } catch (error) {\n const pending = this._pendingRequests.get(msgId);\n if (pending) {\n clearTimeout(pending.timer);\n this._pendingRequests.delete(msgId);\n }\n throw error;\n }\n\n return response;\n }\n\n // ==================== \u5185\u90E8\u5B9E\u73B0 ====================\n\n /** @returns {import('mqtt').MqttClient} */\n _createClient() {\n const client = mqtt.connect(this.broker, buildMqttOptions(this.options));\n this._client = client;\n\n client.on('connect', () => this._handleConnect());\n client.on('reconnect', () => this._handleReconnect());\n client.on('close', () => this._handleClose());\n client.on('offline', () => this._handleOffline());\n client.on('error', (error) => {\n this.lastError = error;\n this._emitError(error);\n });\n\n return client;\n }\n\n _handleConnect() {\n this._connected = true;\n this._emitStatus();\n this.emit('connect');\n this.subscribe(this.topic, { qos: this.qos }).catch((error) => this._emitError(error));\n this._startHeartbeat();\n }\n\n _handleReconnect() {\n this._connected = false;\n this._agentOnline = false;\n this._stopHeartbeat();\n this._emitStatus();\n this.emit('reconnect');\n }\n\n _handleClose() {\n this._connected = false;\n this._agentOnline = false;\n this._stopHeartbeat();\n this._emitStatus();\n this.emit('close');\n }\n\n _handleOffline() {\n this._connected = false;\n this._emitStatus();\n this.emit('offline');\n }\n\n /**\n * @param {string} topic\n * @param {Buffer} payload\n */\n _handleMessage(topic, payload) {\n const text = payload.toString();\n const decoded = decodeIncoming(text, this.secret);\n\n /** @type {ReturnType<typeof parseEnvelope>} */\n let parsed;\n try {\n parsed = parseEnvelope(decoded.text);\n } catch (error) {\n this._emitMessageError(/** @type {Error} */ (error));\n return;\n }\n\n const { data, command, commandError } = parsed;\n\n // 1. \u5FFD\u7565\u81EA\u5DF1\u53D1\u7684\u6D88\u606F\uFF08\u652F\u6301 clientId \u540E\u7F00\uFF09\n if (isOwnMessage(data, this.clientId)) return;\n\n // 2. \u5FC3\u8DF3\n if (data.msg === 'ping') {\n this._sendPong();\n return;\n }\n if (data.msg === 'pong') {\n this._agentOnline = true;\n this._clearPongTimer();\n this.emit('agentStatus', true);\n return;\n }\n\n // 3. \u547D\u4EE4 JSON \u89E3\u6790\u5931\u8D25\n if (commandError) {\n this._emitMessageError(commandError);\n return;\n }\n\n // 4. \u54CD\u5E94\u6D88\u606F\uFF1A\u5148\u914D\u5BF9 request()\uFF0C\u518D\u4ECE\u666E\u901A message \u4E8B\u4EF6\u4E2D\u8FC7\u6EE4\n if (isResponseCommand(command)) {\n this._resolveRequest(data.msgId, { command, envelope: data, topic });\n this.emit('response', { command, envelope: data, topic });\n return;\n }\n\n // 5. \u53BB\u91CD\uFF08\u539F\u5B9E\u73B0\uFF1A\u5DF2\u53D1\u9001 msgId \u5728 5s \u5185\u518D\u6B21\u51FA\u73B0\u5219\u5FFD\u7565\uFF09\n if (typeof data.msgId === 'string' && this._pendingMessages.has(data.msgId)) return;\n\n this.emit('message', {\n command,\n envelope: data,\n topic,\n decrypted: decoded.decrypted,\n });\n }\n\n /**\n * @param {Record<string, any>} envelope\n * @returns {{ id: string, msgId: string, user: string, msg: string, time: number }}\n */\n _completeEnvelope(envelope) {\n if (!envelope || typeof envelope !== 'object' || Array.isArray(envelope)) {\n throw new TypeError('envelope \u5FC5\u987B\u662F\u5BF9\u8C61');\n }\n return buildEnvelope({\n id: /** @type {string} */ (envelope.id ?? this.clientId),\n user: /** @type {string} */ (envelope.user ?? this.options.user),\n userSuffix: /** @type {string} */ (envelope.userSuffix ?? this.options.userSuffix),\n msg: envelope.msg,\n msgId: /** @type {string | undefined} */ (envelope.msgId),\n time: /** @type {number | undefined} */ (envelope.time),\n });\n }\n\n /**\n * @param {{ id: string, msgId: string, user: string, msg: string, time: number }} envelope\n * @returns {string}\n */\n _encode(envelope) {\n const json = JSON.stringify(envelope);\n return this.encrypt ? encryptPayload(json, this.secret) : json;\n }\n\n /** @param {unknown} input @returns {Record<string, any>} */\n _normalizeEnvelopeInput(input) {\n if (typeof input === 'string') {\n return parseEnvelope(input).data;\n }\n if (!input || typeof input !== 'object') {\n throw new TypeError('requestEnvelope \u5FC5\u987B\u662F\u5BF9\u8C61\u6216 JSON \u5B57\u7B26\u4E32');\n }\n return /** @type {Record<string, any>} */ (input);\n }\n\n /** @returns {import('mqtt').MqttClient} */\n _requireConnected() {\n if (!this._connected || !this._client) throw new NotConnectedError();\n return this._client;\n }\n\n _startHeartbeat() {\n this._stopHeartbeat();\n if (!this._connected) return;\n\n this._sendPing();\n const interval = this.options.heartbeatInterval;\n if (interval > 0) {\n this._heartbeatTimer = setInterval(() => this._sendPing(), interval);\n this._heartbeatTimer.unref?.();\n }\n }\n\n _stopHeartbeat() {\n if (this._heartbeatTimer) {\n clearInterval(this._heartbeatTimer);\n this._heartbeatTimer = null;\n }\n this._clearPongTimer();\n }\n\n _clearPongTimer() {\n if (this._pongTimer) {\n clearTimeout(this._pongTimer);\n this._pongTimer = null;\n }\n }\n\n _sendPing() {\n if (!this._connected) return;\n this.publish(\n buildEnvelope({\n id: this.clientId,\n user: this.options.user,\n userSuffix: this.options.userSuffix,\n msg: 'ping',\n msgId: generateMsgId({ suffix: 'ping' }),\n }),\n { track: false },\n ).catch((error) => this._emitError(error));\n\n // \u539F\u5B9E\u73B0\u7684 5s pong \u8BA1\u65F6\u5668\u5B9E\u9645\u662F\u7A7A\u56DE\u8C03\uFF1B\u8FD9\u91CC\u9ED8\u8BA4\u4E0D\u5224\u5B9A\u79BB\u7EBF\uFF08pongTimeout=0\uFF09\u3002\n if (this.options.pongTimeout > 0) {\n this._clearPongTimer();\n this._pongTimer = setTimeout(() => {\n this._agentOnline = false;\n this.emit('agentStatus', false);\n }, this.options.pongTimeout);\n this._pongTimer.unref?.();\n }\n }\n\n _sendPong() {\n if (!this._connected) return;\n this.publish(\n buildEnvelope({\n id: this.clientId,\n user: this.options.user,\n userSuffix: this.options.userSuffix,\n msg: 'pong',\n msgId: generateMsgId({ suffix: 'pong' }),\n }),\n { track: false },\n ).catch((error) => this._emitError(error));\n }\n\n /** @param {string} msgId */\n _trackMessage(msgId) {\n if (this.options.dedupeTtl <= 0) return;\n this._untrackMessage(msgId);\n const timer = setTimeout(() => {\n this._pendingMessages.delete(msgId);\n }, this.options.dedupeTtl);\n timer.unref?.();\n this._pendingMessages.set(msgId, timer);\n }\n\n /** @param {string} msgId */\n _untrackMessage(msgId) {\n const timer = this._pendingMessages.get(msgId);\n if (timer) {\n clearTimeout(timer);\n this._pendingMessages.delete(msgId);\n }\n }\n\n _clearPendingMessages() {\n for (const timer of this._pendingMessages.values()) clearTimeout(timer);\n this._pendingMessages.clear();\n }\n\n /**\n * @param {string | undefined} msgId\n * @param {IncomingMessage} value\n * @returns {boolean}\n */\n _resolveRequest(msgId, value) {\n if (typeof msgId !== 'string') return false;\n const pending = this._pendingRequests.get(msgId);\n if (!pending) return false;\n clearTimeout(pending.timer);\n this._pendingRequests.delete(msgId);\n pending.resolve(value);\n return true;\n }\n\n /** @param {Error} error */\n _rejectPendingRequests(error) {\n for (const pending of this._pendingRequests.values()) {\n clearTimeout(pending.timer);\n pending.reject(error);\n }\n this._pendingRequests.clear();\n }\n\n /** @param {Error} error */\n _emitError(error) {\n this.lastError = error;\n if (this.listenerCount('error') > 0) this.emit('error', error);\n }\n\n /** @param {Error} error */\n _emitMessageError(error) {\n if (this.listenerCount('messageError') > 0) this.emit('messageError', error);\n }\n\n _emitStatus() {\n this.emit('status', { connected: this._connected, agentOnline: this._agentOnline });\n }\n}\n\n/**\n * @param {Parameters<typeof resolveOptions>[0]} [options]\n * @returns {MqttCryptoClient}\n */\nexport function createClient(options = {}) {\n return new MqttCryptoClient(options);\n}\n", "/**\n * \u4E0E\u539F\u5B9E\u73B0\uFF08CryptoJS.AES.encrypt(payload, passphrase).toString()\uFF09\u9010\u5B57\u8282\u517C\u5BB9\u7684\u52A0\u89E3\u5BC6\u5DE5\u5177\u3002\n *\n * \u517C\u5BB9\u683C\u5F0F\uFF08OpenSSL \"Salted__\" \u683C\u5F0F\uFF09\uFF1A\n * \u5BC6\u6587 = base64( \"Salted__\"\uFF088 \u5B57\u8282\uFF09 + salt\uFF08\u9ED8\u8BA4 8 \u5B57\u8282\uFF09 + AES-256-CBC \u5BC6\u6587 )\n * \u5BC6\u94A5/IV = EVP_BytesToKey(MD5, 1 \u6B21\u8FED\u4EE3, passphrase, salt)\uFF0Ckey 32 \u5B57\u8282 + IV 16 \u5B57\u8282\n * \u586B\u5145 = PKCS#7\n *\n * \u8BF4\u660E\uFF1A\u8FD9\u662F\"\u53E3\u4EE4\u6D3E\u751F + CBC\"\u683C\u5F0F\uFF0C\u6CA1\u6709\u5B8C\u6574\u6027\u6821\u9A8C\uFF08\u65E0 MAC/AEAD\uFF09\uFF0C\n * \u53EA\u80FD\u9632\u65C1\u89C2\u8005\u76F4\u63A5\u8BFB\u53D6\u660E\u6587\uFF0C\u4E0D\u80FD\u9632\u7BE1\u6539\u3002\u8BE6\u89C1 README \u7684\u5B89\u5168\u8BF4\u660E\u3002\n */\nimport { createCipheriv, createDecipheriv, createHash, randomBytes } from 'node:crypto';\nimport { TextDecoder } from 'node:util';\nimport { CryptoError } from './errors.js';\n\nconst SALT_HEADER = Buffer.from('Salted__', 'utf8');\nconst KEY_LENGTH = 32;\nconst IV_LENGTH = 16;\nconst DEFAULT_SALT_LENGTH = 8;\nconst AES_ALGORITHM = 'aes-256-cbc';\nconst BASE64_PATTERN = /^[A-Za-z0-9+/]+={0,2}$/;\n\nconst strictUtf8Decoder = new TextDecoder('utf-8', { fatal: true });\n\n/**\n * @param {unknown} secret\n * @returns {Buffer}\n */\nfunction toSecretBuffer(secret) {\n if (typeof secret !== 'string' || secret.length === 0) {\n throw new CryptoError('secret \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32', 'MISSING_SECRET');\n }\n return Buffer.from(secret, 'utf8');\n}\n\n/**\n * OpenSSL EVP_BytesToKey\uFF08MD5\uFF0Ccount=1\uFF09\uFF0C\u4E0E CryptoJS \u7684 OpenSSLKdf \u4E00\u81F4\u3002\n * @param {string} secret \u53E3\u4EE4\n * @param {Buffer} salt \u76D0\uFF08\u53EF\u4EE5\u4E3A\u7A7A Buffer\uFF0C\u7528\u4E8E\u517C\u5BB9\u65E0\u76D0\u5BC6\u6587\uFF09\n * @param {number} [keyLength]\n * @param {number} [ivLength]\n * @returns {{ key: Buffer, iv: Buffer }}\n */\nexport function deriveKeyAndIv(secret, salt, keyLength = KEY_LENGTH, ivLength = IV_LENGTH) {\n const password = toSecretBuffer(secret);\n if (!Buffer.isBuffer(salt)) {\n throw new CryptoError('salt \u5FC5\u987B\u662F Buffer', 'INVALID_SALT');\n }\n\n const targetLength = keyLength + ivLength;\n /** @type {Buffer[]} */\n const blocks = [];\n let block = Buffer.alloc(0);\n let generated = 0;\n\n while (generated < targetLength) {\n block = createHash('md5')\n .update(Buffer.concat([block, password, salt]))\n .digest();\n blocks.push(block);\n generated += block.length;\n }\n\n const derived = Buffer.concat(blocks);\n return {\n key: derived.subarray(0, keyLength),\n iv: derived.subarray(keyLength, targetLength),\n };\n}\n\n/**\n * \u52A0\u5BC6\u4EFB\u610F\u5B57\u7B26\u4E32\uFF08\u901A\u5E38\u662F JSON \u4FE1\u5C01\uFF09\uFF0C\u8FD4\u56DE\u4E0E CryptoJS \u5B8C\u5168\u517C\u5BB9\u7684 base64 \u5BC6\u6587\u3002\n * @param {string} plaintext \u660E\u6587\n * @param {string} secret \u53E3\u4EE4\n * @param {{ saltLength?: number, salt?: Buffer }} [options]\n * @returns {string}\n */\nexport function encryptPayload(plaintext, secret, options = {}) {\n if (typeof plaintext !== 'string') {\n throw new CryptoError('plaintext \u5FC5\u987B\u662F\u5B57\u7B26\u4E32', 'INVALID_PLAINTEXT');\n }\n const saltLength = options.saltLength ?? DEFAULT_SALT_LENGTH;\n if (!Number.isInteger(saltLength) || saltLength < 0) {\n throw new CryptoError('saltLength \u5FC5\u987B\u662F\u975E\u8D1F\u6574\u6570', 'INVALID_SALT');\n }\n\n const salt = options.salt ?? randomBytes(saltLength);\n if (!Buffer.isBuffer(salt)) {\n throw new CryptoError('salt \u5FC5\u987B\u662F Buffer', 'INVALID_SALT');\n }\n\n const { key, iv } = deriveKeyAndIv(secret, salt);\n try {\n const cipher = createCipheriv(AES_ALGORITHM, key, iv);\n const ciphertext = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);\n return Buffer.concat([SALT_HEADER, salt, ciphertext]).toString('base64');\n } catch (error) {\n throw new CryptoError('\u52A0\u5BC6\u5931\u8D25', 'ENCRYPT_FAILED', /** @type {Error} */ (error));\n }\n}\n\n/**\n * \u89E3\u6790 base64 \u5BC6\u6587\u3002\u5E26 \"Salted__\" \u5934\u65F6\u4F7F\u7528\u5176\u4E2D\u7684 salt\uFF1B\n * \u4E0D\u542B\u5934\u65F6\u6309 CryptoJS \u7684\u517C\u5BB9\u884C\u4E3A\u4F7F\u7528\u7A7A salt\u3002\n * @param {string} ciphertext\n * @returns {{ salt: Buffer, ciphertext: Buffer }}\n */\nfunction parseCiphertext(ciphertext) {\n if (typeof ciphertext !== 'string') {\n throw new CryptoError('\u5BC6\u6587\u5FC5\u987B\u662F\u5B57\u7B26\u4E32', 'INVALID_CIPHERTEXT');\n }\n const normalized = ciphertext.trim();\n if (!normalized || normalized.length % 4 !== 0 || !BASE64_PATTERN.test(normalized)) {\n throw new CryptoError('\u5BC6\u6587\u4E0D\u662F\u5408\u6CD5\u7684 base64', 'INVALID_CIPHERTEXT');\n }\n\n const raw = Buffer.from(normalized, 'base64');\n if (raw.length < SALT_HEADER.length) {\n throw new CryptoError('\u5BC6\u6587\u957F\u5EA6\u4E0D\u8DB3', 'INVALID_CIPHERTEXT');\n }\n\n if (raw.subarray(0, SALT_HEADER.length).equals(SALT_HEADER)) {\n if (raw.length < SALT_HEADER.length + DEFAULT_SALT_LENGTH) {\n throw new CryptoError('\u5BC6\u6587\u7F3A\u5C11 salt', 'INVALID_CIPHERTEXT');\n }\n return {\n salt: raw.subarray(SALT_HEADER.length, SALT_HEADER.length + DEFAULT_SALT_LENGTH),\n ciphertext: raw.subarray(SALT_HEADER.length + DEFAULT_SALT_LENGTH),\n };\n }\n\n return { salt: Buffer.alloc(0), ciphertext: raw };\n}\n\n/**\n * \u89E3\u5BC6\u5E76\u8FD4\u56DE UTF-8 \u660E\u6587\uFF1B\u5931\u8D25\u65F6\u629B\u51FA CryptoError\u3002\n * @param {string} ciphertext base64 \u5BC6\u6587\n * @param {string} secret \u53E3\u4EE4\n * @returns {string}\n */\nexport function decryptPayload(ciphertext, secret) {\n toSecretBuffer(secret);\n const { salt, ciphertext: body } = parseCiphertext(ciphertext);\n if (body.length === 0 || body.length % 16 !== 0) {\n throw new CryptoError('\u5BC6\u6587\u5757\u957F\u5EA6\u975E\u6CD5', 'INVALID_CIPHERTEXT');\n }\n\n const { key, iv } = deriveKeyAndIv(secret, salt);\n try {\n const decipher = createDecipheriv(AES_ALGORITHM, key, iv);\n const plaintext = Buffer.concat([decipher.update(body), decipher.final()]);\n return strictUtf8Decoder.decode(plaintext);\n } catch (error) {\n throw new CryptoError('\u89E3\u5BC6\u5931\u8D25\uFF08\u53E3\u4EE4\u9519\u8BEF\u3001\u5BC6\u6587\u635F\u574F\u6216\u4E0D\u662F UTF-8\uFF09', 'DECRYPT_FAILED', /** @type {Error} */ (error));\n }\n}\n\n/**\n * \u5BBD\u677E\u89E3\u5BC6\uFF1A\u4EFB\u4F55\u5931\u8D25\u90FD\u8FD4\u56DE null\uFF0C\u7528\u4E8E\"\u5148\u89E3\u5BC6\u3001\u5931\u8D25\u518D\u6309\u660E\u6587\u5904\u7406\"\u7684\u517C\u5BB9\u8DEF\u5F84\u3002\n * @param {string} ciphertext\n * @param {string} secret\n * @returns {string | null}\n */\nexport function tryDecrypt(ciphertext, secret) {\n if (typeof ciphertext !== 'string' || !ciphertext || !secret) return null;\n try {\n const plaintext = decryptPayload(ciphertext, secret);\n return plaintext.length > 0 ? plaintext : null;\n } catch {\n return null;\n }\n}\n\n/**\n * \u5224\u65AD\u5B57\u7B26\u4E32\u662F\u5426\u662F\u672C\u5E93/CryptoJS \u7684 \"Salted__\" base64 \u5BC6\u6587\uFF08\u4EC5\u770B\u5934\u90E8\uFF0C\u4E0D\u6821\u9A8C\u5185\u5BB9\uFF09\u3002\n * @param {string} value\n * @returns {boolean}\n */\nexport function isEncryptedPayload(value) {\n if (typeof value !== 'string') return false;\n const normalized = value.trim();\n if (!normalized || normalized.length % 4 !== 0 || !BASE64_PATTERN.test(normalized)) return false;\n const raw = Buffer.from(normalized, 'base64');\n return raw.length >= SALT_HEADER.length && raw.subarray(0, SALT_HEADER.length).equals(SALT_HEADER);\n}\n", "/**\n * \u5E93\u5185\u7EDF\u4E00\u9519\u8BEF\u7C7B\u578B\u3002\n * \u6240\u6709\u53EF\u9884\u671F\u7684\u9519\u8BEF\u90FD\u5E26\u6709\u7A33\u5B9A\u7684 `code`\uFF0C\u4FBF\u4E8E\u8C03\u7528\u65B9\u5206\u652F\u5904\u7406\u3002\n */\nexport class MqttCryptoError extends Error {\n /**\n * @param {string} message \u9519\u8BEF\u63CF\u8FF0\n * @param {string} [code] \u7A33\u5B9A\u7684\u9519\u8BEF\u7801\n * @param {Error & {code?: string}} [cause] \u539F\u59CB\u9519\u8BEF\n */\n constructor(message, code = 'MQTT_CRYPTO_ERROR', cause) {\n super(message, cause ? { cause } : undefined);\n this.name = 'MqttCryptoError';\n this.code = code;\n }\n}\n\n/** \u914D\u7F6E\u975E\u6CD5\uFF08broker/topic/qos/secret \u7B49\uFF09 */\nexport class InvalidConfigError extends MqttCryptoError {\n /** @param {string} message */\n constructor(message) {\n super(message, 'INVALID_CONFIG');\n this.name = 'InvalidConfigError';\n }\n}\n\n/** \u672A\u8FDE\u63A5\u65F6\u5C1D\u8BD5\u6267\u884C\u9700\u8981\u8FDE\u63A5\u7684\u64CD\u4F5C */\nexport class NotConnectedError extends MqttCryptoError {\n /** @param {string} [message] */\n constructor(message = 'MQTT \u5BA2\u6237\u7AEF\u5C1A\u672A\u8FDE\u63A5') {\n super(message, 'NOT_CONNECTED');\n this.name = 'NotConnectedError';\n }\n}\n\n/** \u8BF7\u6C42\u7B49\u5F85\u54CD\u5E94\u8D85\u65F6 */\nexport class RequestTimeoutError extends MqttCryptoError {\n /**\n * @param {string} msgId \u8BF7\u6C42\u7684\u6D88\u606F ID\n * @param {number} timeout \u8D85\u65F6\u6BEB\u79D2\u6570\n */\n constructor(msgId, timeout) {\n super(`\u8BF7\u6C42 ${msgId} \u5728 ${timeout}ms \u5185\u6CA1\u6709\u6536\u5230\u54CD\u5E94`, 'REQUEST_TIMEOUT');\n this.name = 'RequestTimeoutError';\n this.msgId = msgId;\n this.timeout = timeout;\n }\n}\n\n/** \u8FDE\u63A5\u5C31\u7EEA\u7B49\u5F85\u8D85\u65F6\uFF08\u5E95\u5C42\u5BA2\u6237\u7AEF\u4ECD\u4F1A\u6309 reconnectPeriod \u7EE7\u7EED\u91CD\u8BD5\uFF09 */\nexport class ConnectTimeoutError extends MqttCryptoError {\n /** @param {number} timeout */\n constructor(timeout) {\n super(`MQTT \u8FDE\u63A5\u5728 ${timeout}ms \u5185\u672A\u5C31\u7EEA`, 'CONNECT_TIMEOUT');\n this.name = 'ConnectTimeoutError';\n this.timeout = timeout;\n }\n}\n\n/** topic \u975E\u6CD5 */\nexport class TopicError extends MqttCryptoError {\n /** @param {string} message */\n constructor(message) {\n super(message, 'INVALID_TOPIC');\n this.name = 'TopicError';\n }\n}\n\n/** \u52A0\u89E3\u5BC6\u5931\u8D25 */\nexport class CryptoError extends MqttCryptoError {\n /**\n * @param {string} message\n * @param {string} [code]\n * @param {Error} [cause]\n */\n constructor(message, code = 'CRYPTO_ERROR', cause) {\n super(message, code, cause);\n this.name = 'CryptoError';\n }\n}\n\n/** \u4FE1\u5C01\u89E3\u6790\u5931\u8D25 */\nexport class EnvelopeError extends MqttCryptoError {\n /**\n * @param {string} message\n * @param {string} [code]\n * @param {Error} [cause]\n */\n constructor(message, code = 'INVALID_ENVELOPE', cause) {\n super(message, code, cause);\n this.name = 'EnvelopeError';\n }\n}\n", "/**\n * \u6D88\u606F\u4FE1\u5C01\uFF08envelope\uFF09\u6784\u9020\u4E0E\u89E3\u6790\u3002\n * \u4E0E\u539F\u5B9E\u73B0\u4FDD\u6301\u4E00\u81F4\u7684\u5B57\u6BB5\uFF1A{ id, msgId, user, msg, time }\u3002\n */\nimport { EnvelopeError } from './errors.js';\n\n/** \u539F Vue \u5B9E\u73B0\u4F7F\u7528\u7684\u9ED8\u8BA4 user \u524D\u7F00 */\nexport const DEFAULT_USER = 'fangzheng-agent';\n/** \u9ED8\u8BA4 clientId \u524D\u7F00\uFF08\u539F Vue \u5B9E\u73B0\u4E3A `vue_`\uFF09 */\nexport const DEFAULT_CLIENT_ID_PREFIX = 'vue_';\n\n/**\n * \u751F\u6210\u5BA2\u6237\u7AEF ID\uFF1A`\u524D\u7F00 + 6 \u4F4D\u5341\u516D\u8FDB\u5236\u968F\u673A\u6570`\uFF08\u4E0E Math.random().toString(16).slice(2, 8) \u7B49\u4EF7\uFF09\u3002\n * @param {string} [prefix]\n * @param {() => number} [random] \u4FBF\u4E8E\u6D4B\u8BD5\u6CE8\u5165\n * @returns {string}\n */\nexport function createClientId(prefix = DEFAULT_CLIENT_ID_PREFIX, random = Math.random) {\n return `${prefix}${random().toString(16).slice(2, 8)}`;\n}\n\n/**\n * \u751F\u6210 msgId\uFF1A`\u65F6\u95F4\u6233_4 \u4F4D\u5341\u516D\u8FDB\u5236\u968F\u673A\u6570`\uFF0C\u53EF\u9644\u52A0\u540E\u7F00\u3002\n * @param {{ now?: number, suffix?: string, random?: () => number }} [options]\n * @returns {string}\n */\nexport function generateMsgId(options = {}) {\n const { now = Date.now(), suffix = '', random = Math.random } = options;\n const base = `${now}_${random().toString(16).slice(2, 6)}`;\n return suffix ? `${base}_${suffix}` : base;\n}\n\n/**\n * \u6784\u9020\u4FE1\u5C01\u3002`msg` \u53EF\u4EE5\u662F\u5B57\u7B26\u4E32\uFF0C\u4E5F\u53EF\u4EE5\u662F\u4F1A\u88AB JSON.stringify \u7684\u5BF9\u8C61\u3002\n * @param {{\n * id: string,\n * msg: string | object,\n * user?: string,\n * userSuffix?: string,\n * msgId?: string,\n * time?: number\n * }} input\n * @returns {{ id: string, msgId: string, user: string, msg: string, time: number }}\n */\nexport function buildEnvelope(input) {\n const { id, user = DEFAULT_USER, userSuffix = '', msgId, time = Date.now() } = input;\n if (typeof id !== 'string' || id.length === 0) {\n throw new EnvelopeError('\u4FE1\u5C01 id \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32', 'INVALID_ENVELOPE_ID');\n }\n if (typeof user !== 'string' || typeof userSuffix !== 'string') {\n throw new EnvelopeError('user/userSuffix \u5FC5\u987B\u662F\u5B57\u7B26\u4E32', 'INVALID_ENVELOPE_USER');\n }\n\n let msg;\n if (typeof input.msg === 'string') {\n msg = input.msg;\n } else if (input.msg && typeof input.msg === 'object') {\n msg = JSON.stringify(input.msg);\n } else {\n throw new EnvelopeError('\u4FE1\u5C01 msg \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6216\u5BF9\u8C61', 'INVALID_ENVELOPE_MSG');\n }\n\n return {\n id,\n msgId: msgId || generateMsgId({ now: time }),\n user: `${user}${userSuffix}`,\n msg,\n time,\n };\n}\n\n/**\n * \u89E3\u6790\u4FE1\u5C01\u53CA\u5176\u4E2D\u7684\u547D\u4EE4\u3002\n *\n * - `data`\uFF1A\u539F\u59CB\u4FE1\u5C01\u5BF9\u8C61\n * - `command`\uFF1A`msg` \u89E3\u6790\u540E\u7684\u547D\u4EE4\u5BF9\u8C61\uFF1B`ping`/`pong` \u6216\u89E3\u6790\u5931\u8D25\u65F6\u4E3A null\n * - `commandError`\uFF1A`msg` \u975E ping/pong \u4F46\u4E0D\u662F\u5408\u6CD5 JSON \u65F6\u7684\u9519\u8BEF\n *\n * @param {string | object} input JSON \u5B57\u7B26\u4E32\u6216\u5DF2\u89E3\u6790\u5BF9\u8C61\n * @returns {{ data: Record<string, any>, command: Record<string, any> | null, commandError: Error | null }}\n */\nexport function parseEnvelope(input) {\n let data;\n if (typeof input === 'string') {\n try {\n data = JSON.parse(input);\n } catch (error) {\n throw new EnvelopeError('\u4FE1\u5C01\u4E0D\u662F\u5408\u6CD5 JSON', 'INVALID_JSON', /** @type {Error} */ (error));\n }\n } else {\n data = input;\n }\n\n if (!data || typeof data !== 'object' || Array.isArray(data)) {\n throw new EnvelopeError('\u4FE1\u5C01\u5FC5\u987B\u662F\u5BF9\u8C61', 'INVALID_ENVELOPE');\n }\n\n let command = null;\n let commandError = null;\n const { msg } = data;\n\n if (typeof msg === 'string') {\n if (msg !== 'ping' && msg !== 'pong') {\n try {\n command = JSON.parse(msg);\n } catch (error) {\n command = null;\n commandError = new EnvelopeError('\u4FE1\u5C01 msg \u4E0D\u662F\u5408\u6CD5 JSON', 'INVALID_COMMAND_JSON', /** @type {Error} */ (error));\n }\n }\n } else if (msg && typeof msg === 'object') {\n command = msg;\n }\n\n return { data, command, commandError };\n}\n\n/**\n * \u662F\u5426\u4E3A\"\u81EA\u5DF1\u53D1\u51FA\u7684\u6D88\u606F\"\uFF08\u652F\u6301\u5E26\u670D\u52A1\u5668\u540E\u7F00\u7684 clientId \u524D\u7F00\u5339\u914D\uFF09\u3002\n * @param {{ id?: unknown } | null | undefined} data\n * @param {string} clientId\n * @returns {boolean}\n */\nexport function isOwnMessage(data, clientId) {\n return Boolean(data && typeof data.id === 'string' && clientId && data.id.startsWith(clientId));\n}\n\n/**\n * \u662F\u5426\u5C5E\u4E8E\u54CD\u5E94\u6D88\u606F\uFF08\u539F\u5B9E\u73B0\u4F1A\u4ECE\u666E\u901A\u6D88\u606F\u56DE\u8C03\u4E2D\u8FC7\u6EE4\u6389\u5B83\u4EEC\uFF09\u3002\n * \u89C4\u5219\uFF1A`action === 'response'`\uFF0C\u6216\u6CA1\u6709 `action` \u4F46\u5E26\u6709 `type`\u3002\n * @param {Record<string, any> | null | undefined} command\n * @returns {boolean}\n */\nexport function isResponseCommand(command) {\n if (!command) return false;\n return command.action === 'response' || (!command.action && Boolean(command.type));\n}\n", "/**\n * \u5165\u7AD9\u6D88\u606F\u89E3\u7801\uFF1A\u5148\u5C1D\u8BD5 AES \u89E3\u5BC6\uFF0C\u5931\u8D25\u5219\u6309\u660E\u6587\u5904\u7406\uFF08\u539F\u5B9E\u73B0\u884C\u4E3A\uFF09\u3002\n */\nimport { tryDecrypt } from './crypto.js';\n\n/**\n * @param {string} text MQTT payload \u7684\u5B57\u7B26\u4E32\u5F62\u5F0F\n * @param {string} [secret] AES \u53E3\u4EE4\uFF1B\u4E3A\u7A7A\u65F6\u8DF3\u8FC7\u89E3\u5BC6\n * @returns {{ text: string, decrypted: boolean }}\n */\nexport function decodeIncoming(text, secret) {\n if (typeof text !== 'string') {\n return { text: String(text), decrypted: false };\n }\n if (!secret) {\n return { text, decrypted: false };\n }\n\n const decrypted = tryDecrypt(text, secret);\n if (decrypted === null) {\n return { text, decrypted: false };\n }\n return { text: decrypted, decrypted: true };\n}\n", "/**\n * Broker \u9884\u8BBE\u4E0E topic \u5DE5\u5177\u3002\n * \u539F\u5B9E\u73B0\u7684 topic \u662F\u6BCF\u4E2A\u670D\u52A1\u5668\u914D\u7F6E\u91CC\u7684\u5355\u4E00\u56FA\u5B9A topic\uFF08\u9ED8\u8BA4 'secure/stock-condition-order'\uFF09\uFF0C\n * \u6CA1\u6709\u6309\u7528\u6237/\u5B9E\u4F8B\u518D\u62FC\u63A5\u540E\u7F00\u7684\u89C4\u5219\u3002\n */\nimport { TopicError } from './errors.js';\n\n/** \u539F\u5B9E\u73B0\u9ED8\u8BA4 topic */\nexport const DEFAULT_TOPIC = 'secure/stock-condition-order';\n\n/** \u539F\u5B9E\u73B0\u5185\u7F6E\u7684\u4E09\u4E2A\u516C\u5171 Broker\uFF08MQTT over WebSocket\uFF09 */\nexport const PRESET_BROKERS = Object.freeze([\n 'wss://broker.emqx.io:8084/mqtt',\n 'wss://test.mosquitto.org:8081/mqtt',\n 'wss://broker.hivemq.com:8884/mqtt',\n]);\n\n/**\n * \u6821\u9A8C topic\u3002\u9ED8\u8BA4\u62D2\u7EDD\u901A\u914D\u7B26\uFF0C\u56E0\u4E3A\u53D1\u5E03/\u8BA2\u9605\u4E1A\u52A1 topic \u65F6\u4E0D\u5E94\u5E26 `+` \u6216 `#`\u3002\n * @param {string} topic\n * @param {{ allowWildcards?: boolean }} [options]\n * @returns {string}\n */\nexport function validateTopic(topic, options = {}) {\n const { allowWildcards = false } = options;\n if (typeof topic !== 'string' || topic.length === 0) {\n throw new TopicError('topic \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32');\n }\n if (topic.length > 65535) {\n throw new TopicError('topic \u957F\u5EA6\u8D85\u8FC7 65535 \u5B57\u8282\u4E0A\u9650');\n }\n if (topic.includes('\\u0000')) {\n throw new TopicError('topic \u4E0D\u80FD\u5305\u542B\u7A7A\u5B57\u7B26');\n }\n if (!allowWildcards && /[+#]/.test(topic)) {\n throw new TopicError('\u4E1A\u52A1 topic \u4E0D\u80FD\u5305\u542B\u901A\u914D\u7B26 + \u6216 #');\n }\n return topic;\n}\n\n/**\n * \u7528 `/` \u62FC\u63A5 topic \u5C42\u7EA7\u5E76\u6821\u9A8C\u3002\u7A7A\u5B57\u7B26\u4E32\u3001\u9996\u5C3E\u659C\u6760\u3001\u901A\u914D\u7B26\u90FD\u4F1A\u88AB\u62D2\u7EDD\u3002\n * @param {...string} segments\n * @returns {string}\n */\nexport function buildTopic(...segments) {\n if (segments.length === 0) {\n throw new TopicError('\u81F3\u5C11\u9700\u8981\u4E00\u4E2A topic \u7247\u6BB5');\n }\n\n const parts = segments.map((segment, index) => {\n if (typeof segment !== 'string' || segment.length === 0) {\n throw new TopicError(`\u7B2C ${index + 1} \u4E2A topic \u7247\u6BB5\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32`);\n }\n if (segment.startsWith('/') || segment.endsWith('/')) {\n throw new TopicError(`topic \u7247\u6BB5\u4E0D\u80FD\u4EE5 / \u5F00\u5934\u6216\u7ED3\u5C3E: \"${segment}\"`);\n }\n return segment;\n });\n\n return validateTopic(parts.join('/'));\n}\n", "/**\n * \u914D\u7F6E\u89E3\u6790\u4E0E\u5E95\u5C42 mqtt.connect options \u62FC\u88C5\u3002\n * \u8FD9\u91CC\u96C6\u4E2D\u4FDD\u7559\u539F\u5B9E\u73B0\u7684\u8FDE\u63A5\u53C2\u6570\uFF1A\u6BCF\u5B9E\u4F8B clientId\u30015s \u91CD\u8FDE\u300130s \u8FDE\u63A5\u8D85\u65F6\u3001clean session\u3002\n */\nimport { InvalidConfigError } from './errors.js';\nimport { DEFAULT_CLIENT_ID_PREFIX, DEFAULT_USER, createClientId } from './envelope.js';\nimport { DEFAULT_TOPIC, validateTopic } from './topic.js';\n\n/** \u652F\u6301\u7684 broker \u534F\u8BAE\uFF08\u5E93\u4EE5 MQTT over WebSocket \u4E3A\u4E3B\uFF0C\u540C\u65F6\u4FDD\u7559 TCP/TLS \u80FD\u529B\uFF09 */\nconst SUPPORTED_PROTOCOLS = new Set(['ws:', 'wss:', 'mqtt:', 'mqtts:', 'tcp:', 'tls:']);\n\n/**\n * \u9ED8\u8BA4\u914D\u7F6E\u3002`secret` \u5BF9\u5E94\u539F\u5B9E\u73B0\u670D\u52A1\u5668\u914D\u7F6E\u91CC\u7684 `password`\uFF08AES \u53E3\u4EE4\uFF09\u3002\n * @type {Readonly<Record<string, any>>}\n */\nexport const DEFAULT_OPTIONS = Object.freeze({\n broker: 'wss://broker.emqx.io:8084/mqtt',\n topic: DEFAULT_TOPIC,\n secret: '',\n encrypt: true,\n clientId: '',\n clientIdPrefix: DEFAULT_CLIENT_ID_PREFIX,\n clientIdSuffix: '',\n user: DEFAULT_USER,\n userSuffix: '',\n qos: 1,\n reconnectPeriod: 5000,\n connectTimeout: 30000,\n clean: true,\n resubscribe: true,\n heartbeatInterval: 30000,\n pongTimeout: 0,\n dedupeTtl: 5000,\n requestTimeout: 5000,\n auth: null,\n protocolVersion: undefined,\n});\n\n/**\n * @param {number} value\n * @param {string} name\n * @param {{ min?: number, allowZero?: boolean }} [rules]\n * @returns {number}\n */\nfunction requireNumber(value, name, rules = {}) {\n const { min = 0, allowZero = true } = rules;\n const validType = typeof value === 'number' && Number.isFinite(value);\n const validValue = validType && (allowZero ? value >= min : value > min);\n if (!validValue) {\n throw new InvalidConfigError(`${name} \u5FC5\u987B\u662F${allowZero ? ' >= ' : ' > '}${min} \u7684\u6570\u5B57`);\n }\n return value;\n}\n\n/**\n * @param {string} broker\n * @returns {string}\n */\nfunction validateBroker(broker) {\n if (typeof broker !== 'string' || broker.length === 0) {\n throw new InvalidConfigError('broker \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32');\n }\n let url;\n try {\n url = new URL(broker);\n } catch {\n throw new InvalidConfigError(`broker \u4E0D\u662F\u5408\u6CD5 URL: ${broker}`);\n }\n if (!SUPPORTED_PROTOCOLS.has(url.protocol)) {\n throw new InvalidConfigError(`\u4E0D\u652F\u6301\u7684 broker \u534F\u8BAE: ${url.protocol}\uFF08\u652F\u6301 ws/wss/mqtt/mqtts/tcp/tls\uFF09`);\n }\n if (!url.hostname) {\n throw new InvalidConfigError('broker \u7F3A\u5C11\u4E3B\u673A\u540D');\n }\n return broker;\n}\n\n/**\n * \u5408\u5E76\u5E76\u6821\u9A8C\u914D\u7F6E\uFF0C\u8FD4\u56DE\u89C4\u8303\u5316\u540E\u7684\u53EA\u8BFB\u914D\u7F6E\u5BF9\u8C61\u3002\n * @param {Partial<typeof DEFAULT_OPTIONS> & { auth?: { username?: string, password?: string } | null }} [input]\n * @returns {Readonly<Record<string, any>>}\n */\nexport function resolveOptions(input = {}) {\n if (!input || typeof input !== 'object' || Array.isArray(input)) {\n throw new InvalidConfigError('options \u5FC5\u987B\u662F\u5BF9\u8C61');\n }\n\n const options = { ...DEFAULT_OPTIONS, ...input };\n\n options.broker = validateBroker(options.broker);\n options.topic = validateTopic(options.topic);\n\n if (typeof options.secret !== 'string') {\n throw new InvalidConfigError('secret \u5FC5\u987B\u662F\u5B57\u7B26\u4E32');\n }\n if (options.encrypt !== false && options.secret.length === 0) {\n throw new InvalidConfigError('encrypt \u4E3A true \u65F6\u5FC5\u987B\u63D0\u4F9B\u975E\u7A7A secret');\n }\n if (typeof options.encrypt !== 'boolean') {\n throw new InvalidConfigError('encrypt \u5FC5\u987B\u662F\u5E03\u5C14\u503C');\n }\n\n if (options.clientId !== '' && typeof options.clientId !== 'string') {\n throw new InvalidConfigError('clientId \u5FC5\u987B\u662F\u5B57\u7B26\u4E32');\n }\n if (typeof options.clientIdPrefix !== 'string') {\n throw new InvalidConfigError('clientIdPrefix \u5FC5\u987B\u662F\u5B57\u7B26\u4E32');\n }\n if (typeof options.clientIdSuffix !== 'string') {\n throw new InvalidConfigError('clientIdSuffix \u5FC5\u987B\u662F\u5B57\u7B26\u4E32');\n }\n if (!options.clientId) {\n options.clientId = createClientId(options.clientIdPrefix);\n }\n if (!options.clientId) {\n throw new InvalidConfigError('clientId \u4E0D\u80FD\u4E3A\u7A7A');\n }\n\n if (typeof options.user !== 'string' || options.user.length === 0) {\n throw new InvalidConfigError('user \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32');\n }\n if (typeof options.userSuffix !== 'string') {\n throw new InvalidConfigError('userSuffix \u5FC5\u987B\u662F\u5B57\u7B26\u4E32');\n }\n\n if (![0, 1, 2].includes(options.qos)) {\n throw new InvalidConfigError('qos \u53EA\u80FD\u662F 0\u30011 \u6216 2');\n }\n\n options.reconnectPeriod = requireNumber(options.reconnectPeriod, 'reconnectPeriod');\n options.connectTimeout = requireNumber(options.connectTimeout, 'connectTimeout', { allowZero: false });\n options.heartbeatInterval = requireNumber(options.heartbeatInterval, 'heartbeatInterval');\n options.pongTimeout = requireNumber(options.pongTimeout, 'pongTimeout');\n options.dedupeTtl = requireNumber(options.dedupeTtl, 'dedupeTtl');\n options.requestTimeout = requireNumber(options.requestTimeout, 'requestTimeout', { allowZero: false });\n\n if (typeof options.clean !== 'boolean') {\n throw new InvalidConfigError('clean \u5FC5\u987B\u662F\u5E03\u5C14\u503C');\n }\n if (typeof options.resubscribe !== 'boolean') {\n throw new InvalidConfigError('resubscribe \u5FC5\u987B\u662F\u5E03\u5C14\u503C');\n }\n\n if (options.protocolVersion !== undefined && ![4, 5].includes(options.protocolVersion)) {\n throw new InvalidConfigError('protocolVersion \u53EA\u80FD\u662F 4 \u6216 5');\n }\n\n if (options.auth !== null && options.auth !== undefined) {\n const { username, password } = options.auth;\n if (typeof options.auth !== 'object' || Array.isArray(options.auth)) {\n throw new InvalidConfigError('auth \u5FC5\u987B\u662F\u5BF9\u8C61');\n }\n if (username !== undefined && typeof username !== 'string') {\n throw new InvalidConfigError('auth.username \u5FC5\u987B\u662F\u5B57\u7B26\u4E32');\n }\n if (password !== undefined && typeof password !== 'string') {\n throw new InvalidConfigError('auth.password \u5FC5\u987B\u662F\u5B57\u7B26\u4E32');\n }\n options.auth = { username, password };\n } else {\n options.auth = null;\n }\n\n return Object.freeze(options);\n}\n\n/**\n * \u751F\u6210\u4F20\u7ED9 `mqtt.connect()` \u7684 options\u3002\n * \u539F\u5B9E\u73B0\uFF1AclientId = \u57FA\u7840 clientId + '_' + serverId\uFF1BreconnectPeriod=5000\uFF1BconnectTimeout=30000\uFF1Bclean=true\u3002\n * @param {ReturnType<typeof resolveOptions>} options\n * @returns {Record<string, any>}\n */\nexport function buildMqttOptions(options) {\n if (!options || typeof options !== 'object') {\n throw new InvalidConfigError('buildMqttOptions \u9700\u8981 resolveOptions \u7684\u7ED3\u679C');\n }\n\n /** @type {Record<string, any>} */\n const mqttOptions = {\n clientId: `${options.clientId}${options.clientIdSuffix}`,\n reconnectPeriod: options.reconnectPeriod,\n connectTimeout: options.connectTimeout,\n clean: options.clean,\n resubscribe: options.resubscribe,\n };\n\n if (options.protocolVersion !== undefined) {\n mqttOptions.protocolVersion = options.protocolVersion;\n }\n if (options.auth) {\n if (options.auth.username !== undefined) mqttOptions.username = options.auth.username;\n if (options.auth.password !== undefined) mqttOptions.password = options.auth.password;\n }\n\n return mqttOptions;\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
3
|
+
"sources": ["../src/index.js", "../src/client.js", "../src/crypto.js", "../src/errors.js", "../src/envelope.js", "../src/message.js", "../src/topic.js", "../src/config-string.js", "../src/options.js"],
|
|
4
|
+
"sourcesContent": ["/**\n * mqtt-crypto-client\n * MQTT over WebSocket + CryptoJS \u517C\u5BB9 AES \u4FE1\u5C01\u52A0\u5BC6\u7684 Node.js \u5BA2\u6237\u7AEF\u3002\n */\nexport { MqttCryptoClient, createClient } from './client.js';\n\nexport {\n decryptPayload,\n deriveKeyAndIv,\n encryptPayload,\n isEncryptedPayload,\n tryDecrypt,\n} from './crypto.js';\n\nexport {\n DEFAULT_CLIENT_ID_PREFIX,\n DEFAULT_USER,\n buildEnvelope,\n createClientId,\n generateMsgId,\n isOwnMessage,\n isResponseCommand,\n parseEnvelope,\n} from './envelope.js';\n\nexport { decodeIncoming } from './message.js';\n\nexport {\n DEFAULT_OPTIONS,\n buildMqttOptions,\n resolveOptions,\n} from './options.js';\n\nexport { parseConfigString, serializeConfigString } from './config-string.js';\n\nexport { DEFAULT_TOPIC, PRESET_BROKERS, buildTopic, validateTopic } from './topic.js';\n\nexport {\n ConnectTimeoutError,\n CryptoError,\n EnvelopeError,\n InvalidConfigError,\n MqttCryptoError,\n NotConnectedError,\n RequestTimeoutError,\n TopicError,\n} from './errors.js';\n", "/**\n * MQTT over WebSocket \u5BA2\u6237\u7AEF\uFF1A\u52A0\u5BC6\u4FE1\u5C01\u6536\u53D1\u3001\u5FC3\u8DF3\u3001\u53BB\u91CD\u3001\u8BF7\u6C42/\u54CD\u5E94\u914D\u5BF9\u3002\n *\n * \u4E8B\u4EF6\uFF1A\n * connect \u9996\u6B21/\u6BCF\u6B21\u8FDE\u63A5\u6210\u529F\uFF08\u5DF2\u53D1\u8D77\u8BA2\u9605\uFF09\n * reconnect \u5E95\u5C42\u6B63\u5728\u91CD\u8FDE\n * close / offline \u8FDE\u63A5\u5173\u95ED / \u79BB\u7EBF\n * error Error\uFF08\u4EC5\u5728\u5B58\u5728 error \u76D1\u542C\u5668\u65F6\u629B\u51FA\uFF0C\u907F\u514D\u672A\u5904\u7406\u5F02\u5E38\uFF09\n * message { envelope, command, topic, decrypted }\n * response { envelope, command, topic }\n * agentStatus boolean\uFF08\u6536\u5230 pong = true\uFF1B\u4EC5\u5F53\u914D\u7F6E pongTimeout > 0 \u65F6\u624D\u53EF\u80FD\u4E3A false\uFF09\n * status { connected, agentOnline }\n * messageError Error\uFF08\u4FE1\u5C01/\u547D\u4EE4 JSON \u89E3\u6790\u5931\u8D25\uFF09\n */\nimport { EventEmitter } from 'node:events';\nimport mqtt from 'mqtt';\nimport { encryptPayload } from './crypto.js';\nimport {\n buildEnvelope,\n generateMsgId,\n isOwnMessage,\n isResponseCommand,\n parseEnvelope,\n} from './envelope.js';\nimport { ConnectTimeoutError, NotConnectedError, RequestTimeoutError } from './errors.js';\nimport { decodeIncoming } from './message.js';\nimport { buildMqttOptions, resolveOptions } from './options.js';\n\n/**\n * @typedef {{ command: Record<string, any> | null, envelope: Record<string, any>, topic: string }} IncomingMessage\n * @typedef {{\n * resolve: (value: IncomingMessage) => void,\n * reject: (reason?: any) => void,\n * timer: NodeJS.Timeout\n * }} PendingRequest\n */\n\nexport class MqttCryptoClient extends EventEmitter {\n /**\n * @param {Parameters<typeof resolveOptions>[0]} [options]\n */\n constructor(options = {}) {\n super();\n /** @type {ReturnType<typeof resolveOptions>} */\n this.options = resolveOptions(options);\n this.broker = this.options.broker;\n this.topic = this.options.topic;\n this.clientId = this.options.clientId;\n this.qos = this.options.qos;\n this.secret = this.options.secret;\n this.encrypt = this.options.encrypt;\n\n /** @type {import('mqtt').MqttClient | null} */\n this._client = null;\n this._connected = false;\n this._agentOnline = false;\n /** @type {Map<string, NodeJS.Timeout>} \u5DF2\u53D1\u9001 msgId -> \u53BB\u91CD\u8BA1\u65F6\u5668 */\n this._pendingMessages = new Map();\n /** @type {Map<string, PendingRequest>} */\n this._pendingRequests = new Map();\n /** @type {NodeJS.Timeout | null} */\n this._heartbeatTimer = null;\n /** @type {NodeJS.Timeout | null} */\n this._pongTimer = null;\n /** @type {Error | null} \u6700\u8FD1\u4E00\u6B21\u8FDE\u63A5\u9519\u8BEF\uFF08\u65E0 error \u76D1\u542C\u5668\u65F6\u4E5F\u4FBF\u4E8E\u6392\u67E5\uFF09 */\n this.lastError = null;\n }\n\n /** \u5E95\u5C42 mqtt \u5BA2\u6237\u7AEF\uFF08\u9AD8\u7EA7\u7528\u6CD5\uFF1B\u8FDE\u63A5\u524D\u4E3A null\uFF09 */\n get mqttClient() {\n return this._client;\n }\n\n /** \u662F\u5426\u5DF2\u8FDE\u63A5\u5E76\u5B8C\u6210\u8BA2\u9605 */\n isConnected() {\n return this._connected;\n }\n\n /** \u5BF9\u7AEF agent \u662F\u5426\u5728\u7EBF\uFF08\u6536\u5230 pong\uFF09 */\n isAgentOnline() {\n return this._agentOnline;\n }\n\n /**\n * \u5EFA\u7ACB\u8FDE\u63A5\u3002\u5E95\u5C42\u4F1A\u6309 reconnectPeriod \u6301\u7EED\u91CD\u8BD5\uFF1B\n * \u8BE5 Promise \u5728\u9996\u6B21\u8FDE\u63A5\u6210\u529F\u65F6 resolve\uFF0C\u8D85\u8FC7 timeout \u4ECD\u672A\u8FDE\u63A5\u5219 reject\uFF08\u4F46\u91CD\u8BD5\u7EE7\u7EED\uFF09\u3002\n * @param {number} [timeout]\n * @returns {Promise<MqttCryptoClient>}\n */\n connect(timeout = this.options.connectTimeout) {\n if (this._connected) return Promise.resolve(this);\n\n try {\n if (!this._client) this._createClient();\n } catch (error) {\n return Promise.reject(error);\n }\n\n return new Promise((resolve, reject) => {\n let settled = false;\n /** @param {Error} error */\n const onError = (error) => {\n // \u8FDE\u63A5\u9636\u6BB5\u7684\u9996\u4E2A\u9519\u8BEF\u4E0D\u7ACB\u5373 reject\uFF1A\u5E95\u5C42\u4F1A\u81EA\u52A8\u91CD\u8BD5\uFF0C\u7531\u8D85\u65F6\u515C\u5E95\u3002\n this.lastError = error;\n };\n const timer = setTimeout(() => {\n if (settled) return;\n settled = true;\n this.off('connect', onConnect);\n this.off('error', onError);\n reject(new ConnectTimeoutError(timeout));\n }, timeout);\n // \u4FDD\u6301\u5F15\u7528\uFF1A\u786E\u4FDD await connect() \u5728\u8FDB\u7A0B\u9000\u51FA\u524D\u80FD\u6B63\u5E38\u7ED3\u7B97\n\n const onConnect = () => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n this.off('error', onError);\n resolve(this);\n };\n\n this.once('connect', onConnect);\n this.on('error', onError);\n });\n }\n\n /**\n * \u65AD\u5F00\u8FDE\u63A5\u5E76\u6E05\u7406\u6240\u6709\u8BA1\u65F6\u5668\u4E0E\u672A\u5B8C\u6210\u7684\u8BF7\u6C42\u3002\n * @param {{ force?: boolean }} [options]\n * @returns {Promise<void>}\n */\n async disconnect(options = {}) {\n const { force = true } = options;\n this._stopHeartbeat();\n this._clearPendingMessages();\n this._rejectPendingRequests(new NotConnectedError('\u5BA2\u6237\u7AEF\u5DF2\u65AD\u5F00'));\n this._connected = false;\n this._agentOnline = false;\n\n const client = this._client;\n this._client = null;\n if (!client) {\n this._emitStatus();\n return;\n }\n\n await /** @type {Promise<void>} */ (new Promise((resolve) => {\n let settled = false;\n const done = () => {\n if (settled) return;\n settled = true;\n resolve();\n };\n // \u9632\u5FA1\uFF1Aend \u56DE\u8C03\u5728\u4E2A\u522B broker \u5F02\u5E38\u65F6\u4E0D\u89E6\u53D1\n const guard = setTimeout(done, 1000);\n guard.unref?.();\n try {\n client.end(force, {}, done);\n } catch {\n done();\n }\n }));\n\n client.removeAllListeners();\n this._emitStatus();\n }\n\n /**\n * \u8BA2\u9605 topic\uFF08\u9ED8\u8BA4\u4F7F\u7528\u914D\u7F6E\u4E2D\u7684 topic\uFF09\u3002\n * @param {string} [topic]\n * @param {{ qos?: number }} [options]\n * @returns {Promise<unknown>}\n */\n async subscribe(topic = this.topic, options = {}) {\n const qos = options.qos ?? this.qos;\n const client = this._client;\n if (!client || !this._connected) throw new NotConnectedError();\n return new Promise((resolve, reject) => {\n client.subscribe(topic, { qos }, (error, granted) => {\n if (error) reject(error);\n else resolve(granted);\n });\n });\n }\n\n /**\n * \u53D1\u5E03\u4E00\u4E2A\u4FE1\u5C01\uFF08\u81EA\u52A8\u8865\u9F50 id/user/time/msgId\uFF0C\u5E76\u6309\u914D\u7F6E\u52A0\u5BC6\uFF09\u3002\n * @param {Record<string, any>} envelope\n * @param {{ qos?: number, track?: boolean }} [options]\n * @returns {Promise<string>} msgId\n */\n async publish(envelope, options = {}) {\n const client = this._requireConnected();\n const { qos = this.qos, track = true } = options;\n const built = this._completeEnvelope(envelope);\n const payload = this._encode(built);\n\n if (track) this._trackMessage(built.msgId);\n\n await new Promise((resolve, reject) => {\n client.publish(this.topic, payload, { qos }, (error) => {\n if (error) {\n if (track) this._untrackMessage(built.msgId);\n this._emitError(error);\n reject(error);\n return;\n }\n resolve(undefined);\n });\n });\n\n return built.msgId;\n }\n\n /**\n * \u53D1\u9001\u547D\u4EE4\uFF1Amsg = JSON.stringify({ action, data })\u3002\n * @param {string} action\n * @param {Record<string, any>} [data]\n * @param {{ qos?: number, msgId?: string, track?: boolean }} [options]\n * @returns {Promise<string>} msgId\n */\n async sendCommand(action, data = {}, options = {}) {\n if (typeof action !== 'string' || action.length === 0) {\n throw new TypeError('action \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32');\n }\n const { qos = this.qos, msgId, track = true } = options;\n return this.publish(\n buildEnvelope({\n id: this.clientId,\n user: this.options.user,\n userSuffix: this.options.userSuffix,\n msg: JSON.stringify({ action, data }),\n msgId,\n }),\n { qos, track },\n );\n }\n\n /**\n * \u56DE\u590D\u8BF7\u6C42\uFF1A\u56DE\u663E\u8BF7\u6C42\u7684 msgId\uFF08\u539F\u5B9E\u73B0\u7684 msgId \u5173\u8054\u89C4\u5219\uFF09\u3002\n * @param {Record<string, any>} requestEnvelope \u8BF7\u6C42\u4FE1\u5C01\uFF08\u4E5F\u53EF\u4EE5\u662F JSON \u5B57\u7B26\u4E32\uFF09\n * @param {string} action\n * @param {Record<string, any>} [data]\n * @param {{ qos?: number, track?: boolean }} [options]\n * @returns {Promise<string>} msgId\n */\n async reply(requestEnvelope, action, data = {}, options = {}) {\n const request = this._normalizeEnvelopeInput(requestEnvelope);\n const msgId = request.msgId;\n const { qos = this.qos, track = Boolean(msgId) } = options;\n\n return this.publish(\n buildEnvelope({\n id: this.clientId,\n user: this.options.user,\n userSuffix: this.options.userSuffix,\n msg: JSON.stringify({ action, data }),\n msgId,\n }),\n { qos, track },\n );\n }\n\n /**\n * \u53D1\u9001\u547D\u4EE4\u5E76\u7B49\u5F85\u540C msgId \u7684\u54CD\u5E94\uFF08\u54CD\u5E94\u8D85\u65F6 reject\uFF09\u3002\n * \u7528\u4E8E\u53D6\u4EF7\u7B49\"\u8BF7\u6C42-\u54CD\u5E94\"\u573A\u666F\uFF0C\u539F\u811A\u672C\u6309 msgId \u914D\u5BF9\u3002\n * @param {string} action\n * @param {Record<string, any>} [data]\n * @param {{ qos?: number, timeout?: number }} [options]\n * @returns {Promise<IncomingMessage>}\n */\n async request(action, data = {}, options = {}) {\n this._requireConnected();\n const { qos = this.qos, timeout = this.options.requestTimeout } = options;\n const msgId = generateMsgId();\n\n /** @type {Promise<IncomingMessage>} */\n const response = new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this._pendingRequests.delete(msgId);\n reject(new RequestTimeoutError(msgId, timeout));\n }, timeout);\n this._pendingRequests.set(msgId, { resolve, reject, timer });\n });\n\n try {\n await this.publish(\n buildEnvelope({\n id: this.clientId,\n user: this.options.user,\n userSuffix: this.options.userSuffix,\n msg: JSON.stringify({ action, data }),\n msgId,\n }),\n { qos, track: false },\n );\n } catch (error) {\n const pending = this._pendingRequests.get(msgId);\n if (pending) {\n clearTimeout(pending.timer);\n this._pendingRequests.delete(msgId);\n }\n throw error;\n }\n\n return response;\n }\n\n // ==================== \u5185\u90E8\u5B9E\u73B0 ====================\n\n /** @returns {import('mqtt').MqttClient} */\n _createClient() {\n const client = mqtt.connect(this.broker, buildMqttOptions(this.options));\n this._client = client;\n\n client.on('connect', () => this._handleConnect());\n client.on('reconnect', () => this._handleReconnect());\n client.on('close', () => this._handleClose());\n client.on('offline', () => this._handleOffline());\n client.on('error', (error) => {\n this.lastError = error;\n this._emitError(error);\n });\n\n return client;\n }\n\n _handleConnect() {\n this._connected = true;\n this._emitStatus();\n this.emit('connect');\n this.subscribe(this.topic, { qos: this.qos }).catch((error) => this._emitError(error));\n this._startHeartbeat();\n }\n\n _handleReconnect() {\n this._connected = false;\n this._agentOnline = false;\n this._stopHeartbeat();\n this._emitStatus();\n this.emit('reconnect');\n }\n\n _handleClose() {\n this._connected = false;\n this._agentOnline = false;\n this._stopHeartbeat();\n this._emitStatus();\n this.emit('close');\n }\n\n _handleOffline() {\n this._connected = false;\n this._emitStatus();\n this.emit('offline');\n }\n\n /**\n * @param {string} topic\n * @param {Buffer} payload\n */\n _handleMessage(topic, payload) {\n const text = payload.toString();\n const decoded = decodeIncoming(text, this.secret);\n\n /** @type {ReturnType<typeof parseEnvelope>} */\n let parsed;\n try {\n parsed = parseEnvelope(decoded.text);\n } catch (error) {\n this._emitMessageError(/** @type {Error} */ (error));\n return;\n }\n\n const { data, command, commandError } = parsed;\n\n // 1. \u5FFD\u7565\u81EA\u5DF1\u53D1\u7684\u6D88\u606F\uFF08\u652F\u6301 clientId \u540E\u7F00\uFF09\n if (isOwnMessage(data, this.clientId)) return;\n\n // 2. \u5FC3\u8DF3\n if (data.msg === 'ping') {\n this._sendPong();\n return;\n }\n if (data.msg === 'pong') {\n this._agentOnline = true;\n this._clearPongTimer();\n this.emit('agentStatus', true);\n return;\n }\n\n // 3. \u547D\u4EE4 JSON \u89E3\u6790\u5931\u8D25\n if (commandError) {\n this._emitMessageError(commandError);\n return;\n }\n\n // 4. \u54CD\u5E94\u6D88\u606F\uFF1A\u5148\u914D\u5BF9 request()\uFF0C\u518D\u4ECE\u666E\u901A message \u4E8B\u4EF6\u4E2D\u8FC7\u6EE4\n if (isResponseCommand(command)) {\n this._resolveRequest(data.msgId, { command, envelope: data, topic });\n this.emit('response', { command, envelope: data, topic });\n return;\n }\n\n // 5. \u53BB\u91CD\uFF08\u539F\u5B9E\u73B0\uFF1A\u5DF2\u53D1\u9001 msgId \u5728 5s \u5185\u518D\u6B21\u51FA\u73B0\u5219\u5FFD\u7565\uFF09\n if (typeof data.msgId === 'string' && this._pendingMessages.has(data.msgId)) return;\n\n this.emit('message', {\n command,\n envelope: data,\n topic,\n decrypted: decoded.decrypted,\n });\n }\n\n /**\n * @param {Record<string, any>} envelope\n * @returns {{ id: string, msgId: string, user: string, msg: string, time: number }}\n */\n _completeEnvelope(envelope) {\n if (!envelope || typeof envelope !== 'object' || Array.isArray(envelope)) {\n throw new TypeError('envelope \u5FC5\u987B\u662F\u5BF9\u8C61');\n }\n return buildEnvelope({\n id: /** @type {string} */ (envelope.id ?? this.clientId),\n user: /** @type {string} */ (envelope.user ?? this.options.user),\n userSuffix: /** @type {string} */ (envelope.userSuffix ?? this.options.userSuffix),\n msg: envelope.msg,\n msgId: /** @type {string | undefined} */ (envelope.msgId),\n time: /** @type {number | undefined} */ (envelope.time),\n });\n }\n\n /**\n * @param {{ id: string, msgId: string, user: string, msg: string, time: number }} envelope\n * @returns {string}\n */\n _encode(envelope) {\n const json = JSON.stringify(envelope);\n return this.encrypt ? encryptPayload(json, this.secret) : json;\n }\n\n /** @param {unknown} input @returns {Record<string, any>} */\n _normalizeEnvelopeInput(input) {\n if (typeof input === 'string') {\n return parseEnvelope(input).data;\n }\n if (!input || typeof input !== 'object') {\n throw new TypeError('requestEnvelope \u5FC5\u987B\u662F\u5BF9\u8C61\u6216 JSON \u5B57\u7B26\u4E32');\n }\n return /** @type {Record<string, any>} */ (input);\n }\n\n /** @returns {import('mqtt').MqttClient} */\n _requireConnected() {\n if (!this._connected || !this._client) throw new NotConnectedError();\n return this._client;\n }\n\n _startHeartbeat() {\n this._stopHeartbeat();\n if (!this._connected) return;\n\n this._sendPing();\n const interval = this.options.heartbeatInterval;\n if (interval > 0) {\n this._heartbeatTimer = setInterval(() => this._sendPing(), interval);\n this._heartbeatTimer.unref?.();\n }\n }\n\n _stopHeartbeat() {\n if (this._heartbeatTimer) {\n clearInterval(this._heartbeatTimer);\n this._heartbeatTimer = null;\n }\n this._clearPongTimer();\n }\n\n _clearPongTimer() {\n if (this._pongTimer) {\n clearTimeout(this._pongTimer);\n this._pongTimer = null;\n }\n }\n\n _sendPing() {\n if (!this._connected) return;\n this.publish(\n buildEnvelope({\n id: this.clientId,\n user: this.options.user,\n userSuffix: this.options.userSuffix,\n msg: 'ping',\n msgId: generateMsgId({ suffix: 'ping' }),\n }),\n { track: false },\n ).catch((error) => this._emitError(error));\n\n // \u539F\u5B9E\u73B0\u7684 5s pong \u8BA1\u65F6\u5668\u5B9E\u9645\u662F\u7A7A\u56DE\u8C03\uFF1B\u8FD9\u91CC\u9ED8\u8BA4\u4E0D\u5224\u5B9A\u79BB\u7EBF\uFF08pongTimeout=0\uFF09\u3002\n if (this.options.pongTimeout > 0) {\n this._clearPongTimer();\n this._pongTimer = setTimeout(() => {\n this._agentOnline = false;\n this.emit('agentStatus', false);\n }, this.options.pongTimeout);\n this._pongTimer.unref?.();\n }\n }\n\n _sendPong() {\n if (!this._connected) return;\n this.publish(\n buildEnvelope({\n id: this.clientId,\n user: this.options.user,\n userSuffix: this.options.userSuffix,\n msg: 'pong',\n msgId: generateMsgId({ suffix: 'pong' }),\n }),\n { track: false },\n ).catch((error) => this._emitError(error));\n }\n\n /** @param {string} msgId */\n _trackMessage(msgId) {\n if (this.options.dedupeTtl <= 0) return;\n this._untrackMessage(msgId);\n const timer = setTimeout(() => {\n this._pendingMessages.delete(msgId);\n }, this.options.dedupeTtl);\n timer.unref?.();\n this._pendingMessages.set(msgId, timer);\n }\n\n /** @param {string} msgId */\n _untrackMessage(msgId) {\n const timer = this._pendingMessages.get(msgId);\n if (timer) {\n clearTimeout(timer);\n this._pendingMessages.delete(msgId);\n }\n }\n\n _clearPendingMessages() {\n for (const timer of this._pendingMessages.values()) clearTimeout(timer);\n this._pendingMessages.clear();\n }\n\n /**\n * @param {string | undefined} msgId\n * @param {IncomingMessage} value\n * @returns {boolean}\n */\n _resolveRequest(msgId, value) {\n if (typeof msgId !== 'string') return false;\n const pending = this._pendingRequests.get(msgId);\n if (!pending) return false;\n clearTimeout(pending.timer);\n this._pendingRequests.delete(msgId);\n pending.resolve(value);\n return true;\n }\n\n /** @param {Error} error */\n _rejectPendingRequests(error) {\n for (const pending of this._pendingRequests.values()) {\n clearTimeout(pending.timer);\n pending.reject(error);\n }\n this._pendingRequests.clear();\n }\n\n /** @param {Error} error */\n _emitError(error) {\n this.lastError = error;\n if (this.listenerCount('error') > 0) this.emit('error', error);\n }\n\n /** @param {Error} error */\n _emitMessageError(error) {\n if (this.listenerCount('messageError') > 0) this.emit('messageError', error);\n }\n\n _emitStatus() {\n this.emit('status', { connected: this._connected, agentOnline: this._agentOnline });\n }\n}\n\n/**\n * @param {Parameters<typeof resolveOptions>[0]} [options]\n * @returns {MqttCryptoClient}\n */\nexport function createClient(options = {}) {\n return new MqttCryptoClient(options);\n}\n", "/**\n * \u4E0E\u539F\u5B9E\u73B0\uFF08CryptoJS.AES.encrypt(payload, passphrase).toString()\uFF09\u9010\u5B57\u8282\u517C\u5BB9\u7684\u52A0\u89E3\u5BC6\u5DE5\u5177\u3002\n *\n * \u517C\u5BB9\u683C\u5F0F\uFF08OpenSSL \"Salted__\" \u683C\u5F0F\uFF09\uFF1A\n * \u5BC6\u6587 = base64( \"Salted__\"\uFF088 \u5B57\u8282\uFF09 + salt\uFF08\u9ED8\u8BA4 8 \u5B57\u8282\uFF09 + AES-256-CBC \u5BC6\u6587 )\n * \u5BC6\u94A5/IV = EVP_BytesToKey(MD5, 1 \u6B21\u8FED\u4EE3, passphrase, salt)\uFF0Ckey 32 \u5B57\u8282 + IV 16 \u5B57\u8282\n * \u586B\u5145 = PKCS#7\n *\n * \u8BF4\u660E\uFF1A\u8FD9\u662F\"\u53E3\u4EE4\u6D3E\u751F + CBC\"\u683C\u5F0F\uFF0C\u6CA1\u6709\u5B8C\u6574\u6027\u6821\u9A8C\uFF08\u65E0 MAC/AEAD\uFF09\uFF0C\n * \u53EA\u80FD\u9632\u65C1\u89C2\u8005\u76F4\u63A5\u8BFB\u53D6\u660E\u6587\uFF0C\u4E0D\u80FD\u9632\u7BE1\u6539\u3002\u8BE6\u89C1 README \u7684\u5B89\u5168\u8BF4\u660E\u3002\n */\nimport { createCipheriv, createDecipheriv, createHash, randomBytes } from 'node:crypto';\nimport { TextDecoder } from 'node:util';\nimport { CryptoError } from './errors.js';\n\nconst SALT_HEADER = Buffer.from('Salted__', 'utf8');\nconst KEY_LENGTH = 32;\nconst IV_LENGTH = 16;\nconst DEFAULT_SALT_LENGTH = 8;\nconst AES_ALGORITHM = 'aes-256-cbc';\nconst BASE64_PATTERN = /^[A-Za-z0-9+/]+={0,2}$/;\n\nconst strictUtf8Decoder = new TextDecoder('utf-8', { fatal: true });\n\n/**\n * @param {unknown} secret\n * @returns {Buffer}\n */\nfunction toSecretBuffer(secret) {\n if (typeof secret !== 'string' || secret.length === 0) {\n throw new CryptoError('secret \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32', 'MISSING_SECRET');\n }\n return Buffer.from(secret, 'utf8');\n}\n\n/**\n * OpenSSL EVP_BytesToKey\uFF08MD5\uFF0Ccount=1\uFF09\uFF0C\u4E0E CryptoJS \u7684 OpenSSLKdf \u4E00\u81F4\u3002\n * @param {string} secret \u53E3\u4EE4\n * @param {Buffer} salt \u76D0\uFF08\u53EF\u4EE5\u4E3A\u7A7A Buffer\uFF0C\u7528\u4E8E\u517C\u5BB9\u65E0\u76D0\u5BC6\u6587\uFF09\n * @param {number} [keyLength]\n * @param {number} [ivLength]\n * @returns {{ key: Buffer, iv: Buffer }}\n */\nexport function deriveKeyAndIv(secret, salt, keyLength = KEY_LENGTH, ivLength = IV_LENGTH) {\n const password = toSecretBuffer(secret);\n if (!Buffer.isBuffer(salt)) {\n throw new CryptoError('salt \u5FC5\u987B\u662F Buffer', 'INVALID_SALT');\n }\n\n const targetLength = keyLength + ivLength;\n /** @type {Buffer[]} */\n const blocks = [];\n let block = Buffer.alloc(0);\n let generated = 0;\n\n while (generated < targetLength) {\n block = createHash('md5')\n .update(Buffer.concat([block, password, salt]))\n .digest();\n blocks.push(block);\n generated += block.length;\n }\n\n const derived = Buffer.concat(blocks);\n return {\n key: derived.subarray(0, keyLength),\n iv: derived.subarray(keyLength, targetLength),\n };\n}\n\n/**\n * \u52A0\u5BC6\u4EFB\u610F\u5B57\u7B26\u4E32\uFF08\u901A\u5E38\u662F JSON \u4FE1\u5C01\uFF09\uFF0C\u8FD4\u56DE\u4E0E CryptoJS \u5B8C\u5168\u517C\u5BB9\u7684 base64 \u5BC6\u6587\u3002\n * @param {string} plaintext \u660E\u6587\n * @param {string} secret \u53E3\u4EE4\n * @param {{ saltLength?: number, salt?: Buffer }} [options]\n * @returns {string}\n */\nexport function encryptPayload(plaintext, secret, options = {}) {\n if (typeof plaintext !== 'string') {\n throw new CryptoError('plaintext \u5FC5\u987B\u662F\u5B57\u7B26\u4E32', 'INVALID_PLAINTEXT');\n }\n const saltLength = options.saltLength ?? DEFAULT_SALT_LENGTH;\n if (!Number.isInteger(saltLength) || saltLength < 0) {\n throw new CryptoError('saltLength \u5FC5\u987B\u662F\u975E\u8D1F\u6574\u6570', 'INVALID_SALT');\n }\n\n const salt = options.salt ?? randomBytes(saltLength);\n if (!Buffer.isBuffer(salt)) {\n throw new CryptoError('salt \u5FC5\u987B\u662F Buffer', 'INVALID_SALT');\n }\n\n const { key, iv } = deriveKeyAndIv(secret, salt);\n try {\n const cipher = createCipheriv(AES_ALGORITHM, key, iv);\n const ciphertext = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);\n return Buffer.concat([SALT_HEADER, salt, ciphertext]).toString('base64');\n } catch (error) {\n throw new CryptoError('\u52A0\u5BC6\u5931\u8D25', 'ENCRYPT_FAILED', /** @type {Error} */ (error));\n }\n}\n\n/**\n * \u89E3\u6790 base64 \u5BC6\u6587\u3002\u5E26 \"Salted__\" \u5934\u65F6\u4F7F\u7528\u5176\u4E2D\u7684 salt\uFF1B\n * \u4E0D\u542B\u5934\u65F6\u6309 CryptoJS \u7684\u517C\u5BB9\u884C\u4E3A\u4F7F\u7528\u7A7A salt\u3002\n * @param {string} ciphertext\n * @returns {{ salt: Buffer, ciphertext: Buffer }}\n */\nfunction parseCiphertext(ciphertext) {\n if (typeof ciphertext !== 'string') {\n throw new CryptoError('\u5BC6\u6587\u5FC5\u987B\u662F\u5B57\u7B26\u4E32', 'INVALID_CIPHERTEXT');\n }\n const normalized = ciphertext.trim();\n if (!normalized || normalized.length % 4 !== 0 || !BASE64_PATTERN.test(normalized)) {\n throw new CryptoError('\u5BC6\u6587\u4E0D\u662F\u5408\u6CD5\u7684 base64', 'INVALID_CIPHERTEXT');\n }\n\n const raw = Buffer.from(normalized, 'base64');\n if (raw.length < SALT_HEADER.length) {\n throw new CryptoError('\u5BC6\u6587\u957F\u5EA6\u4E0D\u8DB3', 'INVALID_CIPHERTEXT');\n }\n\n if (raw.subarray(0, SALT_HEADER.length).equals(SALT_HEADER)) {\n if (raw.length < SALT_HEADER.length + DEFAULT_SALT_LENGTH) {\n throw new CryptoError('\u5BC6\u6587\u7F3A\u5C11 salt', 'INVALID_CIPHERTEXT');\n }\n return {\n salt: raw.subarray(SALT_HEADER.length, SALT_HEADER.length + DEFAULT_SALT_LENGTH),\n ciphertext: raw.subarray(SALT_HEADER.length + DEFAULT_SALT_LENGTH),\n };\n }\n\n return { salt: Buffer.alloc(0), ciphertext: raw };\n}\n\n/**\n * \u89E3\u5BC6\u5E76\u8FD4\u56DE UTF-8 \u660E\u6587\uFF1B\u5931\u8D25\u65F6\u629B\u51FA CryptoError\u3002\n * @param {string} ciphertext base64 \u5BC6\u6587\n * @param {string} secret \u53E3\u4EE4\n * @returns {string}\n */\nexport function decryptPayload(ciphertext, secret) {\n toSecretBuffer(secret);\n const { salt, ciphertext: body } = parseCiphertext(ciphertext);\n if (body.length === 0 || body.length % 16 !== 0) {\n throw new CryptoError('\u5BC6\u6587\u5757\u957F\u5EA6\u975E\u6CD5', 'INVALID_CIPHERTEXT');\n }\n\n const { key, iv } = deriveKeyAndIv(secret, salt);\n try {\n const decipher = createDecipheriv(AES_ALGORITHM, key, iv);\n const plaintext = Buffer.concat([decipher.update(body), decipher.final()]);\n return strictUtf8Decoder.decode(plaintext);\n } catch (error) {\n throw new CryptoError('\u89E3\u5BC6\u5931\u8D25\uFF08\u53E3\u4EE4\u9519\u8BEF\u3001\u5BC6\u6587\u635F\u574F\u6216\u4E0D\u662F UTF-8\uFF09', 'DECRYPT_FAILED', /** @type {Error} */ (error));\n }\n}\n\n/**\n * \u5BBD\u677E\u89E3\u5BC6\uFF1A\u4EFB\u4F55\u5931\u8D25\u90FD\u8FD4\u56DE null\uFF0C\u7528\u4E8E\"\u5148\u89E3\u5BC6\u3001\u5931\u8D25\u518D\u6309\u660E\u6587\u5904\u7406\"\u7684\u517C\u5BB9\u8DEF\u5F84\u3002\n * @param {string} ciphertext\n * @param {string} secret\n * @returns {string | null}\n */\nexport function tryDecrypt(ciphertext, secret) {\n if (typeof ciphertext !== 'string' || !ciphertext || !secret) return null;\n try {\n const plaintext = decryptPayload(ciphertext, secret);\n return plaintext.length > 0 ? plaintext : null;\n } catch {\n return null;\n }\n}\n\n/**\n * \u5224\u65AD\u5B57\u7B26\u4E32\u662F\u5426\u662F\u672C\u5E93/CryptoJS \u7684 \"Salted__\" base64 \u5BC6\u6587\uFF08\u4EC5\u770B\u5934\u90E8\uFF0C\u4E0D\u6821\u9A8C\u5185\u5BB9\uFF09\u3002\n * @param {string} value\n * @returns {boolean}\n */\nexport function isEncryptedPayload(value) {\n if (typeof value !== 'string') return false;\n const normalized = value.trim();\n if (!normalized || normalized.length % 4 !== 0 || !BASE64_PATTERN.test(normalized)) return false;\n const raw = Buffer.from(normalized, 'base64');\n return raw.length >= SALT_HEADER.length && raw.subarray(0, SALT_HEADER.length).equals(SALT_HEADER);\n}\n", "/**\n * \u5E93\u5185\u7EDF\u4E00\u9519\u8BEF\u7C7B\u578B\u3002\n * \u6240\u6709\u53EF\u9884\u671F\u7684\u9519\u8BEF\u90FD\u5E26\u6709\u7A33\u5B9A\u7684 `code`\uFF0C\u4FBF\u4E8E\u8C03\u7528\u65B9\u5206\u652F\u5904\u7406\u3002\n */\nexport class MqttCryptoError extends Error {\n /**\n * @param {string} message \u9519\u8BEF\u63CF\u8FF0\n * @param {string} [code] \u7A33\u5B9A\u7684\u9519\u8BEF\u7801\n * @param {Error & {code?: string}} [cause] \u539F\u59CB\u9519\u8BEF\n */\n constructor(message, code = 'MQTT_CRYPTO_ERROR', cause) {\n super(message, cause ? { cause } : undefined);\n this.name = 'MqttCryptoError';\n this.code = code;\n }\n}\n\n/** \u914D\u7F6E\u975E\u6CD5\uFF08broker/topic/qos/secret \u7B49\uFF09 */\nexport class InvalidConfigError extends MqttCryptoError {\n /** @param {string} message */\n constructor(message) {\n super(message, 'INVALID_CONFIG');\n this.name = 'InvalidConfigError';\n }\n}\n\n/** \u672A\u8FDE\u63A5\u65F6\u5C1D\u8BD5\u6267\u884C\u9700\u8981\u8FDE\u63A5\u7684\u64CD\u4F5C */\nexport class NotConnectedError extends MqttCryptoError {\n /** @param {string} [message] */\n constructor(message = 'MQTT \u5BA2\u6237\u7AEF\u5C1A\u672A\u8FDE\u63A5') {\n super(message, 'NOT_CONNECTED');\n this.name = 'NotConnectedError';\n }\n}\n\n/** \u8BF7\u6C42\u7B49\u5F85\u54CD\u5E94\u8D85\u65F6 */\nexport class RequestTimeoutError extends MqttCryptoError {\n /**\n * @param {string} msgId \u8BF7\u6C42\u7684\u6D88\u606F ID\n * @param {number} timeout \u8D85\u65F6\u6BEB\u79D2\u6570\n */\n constructor(msgId, timeout) {\n super(`\u8BF7\u6C42 ${msgId} \u5728 ${timeout}ms \u5185\u6CA1\u6709\u6536\u5230\u54CD\u5E94`, 'REQUEST_TIMEOUT');\n this.name = 'RequestTimeoutError';\n this.msgId = msgId;\n this.timeout = timeout;\n }\n}\n\n/** \u8FDE\u63A5\u5C31\u7EEA\u7B49\u5F85\u8D85\u65F6\uFF08\u5E95\u5C42\u5BA2\u6237\u7AEF\u4ECD\u4F1A\u6309 reconnectPeriod \u7EE7\u7EED\u91CD\u8BD5\uFF09 */\nexport class ConnectTimeoutError extends MqttCryptoError {\n /** @param {number} timeout */\n constructor(timeout) {\n super(`MQTT \u8FDE\u63A5\u5728 ${timeout}ms \u5185\u672A\u5C31\u7EEA`, 'CONNECT_TIMEOUT');\n this.name = 'ConnectTimeoutError';\n this.timeout = timeout;\n }\n}\n\n/** topic \u975E\u6CD5 */\nexport class TopicError extends MqttCryptoError {\n /** @param {string} message */\n constructor(message) {\n super(message, 'INVALID_TOPIC');\n this.name = 'TopicError';\n }\n}\n\n/** \u52A0\u89E3\u5BC6\u5931\u8D25 */\nexport class CryptoError extends MqttCryptoError {\n /**\n * @param {string} message\n * @param {string} [code]\n * @param {Error} [cause]\n */\n constructor(message, code = 'CRYPTO_ERROR', cause) {\n super(message, code, cause);\n this.name = 'CryptoError';\n }\n}\n\n/** \u4FE1\u5C01\u89E3\u6790\u5931\u8D25 */\nexport class EnvelopeError extends MqttCryptoError {\n /**\n * @param {string} message\n * @param {string} [code]\n * @param {Error} [cause]\n */\n constructor(message, code = 'INVALID_ENVELOPE', cause) {\n super(message, code, cause);\n this.name = 'EnvelopeError';\n }\n}\n", "/**\n * \u6D88\u606F\u4FE1\u5C01\uFF08envelope\uFF09\u6784\u9020\u4E0E\u89E3\u6790\u3002\n * \u4E0E\u539F\u5B9E\u73B0\u4FDD\u6301\u4E00\u81F4\u7684\u5B57\u6BB5\uFF1A{ id, msgId, user, msg, time }\u3002\n */\nimport { EnvelopeError } from './errors.js';\n\n/** \u539F Vue \u5B9E\u73B0\u4F7F\u7528\u7684\u9ED8\u8BA4 user \u524D\u7F00 */\nexport const DEFAULT_USER = 'fangzheng-agent';\n/** \u9ED8\u8BA4 clientId \u524D\u7F00\uFF08\u539F Vue \u5B9E\u73B0\u4E3A `vue_`\uFF09 */\nexport const DEFAULT_CLIENT_ID_PREFIX = 'vue_';\n\n/**\n * \u751F\u6210\u5BA2\u6237\u7AEF ID\uFF1A`\u524D\u7F00 + 6 \u4F4D\u5341\u516D\u8FDB\u5236\u968F\u673A\u6570`\uFF08\u4E0E Math.random().toString(16).slice(2, 8) \u7B49\u4EF7\uFF09\u3002\n * @param {string} [prefix]\n * @param {() => number} [random] \u4FBF\u4E8E\u6D4B\u8BD5\u6CE8\u5165\n * @returns {string}\n */\nexport function createClientId(prefix = DEFAULT_CLIENT_ID_PREFIX, random = Math.random) {\n return `${prefix}${random().toString(16).slice(2, 8)}`;\n}\n\n/**\n * \u751F\u6210 msgId\uFF1A`\u65F6\u95F4\u6233_4 \u4F4D\u5341\u516D\u8FDB\u5236\u968F\u673A\u6570`\uFF0C\u53EF\u9644\u52A0\u540E\u7F00\u3002\n * @param {{ now?: number, suffix?: string, random?: () => number }} [options]\n * @returns {string}\n */\nexport function generateMsgId(options = {}) {\n const { now = Date.now(), suffix = '', random = Math.random } = options;\n const base = `${now}_${random().toString(16).slice(2, 6)}`;\n return suffix ? `${base}_${suffix}` : base;\n}\n\n/**\n * \u6784\u9020\u4FE1\u5C01\u3002`msg` \u53EF\u4EE5\u662F\u5B57\u7B26\u4E32\uFF0C\u4E5F\u53EF\u4EE5\u662F\u4F1A\u88AB JSON.stringify \u7684\u5BF9\u8C61\u3002\n * @param {{\n * id: string,\n * msg: string | object,\n * user?: string,\n * userSuffix?: string,\n * msgId?: string,\n * time?: number\n * }} input\n * @returns {{ id: string, msgId: string, user: string, msg: string, time: number }}\n */\nexport function buildEnvelope(input) {\n const { id, user = DEFAULT_USER, userSuffix = '', msgId, time = Date.now() } = input;\n if (typeof id !== 'string' || id.length === 0) {\n throw new EnvelopeError('\u4FE1\u5C01 id \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32', 'INVALID_ENVELOPE_ID');\n }\n if (typeof user !== 'string' || typeof userSuffix !== 'string') {\n throw new EnvelopeError('user/userSuffix \u5FC5\u987B\u662F\u5B57\u7B26\u4E32', 'INVALID_ENVELOPE_USER');\n }\n\n let msg;\n if (typeof input.msg === 'string') {\n msg = input.msg;\n } else if (input.msg && typeof input.msg === 'object') {\n msg = JSON.stringify(input.msg);\n } else {\n throw new EnvelopeError('\u4FE1\u5C01 msg \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6216\u5BF9\u8C61', 'INVALID_ENVELOPE_MSG');\n }\n\n return {\n id,\n msgId: msgId || generateMsgId({ now: time }),\n user: `${user}${userSuffix}`,\n msg,\n time,\n };\n}\n\n/**\n * \u89E3\u6790\u4FE1\u5C01\u53CA\u5176\u4E2D\u7684\u547D\u4EE4\u3002\n *\n * - `data`\uFF1A\u539F\u59CB\u4FE1\u5C01\u5BF9\u8C61\n * - `command`\uFF1A`msg` \u89E3\u6790\u540E\u7684\u547D\u4EE4\u5BF9\u8C61\uFF1B`ping`/`pong` \u6216\u89E3\u6790\u5931\u8D25\u65F6\u4E3A null\n * - `commandError`\uFF1A`msg` \u975E ping/pong \u4F46\u4E0D\u662F\u5408\u6CD5 JSON \u65F6\u7684\u9519\u8BEF\n *\n * @param {string | object} input JSON \u5B57\u7B26\u4E32\u6216\u5DF2\u89E3\u6790\u5BF9\u8C61\n * @returns {{ data: Record<string, any>, command: Record<string, any> | null, commandError: Error | null }}\n */\nexport function parseEnvelope(input) {\n let data;\n if (typeof input === 'string') {\n try {\n data = JSON.parse(input);\n } catch (error) {\n throw new EnvelopeError('\u4FE1\u5C01\u4E0D\u662F\u5408\u6CD5 JSON', 'INVALID_JSON', /** @type {Error} */ (error));\n }\n } else {\n data = input;\n }\n\n if (!data || typeof data !== 'object' || Array.isArray(data)) {\n throw new EnvelopeError('\u4FE1\u5C01\u5FC5\u987B\u662F\u5BF9\u8C61', 'INVALID_ENVELOPE');\n }\n\n let command = null;\n let commandError = null;\n const { msg } = data;\n\n if (typeof msg === 'string') {\n if (msg !== 'ping' && msg !== 'pong') {\n try {\n command = JSON.parse(msg);\n } catch (error) {\n command = null;\n commandError = new EnvelopeError('\u4FE1\u5C01 msg \u4E0D\u662F\u5408\u6CD5 JSON', 'INVALID_COMMAND_JSON', /** @type {Error} */ (error));\n }\n }\n } else if (msg && typeof msg === 'object') {\n command = msg;\n }\n\n return { data, command, commandError };\n}\n\n/**\n * \u662F\u5426\u4E3A\"\u81EA\u5DF1\u53D1\u51FA\u7684\u6D88\u606F\"\uFF08\u652F\u6301\u5E26\u670D\u52A1\u5668\u540E\u7F00\u7684 clientId \u524D\u7F00\u5339\u914D\uFF09\u3002\n * @param {{ id?: unknown } | null | undefined} data\n * @param {string} clientId\n * @returns {boolean}\n */\nexport function isOwnMessage(data, clientId) {\n return Boolean(data && typeof data.id === 'string' && clientId && data.id.startsWith(clientId));\n}\n\n/**\n * \u662F\u5426\u5C5E\u4E8E\u54CD\u5E94\u6D88\u606F\uFF08\u539F\u5B9E\u73B0\u4F1A\u4ECE\u666E\u901A\u6D88\u606F\u56DE\u8C03\u4E2D\u8FC7\u6EE4\u6389\u5B83\u4EEC\uFF09\u3002\n * \u89C4\u5219\uFF1A`action === 'response'`\uFF0C\u6216\u6CA1\u6709 `action` \u4F46\u5E26\u6709 `type`\u3002\n * @param {Record<string, any> | null | undefined} command\n * @returns {boolean}\n */\nexport function isResponseCommand(command) {\n if (!command) return false;\n return command.action === 'response' || (!command.action && Boolean(command.type));\n}\n", "/**\n * \u5165\u7AD9\u6D88\u606F\u89E3\u7801\uFF1A\u5148\u5C1D\u8BD5 AES \u89E3\u5BC6\uFF0C\u5931\u8D25\u5219\u6309\u660E\u6587\u5904\u7406\uFF08\u539F\u5B9E\u73B0\u884C\u4E3A\uFF09\u3002\n */\nimport { tryDecrypt } from './crypto.js';\n\n/**\n * @param {string} text MQTT payload \u7684\u5B57\u7B26\u4E32\u5F62\u5F0F\n * @param {string} [secret] AES \u53E3\u4EE4\uFF1B\u4E3A\u7A7A\u65F6\u8DF3\u8FC7\u89E3\u5BC6\n * @returns {{ text: string, decrypted: boolean }}\n */\nexport function decodeIncoming(text, secret) {\n if (typeof text !== 'string') {\n return { text: String(text), decrypted: false };\n }\n if (!secret) {\n return { text, decrypted: false };\n }\n\n const decrypted = tryDecrypt(text, secret);\n if (decrypted === null) {\n return { text, decrypted: false };\n }\n return { text: decrypted, decrypted: true };\n}\n", "/**\n * Broker \u9884\u8BBE\u4E0E topic \u5DE5\u5177\u3002\n * \u539F\u5B9E\u73B0\u7684 topic \u662F\u6BCF\u4E2A\u670D\u52A1\u5668\u914D\u7F6E\u91CC\u7684\u5355\u4E00\u56FA\u5B9A topic\uFF08\u9ED8\u8BA4 'secure/stock-condition-order'\uFF09\uFF0C\n * \u6CA1\u6709\u6309\u7528\u6237/\u5B9E\u4F8B\u518D\u62FC\u63A5\u540E\u7F00\u7684\u89C4\u5219\u3002\n */\nimport { TopicError } from './errors.js';\n\n/** \u539F\u5B9E\u73B0\u9ED8\u8BA4 topic */\nexport const DEFAULT_TOPIC = 'secure/stock-condition-order';\n\n/** \u539F\u5B9E\u73B0\u5185\u7F6E\u7684\u4E09\u4E2A\u516C\u5171 Broker\uFF08MQTT over WebSocket\uFF09 */\nexport const PRESET_BROKERS = Object.freeze([\n 'wss://broker.emqx.io:8084/mqtt',\n 'wss://test.mosquitto.org:8081/mqtt',\n 'wss://broker.hivemq.com:8884/mqtt',\n]);\n\n/**\n * \u6821\u9A8C topic\u3002\u9ED8\u8BA4\u62D2\u7EDD\u901A\u914D\u7B26\uFF0C\u56E0\u4E3A\u53D1\u5E03/\u8BA2\u9605\u4E1A\u52A1 topic \u65F6\u4E0D\u5E94\u5E26 `+` \u6216 `#`\u3002\n * @param {string} topic\n * @param {{ allowWildcards?: boolean }} [options]\n * @returns {string}\n */\nexport function validateTopic(topic, options = {}) {\n const { allowWildcards = false } = options;\n if (typeof topic !== 'string' || topic.length === 0) {\n throw new TopicError('topic \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32');\n }\n if (topic.length > 65535) {\n throw new TopicError('topic \u957F\u5EA6\u8D85\u8FC7 65535 \u5B57\u8282\u4E0A\u9650');\n }\n if (topic.includes('\\u0000')) {\n throw new TopicError('topic \u4E0D\u80FD\u5305\u542B\u7A7A\u5B57\u7B26');\n }\n if (!allowWildcards && /[+#]/.test(topic)) {\n throw new TopicError('\u4E1A\u52A1 topic \u4E0D\u80FD\u5305\u542B\u901A\u914D\u7B26 + \u6216 #');\n }\n return topic;\n}\n\n/**\n * \u7528 `/` \u62FC\u63A5 topic \u5C42\u7EA7\u5E76\u6821\u9A8C\u3002\u7A7A\u5B57\u7B26\u4E32\u3001\u9996\u5C3E\u659C\u6760\u3001\u901A\u914D\u7B26\u90FD\u4F1A\u88AB\u62D2\u7EDD\u3002\n * @param {...string} segments\n * @returns {string}\n */\nexport function buildTopic(...segments) {\n if (segments.length === 0) {\n throw new TopicError('\u81F3\u5C11\u9700\u8981\u4E00\u4E2A topic \u7247\u6BB5');\n }\n\n const parts = segments.map((segment, index) => {\n if (typeof segment !== 'string' || segment.length === 0) {\n throw new TopicError(`\u7B2C ${index + 1} \u4E2A topic \u7247\u6BB5\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32`);\n }\n if (segment.startsWith('/') || segment.endsWith('/')) {\n throw new TopicError(`topic \u7247\u6BB5\u4E0D\u80FD\u4EE5 / \u5F00\u5934\u6216\u7ED3\u5C3E: \"${segment}\"`);\n }\n return segment;\n });\n\n return validateTopic(parts.join('/'));\n}\n", "/**\n * MQTT \u914D\u7F6E\u5B57\u7B26\u4E32\uFF08mqtthub \u98CE\u683C\uFF09\u7684\u5E8F\u5217\u5316 / \u53CD\u5E8F\u5217\u5316\u3002\n *\n * \u683C\u5F0F\uFF1A`key=value&key=value`\uFF0C\u6BCF\u4E2A value \u7ECF encodeURIComponent \u7F16\u7801\u3002\u6574\u4E32\u65E2\u53EF\u4F5C\u4E3A URL\n * \u67E5\u8BE2\u4E32\uFF08\u5982 `?broker=...&topic=...&password=...`\uFF09\uFF0C\u4E5F\u53EF\u539F\u6837\u7C98\u8D34\u8FDB\u8BBE\u7F6E\u6846\uFF0C\u662F\u8DE8\u7CFB\u7EDF\u7684\n * \u4FBF\u6377\u4EA4\u6362\u683C\u5F0F\uFF08\u4E0D\u662F\u6301\u4E45\u5316\u683C\u5F0F\uFF1B\u6301\u4E45\u5316\u4ECD\u4EE5\u5BF9\u8C61/JSON \u4FDD\u5B58\uFF09\u3002\n *\n * \u5DF2\u77E5 key\uFF1A\n * - broker (\u5FC5\u586B) MQTT broker URL\uFF0C\u5982 `wss://broker.emqx.io:8084/mqtt`\n * - topic (\u5FC5\u586B) \u8BA2\u9605 / \u53D1\u5E03\u7684 topic\n * - password \u5BF9\u5E94\u672C\u5E93\u7684 `secret`\uFF08AES \u53E3\u4EE4\uFF09\uFF1B\u4E3A\u7A7A\u8868\u793A\u4E0D\u52A0\u5BC6\uFF08encrypt=false\uFF09\n * - name (\u53EF\u9009) \u53EF\u8BFB\u6807\u7B7E\uFF0C\u4EC5\u7528\u4E8E UI\uFF0C\u4E0D\u53C2\u4E0E\u8FDE\u63A5\n *\n * \u5176\u5B83 key \u539F\u6837\u4FDD\u7559\u4E3A\u6269\u5C55\u5B57\u6BB5\uFF08\u4E0D\u53C2\u4E0E\u8FDE\u63A5\uFF0C\u4F46\u53EF\u88AB UI \u4F7F\u7528\uFF09\u3002\n *\n * \u52A0\u5BC6\u4E92\u901A\u8BF4\u660E\uFF1A\u672C\u5E93 `secret` \u7684\u52A0\u5BC6\u65B9\u6848\u4E0E CryptoJS `AES.encrypt(payload, passphrase)`\n * \u5B8C\u5168\u4E00\u81F4\uFF08OpenSSL \"Salted__\" \u683C\u5F0F + EVP_BytesToKey\uFF0CAES-256-CBC\uFF09\uFF0C\u56E0\u6B64\u540C\u4E00 `password`\n * \u5728 mqtthub \u4E0E\u672C\u5E93\u4E4B\u95F4\u53EF\u4E92\u89E3\u5BC6\u2014\u2014\u53EA\u8981\u8FDE\u63A5\u7684\u662F\u540C\u4E00\u4E2A broker/topic \u4E14\u53E3\u4EE4\u76F8\u540C\u3002\n */\nimport { InvalidConfigError } from './errors.js';\n\n/** \u5DF2\u77E5 key\uFF1A\u8FD9\u4E9B key \u5728\u5E8F\u5217\u5316/\u53CD\u5E8F\u5217\u5316\u65F6\u6709\u56FA\u5B9A\u8BED\u4E49\uFF0C\u4E0D\u53C2\u4E0E\"\u6269\u5C55\u5B57\u6BB5\"\u900F\u4F20\u903B\u8F91\u7684\u7279\u6B8A\u5904\u7406 */\nconst KNOWN_KEYS = new Set(['name', 'broker', 'topic', 'password']);\n\n/**\n * \u89E3\u6790\u914D\u7F6E\u5B57\u7B26\u4E32\uFF0C\u8FD4\u56DE\u672C\u5E93 options \u5B50\u96C6\uFF08broker / topic / secret / encrypt + \u6269\u5C55\u5B57\u6BB5\uFF09\u3002\n * \u4E0E serializeConfigString \u5728 broker / topic / secret(password) / name \u8303\u56F4\u5185\u4E92\u9006\u3002\n *\n * @param {string} str \u914D\u7F6E\u5B57\u7B26\u4E32\uFF08`key=value&...`\uFF09\n * @returns {{ broker: string, topic: string, secret: string, encrypt: boolean, [k: string]: any }}\n */\nexport function parseConfigString(str) {\n if (typeof str !== 'string' || str.trim().length === 0) {\n throw new InvalidConfigError('\u914D\u7F6E\u5B57\u7B26\u4E32\u4E3A\u7A7A');\n }\n\n /** @type {Record<string, string>} */\n const raw = {};\n for (const pair of str.trim().split('&')) {\n if (pair.length === 0) continue;\n const idx = pair.indexOf('=');\n if (idx < 0) continue; // \u5BB9\u5FCD\u7F3A\u5C11 = \u7684\u7247\u6BB5\n const k = pair.slice(0, idx).trim();\n if (k.length === 0) continue;\n const v = decodeURIComponent(pair.slice(idx + 1));\n raw[k] = v;\n }\n\n const broker = raw.broker;\n const topic = raw.topic;\n if (!broker || !topic) {\n throw new InvalidConfigError('\u914D\u7F6E\u5B57\u7B26\u4E32\u7F3A\u5C11\u5FC5\u586B\u5B57\u6BB5 broker \u6216 topic');\n }\n\n const password = raw.password || '';\n /** @type {{ broker: string, topic: string, secret: string, encrypt: boolean, [k: string]: any }} */\n const result = {\n broker,\n topic,\n // \u5E93\u7684 secret \u5BF9\u5E94\u5B57\u7B26\u4E32\u7684 password\n secret: password,\n // \u53E3\u4EE4\u975E\u7A7A\u5373\u89C6\u4E3A\u52A0\u5BC6\uFF1B\u7A7A\u53E3\u4EE4 = \u4E0D\u52A0\u5BC6\n encrypt: password.length > 0,\n };\n\n // name \u662F\u53EF\u9009\u53EF\u8BFB\u6807\u7B7E\uFF0C\u539F\u6837\u4FDD\u7559\n if (raw.name !== undefined) result.name = raw.name;\n\n // \u900F\u4F20\u6269\u5C55\u5B57\u6BB5\uFF08\u4E0D\u53C2\u4E0E\u8FDE\u63A5\uFF0C\u4F46\u53EF\u88AB UI \u4F7F\u7528\uFF09\n for (const k of Object.keys(raw)) {\n if (KNOWN_KEYS.has(k)) continue;\n result[k] = raw[k];\n }\n\n return result;\n}\n\n/**\n * \u5C06\u914D\u7F6E\u5BF9\u8C61\u5E8F\u5217\u5316\u4E3A mqtthub \u98CE\u683C\u914D\u7F6E\u5B57\u7B26\u4E32\u3002\n * secret \u4EC5\u5728 encrypt !== false \u65F6\u6620\u5C04\u4E3A password\uFF1Bencrypt=false \u65F6 password \u4E3A\u7A7A\uFF08\u4E0D\u52A0\u5BC6\uFF09\u3002\n *\n * @param {{ broker: string, topic: string, secret?: string, encrypt?: boolean, name?: string, [k: string]: any }} opts\n * @returns {string}\n */\nexport function serializeConfigString(opts) {\n if (!opts || typeof opts !== 'object' || Array.isArray(opts)) {\n throw new InvalidConfigError('serializeConfigString \u9700\u8981\u914D\u7F6E\u5BF9\u8C61');\n }\n\n /** @type {string[]} */\n const entries = [];\n /**\n * @param {string} k\n * @param {any} v\n */\n const push = (k, v) => {\n if (v === undefined || v === null) return;\n entries.push(`${k}=${encodeURIComponent(String(v))}`);\n };\n\n // name \u5728\u524D\uFF0C\u4FBF\u4E8E\u4EBA\u5DE5\u9605\u8BFB\n if (opts.name !== undefined) push('name', opts.name);\n push('broker', opts.broker);\n push('topic', opts.topic);\n\n // \u5E93\u7684 secret \u6620\u5C04\u4E3A\u5B57\u7B26\u4E32\u7684 password\uFF1Bencrypt=false \u65F6\u89C6\u4E3A\u4E0D\u52A0\u5BC6\uFF08password \u4E3A\u7A7A\uFF09\n const password = opts.encrypt === false ? '' : (opts.secret ?? '');\n push('password', password);\n\n // \u900F\u4F20\u6269\u5C55\u5B57\u6BB5\uFF08\u6392\u9664\u5DF2\u663E\u5F0F\u6620\u5C04\u7684\u5B57\u6BB5\uFF09\n for (const k of Object.keys(opts)) {\n if (['broker', 'topic', 'secret', 'encrypt', 'name'].includes(k)) continue;\n push(k, opts[k]);\n }\n\n return entries.join('&');\n}\n", "/**\n * \u914D\u7F6E\u89E3\u6790\u4E0E\u5E95\u5C42 mqtt.connect options \u62FC\u88C5\u3002\n * \u8FD9\u91CC\u96C6\u4E2D\u4FDD\u7559\u539F\u5B9E\u73B0\u7684\u8FDE\u63A5\u53C2\u6570\uFF1A\u6BCF\u5B9E\u4F8B clientId\u30015s \u91CD\u8FDE\u300130s \u8FDE\u63A5\u8D85\u65F6\u3001clean session\u3002\n */\nimport { InvalidConfigError } from './errors.js';\nimport { DEFAULT_CLIENT_ID_PREFIX, DEFAULT_USER, createClientId } from './envelope.js';\nimport { DEFAULT_TOPIC, validateTopic } from './topic.js';\nimport { parseConfigString } from './config-string.js';\n\n/** \u652F\u6301\u7684 broker \u534F\u8BAE\uFF08\u5E93\u4EE5 MQTT over WebSocket \u4E3A\u4E3B\uFF0C\u540C\u65F6\u4FDD\u7559 TCP/TLS \u80FD\u529B\uFF09 */\nconst SUPPORTED_PROTOCOLS = new Set(['ws:', 'wss:', 'mqtt:', 'mqtts:', 'tcp:', 'tls:']);\n\n/**\n * \u9ED8\u8BA4\u914D\u7F6E\u3002`secret` \u5BF9\u5E94\u539F\u5B9E\u73B0\u670D\u52A1\u5668\u914D\u7F6E\u91CC\u7684 `password`\uFF08AES \u53E3\u4EE4\uFF09\u3002\n * @type {Readonly<Record<string, any>>}\n */\nexport const DEFAULT_OPTIONS = Object.freeze({\n broker: 'wss://broker.emqx.io:8084/mqtt',\n topic: DEFAULT_TOPIC,\n secret: '',\n encrypt: true,\n clientId: '',\n clientIdPrefix: DEFAULT_CLIENT_ID_PREFIX,\n clientIdSuffix: '',\n user: DEFAULT_USER,\n userSuffix: '',\n qos: 1,\n reconnectPeriod: 5000,\n connectTimeout: 30000,\n clean: true,\n resubscribe: true,\n heartbeatInterval: 30000,\n pongTimeout: 0,\n dedupeTtl: 5000,\n requestTimeout: 5000,\n auth: null,\n protocolVersion: undefined,\n});\n\n/**\n * @param {number} value\n * @param {string} name\n * @param {{ min?: number, allowZero?: boolean }} [rules]\n * @returns {number}\n */\nfunction requireNumber(value, name, rules = {}) {\n const { min = 0, allowZero = true } = rules;\n const validType = typeof value === 'number' && Number.isFinite(value);\n const validValue = validType && (allowZero ? value >= min : value > min);\n if (!validValue) {\n throw new InvalidConfigError(`${name} \u5FC5\u987B\u662F${allowZero ? ' >= ' : ' > '}${min} \u7684\u6570\u5B57`);\n }\n return value;\n}\n\n/**\n * @param {string} broker\n * @returns {string}\n */\nfunction validateBroker(broker) {\n if (typeof broker !== 'string' || broker.length === 0) {\n throw new InvalidConfigError('broker \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32');\n }\n let url;\n try {\n url = new URL(broker);\n } catch {\n throw new InvalidConfigError(`broker \u4E0D\u662F\u5408\u6CD5 URL: ${broker}`);\n }\n if (!SUPPORTED_PROTOCOLS.has(url.protocol)) {\n throw new InvalidConfigError(`\u4E0D\u652F\u6301\u7684 broker \u534F\u8BAE: ${url.protocol}\uFF08\u652F\u6301 ws/wss/mqtt/mqtts/tcp/tls\uFF09`);\n }\n if (!url.hostname) {\n throw new InvalidConfigError('broker \u7F3A\u5C11\u4E3B\u673A\u540D');\n }\n return broker;\n}\n\n/**\n * \u5408\u5E76\u5E76\u6821\u9A8C\u914D\u7F6E\uFF0C\u8FD4\u56DE\u89C4\u8303\u5316\u540E\u7684\u53EA\u8BFB\u914D\u7F6E\u5BF9\u8C61\u3002\n * @param {Partial<typeof DEFAULT_OPTIONS> & { auth?: { username?: string, password?: string } | null }} [input]\n * @returns {Readonly<Record<string, any>>}\n */\nexport function resolveOptions(input = {}) {\n // \u652F\u6301\u76F4\u63A5\u4F20\u5165 mqtthub \u98CE\u683C\u914D\u7F6E\u5B57\u7B26\u4E32\uFF08key=value&...\uFF09\n if (typeof input === 'string') {\n input = parseConfigString(input);\n }\n if (!input || typeof input !== 'object' || Array.isArray(input)) {\n throw new InvalidConfigError('options \u5FC5\u987B\u662F\u5BF9\u8C61\u6216\u914D\u7F6E\u5B57\u7B26\u4E32');\n }\n\n const options = { ...DEFAULT_OPTIONS, ...input };\n\n options.broker = validateBroker(options.broker);\n options.topic = validateTopic(options.topic);\n\n if (typeof options.secret !== 'string') {\n throw new InvalidConfigError('secret \u5FC5\u987B\u662F\u5B57\u7B26\u4E32');\n }\n if (options.encrypt !== false && options.secret.length === 0) {\n throw new InvalidConfigError('encrypt \u4E3A true \u65F6\u5FC5\u987B\u63D0\u4F9B\u975E\u7A7A secret');\n }\n if (typeof options.encrypt !== 'boolean') {\n throw new InvalidConfigError('encrypt \u5FC5\u987B\u662F\u5E03\u5C14\u503C');\n }\n\n if (options.clientId !== '' && typeof options.clientId !== 'string') {\n throw new InvalidConfigError('clientId \u5FC5\u987B\u662F\u5B57\u7B26\u4E32');\n }\n if (typeof options.clientIdPrefix !== 'string') {\n throw new InvalidConfigError('clientIdPrefix \u5FC5\u987B\u662F\u5B57\u7B26\u4E32');\n }\n if (typeof options.clientIdSuffix !== 'string') {\n throw new InvalidConfigError('clientIdSuffix \u5FC5\u987B\u662F\u5B57\u7B26\u4E32');\n }\n if (!options.clientId) {\n options.clientId = createClientId(options.clientIdPrefix);\n }\n if (!options.clientId) {\n throw new InvalidConfigError('clientId \u4E0D\u80FD\u4E3A\u7A7A');\n }\n\n if (typeof options.user !== 'string' || options.user.length === 0) {\n throw new InvalidConfigError('user \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32');\n }\n if (typeof options.userSuffix !== 'string') {\n throw new InvalidConfigError('userSuffix \u5FC5\u987B\u662F\u5B57\u7B26\u4E32');\n }\n\n if (![0, 1, 2].includes(options.qos)) {\n throw new InvalidConfigError('qos \u53EA\u80FD\u662F 0\u30011 \u6216 2');\n }\n\n options.reconnectPeriod = requireNumber(options.reconnectPeriod, 'reconnectPeriod');\n options.connectTimeout = requireNumber(options.connectTimeout, 'connectTimeout', { allowZero: false });\n options.heartbeatInterval = requireNumber(options.heartbeatInterval, 'heartbeatInterval');\n options.pongTimeout = requireNumber(options.pongTimeout, 'pongTimeout');\n options.dedupeTtl = requireNumber(options.dedupeTtl, 'dedupeTtl');\n options.requestTimeout = requireNumber(options.requestTimeout, 'requestTimeout', { allowZero: false });\n\n if (typeof options.clean !== 'boolean') {\n throw new InvalidConfigError('clean \u5FC5\u987B\u662F\u5E03\u5C14\u503C');\n }\n if (typeof options.resubscribe !== 'boolean') {\n throw new InvalidConfigError('resubscribe \u5FC5\u987B\u662F\u5E03\u5C14\u503C');\n }\n\n if (options.protocolVersion !== undefined && ![4, 5].includes(options.protocolVersion)) {\n throw new InvalidConfigError('protocolVersion \u53EA\u80FD\u662F 4 \u6216 5');\n }\n\n if (options.auth !== null && options.auth !== undefined) {\n const { username, password } = options.auth;\n if (typeof options.auth !== 'object' || Array.isArray(options.auth)) {\n throw new InvalidConfigError('auth \u5FC5\u987B\u662F\u5BF9\u8C61');\n }\n if (username !== undefined && typeof username !== 'string') {\n throw new InvalidConfigError('auth.username \u5FC5\u987B\u662F\u5B57\u7B26\u4E32');\n }\n if (password !== undefined && typeof password !== 'string') {\n throw new InvalidConfigError('auth.password \u5FC5\u987B\u662F\u5B57\u7B26\u4E32');\n }\n options.auth = { username, password };\n } else {\n options.auth = null;\n }\n\n return Object.freeze(options);\n}\n\n/**\n * \u751F\u6210\u4F20\u7ED9 `mqtt.connect()` \u7684 options\u3002\n * \u539F\u5B9E\u73B0\uFF1AclientId = \u57FA\u7840 clientId + '_' + serverId\uFF1BreconnectPeriod=5000\uFF1BconnectTimeout=30000\uFF1Bclean=true\u3002\n * @param {ReturnType<typeof resolveOptions>} options\n * @returns {Record<string, any>}\n */\nexport function buildMqttOptions(options) {\n if (!options || typeof options !== 'object') {\n throw new InvalidConfigError('buildMqttOptions \u9700\u8981 resolveOptions \u7684\u7ED3\u679C');\n }\n\n /** @type {Record<string, any>} */\n const mqttOptions = {\n clientId: `${options.clientId}${options.clientIdSuffix}`,\n reconnectPeriod: options.reconnectPeriod,\n connectTimeout: options.connectTimeout,\n clean: options.clean,\n resubscribe: options.resubscribe,\n };\n\n if (options.protocolVersion !== undefined) {\n mqttOptions.protocolVersion = options.protocolVersion;\n }\n if (options.auth) {\n if (options.auth.username !== undefined) mqttOptions.username = options.auth.username;\n if (options.auth.password !== undefined) mqttOptions.password = options.auth.password;\n }\n\n return mqttOptions;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["mqtt"]
|
|
7
7
|
}
|