@jimiford/webex 0.1.1

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.
@@ -0,0 +1,297 @@
1
+ "use strict";
2
+ /**
3
+ * Webex Webhook Handler Module
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ var __importDefault = (this && this.__importDefault) || function (mod) {
39
+ return (mod && mod.__esModule) ? mod : { "default": mod };
40
+ };
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.WebhookValidationError = exports.WebexWebhookHandler = void 0;
43
+ const crypto = __importStar(require("crypto"));
44
+ const node_fetch_1 = __importDefault(require("node-fetch"));
45
+ const DEFAULT_API_BASE_URL = 'https://webexapis.com/v1';
46
+ class WebexWebhookHandler {
47
+ config;
48
+ apiBaseUrl;
49
+ botId = null;
50
+ constructor(config) {
51
+ this.config = config;
52
+ this.apiBaseUrl = config.apiBaseUrl || DEFAULT_API_BASE_URL;
53
+ }
54
+ /**
55
+ * Initialize the webhook handler (fetch bot info)
56
+ */
57
+ async initialize() {
58
+ const botInfo = await this.getBotInfo();
59
+ this.botId = botInfo.id;
60
+ }
61
+ /**
62
+ * Handle an incoming webhook request
63
+ */
64
+ async handleWebhook(payload, signature) {
65
+ // Verify webhook signature if secret is configured
66
+ if (this.config.webhookSecret && signature) {
67
+ if (!this.verifySignature(payload, signature)) {
68
+ throw new WebhookValidationError('Invalid webhook signature');
69
+ }
70
+ }
71
+ // Only handle message created events
72
+ if (payload.resource !== 'messages' || payload.event !== 'created') {
73
+ return null;
74
+ }
75
+ // Ignore messages from the bot itself
76
+ if (payload.data.personId === this.botId) {
77
+ return null;
78
+ }
79
+ // Check DM policy
80
+ if (payload.data.roomType === 'direct') {
81
+ if (!this.isAllowedSender(payload.data)) {
82
+ return null;
83
+ }
84
+ }
85
+ // Fetch full message details (webhook only contains IDs)
86
+ const message = await this.fetchMessage(payload.data.id);
87
+ // Normalize to OpenClaw envelope
88
+ return this.normalizeMessage(message);
89
+ }
90
+ /**
91
+ * Verify webhook signature using HMAC-SHA1
92
+ */
93
+ verifySignature(payload, signature) {
94
+ if (!this.config.webhookSecret) {
95
+ return true;
96
+ }
97
+ const hmac = crypto.createHmac('sha1', this.config.webhookSecret);
98
+ hmac.update(JSON.stringify(payload));
99
+ const expectedSignature = hmac.digest('hex');
100
+ return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature));
101
+ }
102
+ /**
103
+ * Check if the sender is allowed based on DM policy
104
+ */
105
+ isAllowedSender(data) {
106
+ switch (this.config.dmPolicy) {
107
+ case 'allow':
108
+ return true;
109
+ case 'deny':
110
+ return false;
111
+ case 'allowlisted':
112
+ if (!this.config.allowFrom || this.config.allowFrom.length === 0) {
113
+ return false;
114
+ }
115
+ return this.config.allowFrom.includes(data.personId) ||
116
+ this.config.allowFrom.includes(data.personEmail);
117
+ default:
118
+ return false;
119
+ }
120
+ }
121
+ /**
122
+ * Fetch full message details from Webex API
123
+ */
124
+ async fetchMessage(messageId) {
125
+ const response = await (0, node_fetch_1.default)(`${this.apiBaseUrl}/messages/${messageId}`, {
126
+ method: 'GET',
127
+ headers: {
128
+ 'Authorization': `Bearer ${this.config.token}`,
129
+ 'Content-Type': 'application/json',
130
+ },
131
+ });
132
+ if (!response.ok) {
133
+ throw new Error(`Failed to fetch message: ${response.status} ${response.statusText}`);
134
+ }
135
+ return response.json();
136
+ }
137
+ /**
138
+ * Normalize a Webex message to OpenClaw envelope format
139
+ */
140
+ normalizeMessage(message) {
141
+ const attachments = [];
142
+ // Convert file attachments
143
+ if (message.files && message.files.length > 0) {
144
+ for (const fileUrl of message.files) {
145
+ attachments.push({
146
+ type: 'file',
147
+ url: fileUrl,
148
+ });
149
+ }
150
+ }
151
+ // Convert card attachments
152
+ if (message.attachments && message.attachments.length > 0) {
153
+ for (const attachment of message.attachments) {
154
+ attachments.push({
155
+ type: 'card',
156
+ content: attachment.content,
157
+ });
158
+ }
159
+ }
160
+ return {
161
+ id: message.id,
162
+ channel: 'webex',
163
+ conversationId: message.roomId,
164
+ author: {
165
+ id: message.personId,
166
+ email: message.personEmail,
167
+ displayName: undefined, // Would need additional API call to get
168
+ isBot: false, // Messages from bot are filtered out earlier
169
+ },
170
+ content: {
171
+ text: message.text,
172
+ markdown: message.markdown,
173
+ attachments: attachments.length > 0 ? attachments : undefined,
174
+ },
175
+ metadata: {
176
+ roomType: message.roomType,
177
+ roomId: message.roomId,
178
+ timestamp: message.created,
179
+ mentions: message.mentionedPeople,
180
+ parentId: message.parentId,
181
+ raw: message,
182
+ },
183
+ };
184
+ }
185
+ /**
186
+ * Register webhooks with Webex
187
+ */
188
+ async registerWebhooks() {
189
+ // First, list existing webhooks and remove duplicates
190
+ const existing = await this.listWebhooks();
191
+ const targetUrl = this.config.webhookUrl;
192
+ // Delete existing webhooks with the same target URL
193
+ for (const webhook of existing) {
194
+ if (webhook.targetUrl === targetUrl) {
195
+ await this.deleteWebhook(webhook.id);
196
+ }
197
+ }
198
+ // Create new webhooks for messages
199
+ const webhooks = [];
200
+ // Webhook for new messages
201
+ const messageCreatedWebhook = await this.createWebhook({
202
+ name: 'OpenClaw Message Handler',
203
+ targetUrl,
204
+ resource: 'messages',
205
+ event: 'created',
206
+ secret: this.config.webhookSecret,
207
+ });
208
+ webhooks.push(messageCreatedWebhook);
209
+ return webhooks;
210
+ }
211
+ /**
212
+ * List all webhooks
213
+ */
214
+ async listWebhooks() {
215
+ const response = await (0, node_fetch_1.default)(`${this.apiBaseUrl}/webhooks`, {
216
+ method: 'GET',
217
+ headers: {
218
+ 'Authorization': `Bearer ${this.config.token}`,
219
+ 'Content-Type': 'application/json',
220
+ },
221
+ });
222
+ if (!response.ok) {
223
+ throw new Error(`Failed to list webhooks: ${response.status} ${response.statusText}`);
224
+ }
225
+ const data = await response.json();
226
+ return data.items;
227
+ }
228
+ /**
229
+ * Create a webhook
230
+ */
231
+ async createWebhook(request) {
232
+ const response = await (0, node_fetch_1.default)(`${this.apiBaseUrl}/webhooks`, {
233
+ method: 'POST',
234
+ headers: {
235
+ 'Authorization': `Bearer ${this.config.token}`,
236
+ 'Content-Type': 'application/json',
237
+ },
238
+ body: JSON.stringify(request),
239
+ });
240
+ if (!response.ok) {
241
+ const errorText = await response.text();
242
+ throw new Error(`Failed to create webhook: ${response.status} ${response.statusText} - ${errorText}`);
243
+ }
244
+ return response.json();
245
+ }
246
+ /**
247
+ * Delete a webhook
248
+ */
249
+ async deleteWebhook(webhookId) {
250
+ const response = await (0, node_fetch_1.default)(`${this.apiBaseUrl}/webhooks/${webhookId}`, {
251
+ method: 'DELETE',
252
+ headers: {
253
+ 'Authorization': `Bearer ${this.config.token}`,
254
+ },
255
+ });
256
+ if (!response.ok && response.status !== 404) {
257
+ throw new Error(`Failed to delete webhook: ${response.status} ${response.statusText}`);
258
+ }
259
+ }
260
+ /**
261
+ * Get bot information
262
+ */
263
+ async getBotInfo() {
264
+ const response = await (0, node_fetch_1.default)(`${this.apiBaseUrl}/people/me`, {
265
+ method: 'GET',
266
+ headers: {
267
+ 'Authorization': `Bearer ${this.config.token}`,
268
+ 'Content-Type': 'application/json',
269
+ },
270
+ });
271
+ if (!response.ok) {
272
+ throw new Error(`Failed to get bot info: ${response.status} ${response.statusText}`);
273
+ }
274
+ return response.json();
275
+ }
276
+ /**
277
+ * Get the bot ID (after initialization)
278
+ */
279
+ getBotId() {
280
+ return this.botId;
281
+ }
282
+ }
283
+ exports.WebexWebhookHandler = WebexWebhookHandler;
284
+ /**
285
+ * Custom error for webhook validation failures
286
+ */
287
+ class WebhookValidationError extends Error {
288
+ constructor(message) {
289
+ super(message);
290
+ this.name = 'WebhookValidationError';
291
+ if (Error.captureStackTrace) {
292
+ Error.captureStackTrace(this, WebhookValidationError);
293
+ }
294
+ }
295
+ }
296
+ exports.WebhookValidationError = WebhookValidationError;
297
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2ViaG9vay5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy93ZWJob29rLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7R0FFRzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBRUgsK0NBQWlDO0FBQ2pDLDREQUErQjtBQWEvQixNQUFNLG9CQUFvQixHQUFHLDBCQUEwQixDQUFDO0FBRXhELE1BQWEsbUJBQW1CO0lBQ3RCLE1BQU0sQ0FBcUI7SUFDM0IsVUFBVSxDQUFTO0lBQ25CLEtBQUssR0FBa0IsSUFBSSxDQUFDO0lBRXBDLFlBQVksTUFBMEI7UUFDcEMsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDckIsSUFBSSxDQUFDLFVBQVUsR0FBRyxNQUFNLENBQUMsVUFBVSxJQUFJLG9CQUFvQixDQUFDO0lBQzlELENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxVQUFVO1FBQ2QsTUFBTSxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDeEMsSUFBSSxDQUFDLEtBQUssR0FBRyxPQUFPLENBQUMsRUFBRSxDQUFDO0lBQzFCLENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxhQUFhLENBQ2pCLE9BQTRCLEVBQzVCLFNBQWtCO1FBRWxCLG1EQUFtRDtRQUNuRCxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxJQUFJLFNBQVMsRUFBRSxDQUFDO1lBQzNDLElBQUksQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLE9BQU8sRUFBRSxTQUFTLENBQUMsRUFBRSxDQUFDO2dCQUM5QyxNQUFNLElBQUksc0JBQXNCLENBQUMsMkJBQTJCLENBQUMsQ0FBQztZQUNoRSxDQUFDO1FBQ0gsQ0FBQztRQUVELHFDQUFxQztRQUNyQyxJQUFJLE9BQU8sQ0FBQyxRQUFRLEtBQUssVUFBVSxJQUFJLE9BQU8sQ0FBQyxLQUFLLEtBQUssU0FBUyxFQUFFLENBQUM7WUFD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MkJBQTJCLFFBQVEsQ0FBQyxNQUFNLElBQUksUUFBUSxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUM7UUFDdkYsQ0FBQztRQUVELE9BQU8sUUFBUSxDQUFDLElBQUksRUFBb0UsQ0FBQztJQUMzRixDQUFDO0lBRUQ7O09BRUc7SUFDSCxRQUFRO1FBQ04sT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDO0lBQ3BCLENBQUM7Q0FDRjtBQXRSRCxrREFzUkM7QUFFRDs7R0FFRztBQUNILE1BQWEsc0JBQXVCLFNBQVEsS0FBSztJQUMvQyxZQUFZLE9BQWU7UUFDekIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2YsSUFBSSxDQUFDLElBQUksR0FBRyx3QkFBd0IsQ0FBQztRQUVyQyxJQUFJLEtBQUssQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1lBQzVCLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLEVBQUUsc0JBQXNCLENBQUMsQ0FBQztRQUN4RCxDQUFDO0lBQ0gsQ0FBQztDQUNGO0FBVEQsd0RBU0MiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFdlYmV4IFdlYmhvb2sgSGFuZGxlciBNb2R1bGVcbiAqL1xuXG5pbXBvcnQgKiBhcyBjcnlwdG8gZnJvbSAnY3J5cHRvJztcbmltcG9ydCBmZXRjaCBmcm9tICdub2RlLWZldGNoJztcbmltcG9ydCB0eXBlIHtcbiAgV2ViZXhDaGFubmVsQ29uZmlnLFxuICBXZWJleFdlYmhvb2tQYXlsb2FkLFxuICBXZWJleFdlYmhvb2tEYXRhLFxuICBXZWJleE1lc3NhZ2UsXG4gIFdlYmV4V2ViaG9vayxcbiAgQ3JlYXRlV2ViaG9va1JlcXVlc3QsXG4gIE9wZW5DbGF3RW52ZWxvcGUsXG4gIE9wZW5DbGF3QXR0YWNobWVudCxcbiAgUGFnaW5hdGVkUmVzcG9uc2UsXG59IGZyb20gJy4vdHlwZXMnO1xuXG5jb25zdCBERUZBVUxUX0FQSV9CQVNFX1VSTCA9ICdodHRwczovL3dlYmV4YXBpcy5jb20vdjEnO1xuXG5leHBvcnQgY2xhc3MgV2ViZXhXZWJob29rSGFuZGxlciB7XG4gIHByaXZhdGUgY29uZmlnOiBXZWJleENoYW5uZWxDb25maWc7XG4gIHByaXZhdGUgYXBpQmFzZVVybDogc3RyaW5nO1xuICBwcml2YXRlIGJvdElkOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcblxuICBjb25zdHJ1Y3Rvcihjb25maWc6IFdlYmV4Q2hhbm5lbENvbmZpZykge1xuICAgIHRoaXMuY29uZmlnID0gY29uZmlnO1xuICAgIHRoaXMuYXBpQmFzZVVybCA9IGNvbmZpZy5hcGlCYXNlVXJsIHx8IERFRkFVTFRfQVBJX0JBU0VfVVJMO1xuICB9XG5cbiAgLyoqXG4gICAqIEluaXRpYWxpemUgdGhlIHdlYmhvb2sgaGFuZGxlciAoZmV0Y2ggYm90IGluZm8pXG4gICAqL1xuICBhc3luYyBpbml0aWFsaXplKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGJvdEluZm8gPSBhd2FpdCB0aGlzLmdldEJvdEluZm8oKTtcbiAgICB0aGlzLmJvdElkID0gYm90SW5mby5pZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBIYW5kbGUgYW4gaW5jb21pbmcgd2ViaG9vayByZXF1ZXN0XG4gICAqL1xuICBhc3luYyBoYW5kbGVXZWJob29rKFxuICAgIHBheWxvYWQ6IFdlYmV4V2ViaG9va1BheWxvYWQsXG4gICAgc2lnbmF0dXJlPzogc3RyaW5nXG4gICk6IFByb21pc2U8T3BlbkNsYXdFbnZlbG9wZSB8IG51bGw+IHtcbiAgICAvLyBWZXJpZnkgd2ViaG9vayBzaWduYXR1cmUgaWYgc2VjcmV0IGlzIGNvbmZpZ3VyZWRcbiAgICBpZiAodGhpcy5jb25maWcud2ViaG9va1NlY3JldCAmJiBzaWduYXR1cmUpIHtcbiAgICAgIGlmICghdGhpcy52ZXJpZnlTaWduYXR1cmUocGF5bG9hZCwgc2lnbmF0dXJlKSkge1xuICAgICAgICB0aHJvdyBuZXcgV2ViaG9va1ZhbGlkYXRpb25FcnJvcignSW52YWxpZCB3ZWJob29rIHNpZ25hdHVyZScpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIE9ubHkgaGFuZGxlIG1lc3NhZ2UgY3JlYXRlZCBldmVudHNcbiAgICBpZiAocGF5bG9hZC5yZXNvdXJjZSAhPT0gJ21lc3NhZ2VzJyB8fCBwYXlsb2FkLmV2ZW50ICE9PSAnY3JlYXRlZCcpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIC8vIElnbm9yZSBtZXNzYWdlcyBmcm9tIHRoZSBib3QgaXRzZWxmXG4gICAgaWYgKHBheWxvYWQuZGF0YS5wZXJzb25JZCA9PT0gdGhpcy5ib3RJZCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgRE0gcG9saWN5XG4gICAgaWYgKHBheWxvYWQuZGF0YS5yb29tVHlwZSA9PT0gJ2RpcmVjdCcpIHtcbiAgICAgIGlmICghdGhpcy5pc0FsbG93ZWRTZW5kZXIocGF5bG9hZC5kYXRhKSkge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBGZXRjaCBmdWxsIG1lc3NhZ2UgZGV0YWlscyAod2ViaG9vayBvbmx5IGNvbnRhaW5zIElEcylcbiAgICBjb25zdCBtZXNzYWdlID0gYXdhaXQgdGhpcy5mZXRjaE1lc3NhZ2UocGF5bG9hZC5kYXRhLmlkKTtcblxuICAgIC8vIE5vcm1hbGl6ZSB0byBPcGVuQ2xhdyBlbnZlbG9wZVxuICAgIHJldHVybiB0aGlzLm5vcm1hbGl6ZU1lc3NhZ2UobWVzc2FnZSk7XG4gIH1cblxuICAvKipcbiAgICogVmVyaWZ5IHdlYmhvb2sgc2lnbmF0dXJlIHVzaW5nIEhNQUMtU0hBMVxuICAgKi9cbiAgdmVyaWZ5U2lnbmF0dXJlKHBheWxvYWQ6IFdlYmV4V2ViaG9va1BheWxvYWQsIHNpZ25hdHVyZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgaWYgKCF0aGlzLmNvbmZpZy53ZWJob29rU2VjcmV0KSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICBjb25zdCBobWFjID0gY3J5cHRvLmNyZWF0ZUhtYWMoJ3NoYTEnLCB0aGlzLmNvbmZpZy53ZWJob29rU2VjcmV0KTtcbiAgICBobWFjLnVwZGF0ZShKU09OLnN0cmluZ2lmeShwYXlsb2FkKSk7XG4gICAgY29uc3QgZXhwZWN0ZWRTaWduYXR1cmUgPSBobWFjLmRpZ2VzdCgnaGV4Jyk7XG5cbiAgICByZXR1cm4gY3J5cHRvLnRpbWluZ1NhZmVFcXVhbChcbiAgICAgIEJ1ZmZlci5mcm9tKHNpZ25hdHVyZSksXG4gICAgICBCdWZmZXIuZnJvbShleHBlY3RlZFNpZ25hdHVyZSlcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrIGlmIHRoZSBzZW5kZXIgaXMgYWxsb3dlZCBiYXNlZCBvbiBETSBwb2xpY3lcbiAgICovXG4gIHByaXZhdGUgaXNBbGxvd2VkU2VuZGVyKGRhdGE6IFdlYmV4V2ViaG9va0RhdGEpOiBib29sZWFuIHtcbiAgICBzd2l0Y2ggKHRoaXMuY29uZmlnLmRtUG9saWN5KSB7XG4gICAgICBjYXNlICdhbGxvdyc6XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgY2FzZSAnZGVueSc6XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIGNhc2UgJ2FsbG93bGlzdGVkJzpcbiAgICAgICAgaWYgKCF0aGlzLmNvbmZpZy5hbGxvd0Zyb20gfHwgdGhpcy5jb25maWcuYWxsb3dGcm9tLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5jb25maWcuYWxsb3dGcm9tLmluY2x1ZGVzKGRhdGEucGVyc29uSWQpIHx8XG4gICAgICAgICAgICAgICB0aGlzLmNvbmZpZy5hbGxvd0Zyb20uaW5jbHVkZXMoZGF0YS5wZXJzb25FbWFpbCk7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEZldGNoIGZ1bGwgbWVzc2FnZSBkZXRhaWxzIGZyb20gV2ViZXggQVBJXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGZldGNoTWVzc2FnZShtZXNzYWdlSWQ6IHN0cmluZyk6IFByb21pc2U8V2ViZXhNZXNzYWdlPiB7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChgJHt0aGlzLmFwaUJhc2VVcmx9L21lc3NhZ2VzLyR7bWVzc2FnZUlkfWAsIHtcbiAgICAgIG1ldGhvZDogJ0dFVCcsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdBdXRob3JpemF0aW9uJzogYEJlYXJlciAke3RoaXMuY29uZmlnLnRva2VufWAsXG4gICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGYWlsZWQgdG8gZmV0Y2ggbWVzc2FnZTogJHtyZXNwb25zZS5zdGF0dXN9ICR7cmVzcG9uc2Uuc3RhdHVzVGV4dH1gKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzcG9uc2UuanNvbigpIGFzIFByb21pc2U8V2ViZXhNZXNzYWdlPjtcbiAgfVxuXG4gIC8qKlxuICAgKiBOb3JtYWxpemUgYSBXZWJleCBtZXNzYWdlIHRvIE9wZW5DbGF3IGVudmVsb3BlIGZvcm1hdFxuICAgKi9cbiAgcHJpdmF0ZSBub3JtYWxpemVNZXNzYWdlKG1lc3NhZ2U6IFdlYmV4TWVzc2FnZSk6IE9wZW5DbGF3RW52ZWxvcGUge1xuICAgIGNvbnN0IGF0dGFjaG1lbnRzOiBPcGVuQ2xhd0F0dGFjaG1lbnRbXSA9IFtdO1xuXG4gICAgLy8gQ29udmVydCBmaWxlIGF0dGFjaG1lbnRzXG4gICAgaWYgKG1lc3NhZ2UuZmlsZXMgJiYgbWVzc2FnZS5maWxlcy5sZW5ndGggPiAwKSB7XG4gICAgICBmb3IgKGNvbnN0IGZpbGVVcmwgb2YgbWVzc2FnZS5maWxlcykge1xuICAgICAgICBhdHRhY2htZW50cy5wdXNoKHtcbiAgICAgICAgICB0eXBlOiAnZmlsZScsXG4gICAgICAgICAgdXJsOiBmaWxlVXJsLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBDb252ZXJ0IGNhcmQgYXR0YWNobWVudHNcbiAgICBpZiAobWVzc2FnZS5hdHRhY2htZW50cyAmJiBtZXNzYWdlLmF0dGFjaG1lbnRzLmxlbmd0aCA+IDApIHtcbiAgICAgIGZvciAoY29uc3QgYXR0YWNobWVudCBvZiBtZXNzYWdlLmF0dGFjaG1lbnRzKSB7XG4gICAgICAgIGF0dGFjaG1lbnRzLnB1c2goe1xuICAgICAgICAgIHR5cGU6ICdjYXJkJyxcbiAgICAgICAgICBjb250ZW50OiBhdHRhY2htZW50LmNvbnRlbnQsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBpZDogbWVzc2FnZS5pZCxcbiAgICAgIGNoYW5uZWw6ICd3ZWJleCcsXG4gICAgICBjb252ZXJzYXRpb25JZDogbWVzc2FnZS5yb29tSWQsXG4gICAgICBhdXRob3I6IHtcbiAgICAgICAgaWQ6IG1lc3NhZ2UucGVyc29uSWQsXG4gICAgICAgIGVtYWlsOiBtZXNzYWdlLnBlcnNvbkVtYWlsLFxuICAgICAgICBkaXNwbGF5TmFtZTogdW5kZWZpbmVkLCAvLyBXb3VsZCBuZWVkIGFkZGl0aW9uYWwgQVBJIGNhbGwgdG8gZ2V0XG4gICAgICAgIGlzQm90OiBmYWxzZSwgLy8gTWVzc2FnZXMgZnJvbSBib3QgYXJlIGZpbHRlcmVkIG91dCBlYXJsaWVyXG4gICAgICB9LFxuICAgICAgY29udGVudDoge1xuICAgICAgICB0ZXh0OiBtZXNzYWdlLnRleHQsXG4gICAgICAgIG1hcmtkb3duOiBtZXNzYWdlLm1hcmtkb3duLFxuICAgICAgICBhdHRhY2htZW50czogYXR0YWNobWVudHMubGVuZ3RoID4gMCA/IGF0dGFjaG1lbnRzIDogdW5kZWZpbmVkLFxuICAgICAgfSxcbiAgICAgIG1ldGFkYXRhOiB7XG4gICAgICAgIHJvb21UeXBlOiBtZXNzYWdlLnJvb21UeXBlLFxuICAgICAgICByb29tSWQ6IG1lc3NhZ2Uucm9vbUlkLFxuICAgICAgICB0aW1lc3RhbXA6IG1lc3NhZ2UuY3JlYXRlZCxcbiAgICAgICAgbWVudGlvbnM6IG1lc3NhZ2UubWVudGlvbmVkUGVvcGxlLFxuICAgICAgICBwYXJlbnRJZDogbWVzc2FnZS5wYXJlbnRJZCxcbiAgICAgICAgcmF3OiBtZXNzYWdlLFxuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFJlZ2lzdGVyIHdlYmhvb2tzIHdpdGggV2ViZXhcbiAgICovXG4gIGFzeW5jIHJlZ2lzdGVyV2ViaG9va3MoKTogUHJvbWlzZTxXZWJleFdlYmhvb2tbXT4ge1xuICAgIC8vIEZpcnN0LCBsaXN0IGV4aXN0aW5nIHdlYmhvb2tzIGFuZCByZW1vdmUgZHVwbGljYXRlc1xuICAgIGNvbnN0IGV4aXN0aW5nID0gYXdhaXQgdGhpcy5saXN0V2ViaG9va3MoKTtcbiAgICBjb25zdCB0YXJnZXRVcmwgPSB0aGlzLmNvbmZpZy53ZWJob29rVXJsO1xuXG4gICAgLy8gRGVsZXRlIGV4aXN0aW5nIHdlYmhvb2tzIHdpdGggdGhlIHNhbWUgdGFyZ2V0IFVSTFxuICAgIGZvciAoY29uc3Qgd2ViaG9vayBvZiBleGlzdGluZykge1xuICAgICAgaWYgKHdlYmhvb2sudGFyZ2V0VXJsID09PSB0YXJnZXRVcmwpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5kZWxldGVXZWJob29rKHdlYmhvb2suaWQpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIENyZWF0ZSBuZXcgd2ViaG9va3MgZm9yIG1lc3NhZ2VzXG4gICAgY29uc3Qgd2ViaG9va3M6IFdlYmV4V2ViaG9va1tdID0gW107XG5cbiAgICAvLyBXZWJob29rIGZvciBuZXcgbWVzc2FnZXNcbiAgICBjb25zdCBtZXNzYWdlQ3JlYXRlZFdlYmhvb2sgPSBhd2FpdCB0aGlzLmNyZWF0ZVdlYmhvb2soe1xuICAgICAgbmFtZTogJ09wZW5DbGF3IE1lc3NhZ2UgSGFuZGxlcicsXG4gICAgICB0YXJnZXRVcmwsXG4gICAgICByZXNvdXJjZTogJ21lc3NhZ2VzJyxcbiAgICAgIGV2ZW50OiAnY3JlYXRlZCcsXG4gICAgICBzZWNyZXQ6IHRoaXMuY29uZmlnLndlYmhvb2tTZWNyZXQsXG4gICAgfSk7XG4gICAgd2ViaG9va3MucHVzaChtZXNzYWdlQ3JlYXRlZFdlYmhvb2spO1xuXG4gICAgcmV0dXJuIHdlYmhvb2tzO1xuICB9XG5cbiAgLyoqXG4gICAqIExpc3QgYWxsIHdlYmhvb2tzXG4gICAqL1xuICBhc3luYyBsaXN0V2ViaG9va3MoKTogUHJvbWlzZTxXZWJleFdlYmhvb2tbXT4ge1xuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goYCR7dGhpcy5hcGlCYXNlVXJsfS93ZWJob29rc2AsIHtcbiAgICAgIG1ldGhvZDogJ0dFVCcsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdBdXRob3JpemF0aW9uJzogYEJlYXJlciAke3RoaXMuY29uZmlnLnRva2VufWAsXG4gICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGYWlsZWQgdG8gbGlzdCB3ZWJob29rczogJHtyZXNwb25zZS5zdGF0dXN9ICR7cmVzcG9uc2Uuc3RhdHVzVGV4dH1gKTtcbiAgICB9XG5cbiAgICBjb25zdCBkYXRhID0gYXdhaXQgcmVzcG9uc2UuanNvbigpIGFzIFBhZ2luYXRlZFJlc3BvbnNlPFdlYmV4V2ViaG9vaz47XG4gICAgcmV0dXJuIGRhdGEuaXRlbXM7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIGEgd2ViaG9va1xuICAgKi9cbiAgYXN5bmMgY3JlYXRlV2ViaG9vayhyZXF1ZXN0OiBDcmVhdGVXZWJob29rUmVxdWVzdCk6IFByb21pc2U8V2ViZXhXZWJob29rPiB7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChgJHt0aGlzLmFwaUJhc2VVcmx9L3dlYmhvb2tzYCwge1xuICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdBdXRob3JpemF0aW9uJzogYEJlYXJlciAke3RoaXMuY29uZmlnLnRva2VufWAsXG4gICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICB9LFxuICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkocmVxdWVzdCksXG4gICAgfSk7XG5cbiAgICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgICBjb25zdCBlcnJvclRleHQgPSBhd2FpdCByZXNwb25zZS50ZXh0KCk7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEZhaWxlZCB0byBjcmVhdGUgd2ViaG9vazogJHtyZXNwb25zZS5zdGF0dXN9ICR7cmVzcG9uc2Uuc3RhdHVzVGV4dH0gLSAke2Vycm9yVGV4dH1gKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzcG9uc2UuanNvbigpIGFzIFByb21pc2U8V2ViZXhXZWJob29rPjtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWxldGUgYSB3ZWJob29rXG4gICAqL1xuICBhc3luYyBkZWxldGVXZWJob29rKHdlYmhvb2tJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChgJHt0aGlzLmFwaUJhc2VVcmx9L3dlYmhvb2tzLyR7d2ViaG9va0lkfWAsIHtcbiAgICAgIG1ldGhvZDogJ0RFTEVURScsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdBdXRob3JpemF0aW9uJzogYEJlYXJlciAke3RoaXMuY29uZmlnLnRva2VufWAsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgaWYgKCFyZXNwb25zZS5vayAmJiByZXNwb25zZS5zdGF0dXMgIT09IDQwNCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGYWlsZWQgdG8gZGVsZXRlIHdlYmhvb2s6ICR7cmVzcG9uc2Uuc3RhdHVzfSAke3Jlc3BvbnNlLnN0YXR1c1RleHR9YCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEdldCBib3QgaW5mb3JtYXRpb25cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZ2V0Qm90SW5mbygpOiBQcm9taXNlPHsgaWQ6IHN0cmluZzsgZGlzcGxheU5hbWU6IHN0cmluZzsgZW1haWxzOiBzdHJpbmdbXSB9PiB7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChgJHt0aGlzLmFwaUJhc2VVcmx9L3Blb3BsZS9tZWAsIHtcbiAgICAgIG1ldGhvZDogJ0dFVCcsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdBdXRob3JpemF0aW9uJzogYEJlYXJlciAke3RoaXMuY29uZmlnLnRva2VufWAsXG4gICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGYWlsZWQgdG8gZ2V0IGJvdCBpbmZvOiAke3Jlc3BvbnNlLnN0YXR1c30gJHtyZXNwb25zZS5zdGF0dXNUZXh0fWApO1xuICAgIH1cblxuICAgIHJldHVybiByZXNwb25zZS5qc29uKCkgYXMgUHJvbWlzZTx7IGlkOiBzdHJpbmc7IGRpc3BsYXlOYW1lOiBzdHJpbmc7IGVtYWlsczogc3RyaW5nW10gfT47XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBib3QgSUQgKGFmdGVyIGluaXRpYWxpemF0aW9uKVxuICAgKi9cbiAgZ2V0Qm90SWQoKTogc3RyaW5nIHwgbnVsbCB7XG4gICAgcmV0dXJuIHRoaXMuYm90SWQ7XG4gIH1cbn1cblxuLyoqXG4gKiBDdXN0b20gZXJyb3IgZm9yIHdlYmhvb2sgdmFsaWRhdGlvbiBmYWlsdXJlc1xuICovXG5leHBvcnQgY2xhc3MgV2ViaG9va1ZhbGlkYXRpb25FcnJvciBleHRlbmRzIEVycm9yIHtcbiAgY29uc3RydWN0b3IobWVzc2FnZTogc3RyaW5nKSB7XG4gICAgc3VwZXIobWVzc2FnZSk7XG4gICAgdGhpcy5uYW1lID0gJ1dlYmhvb2tWYWxpZGF0aW9uRXJyb3InO1xuXG4gICAgaWYgKEVycm9yLmNhcHR1cmVTdGFja1RyYWNlKSB7XG4gICAgICBFcnJvci5jYXB0dXJlU3RhY2tUcmFjZSh0aGlzLCBXZWJob29rVmFsaWRhdGlvbkVycm9yKTtcbiAgICB9XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,33 @@
1
+ {
2
+ "id": "webex",
3
+ "name": "Webex Channel",
4
+ "description": "Cisco Webex messaging integration for OpenClaw",
5
+ "channels": ["webex"],
6
+ "configSchema": {
7
+ "type": "object",
8
+ "additionalProperties": false,
9
+ "properties": {}
10
+ },
11
+ "uiHints": {
12
+ "token": {
13
+ "label": "Bot Access Token",
14
+ "sensitive": true,
15
+ "placeholder": "Your Webex bot token"
16
+ },
17
+ "webhookUrl": {
18
+ "label": "Webhook URL",
19
+ "placeholder": "https://your-domain.com/webhooks/webex"
20
+ },
21
+ "webhookSecret": {
22
+ "label": "Webhook Secret",
23
+ "sensitive": true,
24
+ "placeholder": "Optional secret for webhook verification"
25
+ },
26
+ "dmPolicy": {
27
+ "label": "DM Policy"
28
+ },
29
+ "allowFrom": {
30
+ "label": "Allowed Senders"
31
+ }
32
+ }
33
+ }
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@jimiford/webex",
3
+ "version": "0.1.1",
4
+ "description": "OpenClaw channel plugin for Cisco Webex messaging",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "openclaw.plugin.json"
10
+ ],
11
+ "openclaw": {
12
+ "extensions": [
13
+ "./dist/plugin.js"
14
+ ],
15
+ "channel": {
16
+ "id": "webex",
17
+ "label": "Webex",
18
+ "selectionLabel": "Cisco Webex",
19
+ "docsPath": "/channels/webex",
20
+ "blurb": "Cisco Webex messaging via bot webhooks.",
21
+ "aliases": [
22
+ "cisco-webex"
23
+ ]
24
+ },
25
+ "install": {
26
+ "npmSpec": "@jimiford/channel-webex",
27
+ "defaultChoice": "npm"
28
+ }
29
+ },
30
+ "scripts": {
31
+ "build": "tsc",
32
+ "dev": "tsc --watch",
33
+ "lint": "eslint src --ext .ts",
34
+ "test": "vitest run",
35
+ "test:watch": "vitest",
36
+ "test:coverage": "vitest run --coverage",
37
+ "prepublishOnly": "npm run build"
38
+ },
39
+ "keywords": [
40
+ "openclaw",
41
+ "webex",
42
+ "cisco",
43
+ "channel",
44
+ "messaging",
45
+ "bot"
46
+ ],
47
+ "author": "",
48
+ "license": "MIT",
49
+ "peerDependencies": {
50
+ "@openclaw/core": "^1.0.0"
51
+ },
52
+ "peerDependenciesMeta": {
53
+ "@openclaw/core": {
54
+ "optional": true
55
+ }
56
+ },
57
+ "dependencies": {
58
+ "node-fetch": "^2.7.0"
59
+ },
60
+ "devDependencies": {
61
+ "@types/node": "^20.10.0",
62
+ "@types/node-fetch": "^2.6.9",
63
+ "@vitest/coverage-v8": "^4.0.18",
64
+ "openclaw": "^2026.1.30",
65
+ "typescript": "^5.3.0",
66
+ "vitest": "^4.0.18"
67
+ },
68
+ "engines": {
69
+ "node": ">=18.0.0"
70
+ }
71
+ }