vintasend-twilio 0.6.2
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/README.md +125 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/twilio-sms-adapter.d.ts +29 -0
- package/dist/twilio-sms-adapter.d.ts.map +1 -0
- package/dist/twilio-sms-adapter.js +47 -0
- package/package.json +27 -0
package/README.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# VintaSend Twilio Adapter
|
|
2
|
+
|
|
3
|
+
A VintaSend notification adapter using [Twilio](https://www.twilio.com/) for reliable SMS and phone call delivery.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install vintasend-twilio twilio
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Configuration
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { TwilioNotificationAdapterFactory } from 'vintasend-twilio';
|
|
15
|
+
|
|
16
|
+
const adapter = new TwilioNotificationAdapterFactory().create(
|
|
17
|
+
templateRenderer,
|
|
18
|
+
false, // enqueueNotifications
|
|
19
|
+
{
|
|
20
|
+
accountSid: process.env.TWILIO_ACCOUNT_SID,
|
|
21
|
+
authToken: process.env.TWILIO_AUTH_TOKEN,
|
|
22
|
+
fromNumber: '+1234567890',
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Configuration Options
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
interface TwilioConfig {
|
|
31
|
+
accountSid: string; // Twilio Account SID
|
|
32
|
+
authToken: string; // Twilio Auth Token
|
|
33
|
+
fromNumber: string; // Default sender phone number
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Usage
|
|
38
|
+
|
|
39
|
+
### Basic SMS
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
await notificationService.createNotification({
|
|
43
|
+
userId: '123',
|
|
44
|
+
notificationType: 'SMS',
|
|
45
|
+
contextName: 'verification',
|
|
46
|
+
contextParameters: { code: '123456' },
|
|
47
|
+
title: 'Verification Code',
|
|
48
|
+
bodyTemplate: '/templates/verification.pug',
|
|
49
|
+
sendAfter: new Date(),
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### One-Off SMS
|
|
54
|
+
|
|
55
|
+
Send SMS without a user account:
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
await notificationService.createOneOffNotification({
|
|
59
|
+
emailOrPhone: '+1987654321',
|
|
60
|
+
firstName: 'Jane',
|
|
61
|
+
lastName: 'Smith',
|
|
62
|
+
notificationType: 'SMS',
|
|
63
|
+
contextName: 'order-status',
|
|
64
|
+
contextParameters: { status: 'shipped' },
|
|
65
|
+
title: 'Order Status Update',
|
|
66
|
+
bodyTemplate: '/templates/order-status.pug',
|
|
67
|
+
sendAfter: new Date(),
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Scheduled Notifications
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
await notificationService.createNotification({
|
|
75
|
+
userId: '123',
|
|
76
|
+
notificationType: 'SMS',
|
|
77
|
+
contextName: 'reminder',
|
|
78
|
+
contextParameters: { appointmentTime: '2pm' },
|
|
79
|
+
title: 'Appointment Reminder',
|
|
80
|
+
bodyTemplate: '/templates/reminder.pug',
|
|
81
|
+
sendAfter: new Date('2024-01-15T14:00:00Z'),
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Features
|
|
86
|
+
|
|
87
|
+
- ✅ SMS delivery via Twilio API
|
|
88
|
+
- ✅ One-off notifications
|
|
89
|
+
- ✅ Scheduled notifications
|
|
90
|
+
- ✅ Custom sender phone number
|
|
91
|
+
- ✅ Text message templates
|
|
92
|
+
- ✅ Global reach (190+ countries)
|
|
93
|
+
|
|
94
|
+
## API Reference
|
|
95
|
+
|
|
96
|
+
### TwilioNotificationAdapterFactory
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
class TwilioNotificationAdapterFactory<Config extends BaseNotificationTypeConfig>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Methods:**
|
|
103
|
+
- `create<TemplateRenderer>(templateRenderer, enqueueNotifications, config)` - Create adapter instance
|
|
104
|
+
|
|
105
|
+
### TwilioNotificationAdapter
|
|
106
|
+
|
|
107
|
+
**Properties:**
|
|
108
|
+
- `key: string` - Returns `'twilio'`
|
|
109
|
+
- `notificationType: NotificationType` - Returns `'SMS'`
|
|
110
|
+
- `supportsAttachments: boolean` - Returns `false`
|
|
111
|
+
|
|
112
|
+
**Methods:**
|
|
113
|
+
- `send(notification, context)` - Send an SMS message
|
|
114
|
+
|
|
115
|
+
## Environment Variables
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
119
|
+
TWILIO_AUTH_TOKEN=your-auth-token-here
|
|
120
|
+
TWILIO_FROM_NUMBER=+1234567890
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## License
|
|
124
|
+
|
|
125
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { TwilioSmsAdapter, TwilioSmsAdapterFactory } from './twilio-sms-adapter';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { BaseNotificationAdapter } from 'vintasend';
|
|
2
|
+
import type { BaseEmailTemplateRenderer } from 'vintasend';
|
|
3
|
+
import type { JsonObject } from 'vintasend/dist/types/json-values';
|
|
4
|
+
import type { AnyDatabaseNotification } from 'vintasend/dist/types/notification';
|
|
5
|
+
import type { BaseNotificationTypeConfig } from 'vintasend/dist/types/notification-type-config';
|
|
6
|
+
export interface TwilioConfig {
|
|
7
|
+
accountSid: string;
|
|
8
|
+
authToken: string;
|
|
9
|
+
fromNumber: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* SMS adapter using Twilio REST API directly via fetch.
|
|
13
|
+
* Avoids the twilio npm package to keep Medplum bot bundles small.
|
|
14
|
+
*
|
|
15
|
+
* SMS notifications should be created via createOneOffNotification() with
|
|
16
|
+
* the phone number passed as emailOrPhone. The calling service resolves
|
|
17
|
+
* the phone number from the FHIR resource.
|
|
18
|
+
*/
|
|
19
|
+
export declare class TwilioSmsAdapter<TemplateRenderer extends BaseEmailTemplateRenderer<Config>, Config extends BaseNotificationTypeConfig> extends BaseNotificationAdapter<TemplateRenderer, Config> {
|
|
20
|
+
key: string | null;
|
|
21
|
+
private config;
|
|
22
|
+
constructor(templateRenderer: TemplateRenderer, enqueueNotifications: boolean, config: TwilioConfig);
|
|
23
|
+
get supportsAttachments(): boolean;
|
|
24
|
+
send(notification: AnyDatabaseNotification<Config>, context: JsonObject): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
export declare class TwilioSmsAdapterFactory<Config extends BaseNotificationTypeConfig> {
|
|
27
|
+
create<TemplateRenderer extends BaseEmailTemplateRenderer<Config>>(templateRenderer: TemplateRenderer, enqueueNotifications: boolean, config: TwilioConfig): TwilioSmsAdapter<TemplateRenderer, Config>;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=twilio-sms-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"twilio-sms-adapter.d.ts","sourceRoot":"","sources":["../src/twilio-sms-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,+CAA+C,CAAC;AAEhG,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,qBAAa,gBAAgB,CAC3B,gBAAgB,SAAS,yBAAyB,CAAC,MAAM,CAAC,EAC1D,MAAM,SAAS,0BAA0B,CACzC,SAAQ,uBAAuB,CAAC,gBAAgB,EAAE,MAAM,CAAC;IACzD,GAAG,EAAE,MAAM,GAAG,IAAI,CAAgB;IAClC,OAAO,CAAC,MAAM,CAAe;gBAEjB,gBAAgB,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY;IAKnG,IAAI,mBAAmB,IAAI,OAAO,CAEjC;IAEK,IAAI,CAAC,YAAY,EAAE,uBAAuB,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CA2B9F;AAED,qBAAa,uBAAuB,CAAC,MAAM,SAAS,0BAA0B;IAC5E,MAAM,CAAC,gBAAgB,SAAS,yBAAyB,CAAC,MAAM,CAAC,EAC/D,gBAAgB,EAAE,gBAAgB,EAClC,oBAAoB,EAAE,OAAO,EAC7B,MAAM,EAAE,YAAY,GACnB,gBAAgB,CAAC,gBAAgB,EAAE,MAAM,CAAC;CAG9C"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { BaseNotificationAdapter } from 'vintasend';
|
|
2
|
+
/**
|
|
3
|
+
* SMS adapter using Twilio REST API directly via fetch.
|
|
4
|
+
* Avoids the twilio npm package to keep Medplum bot bundles small.
|
|
5
|
+
*
|
|
6
|
+
* SMS notifications should be created via createOneOffNotification() with
|
|
7
|
+
* the phone number passed as emailOrPhone. The calling service resolves
|
|
8
|
+
* the phone number from the FHIR resource.
|
|
9
|
+
*/
|
|
10
|
+
export class TwilioSmsAdapter extends BaseNotificationAdapter {
|
|
11
|
+
constructor(templateRenderer, enqueueNotifications, config) {
|
|
12
|
+
super(templateRenderer, 'SMS', enqueueNotifications);
|
|
13
|
+
this.key = 'twilio-sms';
|
|
14
|
+
this.config = config;
|
|
15
|
+
}
|
|
16
|
+
get supportsAttachments() {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
async send(notification, context) {
|
|
20
|
+
const template = await this.templateRenderer.render(notification, context);
|
|
21
|
+
const recipientPhone = await this.getRecipientEmail(notification);
|
|
22
|
+
const url = `https://api.twilio.com/2010-04-01/Accounts/${this.config.accountSid}/Messages.json`;
|
|
23
|
+
const credentials = btoa(`${this.config.accountSid}:${this.config.authToken}`);
|
|
24
|
+
const body = new URLSearchParams({
|
|
25
|
+
To: recipientPhone,
|
|
26
|
+
From: this.config.fromNumber,
|
|
27
|
+
Body: template.body,
|
|
28
|
+
});
|
|
29
|
+
const response = await fetch(url, {
|
|
30
|
+
method: 'POST',
|
|
31
|
+
headers: {
|
|
32
|
+
Authorization: `Basic ${credentials}`,
|
|
33
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
34
|
+
},
|
|
35
|
+
body: body.toString(),
|
|
36
|
+
});
|
|
37
|
+
if (!response.ok) {
|
|
38
|
+
const errorBody = await response.text();
|
|
39
|
+
throw new Error(`Twilio SMS send failed (${response.status}): ${errorBody}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export class TwilioSmsAdapterFactory {
|
|
44
|
+
create(templateRenderer, enqueueNotifications, config) {
|
|
45
|
+
return new TwilioSmsAdapter(templateRenderer, enqueueNotifications, config);
|
|
46
|
+
}
|
|
47
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vintasend-twilio",
|
|
3
|
+
"version": "0.6.2",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc",
|
|
8
|
+
"prepublishOnly": "npm run build",
|
|
9
|
+
"test": "jest",
|
|
10
|
+
"test:watch": "jest --watch",
|
|
11
|
+
"test:coverage": "jest --coverage"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"author": "Gustavo Carvalho",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"vintasend": "^0.6.2"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/jest": "^30.0.0",
|
|
23
|
+
"jest": "^30.2.0",
|
|
24
|
+
"ts-jest": "^29.4.6",
|
|
25
|
+
"typescript": "^5.9.3"
|
|
26
|
+
}
|
|
27
|
+
}
|