@jimiford/channel-webex 1.0.0

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,223 @@
1
+ /**
2
+ * Webex Channel Plugin Types
3
+ */
4
+ export type DmPolicy = 'allow' | 'deny' | 'allowlisted';
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOztHQUVHIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBXZWJleCBDaGFubmVsIFBsdWdpbiBUeXBlc1xuICovXG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIENvbmZpZ3VyYXRpb24gVHlwZXNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuZXhwb3J0IHR5cGUgRG1Qb2xpY3kgPSAnYWxsb3cnIHwgJ2RlbnknIHwgJ2FsbG93bGlzdGVkJztcblxuZXhwb3J0IGludGVyZmFjZSBXZWJleENoYW5uZWxDb25maWcge1xuICAvKiogV2ViZXggQm90IGFjY2VzcyB0b2tlbiAqL1xuICB0b2tlbjogc3RyaW5nO1xuXG4gIC8qKiBQdWJsaWMgVVJMIHdoZXJlIHdlYmhvb2tzIHdpbGwgYmUgcmVjZWl2ZWQgKi9cbiAgd2ViaG9va1VybDogc3RyaW5nO1xuXG4gIC8qKiBQb2xpY3kgZm9yIGhhbmRsaW5nIGRpcmVjdCBtZXNzYWdlcyAqL1xuICBkbVBvbGljeTogRG1Qb2xpY3k7XG5cbiAgLyoqIExpc3Qgb2YgYWxsb3dlZCBwZXJzb24gSURzIG9yIGVtYWlscyAodXNlZCB3aGVuIGRtUG9saWN5IGlzICdhbGxvd2xpc3RlZCcpICovXG4gIGFsbG93RnJvbT86IHN0cmluZ1tdO1xuXG4gIC8qKiBXZWJob29rIHNlY3JldCBmb3IgcGF5bG9hZCB2ZXJpZmljYXRpb24gKi9cbiAgd2ViaG9va1NlY3JldD86IHN0cmluZztcblxuICAvKiogQmFzZSBVUkwgZm9yIFdlYmV4IEFQSSAoZGVmYXVsdHMgdG8gaHR0cHM6Ly93ZWJleGFwaXMuY29tL3YxKSAqL1xuICBhcGlCYXNlVXJsPzogc3RyaW5nO1xuXG4gIC8qKiBNYXhpbXVtIHJldHJ5IGF0dGVtcHRzIGZvciBmYWlsZWQgcmVxdWVzdHMgKi9cbiAgbWF4UmV0cmllcz86IG51bWJlcjtcblxuICAvKiogUmV0cnkgZGVsYXkgaW4gbWlsbGlzZWNvbmRzICovXG4gIHJldHJ5RGVsYXlNcz86IG51bWJlcjtcbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gV2ViZXggQVBJIFR5cGVzXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbmV4cG9ydCBpbnRlcmZhY2UgV2ViZXhQZXJzb24ge1xuICBpZDogc3RyaW5nO1xuICBlbWFpbHM6IHN0cmluZ1tdO1xuICBkaXNwbGF5TmFtZTogc3RyaW5nO1xuICBuaWNrTmFtZT86IHN0cmluZztcbiAgZmlyc3ROYW1lPzogc3RyaW5nO1xuICBsYXN0TmFtZT86IHN0cmluZztcbiAgYXZhdGFyPzogc3RyaW5nO1xuICBvcmdJZDogc3RyaW5nO1xuICBjcmVhdGVkOiBzdHJpbmc7XG4gIGxhc3RNb2RpZmllZD86IHN0cmluZztcbiAgdHlwZTogJ3BlcnNvbicgfCAnYm90Jztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBXZWJleFJvb20ge1xuICBpZDogc3RyaW5nO1xuICB0aXRsZTogc3RyaW5nO1xuICB0eXBlOiAnZGlyZWN0JyB8ICdncm91cCc7XG4gIGlzTG9ja2VkOiBib29sZWFuO1xuICB0ZWFtSWQ/OiBzdHJpbmc7XG4gIGxhc3RBY3Rpdml0eTogc3RyaW5nO1xuICBjcmVhdG9ySWQ6IHN0cmluZztcbiAgY3JlYXRlZDogc3RyaW5nO1xuICBvd25lcklkPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFdlYmV4TWVzc2FnZSB7XG4gIGlkOiBzdHJpbmc7XG4gIHJvb21JZDogc3RyaW5nO1xuICByb29tVHlwZTogJ2RpcmVjdCcgfCAnZ3JvdXAnO1xuICB0b1BlcnNvbklkPzogc3RyaW5nO1xuICB0b1BlcnNvbkVtYWlsPzogc3RyaW5nO1xuICB0ZXh0Pzogc3RyaW5nO1xuICBtYXJrZG93bj86IHN0cmluZztcbiAgaHRtbD86IHN0cmluZztcbiAgZmlsZXM/OiBzdHJpbmdbXTtcbiAgcGVyc29uSWQ6IHN0cmluZztcbiAgcGVyc29uRW1haWw6IHN0cmluZztcbiAgbWVudGlvbmVkUGVvcGxlPzogc3RyaW5nW107XG4gIG1lbnRpb25lZEdyb3Vwcz86IHN0cmluZ1tdO1xuICBhdHRhY2htZW50cz86IFdlYmV4QXR0YWNobWVudFtdO1xuICBjcmVhdGVkOiBzdHJpbmc7XG4gIHVwZGF0ZWQ/OiBzdHJpbmc7XG4gIHBhcmVudElkPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFdlYmV4QXR0YWNobWVudCB7XG4gIGNvbnRlbnRUeXBlOiAnYXBwbGljYXRpb24vdm5kLm1pY3Jvc29mdC5jYXJkLmFkYXB0aXZlJztcbiAgY29udGVudDogQWRhcHRpdmVDYXJkO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEFkYXB0aXZlQ2FyZCB7XG4gIHR5cGU6ICdBZGFwdGl2ZUNhcmQnO1xuICB2ZXJzaW9uOiBzdHJpbmc7XG4gIGJvZHk6IHVua25vd25bXTtcbiAgYWN0aW9ucz86IHVua25vd25bXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBXZWJleFdlYmhvb2sge1xuICBpZDogc3RyaW5nO1xuICBuYW1lOiBzdHJpbmc7XG4gIHRhcmdldFVybDogc3RyaW5nO1xuICByZXNvdXJjZTogV2ViZXhXZWJob29rUmVzb3VyY2U7XG4gIGV2ZW50OiBXZWJleFdlYmhvb2tFdmVudDtcbiAgZmlsdGVyPzogc3RyaW5nO1xuICBzZWNyZXQ/OiBzdHJpbmc7XG4gIHN0YXR1czogJ2FjdGl2ZScgfCAnaW5hY3RpdmUnO1xuICBjcmVhdGVkOiBzdHJpbmc7XG4gIG9yZ0lkOiBzdHJpbmc7XG4gIGNyZWF0ZWRCeTogc3RyaW5nO1xuICBhcHBJZDogc3RyaW5nO1xuICBvd25lZEJ5OiAnY3JlYXRvcicgfCAnb3JnJztcbn1cblxuZXhwb3J0IHR5cGUgV2ViZXhXZWJob29rUmVzb3VyY2UgPVxuICB8ICdtZXNzYWdlcydcbiAgfCAnbWVtYmVyc2hpcHMnXG4gIHwgJ3Jvb21zJ1xuICB8ICdhdHRhY2htZW50QWN0aW9ucydcbiAgfCAnbWVldGluZ3MnXG4gIHwgJ3JlY29yZGluZ3MnO1xuXG5leHBvcnQgdHlwZSBXZWJleFdlYmhvb2tFdmVudCA9XG4gIHwgJ2NyZWF0ZWQnXG4gIHwgJ3VwZGF0ZWQnXG4gIHwgJ2RlbGV0ZWQnXG4gIHwgJ3N0YXJ0ZWQnXG4gIHwgJ2VuZGVkJztcblxuZXhwb3J0IGludGVyZmFjZSBXZWJleFdlYmhvb2tQYXlsb2FkIHtcbiAgaWQ6IHN0cmluZztcbiAgbmFtZTogc3RyaW5nO1xuICB0YXJnZXRVcmw6IHN0cmluZztcbiAgcmVzb3VyY2U6IFdlYmV4V2ViaG9va1Jlc291cmNlO1xuICBldmVudDogV2ViZXhXZWJob29rRXZlbnQ7XG4gIGZpbHRlcj86IHN0cmluZztcbiAgb3JnSWQ6IHN0cmluZztcbiAgY3JlYXRlZEJ5OiBzdHJpbmc7XG4gIGFwcElkOiBzdHJpbmc7XG4gIG93bmVkQnk6IHN0cmluZztcbiAgc3RhdHVzOiBzdHJpbmc7XG4gIGNyZWF0ZWQ6IHN0cmluZztcbiAgYWN0b3JJZDogc3RyaW5nO1xuICBkYXRhOiBXZWJleFdlYmhvb2tEYXRhO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFdlYmV4V2ViaG9va0RhdGEge1xuICBpZDogc3RyaW5nO1xuICByb29tSWQ6IHN0cmluZztcbiAgcm9vbVR5cGU6ICdkaXJlY3QnIHwgJ2dyb3VwJztcbiAgcGVyc29uSWQ6IHN0cmluZztcbiAgcGVyc29uRW1haWw6IHN0cmluZztcbiAgY3JlYXRlZDogc3RyaW5nO1xuICBtZW50aW9uZWRQZW9wbGU/OiBzdHJpbmdbXTtcbiAgbWVudGlvbmVkR3JvdXBzPzogc3RyaW5nW107XG4gIGZpbGVzPzogc3RyaW5nW107XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIEFQSSBSZXF1ZXN0L1Jlc3BvbnNlIFR5cGVzXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ3JlYXRlTWVzc2FnZVJlcXVlc3Qge1xuICByb29tSWQ/OiBzdHJpbmc7XG4gIHRvUGVyc29uSWQ/OiBzdHJpbmc7XG4gIHRvUGVyc29uRW1haWw/OiBzdHJpbmc7XG4gIHRleHQ/OiBzdHJpbmc7XG4gIG1hcmtkb3duPzogc3RyaW5nO1xuICBmaWxlcz86IHN0cmluZ1tdO1xuICBhdHRhY2htZW50cz86IFdlYmV4QXR0YWNobWVudFtdO1xuICBwYXJlbnRJZD86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDcmVhdGVXZWJob29rUmVxdWVzdCB7XG4gIG5hbWU6IHN0cmluZztcbiAgdGFyZ2V0VXJsOiBzdHJpbmc7XG4gIHJlc291cmNlOiBXZWJleFdlYmhvb2tSZXNvdXJjZTtcbiAgZXZlbnQ6IFdlYmV4V2ViaG9va0V2ZW50O1xuICBmaWx0ZXI/OiBzdHJpbmc7XG4gIHNlY3JldD86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBXZWJleEFwaUVycm9yIHtcbiAgbWVzc2FnZTogc3RyaW5nO1xuICBlcnJvcnM/OiBBcnJheTx7XG4gICAgZGVzY3JpcHRpb246IHN0cmluZztcbiAgfT47XG4gIHRyYWNraW5nSWQ6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBQYWdpbmF0ZWRSZXNwb25zZTxUPiB7XG4gIGl0ZW1zOiBUW107XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIE9wZW5DbGF3IEVudmVsb3BlIFR5cGVzXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbmV4cG9ydCBpbnRlcmZhY2UgT3BlbkNsYXdFbnZlbG9wZSB7XG4gIC8qKiBVbmlxdWUgbWVzc2FnZSBpZGVudGlmaWVyICovXG4gIGlkOiBzdHJpbmc7XG5cbiAgLyoqIENoYW5uZWwgaWRlbnRpZmllciAqL1xuICBjaGFubmVsOiAnd2ViZXgnO1xuXG4gIC8qKiBDb252ZXJzYXRpb24vdGhyZWFkIGlkZW50aWZpZXIgKi9cbiAgY29udmVyc2F0aW9uSWQ6IHN0cmluZztcblxuICAvKiogTWVzc2FnZSBhdXRob3IgaW5mb3JtYXRpb24gKi9cbiAgYXV0aG9yOiB7XG4gICAgaWQ6IHN0cmluZztcbiAgICBlbWFpbD86IHN0cmluZztcbiAgICBkaXNwbGF5TmFtZT86IHN0cmluZztcbiAgICBpc0JvdDogYm9vbGVhbjtcbiAgfTtcblxuICAvKiogTWVzc2FnZSBjb250ZW50ICovXG4gIGNvbnRlbnQ6IHtcbiAgICB0ZXh0Pzogc3RyaW5nO1xuICAgIG1hcmtkb3duPzogc3RyaW5nO1xuICAgIGF0dGFjaG1lbnRzPzogT3BlbkNsYXdBdHRhY2htZW50W107XG4gIH07XG5cbiAgLyoqIE1lc3NhZ2UgbWV0YWRhdGEgKi9cbiAgbWV0YWRhdGE6IHtcbiAgICByb29tVHlwZTogJ2RpcmVjdCcgfCAnZ3JvdXAnO1xuICAgIHJvb21JZDogc3RyaW5nO1xuICAgIHRpbWVzdGFtcDogc3RyaW5nO1xuICAgIG1lbnRpb25zPzogc3RyaW5nW107XG4gICAgcGFyZW50SWQ/OiBzdHJpbmc7XG4gICAgcmF3OiBXZWJleE1lc3NhZ2U7XG4gIH07XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgT3BlbkNsYXdBdHRhY2htZW50IHtcbiAgdHlwZTogJ2ZpbGUnIHwgJ2NhcmQnO1xuICB1cmw/OiBzdHJpbmc7XG4gIGNvbnRlbnQ/OiB1bmtub3duO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIE9wZW5DbGF3T3V0Ym91bmRNZXNzYWdlIHtcbiAgLyoqIFRhcmdldCBjb252ZXJzYXRpb24gSUQgKHJvb21JZCkgb3IgcGVyc29uIElEL2VtYWlsIGZvciBETXMgKi9cbiAgdG86IHN0cmluZztcblxuICAvKiogTWVzc2FnZSBjb250ZW50ICovXG4gIGNvbnRlbnQ6IHtcbiAgICB0ZXh0Pzogc3RyaW5nO1xuICAgIG1hcmtkb3duPzogc3RyaW5nO1xuICAgIGZpbGVzPzogc3RyaW5nW107XG4gICAgY2FyZD86IEFkYXB0aXZlQ2FyZDtcbiAgfTtcblxuICAvKiogT3B0aW9uYWwgcGFyZW50IG1lc3NhZ2UgSUQgZm9yIHRocmVhZGluZyAqL1xuICBwYXJlbnRJZD86IHN0cmluZztcbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gUGx1Z2luIFR5cGVzXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbmV4cG9ydCBpbnRlcmZhY2UgV2ViZXhDaGFubmVsUGx1Z2luIHtcbiAgbmFtZTogc3RyaW5nO1xuICB2ZXJzaW9uOiBzdHJpbmc7XG5cbiAgLyoqIEluaXRpYWxpemUgdGhlIGNoYW5uZWwgd2l0aCBjb25maWd1cmF0aW9uICovXG4gIGluaXRpYWxpemUoY29uZmlnOiBXZWJleENoYW5uZWxDb25maWcpOiBQcm9taXNlPHZvaWQ+O1xuXG4gIC8qKiBTZW5kIGEgbWVzc2FnZSAqL1xuICBzZW5kKG1lc3NhZ2U6IE9wZW5DbGF3T3V0Ym91bmRNZXNzYWdlKTogUHJvbWlzZTxXZWJleE1lc3NhZ2U+O1xuXG4gIC8qKiBIYW5kbGUgaW5jb21pbmcgd2ViaG9vayAqL1xuICBoYW5kbGVXZWJob29rKHBheWxvYWQ6IFdlYmV4V2ViaG9va1BheWxvYWQsIHNpZ25hdHVyZT86IHN0cmluZyk6IFByb21pc2U8T3BlbkNsYXdFbnZlbG9wZSB8IG51bGw+O1xuXG4gIC8qKiBSZWdpc3RlciB3ZWJob29rcyB3aXRoIFdlYmV4ICovXG4gIHJlZ2lzdGVyV2ViaG9va3MoKTogUHJvbWlzZTxXZWJleFdlYmhvb2tbXT47XG5cbiAgLyoqIENsZWFudXAgYW5kIHNodXRkb3duICovXG4gIHNodXRkb3duKCk6IFByb21pc2U8dm9pZD47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgV2ViaG9va0hhbmRsZXIge1xuICAoZW52ZWxvcGU6IE9wZW5DbGF3RW52ZWxvcGUpOiBQcm9taXNlPHZvaWQ+IHwgdm9pZDtcbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gSW50ZXJuYWwgVHlwZXNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuZXhwb3J0IGludGVyZmFjZSBSZXRyeU9wdGlvbnMge1xuICBtYXhSZXRyaWVzOiBudW1iZXI7XG4gIHJldHJ5RGVsYXlNczogbnVtYmVyO1xuICBzaG91bGRSZXRyeT86IChlcnJvcjogRXJyb3IsIGF0dGVtcHQ6IG51bWJlcikgPT4gYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSZXF1ZXN0T3B0aW9ucyB7XG4gIG1ldGhvZDogJ0dFVCcgfCAnUE9TVCcgfCAnUFVUJyB8ICdERUxFVEUnO1xuICBwYXRoOiBzdHJpbmc7XG4gIGJvZHk/OiB1bmtub3duO1xuICBoZWFkZXJzPzogUmVjb3JkPHN0cmluZywgc3RyaW5nPjtcbn1cbiJdfQ==
@@ -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
+ }
@@ -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==