ylib-wecom-openclaw-plugin 2026.4.29
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 +596 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +99 -0
- package/dist/src/accounts.d.ts +57 -0
- package/dist/src/accounts.js +247 -0
- package/dist/src/agent/api-client.d.ts +95 -0
- package/dist/src/agent/api-client.js +425 -0
- package/dist/src/agent/handler.d.ts +64 -0
- package/dist/src/agent/handler.js +731 -0
- package/dist/src/agent/index.d.ts +5 -0
- package/dist/src/agent/index.js +21 -0
- package/dist/src/agent/webhook.d.ts +25 -0
- package/dist/src/agent/webhook.js +294 -0
- package/dist/src/agent/xml.d.ts +21 -0
- package/dist/src/agent/xml.js +43 -0
- package/dist/src/channel.d.ts +5 -0
- package/dist/src/channel.js +815 -0
- package/dist/src/chat-queue.d.ts +31 -0
- package/dist/src/chat-queue.js +53 -0
- package/dist/src/config-schema.d.ts +587 -0
- package/dist/src/config-schema.js +146 -0
- package/dist/src/const.d.ts +128 -0
- package/dist/src/const.js +168 -0
- package/dist/src/dm-policy.d.ts +29 -0
- package/dist/src/dm-policy.js +146 -0
- package/dist/src/dynamic-agent.d.ts +37 -0
- package/dist/src/dynamic-agent.js +67 -0
- package/dist/src/dynamic-routing.d.ts +65 -0
- package/dist/src/dynamic-routing.js +62 -0
- package/dist/src/endpoint-dispatch.d.ts +54 -0
- package/dist/src/endpoint-dispatch.js +967 -0
- package/dist/src/endpoint-event-adapter.d.ts +15 -0
- package/dist/src/endpoint-event-adapter.js +427 -0
- package/dist/src/group-policy.d.ts +30 -0
- package/dist/src/group-policy.js +126 -0
- package/dist/src/http.d.ts +27 -0
- package/dist/src/http.js +168 -0
- package/dist/src/im-runtime-telemetry.d.ts +25 -0
- package/dist/src/im-runtime-telemetry.js +68 -0
- package/dist/src/interface.d.ts +192 -0
- package/dist/src/interface.js +5 -0
- package/dist/src/markdown-chunk.d.ts +1 -0
- package/dist/src/markdown-chunk.js +396 -0
- package/dist/src/mcp/index.d.ts +6 -0
- package/dist/src/mcp/index.js +28 -0
- package/dist/src/mcp/interceptors/biz-error.d.ts +11 -0
- package/dist/src/mcp/interceptors/biz-error.js +73 -0
- package/dist/src/mcp/interceptors/doc-auth-error.d.ts +10 -0
- package/dist/src/mcp/interceptors/doc-auth-error.js +235 -0
- package/dist/src/mcp/interceptors/index.d.ts +35 -0
- package/dist/src/mcp/interceptors/index.js +143 -0
- package/dist/src/mcp/interceptors/msg-media.d.ts +11 -0
- package/dist/src/mcp/interceptors/msg-media.js +201 -0
- package/dist/src/mcp/interceptors/smartpage-create.d.ts +30 -0
- package/dist/src/mcp/interceptors/smartpage-create.js +252 -0
- package/dist/src/mcp/interceptors/smartpage-export.d.ts +17 -0
- package/dist/src/mcp/interceptors/smartpage-export.js +135 -0
- package/dist/src/mcp/interceptors/smartsheet-upload.d.ts +22 -0
- package/dist/src/mcp/interceptors/smartsheet-upload.js +388 -0
- package/dist/src/mcp/interceptors/types.d.ts +64 -0
- package/dist/src/mcp/interceptors/types.js +8 -0
- package/dist/src/mcp/schema.d.ts +11 -0
- package/dist/src/mcp/schema.js +115 -0
- package/dist/src/mcp/tool.d.ts +63 -0
- package/dist/src/mcp/tool.js +318 -0
- package/dist/src/mcp/transport.d.ts +94 -0
- package/dist/src/mcp/transport.js +702 -0
- package/dist/src/media-handler.d.ts +55 -0
- package/dist/src/media-handler.js +306 -0
- package/dist/src/media-uploader.d.ts +142 -0
- package/dist/src/media-uploader.js +446 -0
- package/dist/src/message-parser.d.ts +104 -0
- package/dist/src/message-parser.js +232 -0
- package/dist/src/message-sender.d.ts +54 -0
- package/dist/src/message-sender.js +210 -0
- package/dist/src/monitor.d.ts +69 -0
- package/dist/src/monitor.js +1846 -0
- package/dist/src/onboarding.d.ts +8 -0
- package/dist/src/onboarding.js +248 -0
- package/dist/src/openclaw-compat.d.ts +148 -0
- package/dist/src/openclaw-compat.js +839 -0
- package/dist/src/proactive-markdown-send.d.ts +14 -0
- package/dist/src/proactive-markdown-send.js +205 -0
- package/dist/src/reqid-store.d.ts +23 -0
- package/dist/src/reqid-store.js +136 -0
- package/dist/src/runtime.d.ts +2 -0
- package/dist/src/runtime.js +7 -0
- package/dist/src/shared/command-auth.d.ts +23 -0
- package/dist/src/shared/command-auth.js +112 -0
- package/dist/src/shared/xml-parser.d.ts +46 -0
- package/dist/src/shared/xml-parser.js +228 -0
- package/dist/src/state-dir-resolve.d.ts +2 -0
- package/dist/src/state-dir-resolve.js +33 -0
- package/dist/src/state-manager.d.ts +115 -0
- package/dist/src/state-manager.js +413 -0
- package/dist/src/target.d.ts +35 -0
- package/dist/src/target.js +71 -0
- package/dist/src/template-card-manager.d.ts +55 -0
- package/dist/src/template-card-manager.js +316 -0
- package/dist/src/template-card-parser.d.ts +37 -0
- package/dist/src/template-card-parser.js +672 -0
- package/dist/src/timeout.d.ts +20 -0
- package/dist/src/timeout.js +57 -0
- package/dist/src/types/account.d.ts +29 -0
- package/dist/src/types/account.js +5 -0
- package/dist/src/types/config.d.ts +98 -0
- package/dist/src/types/config.js +8 -0
- package/dist/src/types/constants.d.ts +42 -0
- package/dist/src/types/constants.js +45 -0
- package/dist/src/types/index.d.ts +7 -0
- package/dist/src/types/index.js +17 -0
- package/dist/src/types/message.d.ts +238 -0
- package/dist/src/types/message.js +6 -0
- package/dist/src/utils.d.ts +148 -0
- package/dist/src/utils.js +92 -0
- package/dist/src/version.d.ts +2 -0
- package/dist/src/version.js +28 -0
- package/dist/src/webhook/command-auth.d.ts +47 -0
- package/dist/src/webhook/command-auth.js +137 -0
- package/dist/src/webhook/gateway.d.ts +36 -0
- package/dist/src/webhook/gateway.js +297 -0
- package/dist/src/webhook/handler.d.ts +19 -0
- package/dist/src/webhook/handler.js +481 -0
- package/dist/src/webhook/helpers.d.ts +157 -0
- package/dist/src/webhook/helpers.js +936 -0
- package/dist/src/webhook/http.d.ts +27 -0
- package/dist/src/webhook/http.js +168 -0
- package/dist/src/webhook/index.d.ts +11 -0
- package/dist/src/webhook/index.js +43 -0
- package/dist/src/webhook/media.d.ts +30 -0
- package/dist/src/webhook/media.js +152 -0
- package/dist/src/webhook/monitor.d.ts +59 -0
- package/dist/src/webhook/monitor.js +1672 -0
- package/dist/src/webhook/state.d.ts +220 -0
- package/dist/src/webhook/state.js +568 -0
- package/dist/src/webhook/target.d.ts +41 -0
- package/dist/src/webhook/target.js +165 -0
- package/dist/src/webhook/types.d.ts +348 -0
- package/dist/src/webhook/types.js +36 -0
- package/dist/src/webhook/video-frame.d.ts +13 -0
- package/dist/src/webhook/video-frame.js +108 -0
- package/openclaw.plugin.json +19 -0
- package/package.json +96 -0
- package/schema.json +534 -0
- package/scripts/generate-schema.mjs +33 -0
- package/skills/wecom-contact/SKILL.md +162 -0
- package/skills/wecom-doc/SKILL.md +162 -0
- package/skills/wecom-doc/references/create-doc.md +56 -0
- package/skills/wecom-doc/references/edit-doc-content.md +68 -0
- package/skills/wecom-doc/references/get-doc-content.md +88 -0
- package/skills/wecom-doc/references/smartpage-create.md +125 -0
- package/skills/wecom-doc/references/smartpage-export.md +160 -0
- package/skills/wecom-meeting/SKILL.md +441 -0
- package/skills/wecom-meeting/references/example-full.md +30 -0
- package/skills/wecom-meeting/references/example-reminder.md +46 -0
- package/skills/wecom-meeting/references/example-security.md +22 -0
- package/skills/wecom-meeting/references/response-get-meeting-info.md +148 -0
- package/skills/wecom-msg/SKILL.md +157 -0
- package/skills/wecom-msg/references/api-get-messages.md +93 -0
- package/skills/wecom-msg/references/api-get-msg-chat-list.md +58 -0
- package/skills/wecom-msg/references/api-get-msg-media.md +44 -0
- package/skills/wecom-msg/references/api-send-message.md +39 -0
- package/skills/wecom-preflight/SKILL.md +141 -0
- package/skills/wecom-schedule/SKILL.md +161 -0
- package/skills/wecom-schedule/references/api-check-availability.md +56 -0
- package/skills/wecom-schedule/references/api-create-schedule.md +38 -0
- package/skills/wecom-schedule/references/api-get-schedule-detail.md +81 -0
- package/skills/wecom-schedule/references/api-update-schedule.md +32 -0
- package/skills/wecom-schedule/references/ref-reminders.md +24 -0
- package/skills/wecom-send-media/SKILL.md +68 -0
- package/skills/wecom-send-template-card/SKILL.md +157 -0
- package/skills/wecom-send-template-card/references/api-template-card-types.md +358 -0
- package/skills/wecom-smartsheet/SKILL.md +164 -0
- package/skills/wecom-smartsheet/references/smartsheet-cell-value-formats.md +163 -0
- package/skills/wecom-smartsheet/references/smartsheet-field-types.md +44 -0
- package/skills/wecom-smartsheet/references/smartsheet-get-records.md +96 -0
- package/skills/wecom-smartsheet/references/webhook-examples.md +185 -0
- package/skills/wecom-smartsheet/references/webhook-fallback.md +184 -0
- package/skills/wecom-todo/SKILL.md +392 -0
- package/skills/wecom-todo/examples/workflows.md +163 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/**
|
|
3
|
+
* **WecomHttpOptions (HTTP 选项)**
|
|
4
|
+
*
|
|
5
|
+
* @property proxyUrl 代理服务器地址
|
|
6
|
+
* @property timeoutMs 请求超时时间 (毫秒)
|
|
7
|
+
* @property signal AbortSignal 信号
|
|
8
|
+
*/
|
|
9
|
+
export declare type WecomHttpOptions = {
|
|
10
|
+
proxyUrl?: string;
|
|
11
|
+
timeoutMs?: number;
|
|
12
|
+
signal?: AbortSignal;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* **wecomFetch (统一 HTTP 请求)**
|
|
16
|
+
*
|
|
17
|
+
* 基于 `undici` 的 fetch 封装,自动处理 ProxyAgent 和 Timeout。
|
|
18
|
+
* 所有对企业微信 API 的调用都应经过此函数。
|
|
19
|
+
*/
|
|
20
|
+
export declare function wecomFetch(input: string | URL, init?: RequestInit, opts?: WecomHttpOptions): Promise<Response>;
|
|
21
|
+
/**
|
|
22
|
+
* **readResponseBodyAsBuffer (读取响应 Body)**
|
|
23
|
+
*
|
|
24
|
+
* 将 Response Body 读取为 Buffer,支持最大字节限制以防止内存溢出。
|
|
25
|
+
* 适用于下载媒体文件等场景。
|
|
26
|
+
*/
|
|
27
|
+
export declare function readResponseBodyAsBuffer(res: Response, maxBytes?: number): Promise<Buffer>;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
14
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
15
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
16
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
17
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
18
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
19
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
23
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
24
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
25
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
26
|
+
function step(op) {
|
|
27
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
28
|
+
while (_) try {
|
|
29
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
30
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
31
|
+
switch (op[0]) {
|
|
32
|
+
case 0: case 1: t = op; break;
|
|
33
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
34
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
35
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
36
|
+
default:
|
|
37
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
38
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
39
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
40
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
41
|
+
if (t[2]) _.ops.pop();
|
|
42
|
+
_.trys.pop(); continue;
|
|
43
|
+
}
|
|
44
|
+
op = body.call(thisArg, _);
|
|
45
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
46
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
exports.__esModule = true;
|
|
50
|
+
exports.readResponseBodyAsBuffer = exports.wecomFetch = void 0;
|
|
51
|
+
var undici_1 = require("undici");
|
|
52
|
+
var proxyDispatchers = new Map();
|
|
53
|
+
/**
|
|
54
|
+
* **getProxyDispatcher (获取代理 Dispatcher)**
|
|
55
|
+
*
|
|
56
|
+
* 缓存并复用 ProxyAgent,避免重复创建连接池。
|
|
57
|
+
*/
|
|
58
|
+
function getProxyDispatcher(proxyUrl) {
|
|
59
|
+
var existing = proxyDispatchers.get(proxyUrl);
|
|
60
|
+
if (existing)
|
|
61
|
+
return existing;
|
|
62
|
+
var created = new undici_1.ProxyAgent(proxyUrl);
|
|
63
|
+
proxyDispatchers.set(proxyUrl, created);
|
|
64
|
+
return created;
|
|
65
|
+
}
|
|
66
|
+
function mergeAbortSignal(params) {
|
|
67
|
+
var signals = [];
|
|
68
|
+
if (params.signal)
|
|
69
|
+
signals.push(params.signal);
|
|
70
|
+
if (params.timeoutMs && Number.isFinite(params.timeoutMs) && params.timeoutMs > 0) {
|
|
71
|
+
signals.push(AbortSignal.timeout(params.timeoutMs));
|
|
72
|
+
}
|
|
73
|
+
if (!signals.length)
|
|
74
|
+
return undefined;
|
|
75
|
+
if (signals.length === 1)
|
|
76
|
+
return signals[0];
|
|
77
|
+
return AbortSignal.any(signals);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* **wecomFetch (统一 HTTP 请求)**
|
|
81
|
+
*
|
|
82
|
+
* 基于 `undici` 的 fetch 封装,自动处理 ProxyAgent 和 Timeout。
|
|
83
|
+
* 所有对企业微信 API 的调用都应经过此函数。
|
|
84
|
+
*/
|
|
85
|
+
function wecomFetch(input, init, opts) {
|
|
86
|
+
var _a, _b, _c, _d, _e;
|
|
87
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
88
|
+
var proxyUrl, dispatcher, initSignal, signal, headers, nextInit, err_1, cause;
|
|
89
|
+
return __generator(this, function (_f) {
|
|
90
|
+
switch (_f.label) {
|
|
91
|
+
case 0:
|
|
92
|
+
proxyUrl = (_b = (_a = opts === null || opts === void 0 ? void 0 : opts.proxyUrl) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : "";
|
|
93
|
+
dispatcher = proxyUrl ? getProxyDispatcher(proxyUrl) : undefined;
|
|
94
|
+
initSignal = (_c = init === null || init === void 0 ? void 0 : init.signal) !== null && _c !== void 0 ? _c : undefined;
|
|
95
|
+
signal = mergeAbortSignal({ signal: (_d = opts === null || opts === void 0 ? void 0 : opts.signal) !== null && _d !== void 0 ? _d : initSignal, timeoutMs: opts === null || opts === void 0 ? void 0 : opts.timeoutMs });
|
|
96
|
+
headers = new Headers((_e = init === null || init === void 0 ? void 0 : init.headers) !== null && _e !== void 0 ? _e : {});
|
|
97
|
+
if (!headers.has("User-Agent")) {
|
|
98
|
+
headers.set("User-Agent", "OpenClaw/2.0 (WeCom-Agent)");
|
|
99
|
+
}
|
|
100
|
+
nextInit = __assign(__assign(__assign(__assign({}, (init !== null && init !== void 0 ? init : {})), (signal ? { signal: signal } : {})), (dispatcher ? { dispatcher: dispatcher } : {})), { headers: headers });
|
|
101
|
+
_f.label = 1;
|
|
102
|
+
case 1:
|
|
103
|
+
_f.trys.push([1, 3, , 4]);
|
|
104
|
+
return [4 /*yield*/, undici_1.fetch(input, nextInit)];
|
|
105
|
+
case 2: return [2 /*return*/, _f.sent()];
|
|
106
|
+
case 3:
|
|
107
|
+
err_1 = _f.sent();
|
|
108
|
+
if (err_1 instanceof Error && err_1.name === "TypeError" && err_1.message === "fetch failed") {
|
|
109
|
+
cause = err_1.cause;
|
|
110
|
+
console.error("[wecom-http] fetch failed: " + input + " (proxy: " + (proxyUrl || "none") + ")" + (cause ? " - cause: " + String(cause) : ""));
|
|
111
|
+
}
|
|
112
|
+
throw err_1;
|
|
113
|
+
case 4: return [2 /*return*/];
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
exports.wecomFetch = wecomFetch;
|
|
119
|
+
/**
|
|
120
|
+
* **readResponseBodyAsBuffer (读取响应 Body)**
|
|
121
|
+
*
|
|
122
|
+
* 将 Response Body 读取为 Buffer,支持最大字节限制以防止内存溢出。
|
|
123
|
+
* 适用于下载媒体文件等场景。
|
|
124
|
+
*/
|
|
125
|
+
function readResponseBodyAsBuffer(res, maxBytes) {
|
|
126
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
127
|
+
var limit, chunks, total, reader, _a, done, value, _b;
|
|
128
|
+
return __generator(this, function (_c) {
|
|
129
|
+
switch (_c.label) {
|
|
130
|
+
case 0:
|
|
131
|
+
if (!res.body)
|
|
132
|
+
return [2 /*return*/, Buffer.alloc(0)];
|
|
133
|
+
limit = maxBytes && Number.isFinite(maxBytes) && maxBytes > 0 ? maxBytes : undefined;
|
|
134
|
+
chunks = [];
|
|
135
|
+
total = 0;
|
|
136
|
+
reader = res.body.getReader();
|
|
137
|
+
_c.label = 1;
|
|
138
|
+
case 1:
|
|
139
|
+
if (!true) return [3 /*break*/, 8];
|
|
140
|
+
return [4 /*yield*/, reader.read()];
|
|
141
|
+
case 2:
|
|
142
|
+
_a = _c.sent(), done = _a.done, value = _a.value;
|
|
143
|
+
if (done)
|
|
144
|
+
return [3 /*break*/, 8];
|
|
145
|
+
if (!value)
|
|
146
|
+
return [3 /*break*/, 1];
|
|
147
|
+
total += value.byteLength;
|
|
148
|
+
if (!(limit && total > limit)) return [3 /*break*/, 7];
|
|
149
|
+
_c.label = 3;
|
|
150
|
+
case 3:
|
|
151
|
+
_c.trys.push([3, 5, , 6]);
|
|
152
|
+
return [4 /*yield*/, reader.cancel("body too large")];
|
|
153
|
+
case 4:
|
|
154
|
+
_c.sent();
|
|
155
|
+
return [3 /*break*/, 6];
|
|
156
|
+
case 5:
|
|
157
|
+
_b = _c.sent();
|
|
158
|
+
return [3 /*break*/, 6];
|
|
159
|
+
case 6: throw new Error("response body too large (>" + limit + " bytes)");
|
|
160
|
+
case 7:
|
|
161
|
+
chunks.push(value);
|
|
162
|
+
return [3 /*break*/, 1];
|
|
163
|
+
case 8: return [2 /*return*/, Buffer.concat(chunks.map(function (c) { return Buffer.from(c); }))];
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
exports.readResponseBodyAsBuffer = readResponseBodyAsBuffer;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Webhook 模块公共入口
|
|
3
|
+
*
|
|
4
|
+
* Re-export 所有 Webhook 模式对外暴露的函数和类型。
|
|
5
|
+
*/
|
|
6
|
+
export { handleWecomWebhookRequest } from "./handler.js";
|
|
7
|
+
export { registerWecomWebhookTarget, getRegisteredTargets, getWebhookTargetsMap, hasActiveTargets, parseWebhookPath, } from "./target.js";
|
|
8
|
+
export { startWebhookGateway, stopWebhookGateway, getMonitorState } from "./gateway.js";
|
|
9
|
+
export type { WecomWebhookTarget, WebhookGatewayContext, ResolvedWebhookAccount, WebhookAccountConfig, WecomRuntimeEnv, StreamState, PendingInbound, ActiveReplyState, WebhookInboundMessage, } from "./types.js";
|
|
10
|
+
export { STREAM_TTL_MS, ACTIVE_REPLY_TTL_MS, DEFAULT_DEBOUNCE_MS, STREAM_MAX_BYTES, BOT_WINDOW_MS, BOT_SWITCH_MARGIN_MS, REQUEST_TIMEOUT_MS, PRUNE_INTERVAL_MS, WEBHOOK_PATHS, } from "./types.js";
|
|
11
|
+
export { monitorState, WebhookMonitorState } from "./state.js";
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Webhook 模块公共入口
|
|
4
|
+
*
|
|
5
|
+
* Re-export 所有 Webhook 模式对外暴露的函数和类型。
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
exports.__esModule = true;
|
|
15
|
+
// ── Handler ─────────────────────────────────────────────────────────
|
|
16
|
+
var handler_js_1 = require("./handler.js");
|
|
17
|
+
__createBinding(exports, handler_js_1, "handleWecomWebhookRequest");
|
|
18
|
+
// ── Target ──────────────────────────────────────────────────────────
|
|
19
|
+
var target_js_1 = require("./target.js");
|
|
20
|
+
__createBinding(exports, target_js_1, "registerWecomWebhookTarget");
|
|
21
|
+
__createBinding(exports, target_js_1, "getRegisteredTargets");
|
|
22
|
+
__createBinding(exports, target_js_1, "getWebhookTargetsMap");
|
|
23
|
+
__createBinding(exports, target_js_1, "hasActiveTargets");
|
|
24
|
+
__createBinding(exports, target_js_1, "parseWebhookPath");
|
|
25
|
+
// ── Gateway ─────────────────────────────────────────────────────────
|
|
26
|
+
var gateway_js_1 = require("./gateway.js");
|
|
27
|
+
__createBinding(exports, gateway_js_1, "startWebhookGateway");
|
|
28
|
+
__createBinding(exports, gateway_js_1, "stopWebhookGateway");
|
|
29
|
+
__createBinding(exports, gateway_js_1, "getMonitorState");
|
|
30
|
+
var types_js_1 = require("./types.js");
|
|
31
|
+
__createBinding(exports, types_js_1, "STREAM_TTL_MS");
|
|
32
|
+
__createBinding(exports, types_js_1, "ACTIVE_REPLY_TTL_MS");
|
|
33
|
+
__createBinding(exports, types_js_1, "DEFAULT_DEBOUNCE_MS");
|
|
34
|
+
__createBinding(exports, types_js_1, "STREAM_MAX_BYTES");
|
|
35
|
+
__createBinding(exports, types_js_1, "BOT_WINDOW_MS");
|
|
36
|
+
__createBinding(exports, types_js_1, "BOT_SWITCH_MARGIN_MS");
|
|
37
|
+
__createBinding(exports, types_js_1, "REQUEST_TIMEOUT_MS");
|
|
38
|
+
__createBinding(exports, types_js_1, "PRUNE_INTERVAL_MS");
|
|
39
|
+
__createBinding(exports, types_js_1, "WEBHOOK_PATHS");
|
|
40
|
+
// ── State (全局单例) ────────────────────────────────────────────────
|
|
41
|
+
var state_js_1 = require("./state.js");
|
|
42
|
+
__createBinding(exports, state_js_1, "monitorState");
|
|
43
|
+
__createBinding(exports, state_js_1, "WebhookMonitorState");
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Webhook 入站媒体处理
|
|
3
|
+
*
|
|
4
|
+
* 从 @mocrane/wecom media.ts 部分迁移(仅入站解密)。
|
|
5
|
+
* 负责:AES-CBC 解密企微加密媒体文件、MIME 类型检测。
|
|
6
|
+
*/
|
|
7
|
+
/// <reference types="node" />
|
|
8
|
+
import { WecomHttpOptions } from "./http.js";
|
|
9
|
+
/** 企微使用 32 字节 PKCS#7 块大小(不是 AES 的 16 字节块) */
|
|
10
|
+
export declare const WECOM_PKCS7_BLOCK_SIZE = 32;
|
|
11
|
+
/** 解密后的媒体文件及源信息(对齐原版 DecryptedWecomMedia) */
|
|
12
|
+
export declare type DecryptedWecomMedia = {
|
|
13
|
+
buffer: Buffer;
|
|
14
|
+
/** HTTP Content-Type(归一化后) */
|
|
15
|
+
sourceContentType?: string;
|
|
16
|
+
/** 从 Content-Disposition 提取的文件名 */
|
|
17
|
+
sourceFilename?: string;
|
|
18
|
+
/** 最终请求 URL(跟随重定向后) */
|
|
19
|
+
sourceUrl?: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* **decryptWecomMediaWithMeta (解密企业微信媒体并返回源信息)**
|
|
23
|
+
*
|
|
24
|
+
* 在返回解密结果的同时,保留下载响应中的元信息(content-type / filename / final url),
|
|
25
|
+
* 供上层更准确地推断文件后缀和 MIME。
|
|
26
|
+
*/
|
|
27
|
+
export declare function decryptWecomMediaWithMeta(url: string, encodingAESKey: string, params?: {
|
|
28
|
+
maxBytes?: number;
|
|
29
|
+
http?: WecomHttpOptions;
|
|
30
|
+
}): Promise<DecryptedWecomMedia>;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Webhook 入站媒体处理
|
|
4
|
+
*
|
|
5
|
+
* 从 @mocrane/wecom media.ts 部分迁移(仅入站解密)。
|
|
6
|
+
* 负责:AES-CBC 解密企微加密媒体文件、MIME 类型检测。
|
|
7
|
+
*/
|
|
8
|
+
var __assign = (this && this.__assign) || function () {
|
|
9
|
+
__assign = Object.assign || function(t) {
|
|
10
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
11
|
+
s = arguments[i];
|
|
12
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
13
|
+
t[p] = s[p];
|
|
14
|
+
}
|
|
15
|
+
return t;
|
|
16
|
+
};
|
|
17
|
+
return __assign.apply(this, arguments);
|
|
18
|
+
};
|
|
19
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
20
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
21
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
22
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
23
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
24
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
25
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
29
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
30
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
31
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
32
|
+
function step(op) {
|
|
33
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
34
|
+
while (_) try {
|
|
35
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
36
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
37
|
+
switch (op[0]) {
|
|
38
|
+
case 0: case 1: t = op; break;
|
|
39
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
40
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
41
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
42
|
+
default:
|
|
43
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
44
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
45
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
46
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
47
|
+
if (t[2]) _.ops.pop();
|
|
48
|
+
_.trys.pop(); continue;
|
|
49
|
+
}
|
|
50
|
+
op = body.call(thisArg, _);
|
|
51
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
52
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
56
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
57
|
+
};
|
|
58
|
+
exports.__esModule = true;
|
|
59
|
+
exports.decryptWecomMediaWithMeta = exports.WECOM_PKCS7_BLOCK_SIZE = void 0;
|
|
60
|
+
var node_crypto_1 = __importDefault(require("node:crypto"));
|
|
61
|
+
var aibot_node_sdk_1 = require("@wecom/aibot-node-sdk");
|
|
62
|
+
var http_js_1 = require("./http.js");
|
|
63
|
+
// ============================================================================
|
|
64
|
+
// 媒体文件解密
|
|
65
|
+
// ============================================================================
|
|
66
|
+
/** 企微使用 32 字节 PKCS#7 块大小(不是 AES 的 16 字节块) */
|
|
67
|
+
exports.WECOM_PKCS7_BLOCK_SIZE = 32;
|
|
68
|
+
/**
|
|
69
|
+
* **decryptWecomMediaWithMeta (解密企业微信媒体并返回源信息)**
|
|
70
|
+
*
|
|
71
|
+
* 在返回解密结果的同时,保留下载响应中的元信息(content-type / filename / final url),
|
|
72
|
+
* 供上层更准确地推断文件后缀和 MIME。
|
|
73
|
+
*/
|
|
74
|
+
function decryptWecomMediaWithMeta(url, encodingAESKey, params) {
|
|
75
|
+
var _a, _b;
|
|
76
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
77
|
+
var res, sourceContentType, sourceFilename, sourceUrl, encryptedData, aesKey, iv, decipher, decryptedPadded;
|
|
78
|
+
return __generator(this, function (_c) {
|
|
79
|
+
switch (_c.label) {
|
|
80
|
+
case 0: return [4 /*yield*/, http_js_1.wecomFetch(url, undefined, __assign(__assign({}, params === null || params === void 0 ? void 0 : params.http), { timeoutMs: (_b = (_a = params === null || params === void 0 ? void 0 : params.http) === null || _a === void 0 ? void 0 : _a.timeoutMs) !== null && _b !== void 0 ? _b : 15000 }))];
|
|
81
|
+
case 1:
|
|
82
|
+
res = _c.sent();
|
|
83
|
+
if (!res.ok) {
|
|
84
|
+
throw new Error("failed to download media: " + res.status);
|
|
85
|
+
}
|
|
86
|
+
sourceContentType = normalizeMime(res.headers.get("content-type"));
|
|
87
|
+
sourceFilename = extractFilenameFromContentDisposition(res.headers.get("content-disposition"));
|
|
88
|
+
sourceUrl = res.url || url;
|
|
89
|
+
return [4 /*yield*/, http_js_1.readResponseBodyAsBuffer(res, params === null || params === void 0 ? void 0 : params.maxBytes)];
|
|
90
|
+
case 2:
|
|
91
|
+
encryptedData = _c.sent();
|
|
92
|
+
aesKey = aibot_node_sdk_1.decodeEncodingAESKey(encodingAESKey);
|
|
93
|
+
iv = aesKey.subarray(0, 16);
|
|
94
|
+
decipher = node_crypto_1["default"].createDecipheriv("aes-256-cbc", aesKey, iv);
|
|
95
|
+
decipher.setAutoPadding(false);
|
|
96
|
+
decryptedPadded = Buffer.concat([
|
|
97
|
+
decipher.update(encryptedData),
|
|
98
|
+
decipher.final(),
|
|
99
|
+
]);
|
|
100
|
+
// 4. Unpad
|
|
101
|
+
// Note: Unlike msg bodies, usually removing PKCS#7 padding is enough for media files.
|
|
102
|
+
// The Python SDK logic: pad_len = decrypted_data[-1]; decrypted_data = decrypted_data[:-pad_len]
|
|
103
|
+
// Our pkcs7Unpad function does exactly this + validation.
|
|
104
|
+
return [2 /*return*/, {
|
|
105
|
+
buffer: aibot_node_sdk_1.pkcs7Unpad(decryptedPadded, exports.WECOM_PKCS7_BLOCK_SIZE),
|
|
106
|
+
sourceContentType: sourceContentType,
|
|
107
|
+
sourceFilename: sourceFilename,
|
|
108
|
+
sourceUrl: sourceUrl
|
|
109
|
+
}];
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
exports.decryptWecomMediaWithMeta = decryptWecomMediaWithMeta;
|
|
115
|
+
// ============================================================================
|
|
116
|
+
// HTTP 头信息解析(供 decryptWecomMediaWithMeta 使用)
|
|
117
|
+
// ============================================================================
|
|
118
|
+
/** 归一化 MIME 类型 */
|
|
119
|
+
function normalizeMime(contentType) {
|
|
120
|
+
var _a;
|
|
121
|
+
var raw = String(contentType !== null && contentType !== void 0 ? contentType : "").trim();
|
|
122
|
+
if (!raw)
|
|
123
|
+
return undefined;
|
|
124
|
+
return ((_a = raw.split(";")[0]) === null || _a === void 0 ? void 0 : _a.trim().toLowerCase()) || undefined;
|
|
125
|
+
}
|
|
126
|
+
/** 从 Content-Disposition 提取文件名 */
|
|
127
|
+
function extractFilenameFromContentDisposition(disposition) {
|
|
128
|
+
var raw = String(disposition !== null && disposition !== void 0 ? disposition : "").trim();
|
|
129
|
+
if (!raw)
|
|
130
|
+
return undefined;
|
|
131
|
+
// 优先 filename*(RFC 5987 编码)
|
|
132
|
+
var star = raw.match(/filename\*\s*=\s*([^;]+)/i);
|
|
133
|
+
if (star === null || star === void 0 ? void 0 : star[1]) {
|
|
134
|
+
var v = star[1].trim().replace(/^UTF-8''/i, "").replace(/^"(.*)"$/, "$1");
|
|
135
|
+
try {
|
|
136
|
+
var decoded = decodeURIComponent(v);
|
|
137
|
+
if (decoded.trim())
|
|
138
|
+
return decoded.trim();
|
|
139
|
+
}
|
|
140
|
+
catch ( /* ignore */_a) { /* ignore */ }
|
|
141
|
+
if (v.trim())
|
|
142
|
+
return v.trim();
|
|
143
|
+
}
|
|
144
|
+
// 再尝试 filename
|
|
145
|
+
var plain = raw.match(/filename\s*=\s*([^;]+)/i);
|
|
146
|
+
if (plain === null || plain === void 0 ? void 0 : plain[1]) {
|
|
147
|
+
var v = plain[1].trim().replace(/^"(.*)"$/, "$1").trim();
|
|
148
|
+
if (v)
|
|
149
|
+
return v;
|
|
150
|
+
}
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Webhook 核心消息处理
|
|
3
|
+
*
|
|
4
|
+
* 从 @mocrane/wecom monitor.ts 部分迁移 + 重构。
|
|
5
|
+
* 负责:入站消息解析、防抖聚合、Agent 调度、流式输出、超时兜底。
|
|
6
|
+
*/
|
|
7
|
+
import type { WecomWebhookTarget, WebhookInboundMessage } from "./types.js";
|
|
8
|
+
/**
|
|
9
|
+
* 处理入站消息
|
|
10
|
+
*
|
|
11
|
+
* 解析消息类型和内容,创建/获取 stream,加入防抖队列,返回占位符响应。
|
|
12
|
+
*/
|
|
13
|
+
export declare function handleInboundMessage(target: WecomWebhookTarget, message: WebhookInboundMessage, timestamp: string, nonce: string, proxyUrl?: string, msgFilterData?: {
|
|
14
|
+
senderUserId?: string;
|
|
15
|
+
chatId?: string;
|
|
16
|
+
}): Promise<Record<string, unknown> | null>;
|
|
17
|
+
/**
|
|
18
|
+
* 处理 stream_refresh 请求
|
|
19
|
+
*
|
|
20
|
+
* 返回 StreamState 中的当前累积内容、图片附件和 finish 标记。
|
|
21
|
+
*/
|
|
22
|
+
export declare function handleStreamRefresh(target: WecomWebhookTarget, message: WebhookInboundMessage): Promise<Record<string, unknown> | null>;
|
|
23
|
+
/**
|
|
24
|
+
* 处理 enter_chat 事件
|
|
25
|
+
*
|
|
26
|
+
* 返回可配置的欢迎消息。
|
|
27
|
+
*/
|
|
28
|
+
export declare function handleEnterChat(target: WecomWebhookTarget, message: WebhookInboundMessage): Promise<Record<string, unknown> | null>;
|
|
29
|
+
/**
|
|
30
|
+
* 处理模板卡片事件(对齐原版 template_card_event 逻辑)
|
|
31
|
+
*
|
|
32
|
+
* 原版流程:
|
|
33
|
+
* 1. msgid 去重:跳过已处理的卡片事件
|
|
34
|
+
* 2. 解析卡片交互数据:event_key、selected_items、task_id
|
|
35
|
+
* 3. 立即返回空加密回复(非阻塞)
|
|
36
|
+
* 4. 创建 stream 并标记开始
|
|
37
|
+
* 5. 存储 response_url(用于后续推送)
|
|
38
|
+
* 6. 构造交互描述文本,作为文本消息启动 Agent 处理
|
|
39
|
+
*/
|
|
40
|
+
export declare function handleTemplateCardEvent(target: WecomWebhookTarget, message: WebhookInboundMessage, timestamp: string, nonce: string, proxyUrl?: string): Promise<Record<string, unknown> | null>;
|
|
41
|
+
/**
|
|
42
|
+
* **startAgentForStream (启动 Agent 处理流程)**
|
|
43
|
+
*
|
|
44
|
+
* 将接收到的(或聚合的)消息转换为 OpenClaw 内部格式,并分发给对应的 Agent。
|
|
45
|
+
* 包含:
|
|
46
|
+
* 1. 消息解密与媒体保存。
|
|
47
|
+
* 2. 路由解析 (Agent Route)。
|
|
48
|
+
* 3. 会话记录 (Session Recording)。
|
|
49
|
+
* 4. 触发 Agent 响应 (Dispatch Reply)。
|
|
50
|
+
* 5. 处理 Agent 输出(包括文本、Markdown 表格转换、<think> 标签保护、模板卡片识别)。
|
|
51
|
+
*/
|
|
52
|
+
export declare function startAgentForStream(params: {
|
|
53
|
+
target: WecomWebhookTarget;
|
|
54
|
+
accountId: string;
|
|
55
|
+
msg: WebhookInboundMessage;
|
|
56
|
+
streamId: string;
|
|
57
|
+
mergedContents?: string;
|
|
58
|
+
mergedMsgids?: string[];
|
|
59
|
+
}): Promise<void>;
|