@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.
package/dist/send.js ADDED
@@ -0,0 +1,304 @@
1
+ "use strict";
2
+ /**
3
+ * Webex Message Sending Module
4
+ */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.WebexApiRequestError = exports.WebexSender = void 0;
10
+ const node_fetch_1 = __importDefault(require("node-fetch"));
11
+ const DEFAULT_API_BASE_URL = 'https://webexapis.com/v1';
12
+ const DEFAULT_MAX_RETRIES = 3;
13
+ const DEFAULT_RETRY_DELAY_MS = 1000;
14
+ // Rate limit status codes that should trigger retry
15
+ const RETRY_STATUS_CODES = [429, 502, 503, 504];
16
+ class WebexSender {
17
+ config;
18
+ apiBaseUrl;
19
+ retryOptions;
20
+ constructor(config) {
21
+ this.config = config;
22
+ this.apiBaseUrl = config.apiBaseUrl || DEFAULT_API_BASE_URL;
23
+ this.retryOptions = {
24
+ maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,
25
+ retryDelayMs: config.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS,
26
+ };
27
+ }
28
+ /**
29
+ * Send a message to Webex
30
+ */
31
+ async send(message) {
32
+ const request = this.buildMessageRequest(message);
33
+ return this.createMessage(request);
34
+ }
35
+ /**
36
+ * Send a text message to a room
37
+ */
38
+ async sendToRoom(roomId, text, markdown) {
39
+ return this.createMessage({
40
+ roomId,
41
+ text,
42
+ markdown,
43
+ });
44
+ }
45
+ /**
46
+ * Send a direct message to a person by ID
47
+ */
48
+ async sendDirectById(personId, text, markdown) {
49
+ return this.createMessage({
50
+ toPersonId: personId,
51
+ text,
52
+ markdown,
53
+ });
54
+ }
55
+ /**
56
+ * Send a direct message to a person by email
57
+ */
58
+ async sendDirectByEmail(email, text, markdown) {
59
+ return this.createMessage({
60
+ toPersonEmail: email,
61
+ text,
62
+ markdown,
63
+ });
64
+ }
65
+ /**
66
+ * Send a message with file attachment
67
+ */
68
+ async sendWithFile(roomId, text, fileUrl) {
69
+ return this.createMessage({
70
+ roomId,
71
+ text,
72
+ files: [fileUrl],
73
+ });
74
+ }
75
+ /**
76
+ * Send a threaded reply
77
+ */
78
+ async sendReply(roomId, parentId, text, markdown) {
79
+ return this.createMessage({
80
+ roomId,
81
+ parentId,
82
+ text,
83
+ markdown,
84
+ });
85
+ }
86
+ /**
87
+ * Get a message by ID
88
+ */
89
+ async getMessage(messageId) {
90
+ return this.request({
91
+ method: 'GET',
92
+ path: `/messages/${messageId}`,
93
+ });
94
+ }
95
+ /**
96
+ * Delete a message by ID
97
+ */
98
+ async deleteMessage(messageId) {
99
+ await this.request({
100
+ method: 'DELETE',
101
+ path: `/messages/${messageId}`,
102
+ });
103
+ }
104
+ /**
105
+ * Build a Webex message request from an OpenClaw outbound message
106
+ */
107
+ buildMessageRequest(message) {
108
+ const request = {};
109
+ // Determine target: roomId, personId, or email
110
+ const to = message.to;
111
+ if (to.includes('@')) {
112
+ request.toPersonEmail = to;
113
+ }
114
+ else if (to.startsWith('Y2lzY29zcGFyazovL3')) {
115
+ // Base64-encoded Webex IDs start with this prefix
116
+ if (to.includes('ROOM')) {
117
+ request.roomId = to;
118
+ }
119
+ else {
120
+ request.toPersonId = to;
121
+ }
122
+ }
123
+ else {
124
+ // Assume it's a roomId if not an email
125
+ request.roomId = to;
126
+ }
127
+ // Set content
128
+ if (message.content.text) {
129
+ request.text = message.content.text;
130
+ }
131
+ if (message.content.markdown) {
132
+ request.markdown = message.content.markdown;
133
+ }
134
+ if (message.content.files && message.content.files.length > 0) {
135
+ // Webex only allows one file per message
136
+ request.files = [message.content.files[0]];
137
+ }
138
+ if (message.content.card) {
139
+ request.attachments = [
140
+ {
141
+ contentType: 'application/vnd.microsoft.card.adaptive',
142
+ content: message.content.card,
143
+ },
144
+ ];
145
+ }
146
+ // Set threading
147
+ if (message.parentId) {
148
+ request.parentId = message.parentId;
149
+ }
150
+ return request;
151
+ }
152
+ /**
153
+ * Create a message via the Webex API
154
+ */
155
+ async createMessage(request) {
156
+ this.validateMessageRequest(request);
157
+ return this.request({
158
+ method: 'POST',
159
+ path: '/messages',
160
+ body: request,
161
+ });
162
+ }
163
+ /**
164
+ * Validate a message request before sending
165
+ */
166
+ validateMessageRequest(request) {
167
+ // Must have a target
168
+ if (!request.roomId && !request.toPersonId && !request.toPersonEmail) {
169
+ throw new Error('Message must have a target: roomId, toPersonId, or toPersonEmail');
170
+ }
171
+ // Must have content
172
+ if (!request.text && !request.markdown && !request.files?.length && !request.attachments?.length) {
173
+ throw new Error('Message must have content: text, markdown, files, or attachments');
174
+ }
175
+ // Text has a max size of 7439 bytes
176
+ if (request.text && Buffer.byteLength(request.text, 'utf8') > 7439) {
177
+ throw new Error('Message text exceeds maximum size of 7439 bytes');
178
+ }
179
+ }
180
+ /**
181
+ * Make an API request with retry logic
182
+ */
183
+ async request(options) {
184
+ let lastError = null;
185
+ let attempt = 0;
186
+ while (attempt <= this.retryOptions.maxRetries) {
187
+ try {
188
+ return await this.executeRequest(options);
189
+ }
190
+ catch (error) {
191
+ lastError = error;
192
+ attempt++;
193
+ if (attempt > this.retryOptions.maxRetries) {
194
+ break;
195
+ }
196
+ if (!this.shouldRetry(error, attempt)) {
197
+ break;
198
+ }
199
+ // Exponential backoff with jitter
200
+ const delay = this.calculateBackoff(attempt);
201
+ await this.sleep(delay);
202
+ }
203
+ }
204
+ throw lastError || new Error('Request failed after retries');
205
+ }
206
+ /**
207
+ * Execute a single API request
208
+ */
209
+ async executeRequest(options) {
210
+ const url = `${this.apiBaseUrl}${options.path}`;
211
+ const headers = {
212
+ 'Authorization': `Bearer ${this.config.token}`,
213
+ 'Content-Type': 'application/json',
214
+ ...options.headers,
215
+ };
216
+ const response = await (0, node_fetch_1.default)(url, {
217
+ method: options.method,
218
+ headers,
219
+ body: options.body ? JSON.stringify(options.body) : undefined,
220
+ });
221
+ if (!response.ok) {
222
+ const error = await this.parseErrorResponse(response);
223
+ throw error;
224
+ }
225
+ // DELETE requests return 204 No Content
226
+ if (response.status === 204) {
227
+ return undefined;
228
+ }
229
+ return response.json();
230
+ }
231
+ /**
232
+ * Parse error response from Webex API
233
+ */
234
+ async parseErrorResponse(response) {
235
+ let errorData = null;
236
+ try {
237
+ errorData = await response.json();
238
+ }
239
+ catch {
240
+ // Response body might not be JSON
241
+ }
242
+ const message = errorData?.message || `HTTP ${response.status}: ${response.statusText}`;
243
+ const error = new WebexApiRequestError(message, response.status, errorData?.trackingId, errorData?.errors);
244
+ return error;
245
+ }
246
+ /**
247
+ * Determine if a request should be retried
248
+ */
249
+ shouldRetry(error, attempt) {
250
+ if (error instanceof WebexApiRequestError) {
251
+ return RETRY_STATUS_CODES.includes(error.statusCode);
252
+ }
253
+ // Retry network errors
254
+ return error.message.includes('ECONNRESET') ||
255
+ error.message.includes('ETIMEDOUT') ||
256
+ error.message.includes('ENOTFOUND');
257
+ }
258
+ /**
259
+ * Calculate backoff delay with exponential backoff and jitter
260
+ */
261
+ calculateBackoff(attempt) {
262
+ const baseDelay = this.retryOptions.retryDelayMs;
263
+ const exponentialDelay = baseDelay * Math.pow(2, attempt - 1);
264
+ const jitter = Math.random() * 0.3 * exponentialDelay;
265
+ return Math.min(exponentialDelay + jitter, 30000); // Cap at 30 seconds
266
+ }
267
+ /**
268
+ * Sleep for a given number of milliseconds
269
+ */
270
+ sleep(ms) {
271
+ return new Promise(resolve => setTimeout(resolve, ms));
272
+ }
273
+ }
274
+ exports.WebexSender = WebexSender;
275
+ /**
276
+ * Custom error class for Webex API errors
277
+ */
278
+ class WebexApiRequestError extends Error {
279
+ statusCode;
280
+ trackingId;
281
+ details;
282
+ constructor(message, statusCode, trackingId, details) {
283
+ super(message);
284
+ this.name = 'WebexApiRequestError';
285
+ this.statusCode = statusCode;
286
+ this.trackingId = trackingId;
287
+ this.details = details;
288
+ // Maintains proper stack trace for where error was thrown
289
+ if (Error.captureStackTrace) {
290
+ Error.captureStackTrace(this, WebexApiRequestError);
291
+ }
292
+ }
293
+ toJSON() {
294
+ return {
295
+ name: this.name,
296
+ message: this.message,
297
+ statusCode: this.statusCode,
298
+ trackingId: this.trackingId,
299
+ details: this.details,
300
+ };
301
+ }
302
+ }
303
+ exports.WebexApiRequestError = WebexApiRequestError;
304
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VuZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9zZW5kLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7R0FFRzs7Ozs7O0FBRUgsNERBQTZDO0FBVzdDLE1BQU0sb0JBQW9CLEdBQUcsMEJBQTBCLENBQUM7QUFDeEQsTUFBTSxtQkFBbUIsR0FBRyxDQUFDLENBQUM7QUFDOUIsTUFBTSxzQkFBc0IsR0FBRyxJQUFJLENBQUM7QUFFcEMsb0RBQW9EO0FBQ3BELE1BQU0sa0JBQWtCLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FBQztBQUVoRCxNQUFhLFdBQVc7SUFDZCxNQUFNLENBQXFCO0lBQzNCLFVBQVUsQ0FBUztJQUNuQixZQUFZLENBQWU7SUFFbkMsWUFBWSxNQUEwQjtRQUNwQyxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztRQUNyQixJQUFJLENBQUMsVUFBVSxHQUFHLE1BQU0sQ0FBQyxVQUFVLElBQUksb0JBQW9CLENBQUM7UUFDNUQsSUFBSSxDQUFDLFlBQVksR0FBRztZQUNsQixVQUFVLEVBQUUsTUFBTSxDQUFDLFVBQVUsSUFBSSxtQkFBbUI7WUFDcEQsWUFBWSxFQUFFLE1BQU0sQ0FBQyxZQUFZLElBQUksc0JBQXNCO1NBQzVELENBQUM7SUFDSixDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsSUFBSSxDQUFDLE9BQWdDO1FBQ3pDLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNsRCxPQUFPLElBQUksQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDckMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLFVBQVUsQ0FBQyxNQUFjLEVBQUUsSUFBWSxFQUFFLFFBQWlCO1FBQzlELE9BQU8sSUFBSSxDQUFDLGFBQWEsQ0FBQztZQUN4QixNQUFNO1lBQ04sSUFBSTtZQUNKLFFB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aENELG9EQWdDQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogV2ViZXggTWVzc2FnZSBTZW5kaW5nIE1vZHVsZVxuICovXG5cbmltcG9ydCBmZXRjaCwgeyBSZXNwb25zZSB9IGZyb20gJ25vZGUtZmV0Y2gnO1xuaW1wb3J0IHR5cGUge1xuICBXZWJleENoYW5uZWxDb25maWcsXG4gIFdlYmV4TWVzc2FnZSxcbiAgQ3JlYXRlTWVzc2FnZVJlcXVlc3QsXG4gIE9wZW5DbGF3T3V0Ym91bmRNZXNzYWdlLFxuICBXZWJleEFwaUVycm9yLFxuICBSZXRyeU9wdGlvbnMsXG4gIFJlcXVlc3RPcHRpb25zLFxufSBmcm9tICcuL3R5cGVzJztcblxuY29uc3QgREVGQVVMVF9BUElfQkFTRV9VUkwgPSAnaHR0cHM6Ly93ZWJleGFwaXMuY29tL3YxJztcbmNvbnN0IERFRkFVTFRfTUFYX1JFVFJJRVMgPSAzO1xuY29uc3QgREVGQVVMVF9SRVRSWV9ERUxBWV9NUyA9IDEwMDA7XG5cbi8vIFJhdGUgbGltaXQgc3RhdHVzIGNvZGVzIHRoYXQgc2hvdWxkIHRyaWdnZXIgcmV0cnlcbmNvbnN0IFJFVFJZX1NUQVRVU19DT0RFUyA9IFs0MjksIDUwMiwgNTAzLCA1MDRdO1xuXG5leHBvcnQgY2xhc3MgV2ViZXhTZW5kZXIge1xuICBwcml2YXRlIGNvbmZpZzogV2ViZXhDaGFubmVsQ29uZmlnO1xuICBwcml2YXRlIGFwaUJhc2VVcmw6IHN0cmluZztcbiAgcHJpdmF0ZSByZXRyeU9wdGlvbnM6IFJldHJ5T3B0aW9ucztcblxuICBjb25zdHJ1Y3Rvcihjb25maWc6IFdlYmV4Q2hhbm5lbENvbmZpZykge1xuICAgIHRoaXMuY29uZmlnID0gY29uZmlnO1xuICAgIHRoaXMuYXBpQmFzZVVybCA9IGNvbmZpZy5hcGlCYXNlVXJsIHx8IERFRkFVTFRfQVBJX0JBU0VfVVJMO1xuICAgIHRoaXMucmV0cnlPcHRpb25zID0ge1xuICAgICAgbWF4UmV0cmllczogY29uZmlnLm1heFJldHJpZXMgPz8gREVGQVVMVF9NQVhfUkVUUklFUyxcbiAgICAgIHJldHJ5RGVsYXlNczogY29uZmlnLnJldHJ5RGVsYXlNcyA/PyBERUZBVUxUX1JFVFJZX0RFTEFZX01TLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogU2VuZCBhIG1lc3NhZ2UgdG8gV2ViZXhcbiAgICovXG4gIGFzeW5jIHNlbmQobWVzc2FnZTogT3BlbkNsYXdPdXRib3VuZE1lc3NhZ2UpOiBQcm9taXNlPFdlYmV4TWVzc2FnZT4ge1xuICAgIGNvbnN0IHJlcXVlc3QgPSB0aGlzLmJ1aWxkTWVzc2FnZVJlcXVlc3QobWVzc2FnZSk7XG4gICAgcmV0dXJuIHRoaXMuY3JlYXRlTWVzc2FnZShyZXF1ZXN0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZW5kIGEgdGV4dCBtZXNzYWdlIHRvIGEgcm9vbVxuICAgKi9cbiAgYXN5bmMgc2VuZFRvUm9vbShyb29tSWQ6IHN0cmluZywgdGV4dDogc3RyaW5nLCBtYXJrZG93bj86IHN0cmluZyk6IFByb21pc2U8V2ViZXhNZXNzYWdlPiB7XG4gICAgcmV0dXJuIHRoaXMuY3JlYXRlTWVzc2FnZSh7XG4gICAgICByb29tSWQsXG4gICAgICB0ZXh0LFxuICAgICAgbWFya2Rvd24sXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogU2VuZCBhIGRpcmVjdCBtZXNzYWdlIHRvIGEgcGVyc29uIGJ5IElEXG4gICAqL1xuICBhc3luYyBzZW5kRGlyZWN0QnlJZChwZXJzb25JZDogc3RyaW5nLCB0ZXh0OiBzdHJpbmcsIG1hcmtkb3duPzogc3RyaW5nKTogUHJvbWlzZTxXZWJleE1lc3NhZ2U+IHtcbiAgICByZXR1cm4gdGhpcy5jcmVhdGVNZXNzYWdlKHtcbiAgICAgIHRvUGVyc29uSWQ6IHBlcnNvbklkLFxuICAgICAgdGV4dCxcbiAgICAgIG1hcmtkb3duLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFNlbmQgYSBkaXJlY3QgbWVzc2FnZSB0byBhIHBlcnNvbiBieSBlbWFpbFxuICAgKi9cbiAgYXN5bmMgc2VuZERpcmVjdEJ5RW1haWwoZW1haWw6IHN0cmluZywgdGV4dDogc3RyaW5nLCBtYXJrZG93bj86IHN0cmluZyk6IFByb21pc2U8V2ViZXhNZXNzYWdlPiB7XG4gICAgcmV0dXJuIHRoaXMuY3JlYXRlTWVzc2FnZSh7XG4gICAgICB0b1BlcnNvbkVtYWlsOiBlbWFpbCxcbiAgICAgIHRleHQsXG4gICAgICBtYXJrZG93bixcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZW5kIGEgbWVzc2FnZSB3aXRoIGZpbGUgYXR0YWNobWVudFxuICAgKi9cbiAgYXN5bmMgc2VuZFdpdGhGaWxlKFxuICAgIHJvb21JZDogc3RyaW5nLFxuICAgIHRleHQ6IHN0cmluZyxcbiAgICBmaWxlVXJsOiBzdHJpbmdcbiAgKTogUHJvbWlzZTxXZWJleE1lc3NhZ2U+IHtcbiAgICByZXR1cm4gdGhpcy5jcmVhdGVNZXNzYWdlKHtcbiAgICAgIHJvb21JZCxcbiAgICAgIHRleHQsXG4gICAgICBmaWxlczogW2ZpbGVVcmxdLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFNlbmQgYSB0aHJlYWRlZCByZXBseVxuICAgKi9cbiAgYXN5bmMgc2VuZFJlcGx5KFxuICAgIHJvb21JZDogc3RyaW5nLFxuICAgIHBhcmVudElkOiBzdHJpbmcsXG4gICAgdGV4dDogc3RyaW5nLFxuICAgIG1hcmtkb3duPzogc3RyaW5nXG4gICk6IFByb21pc2U8V2ViZXhNZXNzYWdlPiB7XG4gICAgcmV0dXJuIHRoaXMuY3JlYXRlTWVzc2FnZSh7XG4gICAgICByb29tSWQsXG4gICAgICBwYXJlbnRJZCxcbiAgICAgIHRleHQsXG4gICAgICBtYXJrZG93bixcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgYSBtZXNzYWdlIGJ5IElEXG4gICAqL1xuICBhc3luYyBnZXRNZXNzYWdlKG1lc3NhZ2VJZDogc3RyaW5nKTogUHJvbWlzZTxXZWJleE1lc3NhZ2U+IHtcbiAgICByZXR1cm4gdGhpcy5yZXF1ZXN0PFdlYmV4TWVzc2FnZT4oe1xuICAgICAgbWV0aG9kOiAnR0VUJyxcbiAgICAgIHBhdGg6IGAvbWVzc2FnZXMvJHttZXNzYWdlSWR9YCxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWxldGUgYSBtZXNzYWdlIGJ5IElEXG4gICAqL1xuICBhc3luYyBkZWxldGVNZXNzYWdlKG1lc3NhZ2VJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5yZXF1ZXN0PHZvaWQ+KHtcbiAgICAgIG1ldGhvZDogJ0RFTEVURScsXG4gICAgICBwYXRoOiBgL21lc3NhZ2VzLyR7bWVzc2FnZUlkfWAsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQnVpbGQgYSBXZWJleCBtZXNzYWdlIHJlcXVlc3QgZnJvbSBhbiBPcGVuQ2xhdyBvdXRib3VuZCBtZXNzYWdlXG4gICAqL1xuICBwcml2YXRlIGJ1aWxkTWVzc2FnZVJlcXVlc3QobWVzc2FnZTogT3BlbkNsYXdPdXRib3VuZE1lc3NhZ2UpOiBDcmVhdGVNZXNzYWdlUmVxdWVzdCB7XG4gICAgY29uc3QgcmVxdWVzdDogQ3JlYXRlTWVzc2FnZVJlcXVlc3QgPSB7fTtcblxuICAgIC8vIERldGVybWluZSB0YXJnZXQ6IHJvb21JZCwgcGVyc29uSWQsIG9yIGVtYWlsXG4gICAgY29uc3QgdG8gPSBtZXNzYWdlLnRvO1xuICAgIGlmICh0by5pbmNsdWRlcygnQCcpKSB7XG4gICAgICByZXF1ZXN0LnRvUGVyc29uRW1haWwgPSB0bztcbiAgICB9IGVsc2UgaWYgKHRvLnN0YXJ0c1dpdGgoJ1kybHpZMjl6Y0dGeWF6b3ZMMycpKSB7XG4gICAgICAvLyBCYXNlNjQtZW5jb2RlZCBXZWJleCBJRHMgc3RhcnQgd2l0aCB0aGlzIHByZWZpeFxuICAgICAgaWYgKHRvLmluY2x1ZGVzKCdST09NJykpIHtcbiAgICAgICAgcmVxdWVzdC5yb29tSWQgPSB0bztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJlcXVlc3QudG9QZXJzb25JZCA9IHRvO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBBc3N1bWUgaXQncyBhIHJvb21JZCBpZiBub3QgYW4gZW1haWxcbiAgICAgIHJlcXVlc3Qucm9vbUlkID0gdG87XG4gICAgfVxuXG4gICAgLy8gU2V0IGNvbnRlbnRcbiAgICBpZiAobWVzc2FnZS5jb250ZW50LnRleHQpIHtcbiAgICAgIHJlcXVlc3QudGV4dCA9IG1lc3NhZ2UuY29udGVudC50ZXh0O1xuICAgIH1cbiAgICBpZiAobWVzc2FnZS5jb250ZW50Lm1hcmtkb3duKSB7XG4gICAgICByZXF1ZXN0Lm1hcmtkb3duID0gbWVzc2FnZS5jb250ZW50Lm1hcmtkb3duO1xuICAgIH1cbiAgICBpZiAobWVzc2FnZS5jb250ZW50LmZpbGVzICYmIG1lc3NhZ2UuY29udGVudC5maWxlcy5sZW5ndGggPiAwKSB7XG4gICAgICAvLyBXZWJleCBvbmx5IGFsbG93cyBvbmUgZmlsZSBwZXIgbWVzc2FnZVxuICAgICAgcmVxdWVzdC5maWxlcyA9IFttZXNzYWdlLmNvbnRlbnQuZmlsZXNbMF1dO1xuICAgIH1cbiAgICBpZiAobWVzc2FnZS5jb250ZW50LmNhcmQpIHtcbiAgICAgIHJlcXVlc3QuYXR0YWNobWVudHMgPSBbXG4gICAgICAgIHtcbiAgICAgICAgICBjb250ZW50VHlwZTogJ2FwcGxpY2F0aW9uL3ZuZC5taWNyb3NvZnQuY2FyZC5hZGFwdGl2ZScsXG4gICAgICAgICAgY29udGVudDogbWVzc2FnZS5jb250ZW50LmNhcmQsXG4gICAgICAgIH0sXG4gICAgICBdO1xuICAgIH1cblxuICAgIC8vIFNldCB0aHJlYWRpbmdcbiAgICBpZiAobWVzc2FnZS5wYXJlbnRJZCkge1xuICAgICAgcmVxdWVzdC5wYXJlbnRJZCA9IG1lc3NhZ2UucGFyZW50SWQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlcXVlc3Q7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIGEgbWVzc2FnZSB2aWEgdGhlIFdlYmV4IEFQSVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBjcmVhdGVNZXNzYWdlKHJlcXVlc3Q6IENyZWF0ZU1lc3NhZ2VSZXF1ZXN0KTogUHJvbWlzZTxXZWJleE1lc3NhZ2U+IHtcbiAgICB0aGlzLnZhbGlkYXRlTWVzc2FnZVJlcXVlc3QocmVxdWVzdCk7XG5cbiAgICByZXR1cm4gdGhpcy5yZXF1ZXN0PFdlYmV4TWVzc2FnZT4oe1xuICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICBwYXRoOiAnL21lc3NhZ2VzJyxcbiAgICAgIGJvZHk6IHJlcXVlc3QsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgYSBtZXNzYWdlIHJlcXVlc3QgYmVmb3JlIHNlbmRpbmdcbiAgICovXG4gIHByaXZhdGUgdmFsaWRhdGVNZXNzYWdlUmVxdWVzdChyZXF1ZXN0OiBDcmVhdGVNZXNzYWdlUmVxdWVzdCk6IHZvaWQge1xuICAgIC8vIE11c3QgaGF2ZSBhIHRhcmdldFxuICAgIGlmICghcmVxdWVzdC5yb29tSWQgJiYgIXJlcXVlc3QudG9QZXJzb25JZCAmJiAhcmVxdWVzdC50b1BlcnNvbkVtYWlsKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ01lc3NhZ2UgbXVzdCBoYXZlIGEgdGFyZ2V0OiByb29tSWQsIHRvUGVyc29uSWQsIG9yIHRvUGVyc29uRW1haWwnKTtcbiAgICB9XG5cbiAgICAvLyBNdXN0IGhhdmUgY29udGVudFxuICAgIGlmICghcmVxdWVzdC50ZXh0ICYmICFyZXF1ZXN0Lm1hcmtkb3duICYmICFyZXF1ZXN0LmZpbGVzPy5sZW5ndGggJiYgIXJlcXVlc3QuYXR0YWNobWVudHM/Lmxlbmd0aCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdNZXNzYWdlIG11c3QgaGF2ZSBjb250ZW50OiB0ZXh0LCBtYXJrZG93biwgZmlsZXMsIG9yIGF0dGFjaG1lbnRzJyk7XG4gICAgfVxuXG4gICAgLy8gVGV4dCBoYXMgYSBtYXggc2l6ZSBvZiA3NDM5IGJ5dGVzXG4gICAgaWYgKHJlcXVlc3QudGV4dCAmJiBCdWZmZXIuYnl0ZUxlbmd0aChyZXF1ZXN0LnRleHQsICd1dGY4JykgPiA3NDM5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ01lc3NhZ2UgdGV4dCBleGNlZWRzIG1heGltdW0gc2l6ZSBvZiA3NDM5IGJ5dGVzJyk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIE1ha2UgYW4gQVBJIHJlcXVlc3Qgd2l0aCByZXRyeSBsb2dpY1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyByZXF1ZXN0PFQ+KG9wdGlvbnM6IFJlcXVlc3RPcHRpb25zKTogUHJvbWlzZTxUPiB7XG4gICAgbGV0IGxhc3RFcnJvcjogRXJyb3IgfCBudWxsID0gbnVsbDtcbiAgICBsZXQgYXR0ZW1wdCA9IDA7XG5cbiAgICB3aGlsZSAoYXR0ZW1wdCA8PSB0aGlzLnJldHJ5T3B0aW9ucy5tYXhSZXRyaWVzKSB7XG4gICAgICB0cnkge1xuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5leGVjdXRlUmVxdWVzdDxUPihvcHRpb25zKTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGxhc3RFcnJvciA9IGVycm9yIGFzIEVycm9yO1xuICAgICAgICBhdHRlbXB0Kys7XG5cbiAgICAgICAgaWYgKGF0dGVtcHQgPiB0aGlzLnJldHJ5T3B0aW9ucy5tYXhSZXRyaWVzKSB7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIXRoaXMuc2hvdWxkUmV0cnkoZXJyb3IgYXMgRXJyb3IsIGF0dGVtcHQpKSB7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBFeHBvbmVudGlhbCBiYWNrb2ZmIHdpdGggaml0dGVyXG4gICAgICAgIGNvbnN0IGRlbGF5ID0gdGhpcy5jYWxjdWxhdGVCYWNrb2ZmKGF0dGVtcHQpO1xuICAgICAgICBhd2FpdCB0aGlzLnNsZWVwKGRlbGF5KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aHJvdyBsYXN0RXJyb3IgfHwgbmV3IEVycm9yKCdSZXF1ZXN0IGZhaWxlZCBhZnRlciByZXRyaWVzJyk7XG4gIH1cblxuICAvKipcbiAgICogRXhlY3V0ZSBhIHNpbmdsZSBBUEkgcmVxdWVzdFxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBleGVjdXRlUmVxdWVzdDxUPihvcHRpb25zOiBSZXF1ZXN0T3B0aW9ucyk6IFByb21pc2U8VD4ge1xuICAgIGNvbnN0IHVybCA9IGAke3RoaXMuYXBpQmFzZVVybH0ke29wdGlvbnMucGF0aH1gO1xuICAgIGNvbnN0IGhlYWRlcnM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgICAnQXV0aG9yaXphdGlvbic6IGBCZWFyZXIgJHt0aGlzLmNvbmZpZy50b2tlbn1gLFxuICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyxcbiAgICAgIC4uLm9wdGlvbnMuaGVhZGVycyxcbiAgICB9O1xuXG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaCh1cmwsIHtcbiAgICAgIG1ldGhvZDogb3B0aW9ucy5tZXRob2QsXG4gICAgICBoZWFkZXJzLFxuICAgICAgYm9keTogb3B0aW9ucy5ib2R5ID8gSlNPTi5zdHJpbmdpZnkob3B0aW9ucy5ib2R5KSA6IHVuZGVmaW5lZCxcbiAgICB9KTtcblxuICAgIGlmICghcmVzcG9uc2Uub2spIHtcbiAgICAgIGNvbnN0IGVycm9yID0gYXdhaXQgdGhpcy5wYXJzZUVycm9yUmVzcG9uc2UocmVzcG9uc2UpO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuXG4gICAgLy8gREVMRVRFIHJlcXVlc3RzIHJldHVybiAyMDQgTm8gQ29udGVudFxuICAgIGlmIChyZXNwb25zZS5zdGF0dXMgPT09IDIwNCkge1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZCBhcyBUO1xuICAgIH1cblxuICAgIHJldHVybiByZXNwb25zZS5qc29uKCkgYXMgUHJvbWlzZTxUPjtcbiAgfVxuXG4gIC8qKlxuICAgKiBQYXJzZSBlcnJvciByZXNwb25zZSBmcm9tIFdlYmV4IEFQSVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBwYXJzZUVycm9yUmVzcG9uc2UocmVzcG9uc2U6IFJlc3BvbnNlKTogUHJvbWlzZTxFcnJvcj4ge1xuICAgIGxldCBlcnJvckRhdGE6IFdlYmV4QXBpRXJyb3IgfCBudWxsID0gbnVsbDtcblxuICAgIHRyeSB7XG4gICAgICBlcnJvckRhdGEgPSBhd2FpdCByZXNwb25zZS5qc29uKCkgYXMgV2ViZXhBcGlFcnJvcjtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIFJlc3BvbnNlIGJvZHkgbWlnaHQgbm90IGJlIEpTT05cbiAgICB9XG5cbiAgICBjb25zdCBtZXNzYWdlID0gZXJyb3JEYXRhPy5tZXNzYWdlIHx8IGBIVFRQICR7cmVzcG9uc2Uuc3RhdHVzfTogJHtyZXNwb25zZS5zdGF0dXNUZXh0fWA7XG4gICAgY29uc3QgZXJyb3IgPSBuZXcgV2ViZXhBcGlSZXF1ZXN0RXJyb3IoXG4gICAgICBtZXNzYWdlLFxuICAgICAgcmVzcG9uc2Uuc3RhdHVzLFxuICAgICAgZXJyb3JEYXRhPy50cmFja2luZ0lkLFxuICAgICAgZXJyb3JEYXRhPy5lcnJvcnNcbiAgICApO1xuXG4gICAgcmV0dXJuIGVycm9yO1xuICB9XG5cbiAgLyoqXG4gICAqIERldGVybWluZSBpZiBhIHJlcXVlc3Qgc2hvdWxkIGJlIHJldHJpZWRcbiAgICovXG4gIHByaXZhdGUgc2hvdWxkUmV0cnkoZXJyb3I6IEVycm9yLCBhdHRlbXB0OiBudW1iZXIpOiBib29sZWFuIHtcbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBXZWJleEFwaVJlcXVlc3RFcnJvcikge1xuICAgICAgcmV0dXJuIFJFVFJZX1NUQVRVU19DT0RFUy5pbmNsdWRlcyhlcnJvci5zdGF0dXNDb2RlKTtcbiAgICB9XG4gICAgLy8gUmV0cnkgbmV0d29yayBlcnJvcnNcbiAgICByZXR1cm4gZXJyb3IubWVzc2FnZS5pbmNsdWRlcygnRUNPTk5SRVNFVCcpIHx8XG4gICAgICAgICAgIGVycm9yLm1lc3NhZ2UuaW5jbHVkZXMoJ0VUSU1FRE9VVCcpIHx8XG4gICAgICAgICAgIGVycm9yLm1lc3NhZ2UuaW5jbHVkZXMoJ0VOT1RGT1VORCcpO1xuICB9XG5cbiAgLyoqXG4gICAqIENhbGN1bGF0ZSBiYWNrb2ZmIGRlbGF5IHdpdGggZXhwb25lbnRpYWwgYmFja29mZiBhbmQgaml0dGVyXG4gICAqL1xuICBwcml2YXRlIGNhbGN1bGF0ZUJhY2tvZmYoYXR0ZW1wdDogbnVtYmVyKTogbnVtYmVyIHtcbiAgICBjb25zdCBiYXNlRGVsYXkgPSB0aGlzLnJldHJ5T3B0aW9ucy5yZXRyeURlbGF5TXM7XG4gICAgY29uc3QgZXhwb25lbnRpYWxEZWxheSA9IGJhc2VEZWxheSAqIE1hdGgucG93KDIsIGF0dGVtcHQgLSAxKTtcbiAgICBjb25zdCBqaXR0ZXIgPSBNYXRoLnJhbmRvbSgpICogMC4zICogZXhwb25lbnRpYWxEZWxheTtcbiAgICByZXR1cm4gTWF0aC5taW4oZXhwb25lbnRpYWxEZWxheSArIGppdHRlciwgMzAwMDApOyAvLyBDYXAgYXQgMzAgc2Vjb25kc1xuICB9XG5cbiAgLyoqXG4gICAqIFNsZWVwIGZvciBhIGdpdmVuIG51bWJlciBvZiBtaWxsaXNlY29uZHNcbiAgICovXG4gIHByaXZhdGUgc2xlZXAobXM6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZShyZXNvbHZlID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgbXMpKTtcbiAgfVxufVxuXG4vKipcbiAqIEN1c3RvbSBlcnJvciBjbGFzcyBmb3IgV2ViZXggQVBJIGVycm9yc1xuICovXG5leHBvcnQgY2xhc3MgV2ViZXhBcGlSZXF1ZXN0RXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIHJlYWRvbmx5IHN0YXR1c0NvZGU6IG51bWJlcjtcbiAgcmVhZG9ubHkgdHJhY2tpbmdJZD86IHN0cmluZztcbiAgcmVhZG9ubHkgZGV0YWlscz86IEFycmF5PHsgZGVzY3JpcHRpb246IHN0cmluZyB9PjtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBtZXNzYWdlOiBzdHJpbmcsXG4gICAgc3RhdHVzQ29kZTogbnVtYmVyLFxuICAgIHRyYWNraW5nSWQ/OiBzdHJpbmcsXG4gICAgZGV0YWlscz86IEFycmF5PHsgZGVzY3JpcHRpb246IHN0cmluZyB9PlxuICApIHtcbiAgICBzdXBlcihtZXNzYWdlKTtcbiAgICB0aGlzLm5hbWUgPSAnV2ViZXhBcGlSZXF1ZXN0RXJyb3InO1xuICAgIHRoaXMuc3RhdHVzQ29kZSA9IHN0YXR1c0NvZGU7XG4gICAgdGhpcy50cmFja2luZ0lkID0gdHJhY2tpbmdJZDtcbiAgICB0aGlzLmRldGFpbHMgPSBkZXRhaWxzO1xuXG4gICAgLy8gTWFpbnRhaW5zIHByb3BlciBzdGFjayB0cmFjZSBmb3Igd2hlcmUgZXJyb3Igd2FzIHRocm93blxuICAgIGlmIChFcnJvci5jYXB0dXJlU3RhY2tUcmFjZSkge1xuICAgICAgRXJyb3IuY2FwdHVyZVN0YWNrVHJhY2UodGhpcywgV2ViZXhBcGlSZXF1ZXN0RXJyb3IpO1xuICAgIH1cbiAgfVxuXG4gIHRvSlNPTigpOiBvYmplY3Qge1xuICAgIHJldHVybiB7XG4gICAgICBuYW1lOiB0aGlzLm5hbWUsXG4gICAgICBtZXNzYWdlOiB0aGlzLm1lc3NhZ2UsXG4gICAgICBzdGF0dXNDb2RlOiB0aGlzLnN0YXR1c0NvZGUsXG4gICAgICB0cmFja2luZ0lkOiB0aGlzLnRyYWNraW5nSWQsXG4gICAgICBkZXRhaWxzOiB0aGlzLmRldGFpbHMsXG4gICAgfTtcbiAgfVxufVxuIl19
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Webex Channel Plugin Types
3
+ */
4
+ export type DmPolicy = 'allow' | 'deny' | 'allowlisted' | 'allowlist' | 'pairing';
5
+ export interface WebexChannelConfig {
6
+ /** Webex Bot access token */
7
+ token: string;
8
+ /** Public URL where webhooks will be received */
9
+ webhookUrl: string;
10
+ /** Policy for handling direct messages */
11
+ dmPolicy: DmPolicy;
12
+ /** List of allowed person IDs or emails (used when dmPolicy is 'allowlisted') */
13
+ allowFrom?: string[];
14
+ /** Webhook secret for payload verification */
15
+ webhookSecret?: string;
16
+ /** Base URL for Webex API (defaults to https://webexapis.com/v1) */
17
+ apiBaseUrl?: string;
18
+ /** Maximum retry attempts for failed requests */
19
+ maxRetries?: number;
20
+ /** Retry delay in milliseconds */
21
+ retryDelayMs?: number;
22
+ }
23
+ export interface WebexPerson {
24
+ id: string;
25
+ emails: string[];
26
+ displayName: string;
27
+ nickName?: string;
28
+ firstName?: string;
29
+ lastName?: string;
30
+ avatar?: string;
31
+ orgId: string;
32
+ created: string;
33
+ lastModified?: string;
34
+ type: 'person' | 'bot';
35
+ }
36
+ export interface WebexRoom {
37
+ id: string;
38
+ title: string;
39
+ type: 'direct' | 'group';
40
+ isLocked: boolean;
41
+ teamId?: string;
42
+ lastActivity: string;
43
+ creatorId: string;
44
+ created: string;
45
+ ownerId?: string;
46
+ }
47
+ export interface WebexMessage {
48
+ id: string;
49
+ roomId: string;
50
+ roomType: 'direct' | 'group';
51
+ toPersonId?: string;
52
+ toPersonEmail?: string;
53
+ text?: string;
54
+ markdown?: string;
55
+ html?: string;
56
+ files?: string[];
57
+ personId: string;
58
+ personEmail: string;
59
+ mentionedPeople?: string[];
60
+ mentionedGroups?: string[];
61
+ attachments?: WebexAttachment[];
62
+ created: string;
63
+ updated?: string;
64
+ parentId?: string;
65
+ }
66
+ export interface WebexAttachment {
67
+ contentType: 'application/vnd.microsoft.card.adaptive';
68
+ content: AdaptiveCard;
69
+ }
70
+ export interface AdaptiveCard {
71
+ type: 'AdaptiveCard';
72
+ version: string;
73
+ body: unknown[];
74
+ actions?: unknown[];
75
+ }
76
+ export interface WebexWebhook {
77
+ id: string;
78
+ name: string;
79
+ targetUrl: string;
80
+ resource: WebexWebhookResource;
81
+ event: WebexWebhookEvent;
82
+ filter?: string;
83
+ secret?: string;
84
+ status: 'active' | 'inactive';
85
+ created: string;
86
+ orgId: string;
87
+ createdBy: string;
88
+ appId: string;
89
+ ownedBy: 'creator' | 'org';
90
+ }
91
+ export type WebexWebhookResource = 'messages' | 'memberships' | 'rooms' | 'attachmentActions' | 'meetings' | 'recordings';
92
+ export type WebexWebhookEvent = 'created' | 'updated' | 'deleted' | 'started' | 'ended';
93
+ export interface WebexWebhookPayload {
94
+ id: string;
95
+ name: string;
96
+ targetUrl: string;
97
+ resource: WebexWebhookResource;
98
+ event: WebexWebhookEvent;
99
+ filter?: string;
100
+ orgId: string;
101
+ createdBy: string;
102
+ appId: string;
103
+ ownedBy: string;
104
+ status: string;
105
+ created: string;
106
+ actorId: string;
107
+ data: WebexWebhookData;
108
+ }
109
+ export interface WebexWebhookData {
110
+ id: string;
111
+ roomId: string;
112
+ roomType: 'direct' | 'group';
113
+ personId: string;
114
+ personEmail: string;
115
+ created: string;
116
+ mentionedPeople?: string[];
117
+ mentionedGroups?: string[];
118
+ files?: string[];
119
+ }
120
+ export interface CreateMessageRequest {
121
+ roomId?: string;
122
+ toPersonId?: string;
123
+ toPersonEmail?: string;
124
+ text?: string;
125
+ markdown?: string;
126
+ files?: string[];
127
+ attachments?: WebexAttachment[];
128
+ parentId?: string;
129
+ }
130
+ export interface CreateWebhookRequest {
131
+ name: string;
132
+ targetUrl: string;
133
+ resource: WebexWebhookResource;
134
+ event: WebexWebhookEvent;
135
+ filter?: string;
136
+ secret?: string;
137
+ }
138
+ export interface WebexApiError {
139
+ message: string;
140
+ errors?: Array<{
141
+ description: string;
142
+ }>;
143
+ trackingId: string;
144
+ }
145
+ export interface PaginatedResponse<T> {
146
+ items: T[];
147
+ }
148
+ export interface OpenClawEnvelope {
149
+ /** Unique message identifier */
150
+ id: string;
151
+ /** Channel identifier */
152
+ channel: 'webex';
153
+ /** Conversation/thread identifier */
154
+ conversationId: string;
155
+ /** Message author information */
156
+ author: {
157
+ id: string;
158
+ email?: string;
159
+ displayName?: string;
160
+ isBot: boolean;
161
+ };
162
+ /** Message content */
163
+ content: {
164
+ text?: string;
165
+ markdown?: string;
166
+ attachments?: OpenClawAttachment[];
167
+ };
168
+ /** Message metadata */
169
+ metadata: {
170
+ roomType: 'direct' | 'group';
171
+ roomId: string;
172
+ timestamp: string;
173
+ mentions?: string[];
174
+ parentId?: string;
175
+ raw: WebexMessage;
176
+ };
177
+ }
178
+ export interface OpenClawAttachment {
179
+ type: 'file' | 'card';
180
+ url?: string;
181
+ content?: unknown;
182
+ }
183
+ export interface OpenClawOutboundMessage {
184
+ /** Target conversation ID (roomId) or person ID/email for DMs */
185
+ to: string;
186
+ /** Message content */
187
+ content: {
188
+ text?: string;
189
+ markdown?: string;
190
+ files?: string[];
191
+ card?: AdaptiveCard;
192
+ };
193
+ /** Optional parent message ID for threading */
194
+ parentId?: string;
195
+ }
196
+ export interface WebexChannelPlugin {
197
+ name: string;
198
+ version: string;
199
+ /** Initialize the channel with configuration */
200
+ initialize(config: WebexChannelConfig): Promise<void>;
201
+ /** Send a message */
202
+ send(message: OpenClawOutboundMessage): Promise<WebexMessage>;
203
+ /** Handle incoming webhook */
204
+ handleWebhook(payload: WebexWebhookPayload, signature?: string): Promise<OpenClawEnvelope | null>;
205
+ /** Register webhooks with Webex */
206
+ registerWebhooks(): Promise<WebexWebhook[]>;
207
+ /** Cleanup and shutdown */
208
+ shutdown(): Promise<void>;
209
+ }
210
+ export interface WebhookHandler {
211
+ (envelope: OpenClawEnvelope): Promise<void> | void;
212
+ }
213
+ export interface RetryOptions {
214
+ maxRetries: number;
215
+ retryDelayMs: number;
216
+ shouldRetry?: (error: Error, attempt: number) => boolean;
217
+ }
218
+ export interface RequestOptions {
219
+ method: 'GET' | 'POST' | 'PUT' | 'DELETE';
220
+ path: string;
221
+ body?: unknown;
222
+ headers?: Record<string, string>;
223
+ }
package/dist/types.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ /**
3
+ * Webex Channel Plugin Types
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOztHQUVHIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBXZWJleCBDaGFubmVsIFBsdWdpbiBUeXBlc1xuICovXG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIENvbmZpZ3VyYXRpb24gVHlwZXNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuZXhwb3J0IHR5cGUgRG1Qb2xpY3kgPSAnYWxsb3cnIHwgJ2RlbnknIHwgJ2FsbG93bGlzdGVkJyB8ICdhbGxvd2xpc3QnIHwgJ3BhaXJpbmcnO1xuXG5leHBvcnQgaW50ZXJmYWNlIFdlYmV4Q2hhbm5lbENvbmZpZyB7XG4gIC8qKiBXZWJleCBCb3QgYWNjZXNzIHRva2VuICovXG4gIHRva2VuOiBzdHJpbmc7XG5cbiAgLyoqIFB1YmxpYyBVUkwgd2hlcmUgd2ViaG9va3Mgd2lsbCBiZSByZWNlaXZlZCAqL1xuICB3ZWJob29rVXJsOiBzdHJpbmc7XG5cbiAgLyoqIFBvbGljeSBmb3IgaGFuZGxpbmcgZGlyZWN0IG1lc3NhZ2VzICovXG4gIGRtUG9saWN5OiBEbVBvbGljeTtcblxuICAvKiogTGlzdCBvZiBhbGxvd2VkIHBlcnNvbiBJRHMgb3IgZW1haWxzICh1c2VkIHdoZW4gZG1Qb2xpY3kgaXMgJ2FsbG93bGlzdGVkJykgKi9cbiAgYWxsb3dGcm9tPzogc3RyaW5nW107XG5cbiAgLyoqIFdlYmhvb2sgc2VjcmV0IGZvciBwYXlsb2FkIHZlcmlmaWNhdGlvbiAqL1xuICB3ZWJob29rU2VjcmV0Pzogc3RyaW5nO1xuXG4gIC8qKiBCYXNlIFVSTCBmb3IgV2ViZXggQVBJIChkZWZhdWx0cyB0byBodHRwczovL3dlYmV4YXBpcy5jb20vdjEpICovXG4gIGFwaUJhc2VVcmw/OiBzdHJpbmc7XG5cbiAgLyoqIE1heGltdW0gcmV0cnkgYXR0ZW1wdHMgZm9yIGZhaWxlZCByZXF1ZXN0cyAqL1xuICBtYXhSZXRyaWVzPzogbnVtYmVyO1xuXG4gIC8qKiBSZXRyeSBkZWxheSBpbiBtaWxsaXNlY29uZHMgKi9cbiAgcmV0cnlEZWxheU1zPzogbnVtYmVyO1xufVxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBXZWJleCBBUEkgVHlwZXNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuZXhwb3J0IGludGVyZmFjZSBXZWJleFBlcnNvbiB7XG4gIGlkOiBzdHJpbmc7XG4gIGVtYWlsczogc3RyaW5nW107XG4gIGRpc3BsYXlOYW1lOiBzdHJpbmc7XG4gIG5pY2tOYW1lPzogc3RyaW5nO1xuICBmaXJzdE5hbWU/OiBzdHJpbmc7XG4gIGxhc3ROYW1lPzogc3RyaW5nO1xuICBhdmF0YXI/OiBzdHJpbmc7XG4gIG9yZ0lkOiBzdHJpbmc7XG4gIGNyZWF0ZWQ6IHN0cmluZztcbiAgbGFzdE1vZGlmaWVkPzogc3RyaW5nO1xuICB0eXBlOiAncGVyc29uJyB8ICdib3QnO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFdlYmV4Um9vbSB7XG4gIGlkOiBzdHJpbmc7XG4gIHRpdGxlOiBzdHJpbmc7XG4gIHR5cGU6ICdkaXJlY3QnIHwgJ2dyb3VwJztcbiAgaXNMb2NrZWQ6IGJvb2xlYW47XG4gIHRlYW1JZD86IHN0cmluZztcbiAgbGFzdEFjdGl2aXR5OiBzdHJpbmc7XG4gIGNyZWF0b3JJZDogc3RyaW5nO1xuICBjcmVhdGVkOiBzdHJpbmc7XG4gIG93bmVySWQ/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgV2ViZXhNZXNzYWdlIHtcbiAgaWQ6IHN0cmluZztcbiAgcm9vbUlkOiBzdHJpbmc7XG4gIHJvb21UeXBlOiAnZGlyZWN0JyB8ICdncm91cCc7XG4gIHRvUGVyc29uSWQ/OiBzdHJpbmc7XG4gIHRvUGVyc29uRW1haWw/OiBzdHJpbmc7XG4gIHRleHQ/OiBzdHJpbmc7XG4gIG1hcmtkb3duPzogc3RyaW5nO1xuICBodG1sPzogc3RyaW5nO1xuICBmaWxlcz86IHN0cmluZ1tdO1xuICBwZXJzb25JZDogc3RyaW5nO1xuICBwZXJzb25FbWFpbDogc3RyaW5nO1xuICBtZW50aW9uZWRQZW9wbGU/OiBzdHJpbmdbXTtcbiAgbWVudGlvbmVkR3JvdXBzPzogc3RyaW5nW107XG4gIGF0dGFjaG1lbnRzPzogV2ViZXhBdHRhY2htZW50W107XG4gIGNyZWF0ZWQ6IHN0cmluZztcbiAgdXBkYXRlZD86IHN0cmluZztcbiAgcGFyZW50SWQ/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgV2ViZXhBdHRhY2htZW50IHtcbiAgY29udGVudFR5cGU6ICdhcHBsaWNhdGlvbi92bmQubWljcm9zb2Z0LmNhcmQuYWRhcHRpdmUnO1xuICBjb250ZW50OiBBZGFwdGl2ZUNhcmQ7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQWRhcHRpdmVDYXJkIHtcbiAgdHlwZTogJ0FkYXB0aXZlQ2FyZCc7XG4gIHZlcnNpb246IHN0cmluZztcbiAgYm9keTogdW5rbm93bltdO1xuICBhY3Rpb25zPzogdW5rbm93bltdO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFdlYmV4V2ViaG9vayB7XG4gIGlkOiBzdHJpbmc7XG4gIG5hbWU6IHN0cmluZztcbiAgdGFyZ2V0VXJsOiBzdHJpbmc7XG4gIHJlc291cmNlOiBXZWJleFdlYmhvb2tSZXNvdXJjZTtcbiAgZXZlbnQ6IFdlYmV4V2ViaG9va0V2ZW50O1xuICBmaWx0ZXI/OiBzdHJpbmc7XG4gIHNlY3JldD86IHN0cmluZztcbiAgc3RhdHVzOiAnYWN0aXZlJyB8ICdpbmFjdGl2ZSc7XG4gIGNyZWF0ZWQ6IHN0cmluZztcbiAgb3JnSWQ6IHN0cmluZztcbiAgY3JlYXRlZEJ5OiBzdHJpbmc7XG4gIGFwcElkOiBzdHJpbmc7XG4gIG93bmVkQnk6ICdjcmVhdG9yJyB8ICdvcmcnO1xufVxuXG5leHBvcnQgdHlwZSBXZWJleFdlYmhvb2tSZXNvdXJjZSA9XG4gIHwgJ21lc3NhZ2VzJ1xuICB8ICdtZW1iZXJzaGlwcydcbiAgfCAncm9vbXMnXG4gIHwgJ2F0dGFjaG1lbnRBY3Rpb25zJ1xuICB8ICdtZWV0aW5ncydcbiAgfCAncmVjb3JkaW5ncyc7XG5cbmV4cG9ydCB0eXBlIFdlYmV4V2ViaG9va0V2ZW50ID1cbiAgfCAnY3JlYXRlZCdcbiAgfCAndXBkYXRlZCdcbiAgfCAnZGVsZXRlZCdcbiAgfCAnc3RhcnRlZCdcbiAgfCAnZW5kZWQnO1xuXG5leHBvcnQgaW50ZXJmYWNlIFdlYmV4V2ViaG9va1BheWxvYWQge1xuICBpZDogc3RyaW5nO1xuICBuYW1lOiBzdHJpbmc7XG4gIHRhcmdldFVybDogc3RyaW5nO1xuICByZXNvdXJjZTogV2ViZXhXZWJob29rUmVzb3VyY2U7XG4gIGV2ZW50OiBXZWJleFdlYmhvb2tFdmVudDtcbiAgZmlsdGVyPzogc3RyaW5nO1xuICBvcmdJZDogc3RyaW5nO1xuICBjcmVhdGVkQnk6IHN0cmluZztcbiAgYXBwSWQ6IHN0cmluZztcbiAgb3duZWRCeTogc3RyaW5nO1xuICBzdGF0dXM6IHN0cmluZztcbiAgY3JlYXRlZDogc3RyaW5nO1xuICBhY3RvcklkOiBzdHJpbmc7XG4gIGRhdGE6IFdlYmV4V2ViaG9va0RhdGE7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgV2ViZXhXZWJob29rRGF0YSB7XG4gIGlkOiBzdHJpbmc7XG4gIHJvb21JZDogc3RyaW5nO1xuICByb29tVHlwZTogJ2RpcmVjdCcgfCAnZ3JvdXAnO1xuICBwZXJzb25JZDogc3RyaW5nO1xuICBwZXJzb25FbWFpbDogc3RyaW5nO1xuICBjcmVhdGVkOiBzdHJpbmc7XG4gIG1lbnRpb25lZFBlb3BsZT86IHN0cmluZ1tdO1xuICBtZW50aW9uZWRHcm91cHM/OiBzdHJpbmdbXTtcbiAgZmlsZXM/OiBzdHJpbmdbXTtcbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gQVBJIFJlcXVlc3QvUmVzcG9uc2UgVHlwZXNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuZXhwb3J0IGludGVyZmFjZSBDcmVhdGVNZXNzYWdlUmVxdWVzdCB7XG4gIHJvb21JZD86IHN0cmluZztcbiAgdG9QZXJzb25JZD86IHN0cmluZztcbiAgdG9QZXJzb25FbWFpbD86IHN0cmluZztcbiAgdGV4dD86IHN0cmluZztcbiAgbWFya2Rvd24/OiBzdHJpbmc7XG4gIGZpbGVzPzogc3RyaW5nW107XG4gIGF0dGFjaG1lbnRzPzogV2ViZXhBdHRhY2htZW50W107XG4gIHBhcmVudElkPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENyZWF0ZVdlYmhvb2tSZXF1ZXN0IHtcbiAgbmFtZTogc3RyaW5nO1xuICB0YXJnZXRVcmw6IHN0cmluZztcbiAgcmVzb3VyY2U6IFdlYmV4V2ViaG9va1Jlc291cmNlO1xuICBldmVudDogV2ViZXhXZWJob29rRXZlbnQ7XG4gIGZpbHRlcj86IHN0cmluZztcbiAgc2VjcmV0Pzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFdlYmV4QXBpRXJyb3Ige1xuICBtZXNzYWdlOiBzdHJpbmc7XG4gIGVycm9ycz86IEFycmF5PHtcbiAgICBkZXNjcmlwdGlvbjogc3RyaW5nO1xuICB9PjtcbiAgdHJhY2tpbmdJZDogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFBhZ2luYXRlZFJlc3BvbnNlPFQ+IHtcbiAgaXRlbXM6IFRbXTtcbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gT3BlbkNsYXcgRW52ZWxvcGUgVHlwZXNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuZXhwb3J0IGludGVyZmFjZSBPcGVuQ2xhd0VudmVsb3BlIHtcbiAgLyoqIFVuaXF1ZSBtZXNzYWdlIGlkZW50aWZpZXIgKi9cbiAgaWQ6IHN0cmluZztcblxuICAvKiogQ2hhbm5lbCBpZGVudGlmaWVyICovXG4gIGNoYW5uZWw6ICd3ZWJleCc7XG5cbiAgLyoqIENvbnZlcnNhdGlvbi90aHJlYWQgaWRlbnRpZmllciAqL1xuICBjb252ZXJzYXRpb25JZDogc3RyaW5nO1xuXG4gIC8qKiBNZXNzYWdlIGF1dGhvciBpbmZvcm1hdGlvbiAqL1xuICBhdXRob3I6IHtcbiAgICBpZDogc3RyaW5nO1xuICAgIGVtYWlsPzogc3RyaW5nO1xuICAgIGRpc3BsYXlOYW1lPzogc3RyaW5nO1xuICAgIGlzQm90OiBib29sZWFuO1xuICB9O1xuXG4gIC8qKiBNZXNzYWdlIGNvbnRlbnQgKi9cbiAgY29udGVudDoge1xuICAgIHRleHQ/OiBzdHJpbmc7XG4gICAgbWFya2Rvd24/OiBzdHJpbmc7XG4gICAgYXR0YWNobWVudHM/OiBPcGVuQ2xhd0F0dGFjaG1lbnRbXTtcbiAgfTtcblxuICAvKiogTWVzc2FnZSBtZXRhZGF0YSAqL1xuICBtZXRhZGF0YToge1xuICAgIHJvb21UeXBlOiAnZGlyZWN0JyB8ICdncm91cCc7XG4gICAgcm9vbUlkOiBzdHJpbmc7XG4gICAgdGltZXN0YW1wOiBzdHJpbmc7XG4gICAgbWVudGlvbnM/OiBzdHJpbmdbXTtcbiAgICBwYXJlbnRJZD86IHN0cmluZztcbiAgICByYXc6IFdlYmV4TWVzc2FnZTtcbiAgfTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBPcGVuQ2xhd0F0dGFjaG1lbnQge1xuICB0eXBlOiAnZmlsZScgfCAnY2FyZCc7XG4gIHVybD86IHN0cmluZztcbiAgY29udGVudD86IHVua25vd247XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgT3BlbkNsYXdPdXRib3VuZE1lc3NhZ2Uge1xuICAvKiogVGFyZ2V0IGNvbnZlcnNhdGlvbiBJRCAocm9vbUlkKSBvciBwZXJzb24gSUQvZW1haWwgZm9yIERNcyAqL1xuICB0bzogc3RyaW5nO1xuXG4gIC8qKiBNZXNzYWdlIGNvbnRlbnQgKi9cbiAgY29udGVudDoge1xuICAgIHRleHQ/OiBzdHJpbmc7XG4gICAgbWFya2Rvd24/OiBzdHJpbmc7XG4gICAgZmlsZXM/OiBzdHJpbmdbXTtcbiAgICBjYXJkPzogQWRhcHRpdmVDYXJkO1xuICB9O1xuXG4gIC8qKiBPcHRpb25hbCBwYXJlbnQgbWVzc2FnZSBJRCBmb3IgdGhyZWFkaW5nICovXG4gIHBhcmVudElkPzogc3RyaW5nO1xufVxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBQbHVnaW4gVHlwZXNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuZXhwb3J0IGludGVyZmFjZSBXZWJleENoYW5uZWxQbHVnaW4ge1xuICBuYW1lOiBzdHJpbmc7XG4gIHZlcnNpb246IHN0cmluZztcblxuICAvKiogSW5pdGlhbGl6ZSB0aGUgY2hhbm5lbCB3aXRoIGNvbmZpZ3VyYXRpb24gKi9cbiAgaW5pdGlhbGl6ZShjb25maWc6IFdlYmV4Q2hhbm5lbENvbmZpZyk6IFByb21pc2U8dm9pZD47XG5cbiAgLyoqIFNlbmQgYSBtZXNzYWdlICovXG4gIHNlbmQobWVzc2FnZTogT3BlbkNsYXdPdXRib3VuZE1lc3NhZ2UpOiBQcm9taXNlPFdlYmV4TWVzc2FnZT47XG5cbiAgLyoqIEhhbmRsZSBpbmNvbWluZyB3ZWJob29rICovXG4gIGhhbmRsZVdlYmhvb2socGF5bG9hZDogV2ViZXhXZWJob29rUGF5bG9hZCwgc2lnbmF0dXJlPzogc3RyaW5nKTogUHJvbWlzZTxPcGVuQ2xhd0VudmVsb3BlIHwgbnVsbD47XG5cbiAgLyoqIFJlZ2lzdGVyIHdlYmhvb2tzIHdpdGggV2ViZXggKi9cbiAgcmVnaXN0ZXJXZWJob29rcygpOiBQcm9taXNlPFdlYmV4V2ViaG9va1tdPjtcblxuICAvKiogQ2xlYW51cCBhbmQgc2h1dGRvd24gKi9cbiAgc2h1dGRvd24oKTogUHJvbWlzZTx2b2lkPjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBXZWJob29rSGFuZGxlciB7XG4gIChlbnZlbG9wZTogT3BlbkNsYXdFbnZlbG9wZSk6IFByb21pc2U8dm9pZD4gfCB2b2lkO1xufVxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBJbnRlcm5hbCBUeXBlc1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5leHBvcnQgaW50ZXJmYWNlIFJldHJ5T3B0aW9ucyB7XG4gIG1heFJldHJpZXM6IG51bWJlcjtcbiAgcmV0cnlEZWxheU1zOiBudW1iZXI7XG4gIHNob3VsZFJldHJ5PzogKGVycm9yOiBFcnJvciwgYXR0ZW1wdDogbnVtYmVyKSA9PiBib29sZWFuO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJlcXVlc3RPcHRpb25zIHtcbiAgbWV0aG9kOiAnR0VUJyB8ICdQT1NUJyB8ICdQVVQnIHwgJ0RFTEVURSc7XG4gIHBhdGg6IHN0cmluZztcbiAgYm9keT86IHVua25vd247XG4gIGhlYWRlcnM/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xufVxuIl19
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Webex Webhook Handler Module
3
+ */
4
+ import type { WebexChannelConfig, WebexWebhookPayload, WebexWebhook, CreateWebhookRequest, OpenClawEnvelope } from './types';
5
+ export declare class WebexWebhookHandler {
6
+ private config;
7
+ private apiBaseUrl;
8
+ private botId;
9
+ constructor(config: WebexChannelConfig);
10
+ /**
11
+ * Initialize the webhook handler (fetch bot info)
12
+ */
13
+ initialize(): Promise<void>;
14
+ /**
15
+ * Handle an incoming webhook request
16
+ */
17
+ handleWebhook(payload: WebexWebhookPayload, signature?: string): Promise<OpenClawEnvelope | null>;
18
+ /**
19
+ * Verify webhook signature using HMAC-SHA1
20
+ */
21
+ verifySignature(payload: WebexWebhookPayload, signature: string): boolean;
22
+ /**
23
+ * Check if the sender is allowed based on DM policy
24
+ */
25
+ private isAllowedSender;
26
+ /**
27
+ * Fetch full message details from Webex API
28
+ */
29
+ private fetchMessage;
30
+ /**
31
+ * Normalize a Webex message to OpenClaw envelope format
32
+ */
33
+ private normalizeMessage;
34
+ /**
35
+ * Register webhooks with Webex
36
+ */
37
+ registerWebhooks(): Promise<WebexWebhook[]>;
38
+ /**
39
+ * List all webhooks
40
+ */
41
+ listWebhooks(): Promise<WebexWebhook[]>;
42
+ /**
43
+ * Create a webhook
44
+ */
45
+ createWebhook(request: CreateWebhookRequest): Promise<WebexWebhook>;
46
+ /**
47
+ * Delete a webhook
48
+ */
49
+ deleteWebhook(webhookId: string): Promise<void>;
50
+ /**
51
+ * Get bot information
52
+ */
53
+ private getBotInfo;
54
+ /**
55
+ * Get the bot ID (after initialization)
56
+ */
57
+ getBotId(): string | null;
58
+ }
59
+ /**
60
+ * Custom error for webhook validation failures
61
+ */
62
+ export declare class WebhookValidationError extends Error {
63
+ constructor(message: string);
64
+ }