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 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
@@ -0,0 +1,2 @@
1
+ export { TwilioSmsAdapter, TwilioSmsAdapterFactory } from './twilio-sms-adapter';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -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
+ }