@xenterprises/fastify-xtwilio 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.
- package/.dockerignore +63 -0
- package/.env.example +257 -0
- package/API.md +973 -0
- package/CHANGELOG.md +189 -0
- package/LICENSE +15 -0
- package/README.md +261 -0
- package/SECURITY.md +721 -0
- package/index.d.ts +999 -0
- package/package.json +55 -0
- package/server/app.js +88 -0
- package/src/services/conversations.js +328 -0
- package/src/services/email.js +362 -0
- package/src/services/rcs.js +284 -0
- package/src/services/sms.js +268 -0
- package/src/xTwilio.js +37 -0
- package/test/xTwilio.test.js +511 -0
package/index.d.ts
ADDED
|
@@ -0,0 +1,999 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* xTwilio - Fastify Plugin for Twilio Communications and SendGrid Email
|
|
3
|
+
* TypeScript Type Definitions
|
|
4
|
+
*
|
|
5
|
+
* @module @xenterprises/fastify-xtwilio
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { FastifyPluginAsync, FastifyInstance } from 'fastify';
|
|
10
|
+
import { Twilio } from 'twilio';
|
|
11
|
+
import { ClientRequest } from '@sendgrid/client/src/request';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* SMS Message Options
|
|
15
|
+
*/
|
|
16
|
+
export interface SMSOptions {
|
|
17
|
+
/** Custom Twilio account SID (overrides default) */
|
|
18
|
+
accountSid?: string;
|
|
19
|
+
|
|
20
|
+
/** Media URLs for MMS */
|
|
21
|
+
mediaUrls?: string[];
|
|
22
|
+
|
|
23
|
+
/** Custom attributes */
|
|
24
|
+
attributes?: Record<string, string>;
|
|
25
|
+
|
|
26
|
+
/** Attempt number for retry logic */
|
|
27
|
+
attemptNumber?: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* SMS Scheduled Send Options
|
|
32
|
+
*/
|
|
33
|
+
export interface ScheduleSMSOptions extends SMSOptions {
|
|
34
|
+
/** When to send the message */
|
|
35
|
+
sendAt: Date | string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Bulk SMS Message
|
|
40
|
+
*/
|
|
41
|
+
export interface BulkSMSMessage {
|
|
42
|
+
/** Recipient phone number */
|
|
43
|
+
to: string;
|
|
44
|
+
|
|
45
|
+
/** Message body */
|
|
46
|
+
body: string;
|
|
47
|
+
|
|
48
|
+
/** Media URLs (for MMS) */
|
|
49
|
+
mediaUrls?: string[];
|
|
50
|
+
|
|
51
|
+
/** Custom options for this message */
|
|
52
|
+
options?: SMSOptions;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* SMS Send Result
|
|
57
|
+
*/
|
|
58
|
+
export interface SMSResult {
|
|
59
|
+
/** Twilio message SID */
|
|
60
|
+
sid: string;
|
|
61
|
+
|
|
62
|
+
/** Message status */
|
|
63
|
+
status: 'queued' | 'sending' | 'sent' | 'failed' | 'delivered' | 'undelivered';
|
|
64
|
+
|
|
65
|
+
/** Recipient phone number */
|
|
66
|
+
to: string;
|
|
67
|
+
|
|
68
|
+
/** Message body (first 160 chars) */
|
|
69
|
+
body: string;
|
|
70
|
+
|
|
71
|
+
/** Number of SMS segments */
|
|
72
|
+
numSegments: number;
|
|
73
|
+
|
|
74
|
+
/** Price of the message */
|
|
75
|
+
price?: number;
|
|
76
|
+
|
|
77
|
+
/** Currency */
|
|
78
|
+
priceUnit?: string;
|
|
79
|
+
|
|
80
|
+
/** Error details if failed */
|
|
81
|
+
errorCode?: string;
|
|
82
|
+
|
|
83
|
+
/** Error message if failed */
|
|
84
|
+
errorMessage?: string;
|
|
85
|
+
|
|
86
|
+
/** Timestamp of send */
|
|
87
|
+
dateCreated: Date;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* SMS Status
|
|
92
|
+
*/
|
|
93
|
+
export interface SMSStatus {
|
|
94
|
+
/** Message SID */
|
|
95
|
+
sid: string;
|
|
96
|
+
|
|
97
|
+
/** Current status */
|
|
98
|
+
status: string;
|
|
99
|
+
|
|
100
|
+
/** Error code if failed */
|
|
101
|
+
errorCode?: number;
|
|
102
|
+
|
|
103
|
+
/** Error message if failed */
|
|
104
|
+
errorMessage?: string;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Phone Number Validation Result
|
|
109
|
+
*/
|
|
110
|
+
export interface PhoneValidationResult {
|
|
111
|
+
/** Valid phone number in E.164 format */
|
|
112
|
+
phoneNumber: string;
|
|
113
|
+
|
|
114
|
+
/** Valid format */
|
|
115
|
+
isValid: boolean;
|
|
116
|
+
|
|
117
|
+
/** Country information */
|
|
118
|
+
countryCode?: string;
|
|
119
|
+
|
|
120
|
+
/** Type of number (mobile, fixed-line, etc.) */
|
|
121
|
+
numberType?: string;
|
|
122
|
+
|
|
123
|
+
/** Carrier name */
|
|
124
|
+
carrier?: string;
|
|
125
|
+
|
|
126
|
+
/** Error message if invalid */
|
|
127
|
+
error?: string;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Conversation Information
|
|
132
|
+
*/
|
|
133
|
+
export interface ConversationInfo {
|
|
134
|
+
/** Conversation SID */
|
|
135
|
+
sid: string;
|
|
136
|
+
|
|
137
|
+
/** Friendly name */
|
|
138
|
+
friendlyName: string;
|
|
139
|
+
|
|
140
|
+
/** Conversation state: active, inactive, closed */
|
|
141
|
+
state: 'active' | 'inactive' | 'closed';
|
|
142
|
+
|
|
143
|
+
/** Custom attributes */
|
|
144
|
+
attributes?: Record<string, any>;
|
|
145
|
+
|
|
146
|
+
/** Messaging binding address */
|
|
147
|
+
messagingBindingAddress?: string;
|
|
148
|
+
|
|
149
|
+
/** Date created */
|
|
150
|
+
dateCreated: Date;
|
|
151
|
+
|
|
152
|
+
/** Date updated */
|
|
153
|
+
dateUpdated: Date;
|
|
154
|
+
|
|
155
|
+
/** URL of this conversation resource */
|
|
156
|
+
url?: string;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Conversation Participant
|
|
161
|
+
*/
|
|
162
|
+
export interface ConversationParticipant {
|
|
163
|
+
/** Participant SID */
|
|
164
|
+
sid: string;
|
|
165
|
+
|
|
166
|
+
/** Conversation SID */
|
|
167
|
+
conversationSid: string;
|
|
168
|
+
|
|
169
|
+
/** Participant identity */
|
|
170
|
+
identity: string;
|
|
171
|
+
|
|
172
|
+
/** Messaging binding address (email, phone, etc.) */
|
|
173
|
+
messagingBindingAddress?: string;
|
|
174
|
+
|
|
175
|
+
/** Role of participant */
|
|
176
|
+
role: 'guest' | 'agent' | 'supervisor';
|
|
177
|
+
|
|
178
|
+
/** Date added */
|
|
179
|
+
dateCreated: Date;
|
|
180
|
+
|
|
181
|
+
/** Custom attributes */
|
|
182
|
+
attributes?: Record<string, any>;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Conversation Message
|
|
187
|
+
*/
|
|
188
|
+
export interface ConversationMessage {
|
|
189
|
+
/** Message SID */
|
|
190
|
+
sid: string;
|
|
191
|
+
|
|
192
|
+
/** Conversation SID */
|
|
193
|
+
conversationSid: string;
|
|
194
|
+
|
|
195
|
+
/** Account SID */
|
|
196
|
+
accountSid: string;
|
|
197
|
+
|
|
198
|
+
/** Message body */
|
|
199
|
+
body: string;
|
|
200
|
+
|
|
201
|
+
/** Message author */
|
|
202
|
+
author: string;
|
|
203
|
+
|
|
204
|
+
/** Media URL if message contains media */
|
|
205
|
+
mediaUrl?: string;
|
|
206
|
+
|
|
207
|
+
/** Message index number */
|
|
208
|
+
index: number;
|
|
209
|
+
|
|
210
|
+
/** Date created */
|
|
211
|
+
dateCreated: Date;
|
|
212
|
+
|
|
213
|
+
/** Participant SID of author */
|
|
214
|
+
participantSid?: string;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* RCS Rich Card
|
|
219
|
+
*/
|
|
220
|
+
export interface RCSRichCard {
|
|
221
|
+
/** Card title */
|
|
222
|
+
title: string;
|
|
223
|
+
|
|
224
|
+
/** Card description */
|
|
225
|
+
description: string;
|
|
226
|
+
|
|
227
|
+
/** Media URL for card */
|
|
228
|
+
mediaUrl?: string;
|
|
229
|
+
|
|
230
|
+
/** Suggested actions */
|
|
231
|
+
actions?: Array<{
|
|
232
|
+
/** Action type */
|
|
233
|
+
type: 'url' | 'phone' | 'open_app' | 'create_calendar_event' | 'reply';
|
|
234
|
+
|
|
235
|
+
/** Action text */
|
|
236
|
+
text: string;
|
|
237
|
+
|
|
238
|
+
/** Action target (URL, phone number, etc.) */
|
|
239
|
+
url?: string;
|
|
240
|
+
|
|
241
|
+
/** Phone number for phone action */
|
|
242
|
+
phoneNumber?: string;
|
|
243
|
+
|
|
244
|
+
/** Payload for reply action */
|
|
245
|
+
payload?: string;
|
|
246
|
+
}>;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* RCS Quick Reply
|
|
251
|
+
*/
|
|
252
|
+
export interface RCSQuickReply {
|
|
253
|
+
/** Reply text */
|
|
254
|
+
text: string;
|
|
255
|
+
|
|
256
|
+
/** Reply payload */
|
|
257
|
+
payload: string;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* RCS Send Result
|
|
262
|
+
*/
|
|
263
|
+
export interface RCSSendResult {
|
|
264
|
+
/** Twilio message SID */
|
|
265
|
+
messageId: string;
|
|
266
|
+
|
|
267
|
+
/** Message status */
|
|
268
|
+
status: 'accepted' | 'queued' | 'sent' | 'delivered' | 'failed' | 'rejected';
|
|
269
|
+
|
|
270
|
+
/** Recipient phone number */
|
|
271
|
+
to: string;
|
|
272
|
+
|
|
273
|
+
/** Error details if failed */
|
|
274
|
+
error?: {
|
|
275
|
+
code: string;
|
|
276
|
+
message: string;
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
/** Timestamp */
|
|
280
|
+
timestamp: Date;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Email Options
|
|
285
|
+
*/
|
|
286
|
+
export interface EmailOptions {
|
|
287
|
+
/** Email priority */
|
|
288
|
+
priority?: 'low' | 'normal' | 'high';
|
|
289
|
+
|
|
290
|
+
/** Custom headers */
|
|
291
|
+
headers?: Record<string, string>;
|
|
292
|
+
|
|
293
|
+
/** Reply-to address */
|
|
294
|
+
replyTo?: string;
|
|
295
|
+
|
|
296
|
+
/** BCC recipients */
|
|
297
|
+
bcc?: string[];
|
|
298
|
+
|
|
299
|
+
/** Custom categories for tracking */
|
|
300
|
+
categories?: string[];
|
|
301
|
+
|
|
302
|
+
/** Custom metadata */
|
|
303
|
+
metadata?: Record<string, string>;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Email with Attachments Options
|
|
308
|
+
*/
|
|
309
|
+
export interface EmailWithAttachmentsOptions extends EmailOptions {
|
|
310
|
+
/** Attachments array */
|
|
311
|
+
attachments: Array<{
|
|
312
|
+
/** Attachment content (base64) */
|
|
313
|
+
content: string;
|
|
314
|
+
|
|
315
|
+
/** File name */
|
|
316
|
+
filename: string;
|
|
317
|
+
|
|
318
|
+
/** MIME type */
|
|
319
|
+
type: string;
|
|
320
|
+
|
|
321
|
+
/** Content disposition */
|
|
322
|
+
disposition?: 'inline' | 'attachment';
|
|
323
|
+
|
|
324
|
+
/** Content ID for inline attachments */
|
|
325
|
+
contentId?: string;
|
|
326
|
+
}>;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Email Send Result
|
|
331
|
+
*/
|
|
332
|
+
export interface EmailSendResult {
|
|
333
|
+
/** SendGrid message ID */
|
|
334
|
+
messageId: string;
|
|
335
|
+
|
|
336
|
+
/** Send status */
|
|
337
|
+
status: 'success' | 'failed' | 'bounced' | 'spam' | 'blocked';
|
|
338
|
+
|
|
339
|
+
/** Recipient email */
|
|
340
|
+
to: string;
|
|
341
|
+
|
|
342
|
+
/** Subject line */
|
|
343
|
+
subject: string;
|
|
344
|
+
|
|
345
|
+
/** Timestamp of send */
|
|
346
|
+
timestamp: Date;
|
|
347
|
+
|
|
348
|
+
/** Error details if failed */
|
|
349
|
+
error?: {
|
|
350
|
+
code: number;
|
|
351
|
+
message: string;
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Email Contact
|
|
357
|
+
*/
|
|
358
|
+
export interface EmailContact {
|
|
359
|
+
/** Contact ID */
|
|
360
|
+
id: string;
|
|
361
|
+
|
|
362
|
+
/** Email address */
|
|
363
|
+
email: string;
|
|
364
|
+
|
|
365
|
+
/** First name */
|
|
366
|
+
firstName?: string;
|
|
367
|
+
|
|
368
|
+
/** Last name */
|
|
369
|
+
lastName?: string;
|
|
370
|
+
|
|
371
|
+
/** Phone number */
|
|
372
|
+
phone?: string;
|
|
373
|
+
|
|
374
|
+
/** Company */
|
|
375
|
+
company?: string;
|
|
376
|
+
|
|
377
|
+
/** Custom fields */
|
|
378
|
+
customFields?: Record<string, string>;
|
|
379
|
+
|
|
380
|
+
/** Date added */
|
|
381
|
+
createdAt: Date;
|
|
382
|
+
|
|
383
|
+
/** Unsubscribed status */
|
|
384
|
+
isUnsubscribed?: boolean;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Email Contact List
|
|
389
|
+
*/
|
|
390
|
+
export interface EmailContactList {
|
|
391
|
+
/** List ID */
|
|
392
|
+
id: string;
|
|
393
|
+
|
|
394
|
+
/** List name */
|
|
395
|
+
name: string;
|
|
396
|
+
|
|
397
|
+
/** Contact count */
|
|
398
|
+
contactCount: number;
|
|
399
|
+
|
|
400
|
+
/** Date created */
|
|
401
|
+
createdAt: Date;
|
|
402
|
+
|
|
403
|
+
/** Date modified */
|
|
404
|
+
modifiedAt: Date;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* SMS Service Methods
|
|
409
|
+
*/
|
|
410
|
+
export interface SMSService {
|
|
411
|
+
/**
|
|
412
|
+
* Send SMS message
|
|
413
|
+
* @param to Recipient phone number
|
|
414
|
+
* @param body Message body
|
|
415
|
+
* @param options Optional SMS options
|
|
416
|
+
* @returns SMS send result
|
|
417
|
+
*/
|
|
418
|
+
send(to: string, body: string, options?: SMSOptions): Promise<SMSResult>;
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Send MMS (multimedia message)
|
|
422
|
+
* @param to Recipient phone number
|
|
423
|
+
* @param body Message body
|
|
424
|
+
* @param mediaUrl URL of media to attach
|
|
425
|
+
* @param options Optional SMS options
|
|
426
|
+
* @returns SMS send result
|
|
427
|
+
*/
|
|
428
|
+
sendMMS(
|
|
429
|
+
to: string,
|
|
430
|
+
body: string,
|
|
431
|
+
mediaUrl: string,
|
|
432
|
+
options?: SMSOptions
|
|
433
|
+
): Promise<SMSResult>;
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Schedule SMS for future delivery
|
|
437
|
+
* @param to Recipient phone number
|
|
438
|
+
* @param body Message body
|
|
439
|
+
* @param sendAt When to send message
|
|
440
|
+
* @param options Optional SMS options
|
|
441
|
+
* @returns SMS send result
|
|
442
|
+
*/
|
|
443
|
+
schedule(
|
|
444
|
+
to: string,
|
|
445
|
+
body: string,
|
|
446
|
+
sendAt: Date | string,
|
|
447
|
+
options?: SMSOptions
|
|
448
|
+
): Promise<SMSResult>;
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Cancel scheduled message
|
|
452
|
+
* @param messageSid SID of scheduled message
|
|
453
|
+
* @returns Cancellation result
|
|
454
|
+
*/
|
|
455
|
+
cancelScheduled(messageSid: string): Promise<{ success: boolean }>;
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Get message details
|
|
459
|
+
* @param messageSid Message SID
|
|
460
|
+
* @returns SMS message details
|
|
461
|
+
*/
|
|
462
|
+
get(messageSid: string): Promise<SMSResult>;
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Get message status
|
|
466
|
+
* @param messageSid Message SID
|
|
467
|
+
* @returns Message status
|
|
468
|
+
*/
|
|
469
|
+
getStatus(messageSid: string): Promise<SMSStatus>;
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* List messages with optional filters
|
|
473
|
+
* @param filters Query filters
|
|
474
|
+
* @returns Array of SMS results
|
|
475
|
+
*/
|
|
476
|
+
list(filters?: {
|
|
477
|
+
to?: string;
|
|
478
|
+
from?: string;
|
|
479
|
+
status?: string;
|
|
480
|
+
limit?: number;
|
|
481
|
+
}): Promise<SMSResult[]>;
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* Delete message
|
|
485
|
+
* @param messageSid Message SID to delete
|
|
486
|
+
* @returns Deletion result
|
|
487
|
+
*/
|
|
488
|
+
delete(messageSid: string): Promise<{ success: boolean }>;
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Get media from MMS message
|
|
492
|
+
* @param messageSid Message SID
|
|
493
|
+
* @returns Media URLs
|
|
494
|
+
*/
|
|
495
|
+
getMedia(messageSid: string): Promise<string[]>;
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Validate phone number
|
|
499
|
+
* @param phoneNumber Phone number to validate
|
|
500
|
+
* @param options Validation options
|
|
501
|
+
* @returns Validation result
|
|
502
|
+
*/
|
|
503
|
+
validatePhoneNumber(
|
|
504
|
+
phoneNumber: string,
|
|
505
|
+
options?: { countryCode?: string }
|
|
506
|
+
): Promise<PhoneValidationResult>;
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Send bulk SMS messages
|
|
510
|
+
* @param messages Array of bulk messages
|
|
511
|
+
* @returns Array of send results
|
|
512
|
+
*/
|
|
513
|
+
sendBulk(messages: BulkSMSMessage[]): Promise<SMSResult[]>;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Conversations Service Methods
|
|
518
|
+
*/
|
|
519
|
+
export interface ConversationsService {
|
|
520
|
+
/**
|
|
521
|
+
* Create new conversation
|
|
522
|
+
* @param friendlyName Conversation name
|
|
523
|
+
* @param attributes Optional custom attributes
|
|
524
|
+
* @returns Conversation info
|
|
525
|
+
*/
|
|
526
|
+
create(friendlyName: string, attributes?: Record<string, any>): Promise<ConversationInfo>;
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Get conversation details
|
|
530
|
+
* @param conversationSid Conversation SID
|
|
531
|
+
* @returns Conversation info
|
|
532
|
+
*/
|
|
533
|
+
get(conversationSid: string): Promise<ConversationInfo>;
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Update conversation
|
|
537
|
+
* @param conversationSid Conversation SID
|
|
538
|
+
* @param updates Fields to update
|
|
539
|
+
* @returns Updated conversation info
|
|
540
|
+
*/
|
|
541
|
+
update(
|
|
542
|
+
conversationSid: string,
|
|
543
|
+
updates: { friendlyName?: string; state?: string; attributes?: Record<string, any> }
|
|
544
|
+
): Promise<ConversationInfo>;
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* List conversations
|
|
548
|
+
* @param filters Optional filters
|
|
549
|
+
* @returns Array of conversations
|
|
550
|
+
*/
|
|
551
|
+
list(filters?: {
|
|
552
|
+
state?: string;
|
|
553
|
+
limit?: number;
|
|
554
|
+
}): Promise<ConversationInfo[]>;
|
|
555
|
+
|
|
556
|
+
/**
|
|
557
|
+
* Delete conversation
|
|
558
|
+
* @param conversationSid Conversation SID
|
|
559
|
+
* @returns Deletion result
|
|
560
|
+
*/
|
|
561
|
+
delete(conversationSid: string): Promise<{ success: boolean }>;
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Add participant to conversation
|
|
565
|
+
* @param conversationSid Conversation SID
|
|
566
|
+
* @param identity Participant identity (email, user ID, etc.)
|
|
567
|
+
* @param messagingBindingAddress Optional messaging address (phone, email)
|
|
568
|
+
* @returns Participant info
|
|
569
|
+
*/
|
|
570
|
+
addParticipant(
|
|
571
|
+
conversationSid: string,
|
|
572
|
+
identity?: string,
|
|
573
|
+
messagingBindingAddress?: string
|
|
574
|
+
): Promise<ConversationParticipant>;
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* List conversation participants
|
|
578
|
+
* @param conversationSid Conversation SID
|
|
579
|
+
* @returns Array of participants
|
|
580
|
+
*/
|
|
581
|
+
listParticipants(conversationSid: string): Promise<ConversationParticipant[]>;
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* Remove participant from conversation
|
|
585
|
+
* @param conversationSid Conversation SID
|
|
586
|
+
* @param participantSid Participant SID to remove
|
|
587
|
+
* @returns Removal result
|
|
588
|
+
*/
|
|
589
|
+
removeParticipant(
|
|
590
|
+
conversationSid: string,
|
|
591
|
+
participantSid: string
|
|
592
|
+
): Promise<{ success: boolean }>;
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Send message to conversation
|
|
596
|
+
* @param conversationSid Conversation SID
|
|
597
|
+
* @param body Message body
|
|
598
|
+
* @param author Message author
|
|
599
|
+
* @param attributes Optional attributes
|
|
600
|
+
* @returns Message info
|
|
601
|
+
*/
|
|
602
|
+
sendMessage(
|
|
603
|
+
conversationSid: string,
|
|
604
|
+
body: string,
|
|
605
|
+
author: string,
|
|
606
|
+
attributes?: Record<string, any>
|
|
607
|
+
): Promise<ConversationMessage>;
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Send media message to conversation
|
|
611
|
+
* @param conversationSid Conversation SID
|
|
612
|
+
* @param mediaUrl URL of media
|
|
613
|
+
* @param body Optional message text
|
|
614
|
+
* @param author Message author
|
|
615
|
+
* @returns Message info
|
|
616
|
+
*/
|
|
617
|
+
sendMediaMessage(
|
|
618
|
+
conversationSid: string,
|
|
619
|
+
mediaUrl: string,
|
|
620
|
+
body?: string,
|
|
621
|
+
author?: string
|
|
622
|
+
): Promise<ConversationMessage>;
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* Get conversation messages
|
|
626
|
+
* @param conversationSid Conversation SID
|
|
627
|
+
* @param options Query options
|
|
628
|
+
* @returns Array of messages
|
|
629
|
+
*/
|
|
630
|
+
getMessages(
|
|
631
|
+
conversationSid: string,
|
|
632
|
+
options?: { limit?: number; index?: number }
|
|
633
|
+
): Promise<ConversationMessage[]>;
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Get specific message
|
|
637
|
+
* @param conversationSid Conversation SID
|
|
638
|
+
* @param messageSid Message SID
|
|
639
|
+
* @returns Message info
|
|
640
|
+
*/
|
|
641
|
+
getMessage(conversationSid: string, messageSid: string): Promise<ConversationMessage>;
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Delete message from conversation
|
|
645
|
+
* @param conversationSid Conversation SID
|
|
646
|
+
* @param messageSid Message SID to delete
|
|
647
|
+
* @returns Deletion result
|
|
648
|
+
*/
|
|
649
|
+
deleteMessage(conversationSid: string, messageSid: string): Promise<{ success: boolean }>;
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* Get webhook configuration
|
|
653
|
+
* @param conversationSid Conversation SID
|
|
654
|
+
* @returns Webhook config
|
|
655
|
+
*/
|
|
656
|
+
getWebhooks(conversationSid: string): Promise<Record<string, any>>;
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Update webhook configuration
|
|
660
|
+
* @param conversationSid Conversation SID
|
|
661
|
+
* @param webhookConfig New webhook config
|
|
662
|
+
* @returns Updated config
|
|
663
|
+
*/
|
|
664
|
+
updateWebhooks(
|
|
665
|
+
conversationSid: string,
|
|
666
|
+
webhookConfig: Record<string, any>
|
|
667
|
+
): Promise<Record<string, any>>;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* RCS Service Methods
|
|
672
|
+
*/
|
|
673
|
+
export interface RCSService {
|
|
674
|
+
/**
|
|
675
|
+
* Send basic RCS message
|
|
676
|
+
* @param to Recipient phone number
|
|
677
|
+
* @param body Message body
|
|
678
|
+
* @param options Optional send options
|
|
679
|
+
* @returns Send result
|
|
680
|
+
*/
|
|
681
|
+
send(to: string, body: string, options?: SMSOptions): Promise<RCSSendResult>;
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* Send RCS message with media
|
|
685
|
+
* @param to Recipient phone number
|
|
686
|
+
* @param body Message body
|
|
687
|
+
* @param mediaUrl URL of media
|
|
688
|
+
* @returns Send result
|
|
689
|
+
*/
|
|
690
|
+
sendMedia(to: string, body: string, mediaUrl: string): Promise<RCSSendResult>;
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* Send RCS message from template
|
|
694
|
+
* @param to Recipient phone number
|
|
695
|
+
* @param contentSid Template SID
|
|
696
|
+
* @param contentVariables Template variables
|
|
697
|
+
* @returns Send result
|
|
698
|
+
*/
|
|
699
|
+
sendTemplate(
|
|
700
|
+
to: string,
|
|
701
|
+
contentSid: string,
|
|
702
|
+
contentVariables: Record<string, string>
|
|
703
|
+
): Promise<RCSSendResult>;
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* Send rich card
|
|
707
|
+
* @param to Recipient phone number
|
|
708
|
+
* @param card Rich card data
|
|
709
|
+
* @returns Send result
|
|
710
|
+
*/
|
|
711
|
+
sendRichCard(to: string, card: RCSRichCard): Promise<RCSSendResult>;
|
|
712
|
+
|
|
713
|
+
/**
|
|
714
|
+
* Send carousel of rich cards
|
|
715
|
+
* @param to Recipient phone number
|
|
716
|
+
* @param cards Array of rich cards
|
|
717
|
+
* @returns Send result
|
|
718
|
+
*/
|
|
719
|
+
sendCarousel(to: string, cards: RCSRichCard[]): Promise<RCSSendResult>;
|
|
720
|
+
|
|
721
|
+
/**
|
|
722
|
+
* Send with quick reply options
|
|
723
|
+
* @param to Recipient phone number
|
|
724
|
+
* @param body Message body
|
|
725
|
+
* @param replies Quick reply options
|
|
726
|
+
* @returns Send result
|
|
727
|
+
*/
|
|
728
|
+
sendQuickReplies(to: string, body: string, replies: RCSQuickReply[]): Promise<RCSSendResult>;
|
|
729
|
+
|
|
730
|
+
/**
|
|
731
|
+
* Get message status
|
|
732
|
+
* @param messageSid Message SID
|
|
733
|
+
* @returns Message status
|
|
734
|
+
*/
|
|
735
|
+
getStatus(messageSid: string): Promise<{ status: string; timestamp: Date }>;
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* List content templates
|
|
739
|
+
* @param options Query options
|
|
740
|
+
* @returns Array of templates
|
|
741
|
+
*/
|
|
742
|
+
listTemplates(options?: { limit?: number }): Promise<Array<{ sid: string; name: string }>>;
|
|
743
|
+
|
|
744
|
+
/**
|
|
745
|
+
* Get template details
|
|
746
|
+
* @param contentSid Template SID
|
|
747
|
+
* @returns Template details
|
|
748
|
+
*/
|
|
749
|
+
getTemplate(contentSid: string): Promise<Record<string, any>>;
|
|
750
|
+
|
|
751
|
+
/**
|
|
752
|
+
* Delete template
|
|
753
|
+
* @param contentSid Template SID
|
|
754
|
+
* @returns Deletion result
|
|
755
|
+
*/
|
|
756
|
+
deleteTemplate(contentSid: string): Promise<{ success: boolean }>;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
/**
|
|
760
|
+
* Email Service Methods
|
|
761
|
+
*/
|
|
762
|
+
export interface EmailService {
|
|
763
|
+
/**
|
|
764
|
+
* Send email
|
|
765
|
+
* @param to Recipient email address
|
|
766
|
+
* @param subject Email subject
|
|
767
|
+
* @param html HTML content
|
|
768
|
+
* @param text Plain text content
|
|
769
|
+
* @param options Optional email options
|
|
770
|
+
* @returns Send result
|
|
771
|
+
*/
|
|
772
|
+
send(
|
|
773
|
+
to: string,
|
|
774
|
+
subject: string,
|
|
775
|
+
html: string,
|
|
776
|
+
text?: string,
|
|
777
|
+
options?: EmailOptions
|
|
778
|
+
): Promise<EmailSendResult>;
|
|
779
|
+
|
|
780
|
+
/**
|
|
781
|
+
* Send email from template
|
|
782
|
+
* @param to Recipient email address
|
|
783
|
+
* @param subject Email subject
|
|
784
|
+
* @param templateId SendGrid template ID
|
|
785
|
+
* @param dynamicData Template variable data
|
|
786
|
+
* @param options Optional email options
|
|
787
|
+
* @returns Send result
|
|
788
|
+
*/
|
|
789
|
+
sendTemplate(
|
|
790
|
+
to: string,
|
|
791
|
+
subject: string,
|
|
792
|
+
templateId: string,
|
|
793
|
+
dynamicData: Record<string, any>,
|
|
794
|
+
options?: EmailOptions
|
|
795
|
+
): Promise<EmailSendResult>;
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* Send email with attachments
|
|
799
|
+
* @param to Recipient email address
|
|
800
|
+
* @param subject Email subject
|
|
801
|
+
* @param html HTML content
|
|
802
|
+
* @param attachments Array of attachments
|
|
803
|
+
* @param options Optional email options
|
|
804
|
+
* @returns Send result
|
|
805
|
+
*/
|
|
806
|
+
sendWithAttachments(
|
|
807
|
+
to: string,
|
|
808
|
+
subject: string,
|
|
809
|
+
html: string,
|
|
810
|
+
attachments: Array<{ content: string; filename: string; type: string }>,
|
|
811
|
+
options?: EmailOptions
|
|
812
|
+
): Promise<EmailSendResult>;
|
|
813
|
+
|
|
814
|
+
/**
|
|
815
|
+
* Send bulk email to multiple recipients
|
|
816
|
+
* @param to Array of recipient emails
|
|
817
|
+
* @param subject Email subject
|
|
818
|
+
* @param html HTML content
|
|
819
|
+
* @param options Optional email options
|
|
820
|
+
* @returns Array of send results
|
|
821
|
+
*/
|
|
822
|
+
sendBulk(
|
|
823
|
+
to: string[],
|
|
824
|
+
subject: string,
|
|
825
|
+
html: string,
|
|
826
|
+
options?: EmailOptions
|
|
827
|
+
): Promise<EmailSendResult[]>;
|
|
828
|
+
|
|
829
|
+
/**
|
|
830
|
+
* Send personalized bulk email
|
|
831
|
+
* @param messages Array of personalized messages
|
|
832
|
+
* @returns Array of send results
|
|
833
|
+
*/
|
|
834
|
+
sendPersonalizedBulk(
|
|
835
|
+
messages: Array<{
|
|
836
|
+
to: string;
|
|
837
|
+
subject: string;
|
|
838
|
+
html: string;
|
|
839
|
+
personalData?: Record<string, string>;
|
|
840
|
+
}>
|
|
841
|
+
): Promise<EmailSendResult[]>;
|
|
842
|
+
|
|
843
|
+
/**
|
|
844
|
+
* Validate email address
|
|
845
|
+
* @param email Email to validate
|
|
846
|
+
* @returns Validation result
|
|
847
|
+
*/
|
|
848
|
+
validate(
|
|
849
|
+
email: string
|
|
850
|
+
): Promise<{ isValid: boolean; suggestion?: string; error?: string }>;
|
|
851
|
+
|
|
852
|
+
/**
|
|
853
|
+
* Add contact to SendGrid
|
|
854
|
+
* @param email Contact email
|
|
855
|
+
* @param data Contact data
|
|
856
|
+
* @param listIds Optional list IDs
|
|
857
|
+
* @returns Contact info
|
|
858
|
+
*/
|
|
859
|
+
addContact(
|
|
860
|
+
email: string,
|
|
861
|
+
data: Record<string, string>,
|
|
862
|
+
listIds?: string[]
|
|
863
|
+
): Promise<EmailContact>;
|
|
864
|
+
|
|
865
|
+
/**
|
|
866
|
+
* Search for contact
|
|
867
|
+
* @param email Contact email
|
|
868
|
+
* @returns Contact info or null
|
|
869
|
+
*/
|
|
870
|
+
searchContact(email: string): Promise<EmailContact | null>;
|
|
871
|
+
|
|
872
|
+
/**
|
|
873
|
+
* Delete contact
|
|
874
|
+
* @param contactId Contact ID
|
|
875
|
+
* @returns Deletion result
|
|
876
|
+
*/
|
|
877
|
+
deleteContact(contactId: string): Promise<{ success: boolean }>;
|
|
878
|
+
|
|
879
|
+
/**
|
|
880
|
+
* Create contact list
|
|
881
|
+
* @param name List name
|
|
882
|
+
* @returns List info
|
|
883
|
+
*/
|
|
884
|
+
createList(name: string): Promise<EmailContactList>;
|
|
885
|
+
|
|
886
|
+
/**
|
|
887
|
+
* Get all contact lists
|
|
888
|
+
* @returns Array of lists
|
|
889
|
+
*/
|
|
890
|
+
getLists(): Promise<EmailContactList[]>;
|
|
891
|
+
|
|
892
|
+
/**
|
|
893
|
+
* Delete contact list
|
|
894
|
+
* @param listId List ID
|
|
895
|
+
* @returns Deletion result
|
|
896
|
+
*/
|
|
897
|
+
deleteList(listId: string): Promise<{ success: boolean }>;
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
/**
|
|
901
|
+
* Plugin Configuration Options
|
|
902
|
+
*/
|
|
903
|
+
export interface XTwilioPluginOptions {
|
|
904
|
+
/** Twilio configuration */
|
|
905
|
+
twilio?: {
|
|
906
|
+
/** Twilio Account SID */
|
|
907
|
+
accountSid: string;
|
|
908
|
+
|
|
909
|
+
/** Twilio Auth Token */
|
|
910
|
+
authToken: string;
|
|
911
|
+
|
|
912
|
+
/** Twilio phone number for SMS */
|
|
913
|
+
phoneNumber: string;
|
|
914
|
+
|
|
915
|
+
/** Messaging Service SID for RCS */
|
|
916
|
+
messagingServiceSid?: string;
|
|
917
|
+
|
|
918
|
+
/** Enable Twilio service */
|
|
919
|
+
active?: boolean;
|
|
920
|
+
};
|
|
921
|
+
|
|
922
|
+
/** SendGrid configuration */
|
|
923
|
+
sendgrid?: {
|
|
924
|
+
/** SendGrid API Key */
|
|
925
|
+
apiKey: string;
|
|
926
|
+
|
|
927
|
+
/** From email address */
|
|
928
|
+
fromEmail: string;
|
|
929
|
+
|
|
930
|
+
/** From name */
|
|
931
|
+
fromName?: string;
|
|
932
|
+
|
|
933
|
+
/** Enable SendGrid service */
|
|
934
|
+
active?: boolean;
|
|
935
|
+
};
|
|
936
|
+
|
|
937
|
+
/** Enable detailed logging */
|
|
938
|
+
logRequests?: boolean;
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
/**
|
|
942
|
+
* Fastify Instance with xTwilio Decoration
|
|
943
|
+
*/
|
|
944
|
+
declare module 'fastify' {
|
|
945
|
+
interface FastifyInstance {
|
|
946
|
+
/** SMS service methods */
|
|
947
|
+
sms: SMSService;
|
|
948
|
+
|
|
949
|
+
/** Conversations service methods */
|
|
950
|
+
conversations: ConversationsService;
|
|
951
|
+
|
|
952
|
+
/** RCS service methods */
|
|
953
|
+
rcs: RCSService;
|
|
954
|
+
|
|
955
|
+
/** Email service methods */
|
|
956
|
+
email: EmailService;
|
|
957
|
+
|
|
958
|
+
/** Raw Twilio client instance */
|
|
959
|
+
twilio?: Twilio;
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
/**
|
|
964
|
+
* xTwilio Plugin
|
|
965
|
+
* Registers SMS, Conversations, RCS, and Email services with Fastify
|
|
966
|
+
*
|
|
967
|
+
* @example
|
|
968
|
+
* ```typescript
|
|
969
|
+
* import Fastify from 'fastify';
|
|
970
|
+
* import xTwilio from '@xenterprises/fastify-xtwilio';
|
|
971
|
+
*
|
|
972
|
+
* const fastify = Fastify();
|
|
973
|
+
*
|
|
974
|
+
* await fastify.register(xTwilio, {
|
|
975
|
+
* twilio: {
|
|
976
|
+
* accountSid: process.env.TWILIO_ACCOUNT_SID,
|
|
977
|
+
* authToken: process.env.TWILIO_AUTH_TOKEN,
|
|
978
|
+
* phoneNumber: process.env.TWILIO_PHONE_NUMBER,
|
|
979
|
+
* messagingServiceSid: process.env.TWILIO_MESSAGING_SERVICE_SID,
|
|
980
|
+
* },
|
|
981
|
+
* sendgrid: {
|
|
982
|
+
* apiKey: process.env.SENDGRID_API_KEY,
|
|
983
|
+
* fromEmail: process.env.SENDGRID_FROM_EMAIL,
|
|
984
|
+
* },
|
|
985
|
+
* });
|
|
986
|
+
*
|
|
987
|
+
* // Send SMS
|
|
988
|
+
* const result = await fastify.sms.send('+1234567890', 'Hello World!');
|
|
989
|
+
*
|
|
990
|
+
* // Send email
|
|
991
|
+
* await fastify.email.send('user@example.com', 'Welcome', '<h1>Hello</h1>');
|
|
992
|
+
*
|
|
993
|
+
* // Create conversation
|
|
994
|
+
* const convo = await fastify.conversations.create('Support Chat');
|
|
995
|
+
* ```
|
|
996
|
+
*/
|
|
997
|
+
declare const xTwilio: FastifyPluginAsync<XTwilioPluginOptions>;
|
|
998
|
+
|
|
999
|
+
export default xTwilio;
|