@hasna/connectors 0.3.16 → 0.4.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.
- package/bin/index.js +71 -1
- package/bin/mcp.js +71 -1
- package/bin/serve.js +70 -0
- package/connectors/connect-asana/.env.example +11 -0
- package/connectors/connect-asana/CLAUDE.md +128 -0
- package/connectors/connect-asana/README.md +193 -0
- package/connectors/connect-asana/package.json +52 -0
- package/connectors/connect-asana/src/api/client.ts +119 -0
- package/connectors/connect-asana/src/api/index.ts +319 -0
- package/connectors/connect-asana/src/cli/index.ts +731 -0
- package/connectors/connect-asana/src/index.ts +19 -0
- package/connectors/connect-asana/src/types/index.ts +270 -0
- package/connectors/connect-asana/src/utils/config.ts +171 -0
- package/connectors/connect-asana/src/utils/output.ts +119 -0
- package/connectors/connect-asana/tsconfig.json +16 -0
- package/connectors/connect-clickup/.env.example +11 -0
- package/connectors/connect-clickup/CLAUDE.md +128 -0
- package/connectors/connect-clickup/README.md +193 -0
- package/connectors/connect-clickup/package.json +52 -0
- package/connectors/connect-clickup/src/api/client.ts +116 -0
- package/connectors/connect-clickup/src/api/index.ts +400 -0
- package/connectors/connect-clickup/src/cli/index.ts +625 -0
- package/connectors/connect-clickup/src/index.ts +19 -0
- package/connectors/connect-clickup/src/types/index.ts +591 -0
- package/connectors/connect-clickup/src/utils/config.ts +157 -0
- package/connectors/connect-clickup/src/utils/output.ts +119 -0
- package/connectors/connect-clickup/tsconfig.json +16 -0
- package/connectors/connect-confluence/.env.example +11 -0
- package/connectors/connect-confluence/CLAUDE.md +272 -0
- package/connectors/connect-confluence/README.md +193 -0
- package/connectors/connect-confluence/package.json +53 -0
- package/connectors/connect-confluence/scripts/release.ts +179 -0
- package/connectors/connect-confluence/src/api/client.ts +213 -0
- package/connectors/connect-confluence/src/api/example.ts +48 -0
- package/connectors/connect-confluence/src/api/index.ts +51 -0
- package/connectors/connect-confluence/src/cli/index.ts +254 -0
- package/connectors/connect-confluence/src/index.ts +103 -0
- package/connectors/connect-confluence/src/types/index.ts +237 -0
- package/connectors/connect-confluence/src/utils/auth.ts +274 -0
- package/connectors/connect-confluence/src/utils/bulk.ts +212 -0
- package/connectors/connect-confluence/src/utils/config.ts +326 -0
- package/connectors/connect-confluence/src/utils/output.ts +175 -0
- package/connectors/connect-confluence/src/utils/settings.ts +114 -0
- package/connectors/connect-confluence/src/utils/storage.ts +198 -0
- package/connectors/connect-confluence/tsconfig.json +16 -0
- package/connectors/connect-jira/.env.example +11 -0
- package/connectors/connect-jira/CLAUDE.md +128 -0
- package/connectors/connect-jira/README.md +193 -0
- package/connectors/connect-jira/package.json +53 -0
- package/connectors/connect-jira/src/api/client.ts +131 -0
- package/connectors/connect-jira/src/api/index.ts +266 -0
- package/connectors/connect-jira/src/cli/index.ts +653 -0
- package/connectors/connect-jira/src/index.ts +23 -0
- package/connectors/connect-jira/src/types/index.ts +448 -0
- package/connectors/connect-jira/src/utils/config.ts +179 -0
- package/connectors/connect-jira/src/utils/output.ts +119 -0
- package/connectors/connect-jira/tsconfig.json +16 -0
- package/connectors/connect-linear/CLAUDE.md +88 -0
- package/connectors/connect-linear/README.md +201 -0
- package/connectors/connect-linear/package.json +45 -0
- package/connectors/connect-linear/src/api/client.ts +62 -0
- package/connectors/connect-linear/src/api/index.ts +46 -0
- package/connectors/connect-linear/src/api/issues.ts +247 -0
- package/connectors/connect-linear/src/api/projects.ts +179 -0
- package/connectors/connect-linear/src/api/teams.ts +125 -0
- package/connectors/connect-linear/src/api/users.ts +112 -0
- package/connectors/connect-linear/src/cli/index.ts +560 -0
- package/connectors/connect-linear/src/index.ts +27 -0
- package/connectors/connect-linear/src/types/index.ts +275 -0
- package/connectors/connect-linear/src/utils/config.ts +249 -0
- package/connectors/connect-linear/src/utils/output.ts +119 -0
- package/connectors/connect-linear/tsconfig.json +16 -0
- package/connectors/connect-slack/.env.example +7 -0
- package/connectors/connect-slack/CLAUDE.md +69 -0
- package/connectors/connect-slack/README.md +150 -0
- package/connectors/connect-slack/package.json +44 -0
- package/connectors/connect-slack/src/api/channels.ts +112 -0
- package/connectors/connect-slack/src/api/client.ts +97 -0
- package/connectors/connect-slack/src/api/index.ts +42 -0
- package/connectors/connect-slack/src/api/messages.ts +127 -0
- package/connectors/connect-slack/src/api/users.ts +110 -0
- package/connectors/connect-slack/src/cli/index.ts +494 -0
- package/connectors/connect-slack/src/index.ts +21 -0
- package/connectors/connect-slack/src/types/index.ts +263 -0
- package/connectors/connect-slack/src/utils/config.ts +297 -0
- package/connectors/connect-slack/src/utils/output.ts +119 -0
- package/connectors/connect-slack/tsconfig.json +16 -0
- package/connectors/connect-telegram/.env.example +2 -0
- package/connectors/connect-telegram/package.json +49 -0
- package/connectors/connect-todoist/.env.example +11 -0
- package/connectors/connect-todoist/CLAUDE.md +104 -0
- package/connectors/connect-todoist/README.md +193 -0
- package/connectors/connect-todoist/package.json +52 -0
- package/connectors/connect-todoist/src/api/client.ts +117 -0
- package/connectors/connect-todoist/src/api/index.ts +188 -0
- package/connectors/connect-todoist/src/cli/index.ts +990 -0
- package/connectors/connect-todoist/src/index.ts +21 -0
- package/connectors/connect-todoist/src/types/index.ts +240 -0
- package/connectors/connect-todoist/src/utils/config.ts +157 -0
- package/connectors/connect-todoist/src/utils/output.ts +119 -0
- package/connectors/connect-todoist/tsconfig.json +16 -0
- package/connectors/connect-trello/.env.example +11 -0
- package/connectors/connect-trello/CLAUDE.md +128 -0
- package/connectors/connect-trello/README.md +193 -0
- package/connectors/connect-trello/package.json +53 -0
- package/connectors/connect-trello/src/api/client.ts +128 -0
- package/connectors/connect-trello/src/api/index.ts +278 -0
- package/connectors/connect-trello/src/cli/index.ts +737 -0
- package/connectors/connect-trello/src/index.ts +21 -0
- package/connectors/connect-trello/src/types/index.ts +314 -0
- package/connectors/connect-trello/src/utils/config.ts +182 -0
- package/connectors/connect-trello/src/utils/output.ts +119 -0
- package/connectors/connect-trello/tsconfig.json +16 -0
- package/connectors/connect-whatsapp/.env.example +11 -0
- package/connectors/connect-whatsapp/CLAUDE.md +113 -0
- package/connectors/connect-whatsapp/README.md +193 -0
- package/connectors/connect-whatsapp/package.json +53 -0
- package/connectors/connect-whatsapp/src/api/client.ts +133 -0
- package/connectors/connect-whatsapp/src/api/index.ts +365 -0
- package/connectors/connect-whatsapp/src/cli/index.ts +686 -0
- package/connectors/connect-whatsapp/src/index.ts +25 -0
- package/connectors/connect-whatsapp/src/types/index.ts +502 -0
- package/connectors/connect-whatsapp/src/utils/config.ts +179 -0
- package/connectors/connect-whatsapp/src/utils/output.ts +119 -0
- package/connectors/connect-whatsapp/tsconfig.json +16 -0
- package/dist/index.js +70 -0
- package/package.json +1 -1
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
// WhatsApp Business Cloud Connector Types
|
|
2
|
+
// Send messages, manage templates, and handle webhooks
|
|
3
|
+
|
|
4
|
+
// ============================================
|
|
5
|
+
// Configuration
|
|
6
|
+
// ============================================
|
|
7
|
+
|
|
8
|
+
export interface WhatsAppConfig {
|
|
9
|
+
accessToken: string;
|
|
10
|
+
phoneNumberId: string;
|
|
11
|
+
businessAccountId?: string;
|
|
12
|
+
baseUrl?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// ============================================
|
|
16
|
+
// Common Types
|
|
17
|
+
// ============================================
|
|
18
|
+
|
|
19
|
+
export type OutputFormat = 'json' | 'pretty';
|
|
20
|
+
|
|
21
|
+
export type MessageType = 'text' | 'image' | 'audio' | 'video' | 'document' | 'sticker' | 'location' | 'contacts' | 'interactive' | 'template' | 'reaction';
|
|
22
|
+
|
|
23
|
+
export type MessageStatus = 'sent' | 'delivered' | 'read' | 'failed';
|
|
24
|
+
|
|
25
|
+
// ============================================
|
|
26
|
+
// Contact Types
|
|
27
|
+
// ============================================
|
|
28
|
+
|
|
29
|
+
export interface Contact {
|
|
30
|
+
addresses?: Address[];
|
|
31
|
+
birthday?: string;
|
|
32
|
+
emails?: Email[];
|
|
33
|
+
name: Name;
|
|
34
|
+
org?: Organization;
|
|
35
|
+
phones?: Phone[];
|
|
36
|
+
urls?: Url[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface Address {
|
|
40
|
+
street?: string;
|
|
41
|
+
city?: string;
|
|
42
|
+
state?: string;
|
|
43
|
+
zip?: string;
|
|
44
|
+
country?: string;
|
|
45
|
+
country_code?: string;
|
|
46
|
+
type?: 'HOME' | 'WORK';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface Email {
|
|
50
|
+
email?: string;
|
|
51
|
+
type?: 'HOME' | 'WORK';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface Name {
|
|
55
|
+
formatted_name: string;
|
|
56
|
+
first_name?: string;
|
|
57
|
+
last_name?: string;
|
|
58
|
+
middle_name?: string;
|
|
59
|
+
suffix?: string;
|
|
60
|
+
prefix?: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface Organization {
|
|
64
|
+
company?: string;
|
|
65
|
+
department?: string;
|
|
66
|
+
title?: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface Phone {
|
|
70
|
+
phone?: string;
|
|
71
|
+
type?: 'CELL' | 'MAIN' | 'IPHONE' | 'HOME' | 'WORK';
|
|
72
|
+
wa_id?: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface Url {
|
|
76
|
+
url?: string;
|
|
77
|
+
type?: 'HOME' | 'WORK';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ============================================
|
|
81
|
+
// Media Types
|
|
82
|
+
// ============================================
|
|
83
|
+
|
|
84
|
+
export interface Media {
|
|
85
|
+
id?: string;
|
|
86
|
+
link?: string;
|
|
87
|
+
caption?: string;
|
|
88
|
+
filename?: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface MediaObject {
|
|
92
|
+
messaging_product: string;
|
|
93
|
+
url: string;
|
|
94
|
+
mime_type: string;
|
|
95
|
+
sha256: string;
|
|
96
|
+
file_size: number;
|
|
97
|
+
id: string;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// ============================================
|
|
101
|
+
// Location Types
|
|
102
|
+
// ============================================
|
|
103
|
+
|
|
104
|
+
export interface Location {
|
|
105
|
+
longitude: number;
|
|
106
|
+
latitude: number;
|
|
107
|
+
name?: string;
|
|
108
|
+
address?: string;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ============================================
|
|
112
|
+
// Interactive Message Types
|
|
113
|
+
// ============================================
|
|
114
|
+
|
|
115
|
+
export interface Interactive {
|
|
116
|
+
type: 'button' | 'list' | 'product' | 'product_list' | 'flow' | 'cta_url';
|
|
117
|
+
header?: InteractiveHeader;
|
|
118
|
+
body: InteractiveBody;
|
|
119
|
+
footer?: InteractiveFooter;
|
|
120
|
+
action: InteractiveAction;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface InteractiveHeader {
|
|
124
|
+
type: 'text' | 'image' | 'video' | 'document';
|
|
125
|
+
text?: string;
|
|
126
|
+
image?: Media;
|
|
127
|
+
video?: Media;
|
|
128
|
+
document?: Media;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export interface InteractiveBody {
|
|
132
|
+
text: string;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export interface InteractiveFooter {
|
|
136
|
+
text: string;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export interface InteractiveAction {
|
|
140
|
+
button?: string;
|
|
141
|
+
buttons?: InteractiveButton[];
|
|
142
|
+
sections?: InteractiveSection[];
|
|
143
|
+
catalog_id?: string;
|
|
144
|
+
product_retailer_id?: string;
|
|
145
|
+
name?: string;
|
|
146
|
+
parameters?: Record<string, unknown>;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export interface InteractiveButton {
|
|
150
|
+
type: 'reply';
|
|
151
|
+
reply: {
|
|
152
|
+
id: string;
|
|
153
|
+
title: string;
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface InteractiveSection {
|
|
158
|
+
title?: string;
|
|
159
|
+
rows?: InteractiveRow[];
|
|
160
|
+
product_items?: ProductItem[];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export interface InteractiveRow {
|
|
164
|
+
id: string;
|
|
165
|
+
title: string;
|
|
166
|
+
description?: string;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export interface ProductItem {
|
|
170
|
+
product_retailer_id: string;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ============================================
|
|
174
|
+
// Template Types
|
|
175
|
+
// ============================================
|
|
176
|
+
|
|
177
|
+
export interface Template {
|
|
178
|
+
name: string;
|
|
179
|
+
language: TemplateLanguage;
|
|
180
|
+
components?: TemplateComponent[];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export interface TemplateLanguage {
|
|
184
|
+
code: string;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export interface TemplateComponent {
|
|
188
|
+
type: 'header' | 'body' | 'button';
|
|
189
|
+
sub_type?: 'quick_reply' | 'url';
|
|
190
|
+
index?: string;
|
|
191
|
+
parameters?: TemplateParameter[];
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export interface TemplateParameter {
|
|
195
|
+
type: 'text' | 'currency' | 'date_time' | 'image' | 'document' | 'video' | 'payload';
|
|
196
|
+
text?: string;
|
|
197
|
+
currency?: TemplateCurrency;
|
|
198
|
+
date_time?: TemplateDateTime;
|
|
199
|
+
image?: Media;
|
|
200
|
+
document?: Media;
|
|
201
|
+
video?: Media;
|
|
202
|
+
payload?: string;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export interface TemplateCurrency {
|
|
206
|
+
fallback_value: string;
|
|
207
|
+
code: string;
|
|
208
|
+
amount_1000: number;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export interface TemplateDateTime {
|
|
212
|
+
fallback_value: string;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// ============================================
|
|
216
|
+
// Reaction Types
|
|
217
|
+
// ============================================
|
|
218
|
+
|
|
219
|
+
export interface Reaction {
|
|
220
|
+
message_id: string;
|
|
221
|
+
emoji: string;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// ============================================
|
|
225
|
+
// Message Types
|
|
226
|
+
// ============================================
|
|
227
|
+
|
|
228
|
+
export interface TextMessage {
|
|
229
|
+
body: string;
|
|
230
|
+
preview_url?: boolean;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export interface SendMessageInput {
|
|
234
|
+
messaging_product: 'whatsapp';
|
|
235
|
+
recipient_type?: 'individual';
|
|
236
|
+
to: string;
|
|
237
|
+
type: MessageType;
|
|
238
|
+
text?: TextMessage;
|
|
239
|
+
image?: Media;
|
|
240
|
+
audio?: Media;
|
|
241
|
+
video?: Media;
|
|
242
|
+
document?: Media;
|
|
243
|
+
sticker?: Media;
|
|
244
|
+
location?: Location;
|
|
245
|
+
contacts?: Contact[];
|
|
246
|
+
interactive?: Interactive;
|
|
247
|
+
template?: Template;
|
|
248
|
+
reaction?: Reaction;
|
|
249
|
+
context?: {
|
|
250
|
+
message_id: string;
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export interface SendMessageResponse {
|
|
255
|
+
messaging_product: string;
|
|
256
|
+
contacts: {
|
|
257
|
+
input: string;
|
|
258
|
+
wa_id: string;
|
|
259
|
+
}[];
|
|
260
|
+
messages: {
|
|
261
|
+
id: string;
|
|
262
|
+
message_status?: string;
|
|
263
|
+
}[];
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// ============================================
|
|
267
|
+
// Business Profile Types
|
|
268
|
+
// ============================================
|
|
269
|
+
|
|
270
|
+
export interface BusinessProfile {
|
|
271
|
+
messaging_product: string;
|
|
272
|
+
address?: string;
|
|
273
|
+
description?: string;
|
|
274
|
+
email?: string;
|
|
275
|
+
profile_picture_url?: string;
|
|
276
|
+
websites?: string[];
|
|
277
|
+
vertical?: string;
|
|
278
|
+
about?: string;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// ============================================
|
|
282
|
+
// Phone Number Types
|
|
283
|
+
// ============================================
|
|
284
|
+
|
|
285
|
+
export interface PhoneNumber {
|
|
286
|
+
id: string;
|
|
287
|
+
verified_name: string;
|
|
288
|
+
code_verification_status: string;
|
|
289
|
+
display_phone_number: string;
|
|
290
|
+
quality_rating: string;
|
|
291
|
+
platform_type?: string;
|
|
292
|
+
throughput?: {
|
|
293
|
+
level: string;
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export interface PhoneNumbersResponse {
|
|
298
|
+
data: PhoneNumber[];
|
|
299
|
+
paging?: {
|
|
300
|
+
cursors: {
|
|
301
|
+
before: string;
|
|
302
|
+
after: string;
|
|
303
|
+
};
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// ============================================
|
|
308
|
+
// Template Management Types
|
|
309
|
+
// ============================================
|
|
310
|
+
|
|
311
|
+
export interface MessageTemplate {
|
|
312
|
+
id: string;
|
|
313
|
+
name: string;
|
|
314
|
+
status: 'APPROVED' | 'PENDING' | 'REJECTED' | 'DISABLED';
|
|
315
|
+
category: 'MARKETING' | 'UTILITY' | 'AUTHENTICATION';
|
|
316
|
+
language: string;
|
|
317
|
+
components?: MessageTemplateComponent[];
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export interface MessageTemplateComponent {
|
|
321
|
+
type: 'HEADER' | 'BODY' | 'FOOTER' | 'BUTTONS';
|
|
322
|
+
format?: 'TEXT' | 'IMAGE' | 'VIDEO' | 'DOCUMENT';
|
|
323
|
+
text?: string;
|
|
324
|
+
example?: {
|
|
325
|
+
header_text?: string[];
|
|
326
|
+
body_text?: string[][];
|
|
327
|
+
};
|
|
328
|
+
buttons?: MessageTemplateButton[];
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export interface MessageTemplateButton {
|
|
332
|
+
type: 'PHONE_NUMBER' | 'URL' | 'QUICK_REPLY';
|
|
333
|
+
text: string;
|
|
334
|
+
phone_number?: string;
|
|
335
|
+
url?: string;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export interface MessageTemplatesResponse {
|
|
339
|
+
data: MessageTemplate[];
|
|
340
|
+
paging?: {
|
|
341
|
+
cursors: {
|
|
342
|
+
before: string;
|
|
343
|
+
after: string;
|
|
344
|
+
};
|
|
345
|
+
next?: string;
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// ============================================
|
|
350
|
+
// Webhook Types
|
|
351
|
+
// ============================================
|
|
352
|
+
|
|
353
|
+
export interface WebhookPayload {
|
|
354
|
+
object: string;
|
|
355
|
+
entry: WebhookEntry[];
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export interface WebhookEntry {
|
|
359
|
+
id: string;
|
|
360
|
+
changes: WebhookChange[];
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export interface WebhookChange {
|
|
364
|
+
value: WebhookValue;
|
|
365
|
+
field: string;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export interface WebhookValue {
|
|
369
|
+
messaging_product: string;
|
|
370
|
+
metadata: {
|
|
371
|
+
display_phone_number: string;
|
|
372
|
+
phone_number_id: string;
|
|
373
|
+
};
|
|
374
|
+
contacts?: WebhookContact[];
|
|
375
|
+
messages?: WebhookMessage[];
|
|
376
|
+
statuses?: WebhookStatus[];
|
|
377
|
+
errors?: WebhookError[];
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
export interface WebhookContact {
|
|
381
|
+
profile: {
|
|
382
|
+
name: string;
|
|
383
|
+
};
|
|
384
|
+
wa_id: string;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
export interface WebhookMessage {
|
|
388
|
+
from: string;
|
|
389
|
+
id: string;
|
|
390
|
+
timestamp: string;
|
|
391
|
+
type: MessageType;
|
|
392
|
+
text?: TextMessage;
|
|
393
|
+
image?: MediaWebhook;
|
|
394
|
+
audio?: MediaWebhook;
|
|
395
|
+
video?: MediaWebhook;
|
|
396
|
+
document?: MediaWebhook;
|
|
397
|
+
sticker?: MediaWebhook;
|
|
398
|
+
location?: Location;
|
|
399
|
+
contacts?: Contact[];
|
|
400
|
+
interactive?: InteractiveWebhook;
|
|
401
|
+
button?: ButtonWebhook;
|
|
402
|
+
context?: {
|
|
403
|
+
from: string;
|
|
404
|
+
id: string;
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
export interface MediaWebhook {
|
|
409
|
+
id: string;
|
|
410
|
+
mime_type: string;
|
|
411
|
+
sha256?: string;
|
|
412
|
+
caption?: string;
|
|
413
|
+
filename?: string;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
export interface InteractiveWebhook {
|
|
417
|
+
type: string;
|
|
418
|
+
button_reply?: {
|
|
419
|
+
id: string;
|
|
420
|
+
title: string;
|
|
421
|
+
};
|
|
422
|
+
list_reply?: {
|
|
423
|
+
id: string;
|
|
424
|
+
title: string;
|
|
425
|
+
description?: string;
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
export interface ButtonWebhook {
|
|
430
|
+
text: string;
|
|
431
|
+
payload: string;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
export interface WebhookStatus {
|
|
435
|
+
id: string;
|
|
436
|
+
status: MessageStatus;
|
|
437
|
+
timestamp: string;
|
|
438
|
+
recipient_id: string;
|
|
439
|
+
conversation?: {
|
|
440
|
+
id: string;
|
|
441
|
+
expiration_timestamp?: string;
|
|
442
|
+
origin?: {
|
|
443
|
+
type: string;
|
|
444
|
+
};
|
|
445
|
+
};
|
|
446
|
+
pricing?: {
|
|
447
|
+
billable: boolean;
|
|
448
|
+
pricing_model: string;
|
|
449
|
+
category: string;
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
export interface WebhookError {
|
|
454
|
+
code: number;
|
|
455
|
+
title: string;
|
|
456
|
+
message: string;
|
|
457
|
+
error_data?: {
|
|
458
|
+
details: string;
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// ============================================
|
|
463
|
+
// API Error Types
|
|
464
|
+
// ============================================
|
|
465
|
+
|
|
466
|
+
export interface WhatsAppError {
|
|
467
|
+
message: string;
|
|
468
|
+
type: string;
|
|
469
|
+
code: number;
|
|
470
|
+
error_subcode?: number;
|
|
471
|
+
error_data?: {
|
|
472
|
+
messaging_product: string;
|
|
473
|
+
details: string;
|
|
474
|
+
};
|
|
475
|
+
fbtrace_id: string;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
export interface WhatsAppErrorResponse {
|
|
479
|
+
error: WhatsAppError;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
export class WhatsAppApiError extends Error {
|
|
483
|
+
public readonly statusCode: number;
|
|
484
|
+
public readonly errorCode: number;
|
|
485
|
+
public readonly errorSubcode?: number;
|
|
486
|
+
public readonly fbtraceId: string;
|
|
487
|
+
|
|
488
|
+
constructor(
|
|
489
|
+
message: string,
|
|
490
|
+
statusCode: number,
|
|
491
|
+
errorCode: number,
|
|
492
|
+
fbtraceId: string,
|
|
493
|
+
errorSubcode?: number
|
|
494
|
+
) {
|
|
495
|
+
super(message);
|
|
496
|
+
this.name = 'WhatsAppApiError';
|
|
497
|
+
this.statusCode = statusCode;
|
|
498
|
+
this.errorCode = errorCode;
|
|
499
|
+
this.errorSubcode = errorSubcode;
|
|
500
|
+
this.fbtraceId = fbtraceId;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync, rmSync } from 'fs';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
|
|
5
|
+
const CONNECTOR_NAME = 'connect-whatsapp';
|
|
6
|
+
const DEFAULT_PROFILE = 'default';
|
|
7
|
+
|
|
8
|
+
export interface ProfileConfig {
|
|
9
|
+
accessToken?: string;
|
|
10
|
+
phoneNumberId?: string;
|
|
11
|
+
businessAccountId?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let profileOverride: string | undefined;
|
|
15
|
+
|
|
16
|
+
const CONFIG_DIR = join(homedir(), '.connect', CONNECTOR_NAME);
|
|
17
|
+
const PROFILES_DIR = join(CONFIG_DIR, 'profiles');
|
|
18
|
+
const CURRENT_PROFILE_FILE = join(CONFIG_DIR, 'current_profile');
|
|
19
|
+
|
|
20
|
+
export function setProfileOverride(profile: string | undefined): void {
|
|
21
|
+
profileOverride = profile;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function ensureConfigDir(): void {
|
|
25
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
26
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
27
|
+
}
|
|
28
|
+
if (!existsSync(PROFILES_DIR)) {
|
|
29
|
+
mkdirSync(PROFILES_DIR, { recursive: true });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getProfilePath(profile: string): string {
|
|
34
|
+
return join(PROFILES_DIR, `${profile}.json`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function getCurrentProfile(): string {
|
|
38
|
+
if (profileOverride) {
|
|
39
|
+
return profileOverride;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
ensureConfigDir();
|
|
43
|
+
|
|
44
|
+
if (existsSync(CURRENT_PROFILE_FILE)) {
|
|
45
|
+
try {
|
|
46
|
+
const profile = readFileSync(CURRENT_PROFILE_FILE, 'utf-8').trim();
|
|
47
|
+
if (profile && profileExists(profile)) {
|
|
48
|
+
return profile;
|
|
49
|
+
}
|
|
50
|
+
} catch {
|
|
51
|
+
// Fall through to default
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return DEFAULT_PROFILE;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function setCurrentProfile(profile: string): void {
|
|
59
|
+
ensureConfigDir();
|
|
60
|
+
|
|
61
|
+
if (!profileExists(profile) && profile !== DEFAULT_PROFILE) {
|
|
62
|
+
throw new Error(`Profile "${profile}" does not exist`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
writeFileSync(CURRENT_PROFILE_FILE, profile);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function profileExists(profile: string): boolean {
|
|
69
|
+
return existsSync(getProfilePath(profile));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function listProfiles(): string[] {
|
|
73
|
+
ensureConfigDir();
|
|
74
|
+
|
|
75
|
+
if (!existsSync(PROFILES_DIR)) {
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return readdirSync(PROFILES_DIR)
|
|
80
|
+
.filter(f => f.endsWith('.json'))
|
|
81
|
+
.map(f => f.replace('.json', ''))
|
|
82
|
+
.sort();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function createProfile(profile: string, config: ProfileConfig = {}): boolean {
|
|
86
|
+
ensureConfigDir();
|
|
87
|
+
|
|
88
|
+
if (profileExists(profile)) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(profile)) {
|
|
93
|
+
throw new Error('Profile name can only contain letters, numbers, hyphens, and underscores');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
writeFileSync(getProfilePath(profile), JSON.stringify(config, null, 2));
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function deleteProfile(profile: string): boolean {
|
|
101
|
+
if (profile === DEFAULT_PROFILE) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (!profileExists(profile)) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (getCurrentProfile() === profile) {
|
|
110
|
+
setCurrentProfile(DEFAULT_PROFILE);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
rmSync(getProfilePath(profile));
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function loadProfile(profile?: string): ProfileConfig {
|
|
118
|
+
ensureConfigDir();
|
|
119
|
+
const profileName = profile || getCurrentProfile();
|
|
120
|
+
const profilePath = getProfilePath(profileName);
|
|
121
|
+
|
|
122
|
+
if (!existsSync(profilePath)) {
|
|
123
|
+
return {};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
return JSON.parse(readFileSync(profilePath, 'utf-8'));
|
|
128
|
+
} catch {
|
|
129
|
+
return {};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function saveProfile(config: ProfileConfig, profile?: string): void {
|
|
134
|
+
ensureConfigDir();
|
|
135
|
+
const profileName = profile || getCurrentProfile();
|
|
136
|
+
writeFileSync(getProfilePath(profileName), JSON.stringify(config, null, 2));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function getAccessToken(): string | undefined {
|
|
140
|
+
return process.env.WHATSAPP_ACCESS_TOKEN || loadProfile().accessToken;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function setAccessToken(accessToken: string): void {
|
|
144
|
+
const config = loadProfile();
|
|
145
|
+
config.accessToken = accessToken;
|
|
146
|
+
saveProfile(config);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function getPhoneNumberId(): string | undefined {
|
|
150
|
+
return process.env.WHATSAPP_PHONE_NUMBER_ID || loadProfile().phoneNumberId;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function setPhoneNumberId(phoneNumberId: string): void {
|
|
154
|
+
const config = loadProfile();
|
|
155
|
+
config.phoneNumberId = phoneNumberId;
|
|
156
|
+
saveProfile(config);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function getBusinessAccountId(): string | undefined {
|
|
160
|
+
return process.env.WHATSAPP_BUSINESS_ACCOUNT_ID || loadProfile().businessAccountId;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function setBusinessAccountId(businessAccountId: string): void {
|
|
164
|
+
const config = loadProfile();
|
|
165
|
+
config.businessAccountId = businessAccountId;
|
|
166
|
+
saveProfile(config);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function clearConfig(): void {
|
|
170
|
+
saveProfile({});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function getConfigDir(): string {
|
|
174
|
+
return CONFIG_DIR;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export function getActiveProfileName(): string {
|
|
178
|
+
return getCurrentProfile();
|
|
179
|
+
}
|