@elizaos/plugin-whatsapp 0.1.7-alpha.1
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 +154 -0
- package/dist/index.d.mts +72 -0
- package/dist/index.mjs +116 -0
- package/dist/index.mjs.map +1 -0
- package/eslint.config.mjs +9 -0
- package/package.json +26 -0
- package/src/client.ts +38 -0
- package/src/handlers/index.ts +2 -0
- package/src/handlers/message.handler.ts +20 -0
- package/src/handlers/webhook.handler.ts +45 -0
- package/src/index.ts +36 -0
- package/src/types.ts +58 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/validators.ts +44 -0
- package/tsconfig.json +20 -0
- package/tsup.config.ts +19 -0
package/Readme.md
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# WhatsApp Cloud API Plugin
|
|
2
|
+
|
|
3
|
+
A plugin for integrating WhatsApp Cloud API with your application.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
</file>
|
|
8
|
+
|
|
9
|
+
npm install @eliza/plugin-whatsapp
|
|
10
|
+
|
|
11
|
+
## Configuration
|
|
12
|
+
|
|
13
|
+
typescript
|
|
14
|
+
import { WhatsAppPlugin } from '@eliza/plugin-whatsapp';
|
|
15
|
+
const whatsappPlugin = new WhatsAppPlugin({
|
|
16
|
+
accessToken: 'your_access_token',
|
|
17
|
+
phoneNumberId: 'your_phone_number_id',
|
|
18
|
+
webhookVerifyToken: 'your_webhook_verify_token',
|
|
19
|
+
businessAccountId: 'your_business_account_id'
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
### Sending Messages
|
|
25
|
+
|
|
26
|
+
typescript
|
|
27
|
+
// Send a text message
|
|
28
|
+
await whatsappPlugin.sendMessage({
|
|
29
|
+
type: 'text',
|
|
30
|
+
to: '1234567890',
|
|
31
|
+
content: 'Hello from WhatsApp!'
|
|
32
|
+
});
|
|
33
|
+
// Send a template message
|
|
34
|
+
await whatsappPlugin.sendMessage({
|
|
35
|
+
type: 'template',
|
|
36
|
+
to: '1234567890',
|
|
37
|
+
content: {
|
|
38
|
+
name: 'hello_world',
|
|
39
|
+
language: {
|
|
40
|
+
code: 'en'
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
### Handling Webhooks
|
|
46
|
+
|
|
47
|
+
typescript
|
|
48
|
+
// Verify webhook
|
|
49
|
+
app.get('/webhook', (req, res) => {
|
|
50
|
+
const verified = await whatsappPlugin.verifyWebhook(req.query['hub.verify_token']);
|
|
51
|
+
if (verified) {
|
|
52
|
+
res.send(req.query['hub.challenge']);
|
|
53
|
+
} else {
|
|
54
|
+
res.sendStatus(403);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
// Handle webhook events
|
|
58
|
+
app.post('/webhook', (req, res) => {
|
|
59
|
+
await whatsappPlugin.handleWebhook(req.body);
|
|
60
|
+
res.sendStatus(200);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
## Features
|
|
64
|
+
|
|
65
|
+
- Send text messages
|
|
66
|
+
- Send template messages
|
|
67
|
+
- Webhook verification
|
|
68
|
+
- Webhook event handling
|
|
69
|
+
- Message status updates
|
|
70
|
+
|
|
71
|
+
## API Reference
|
|
72
|
+
|
|
73
|
+
### WhatsAppPlugin
|
|
74
|
+
|
|
75
|
+
#### Constructor
|
|
76
|
+
|
|
77
|
+
- `config: WhatsAppConfig` - Configuration object for the plugin
|
|
78
|
+
|
|
79
|
+
#### Methods
|
|
80
|
+
|
|
81
|
+
- `sendMessage(message: WhatsAppMessage): Promise<any>` - Send a WhatsApp message
|
|
82
|
+
- `handleWebhook(event: WhatsAppWebhookEvent): Promise<void>` - Process incoming webhook events
|
|
83
|
+
- `verifyWebhook(token: string): Promise<boolean>` - Verify webhook token
|
|
84
|
+
|
|
85
|
+
### Types
|
|
86
|
+
|
|
87
|
+
typescript
|
|
88
|
+
interface WhatsAppConfig {
|
|
89
|
+
accessToken: string;
|
|
90
|
+
phoneNumberId: string;
|
|
91
|
+
webhookVerifyToken?: string;
|
|
92
|
+
businessAccountId?: string;
|
|
93
|
+
}
|
|
94
|
+
interface WhatsAppMessage {
|
|
95
|
+
type: 'text' | 'template';
|
|
96
|
+
to: string;
|
|
97
|
+
content: string | WhatsAppTemplate;
|
|
98
|
+
}
|
|
99
|
+
interface WhatsAppTemplate {
|
|
100
|
+
name: string;
|
|
101
|
+
language: {
|
|
102
|
+
code: string;
|
|
103
|
+
};
|
|
104
|
+
components?: Array<{
|
|
105
|
+
type: string;
|
|
106
|
+
parameters: Array<{
|
|
107
|
+
type: string;
|
|
108
|
+
text?: string;
|
|
109
|
+
}>;
|
|
110
|
+
}>;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
## Error Handling
|
|
114
|
+
|
|
115
|
+
The plugin throws errors in the following cases:
|
|
116
|
+
|
|
117
|
+
- Invalid configuration
|
|
118
|
+
- Failed message sending
|
|
119
|
+
- Webhook verification failure
|
|
120
|
+
- Invalid webhook payload
|
|
121
|
+
|
|
122
|
+
Example error handling:
|
|
123
|
+
|
|
124
|
+
typescript
|
|
125
|
+
try {
|
|
126
|
+
await whatsappPlugin.sendMessage({
|
|
127
|
+
type: 'text',
|
|
128
|
+
to: '1234567890',
|
|
129
|
+
content: 'Hello!'
|
|
130
|
+
});
|
|
131
|
+
} catch (error) {
|
|
132
|
+
console.error('Failed to send message:', error.message);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
## Best Practices
|
|
136
|
+
|
|
137
|
+
1. Always validate phone numbers before sending messages
|
|
138
|
+
2. Use template messages for first-time messages to users
|
|
139
|
+
3. Store message IDs for tracking delivery status
|
|
140
|
+
4. Implement proper error handling
|
|
141
|
+
5. Set up webhook retry mechanisms
|
|
142
|
+
6. Keep your access tokens secure
|
|
143
|
+
|
|
144
|
+
## Contributing
|
|
145
|
+
|
|
146
|
+
1. Fork the repository
|
|
147
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
148
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
149
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
150
|
+
5. Open a Pull Request
|
|
151
|
+
|
|
152
|
+
## License
|
|
153
|
+
|
|
154
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Plugin } from '@elizaos/core';
|
|
2
|
+
|
|
3
|
+
interface WhatsAppConfig {
|
|
4
|
+
accessToken: string;
|
|
5
|
+
phoneNumberId: string;
|
|
6
|
+
webhookVerifyToken?: string;
|
|
7
|
+
businessAccountId?: string;
|
|
8
|
+
}
|
|
9
|
+
interface WhatsAppMessage {
|
|
10
|
+
type: "text" | "template";
|
|
11
|
+
to: string;
|
|
12
|
+
content: string | WhatsAppTemplate;
|
|
13
|
+
}
|
|
14
|
+
interface WhatsAppTemplate {
|
|
15
|
+
name: string;
|
|
16
|
+
language: {
|
|
17
|
+
code: string;
|
|
18
|
+
};
|
|
19
|
+
components?: Array<{
|
|
20
|
+
type: string;
|
|
21
|
+
parameters: Array<{
|
|
22
|
+
type: string;
|
|
23
|
+
text?: string;
|
|
24
|
+
}>;
|
|
25
|
+
}>;
|
|
26
|
+
}
|
|
27
|
+
interface WhatsAppWebhookEvent {
|
|
28
|
+
object: string;
|
|
29
|
+
entry: Array<{
|
|
30
|
+
id: string;
|
|
31
|
+
changes: Array<{
|
|
32
|
+
value: {
|
|
33
|
+
messaging_product: string;
|
|
34
|
+
metadata: {
|
|
35
|
+
display_phone_number: string;
|
|
36
|
+
phone_number_id: string;
|
|
37
|
+
};
|
|
38
|
+
statuses?: Array<{
|
|
39
|
+
id: string;
|
|
40
|
+
status: string;
|
|
41
|
+
timestamp: string;
|
|
42
|
+
recipient_id: string;
|
|
43
|
+
}>;
|
|
44
|
+
messages?: Array<{
|
|
45
|
+
from: string;
|
|
46
|
+
id: string;
|
|
47
|
+
timestamp: string;
|
|
48
|
+
text?: {
|
|
49
|
+
body: string;
|
|
50
|
+
};
|
|
51
|
+
type: string;
|
|
52
|
+
}>;
|
|
53
|
+
};
|
|
54
|
+
field: string;
|
|
55
|
+
}>;
|
|
56
|
+
}>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
declare class WhatsAppPlugin implements Plugin {
|
|
60
|
+
private config;
|
|
61
|
+
private client;
|
|
62
|
+
private messageHandler;
|
|
63
|
+
private webhookHandler;
|
|
64
|
+
name: string;
|
|
65
|
+
description: string;
|
|
66
|
+
constructor(config: WhatsAppConfig);
|
|
67
|
+
sendMessage(message: WhatsAppMessage): Promise<any>;
|
|
68
|
+
handleWebhook(event: WhatsAppWebhookEvent): Promise<void>;
|
|
69
|
+
verifyWebhook(token: string): Promise<boolean>;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export { type WhatsAppConfig, type WhatsAppMessage, WhatsAppPlugin, type WhatsAppTemplate, type WhatsAppWebhookEvent };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// src/client.ts
|
|
2
|
+
import axios from "axios";
|
|
3
|
+
var WhatsAppClient = class {
|
|
4
|
+
client;
|
|
5
|
+
config;
|
|
6
|
+
constructor(config) {
|
|
7
|
+
this.config = config;
|
|
8
|
+
this.client = axios.create({
|
|
9
|
+
baseURL: "https://graph.facebook.com/v17.0",
|
|
10
|
+
headers: {
|
|
11
|
+
Authorization: `Bearer ${config.accessToken}`,
|
|
12
|
+
"Content-Type": "application/json"
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
async sendMessage(message) {
|
|
17
|
+
const endpoint = `/${this.config.phoneNumberId}/messages`;
|
|
18
|
+
const payload = {
|
|
19
|
+
messaging_product: "whatsapp",
|
|
20
|
+
recipient_type: "individual",
|
|
21
|
+
to: message.to,
|
|
22
|
+
type: message.type,
|
|
23
|
+
...message.type === "text" ? { text: { body: message.content } } : { template: message.content }
|
|
24
|
+
};
|
|
25
|
+
return this.client.post(endpoint, payload);
|
|
26
|
+
}
|
|
27
|
+
async verifyWebhook(token) {
|
|
28
|
+
return token === this.config.webhookVerifyToken;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// src/handlers/message.handler.ts
|
|
33
|
+
var MessageHandler = class {
|
|
34
|
+
constructor(client) {
|
|
35
|
+
this.client = client;
|
|
36
|
+
}
|
|
37
|
+
async send(message) {
|
|
38
|
+
try {
|
|
39
|
+
const response = await this.client.sendMessage(message);
|
|
40
|
+
return response.data;
|
|
41
|
+
} catch (error) {
|
|
42
|
+
if (error instanceof Error) {
|
|
43
|
+
throw new Error(
|
|
44
|
+
`Failed to send WhatsApp message: ${error.message}`
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
throw new Error("Failed to send WhatsApp message");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// src/handlers/webhook.handler.ts
|
|
53
|
+
var WebhookHandler = class {
|
|
54
|
+
constructor(client) {
|
|
55
|
+
this.client = client;
|
|
56
|
+
}
|
|
57
|
+
async handle(event) {
|
|
58
|
+
try {
|
|
59
|
+
if (event.entry?.[0]?.changes?.[0]?.value?.messages) {
|
|
60
|
+
const messages = event.entry[0].changes[0].value.messages;
|
|
61
|
+
for (const message of messages) {
|
|
62
|
+
await this.handleMessage(message);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (event.entry?.[0]?.changes?.[0]?.value?.statuses) {
|
|
66
|
+
const statuses = event.entry[0].changes[0].value.statuses;
|
|
67
|
+
for (const status of statuses) {
|
|
68
|
+
await this.handleStatus(status);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
} catch (error) {
|
|
72
|
+
if (error instanceof Error) {
|
|
73
|
+
throw new Error(
|
|
74
|
+
`Failed to send WhatsApp message: ${error.message}`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
throw new Error("Failed to send WhatsApp message");
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async handleMessage(message) {
|
|
81
|
+
console.log("Received message:", message);
|
|
82
|
+
}
|
|
83
|
+
async handleStatus(status) {
|
|
84
|
+
console.log("Received status update:", status);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// src/index.ts
|
|
89
|
+
var WhatsAppPlugin = class {
|
|
90
|
+
constructor(config) {
|
|
91
|
+
this.config = config;
|
|
92
|
+
this.name = "WhatsApp Cloud API Plugin";
|
|
93
|
+
this.description = "A plugin for integrating WhatsApp Cloud API with your application.";
|
|
94
|
+
this.client = new WhatsAppClient(config);
|
|
95
|
+
this.messageHandler = new MessageHandler(this.client);
|
|
96
|
+
this.webhookHandler = new WebhookHandler(this.client);
|
|
97
|
+
}
|
|
98
|
+
client;
|
|
99
|
+
messageHandler;
|
|
100
|
+
webhookHandler;
|
|
101
|
+
name;
|
|
102
|
+
description;
|
|
103
|
+
async sendMessage(message) {
|
|
104
|
+
return this.messageHandler.send(message);
|
|
105
|
+
}
|
|
106
|
+
async handleWebhook(event) {
|
|
107
|
+
return this.webhookHandler.handle(event);
|
|
108
|
+
}
|
|
109
|
+
async verifyWebhook(token) {
|
|
110
|
+
return this.client.verifyWebhook(token);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
export {
|
|
114
|
+
WhatsAppPlugin
|
|
115
|
+
};
|
|
116
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client.ts","../src/handlers/message.handler.ts","../src/handlers/webhook.handler.ts","../src/index.ts"],"sourcesContent":["import axios, { AxiosInstance } from \"axios\";\nimport { WhatsAppConfig, WhatsAppMessage } from \"./types\";\n\nexport class WhatsAppClient {\n private client: AxiosInstance;\n private config: WhatsAppConfig;\n\n constructor(config: WhatsAppConfig) {\n this.config = config;\n this.client = axios.create({\n baseURL: \"https://graph.facebook.com/v17.0\",\n headers: {\n Authorization: `Bearer ${config.accessToken}`,\n \"Content-Type\": \"application/json\",\n },\n });\n }\n\n async sendMessage(message: WhatsAppMessage): Promise<any> {\n const endpoint = `/${this.config.phoneNumberId}/messages`;\n\n const payload = {\n messaging_product: \"whatsapp\",\n recipient_type: \"individual\",\n to: message.to,\n type: message.type,\n ...(message.type === \"text\"\n ? { text: { body: message.content } }\n : { template: message.content }),\n };\n\n return this.client.post(endpoint, payload);\n }\n\n async verifyWebhook(token: string): Promise<boolean> {\n return token === this.config.webhookVerifyToken;\n }\n}\n","import { WhatsAppClient } from \"../client\";\nimport { WhatsAppMessage } from \"../types\";\n\nexport class MessageHandler {\n constructor(private client: WhatsAppClient) {}\n\n async send(message: WhatsAppMessage): Promise<any> {\n try {\n const response = await this.client.sendMessage(message);\n return response.data;\n } catch (error: unknown) {\n if (error instanceof Error) {\n throw new Error(\n `Failed to send WhatsApp message: ${error.message}`\n );\n }\n throw new Error('Failed to send WhatsApp message');\n }\n }\n}\n","import { WhatsAppClient } from \"../client\";\nimport { WhatsAppWebhookEvent } from \"../types\";\n\nexport class WebhookHandler {\n constructor(private client: WhatsAppClient) {}\n\n async handle(event: WhatsAppWebhookEvent): Promise<void> {\n try {\n // Process messages\n if (event.entry?.[0]?.changes?.[0]?.value?.messages) {\n const messages = event.entry[0].changes[0].value.messages;\n for (const message of messages) {\n await this.handleMessage(message);\n }\n }\n\n // Process status updates\n if (event.entry?.[0]?.changes?.[0]?.value?.statuses) {\n const statuses = event.entry[0].changes[0].value.statuses;\n for (const status of statuses) {\n await this.handleStatus(status);\n }\n }\n } catch (error: unknown) {\n if (error instanceof Error) {\n throw new Error(\n `Failed to send WhatsApp message: ${error.message}`\n );\n }\n throw new Error(\"Failed to send WhatsApp message\");\n }\n }\n\n private async handleMessage(message: any): Promise<void> {\n // Implement message handling logic\n // This could emit events or trigger callbacks based on your framework's needs\n console.log(\"Received message:\", message);\n }\n\n private async handleStatus(status: any): Promise<void> {\n // Implement status update handling logic\n // This could emit events or trigger callbacks based on your framework's needs\n console.log(\"Received status update:\", status);\n }\n}\n","import { Plugin } from \"@elizaos/core\";\nimport { WhatsAppClient } from \"./client\";\nimport { WhatsAppConfig, WhatsAppMessage, WhatsAppWebhookEvent } from \"./types\";\nimport { MessageHandler, WebhookHandler } from \"./handlers\";\n\nexport class WhatsAppPlugin implements Plugin {\n private client: WhatsAppClient;\n private messageHandler: MessageHandler;\n private webhookHandler: WebhookHandler;\n\n name: string;\n description: string;\n\n constructor(private config: WhatsAppConfig) {\n this.name = \"WhatsApp Cloud API Plugin\";\n this.description =\n \"A plugin for integrating WhatsApp Cloud API with your application.\";\n this.client = new WhatsAppClient(config);\n this.messageHandler = new MessageHandler(this.client);\n this.webhookHandler = new WebhookHandler(this.client);\n }\n\n async sendMessage(message: WhatsAppMessage): Promise<any> {\n return this.messageHandler.send(message);\n }\n\n async handleWebhook(event: WhatsAppWebhookEvent): Promise<void> {\n return this.webhookHandler.handle(event);\n }\n\n async verifyWebhook(token: string): Promise<boolean> {\n return this.client.verifyWebhook(token);\n }\n}\n\nexport * from \"./types\";\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@elizaos/plugin-whatsapp",
|
|
3
|
+
"version": "0.1.7-alpha.1",
|
|
4
|
+
"description": "WhatsApp Cloud API plugin",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsup --format esm --dts",
|
|
9
|
+
"dev": "tsup --format esm --dts --watch",
|
|
10
|
+
"test": "jest",
|
|
11
|
+
"lint": "eslint --fix --cache ."
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@elizaos/core": "workspace:*",
|
|
15
|
+
"axios": "1.7.8"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/jest": "29.5.14",
|
|
19
|
+
"@types/node": "20.17.9",
|
|
20
|
+
"@typescript-eslint/eslint-plugin": "8.16.0",
|
|
21
|
+
"@typescript-eslint/parser": "8.16.0",
|
|
22
|
+
"jest": "29.7.0",
|
|
23
|
+
"ts-jest": "29.2.5",
|
|
24
|
+
"typescript": "5.6.3"
|
|
25
|
+
}
|
|
26
|
+
}
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import axios, { AxiosInstance } from "axios";
|
|
2
|
+
import { WhatsAppConfig, WhatsAppMessage } from "./types";
|
|
3
|
+
|
|
4
|
+
export class WhatsAppClient {
|
|
5
|
+
private client: AxiosInstance;
|
|
6
|
+
private config: WhatsAppConfig;
|
|
7
|
+
|
|
8
|
+
constructor(config: WhatsAppConfig) {
|
|
9
|
+
this.config = config;
|
|
10
|
+
this.client = axios.create({
|
|
11
|
+
baseURL: "https://graph.facebook.com/v17.0",
|
|
12
|
+
headers: {
|
|
13
|
+
Authorization: `Bearer ${config.accessToken}`,
|
|
14
|
+
"Content-Type": "application/json",
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async sendMessage(message: WhatsAppMessage): Promise<any> {
|
|
20
|
+
const endpoint = `/${this.config.phoneNumberId}/messages`;
|
|
21
|
+
|
|
22
|
+
const payload = {
|
|
23
|
+
messaging_product: "whatsapp",
|
|
24
|
+
recipient_type: "individual",
|
|
25
|
+
to: message.to,
|
|
26
|
+
type: message.type,
|
|
27
|
+
...(message.type === "text"
|
|
28
|
+
? { text: { body: message.content } }
|
|
29
|
+
: { template: message.content }),
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
return this.client.post(endpoint, payload);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async verifyWebhook(token: string): Promise<boolean> {
|
|
36
|
+
return token === this.config.webhookVerifyToken;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { WhatsAppClient } from "../client";
|
|
2
|
+
import { WhatsAppMessage } from "../types";
|
|
3
|
+
|
|
4
|
+
export class MessageHandler {
|
|
5
|
+
constructor(private client: WhatsAppClient) {}
|
|
6
|
+
|
|
7
|
+
async send(message: WhatsAppMessage): Promise<any> {
|
|
8
|
+
try {
|
|
9
|
+
const response = await this.client.sendMessage(message);
|
|
10
|
+
return response.data;
|
|
11
|
+
} catch (error: unknown) {
|
|
12
|
+
if (error instanceof Error) {
|
|
13
|
+
throw new Error(
|
|
14
|
+
`Failed to send WhatsApp message: ${error.message}`
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
throw new Error('Failed to send WhatsApp message');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { WhatsAppClient } from "../client";
|
|
2
|
+
import { WhatsAppWebhookEvent } from "../types";
|
|
3
|
+
|
|
4
|
+
export class WebhookHandler {
|
|
5
|
+
constructor(private client: WhatsAppClient) {}
|
|
6
|
+
|
|
7
|
+
async handle(event: WhatsAppWebhookEvent): Promise<void> {
|
|
8
|
+
try {
|
|
9
|
+
// Process messages
|
|
10
|
+
if (event.entry?.[0]?.changes?.[0]?.value?.messages) {
|
|
11
|
+
const messages = event.entry[0].changes[0].value.messages;
|
|
12
|
+
for (const message of messages) {
|
|
13
|
+
await this.handleMessage(message);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Process status updates
|
|
18
|
+
if (event.entry?.[0]?.changes?.[0]?.value?.statuses) {
|
|
19
|
+
const statuses = event.entry[0].changes[0].value.statuses;
|
|
20
|
+
for (const status of statuses) {
|
|
21
|
+
await this.handleStatus(status);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
} catch (error: unknown) {
|
|
25
|
+
if (error instanceof Error) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
`Failed to send WhatsApp message: ${error.message}`
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
throw new Error("Failed to send WhatsApp message");
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private async handleMessage(message: any): Promise<void> {
|
|
35
|
+
// Implement message handling logic
|
|
36
|
+
// This could emit events or trigger callbacks based on your framework's needs
|
|
37
|
+
console.log("Received message:", message);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private async handleStatus(status: any): Promise<void> {
|
|
41
|
+
// Implement status update handling logic
|
|
42
|
+
// This could emit events or trigger callbacks based on your framework's needs
|
|
43
|
+
console.log("Received status update:", status);
|
|
44
|
+
}
|
|
45
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Plugin } from "@elizaos/core";
|
|
2
|
+
import { WhatsAppClient } from "./client";
|
|
3
|
+
import { WhatsAppConfig, WhatsAppMessage, WhatsAppWebhookEvent } from "./types";
|
|
4
|
+
import { MessageHandler, WebhookHandler } from "./handlers";
|
|
5
|
+
|
|
6
|
+
export class WhatsAppPlugin implements Plugin {
|
|
7
|
+
private client: WhatsAppClient;
|
|
8
|
+
private messageHandler: MessageHandler;
|
|
9
|
+
private webhookHandler: WebhookHandler;
|
|
10
|
+
|
|
11
|
+
name: string;
|
|
12
|
+
description: string;
|
|
13
|
+
|
|
14
|
+
constructor(private config: WhatsAppConfig) {
|
|
15
|
+
this.name = "WhatsApp Cloud API Plugin";
|
|
16
|
+
this.description =
|
|
17
|
+
"A plugin for integrating WhatsApp Cloud API with your application.";
|
|
18
|
+
this.client = new WhatsAppClient(config);
|
|
19
|
+
this.messageHandler = new MessageHandler(this.client);
|
|
20
|
+
this.webhookHandler = new WebhookHandler(this.client);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async sendMessage(message: WhatsAppMessage): Promise<any> {
|
|
24
|
+
return this.messageHandler.send(message);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async handleWebhook(event: WhatsAppWebhookEvent): Promise<void> {
|
|
28
|
+
return this.webhookHandler.handle(event);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async verifyWebhook(token: string): Promise<boolean> {
|
|
32
|
+
return this.client.verifyWebhook(token);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export * from "./types";
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export interface WhatsAppConfig {
|
|
2
|
+
accessToken: string;
|
|
3
|
+
phoneNumberId: string;
|
|
4
|
+
webhookVerifyToken?: string;
|
|
5
|
+
businessAccountId?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface WhatsAppMessage {
|
|
9
|
+
type: "text" | "template";
|
|
10
|
+
to: string;
|
|
11
|
+
content: string | WhatsAppTemplate;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface WhatsAppTemplate {
|
|
15
|
+
name: string;
|
|
16
|
+
language: {
|
|
17
|
+
code: string;
|
|
18
|
+
};
|
|
19
|
+
components?: Array<{
|
|
20
|
+
type: string;
|
|
21
|
+
parameters: Array<{
|
|
22
|
+
type: string;
|
|
23
|
+
text?: string;
|
|
24
|
+
}>;
|
|
25
|
+
}>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface WhatsAppWebhookEvent {
|
|
29
|
+
object: string;
|
|
30
|
+
entry: Array<{
|
|
31
|
+
id: string;
|
|
32
|
+
changes: Array<{
|
|
33
|
+
value: {
|
|
34
|
+
messaging_product: string;
|
|
35
|
+
metadata: {
|
|
36
|
+
display_phone_number: string;
|
|
37
|
+
phone_number_id: string;
|
|
38
|
+
};
|
|
39
|
+
statuses?: Array<{
|
|
40
|
+
id: string;
|
|
41
|
+
status: string;
|
|
42
|
+
timestamp: string;
|
|
43
|
+
recipient_id: string;
|
|
44
|
+
}>;
|
|
45
|
+
messages?: Array<{
|
|
46
|
+
from: string;
|
|
47
|
+
id: string;
|
|
48
|
+
timestamp: string;
|
|
49
|
+
text?: {
|
|
50
|
+
body: string;
|
|
51
|
+
};
|
|
52
|
+
type: string;
|
|
53
|
+
}>;
|
|
54
|
+
};
|
|
55
|
+
field: string;
|
|
56
|
+
}>;
|
|
57
|
+
}>;
|
|
58
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./validators";
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { WhatsAppMessage, WhatsAppTemplate, WhatsAppConfig } from "../types";
|
|
2
|
+
|
|
3
|
+
export function validateConfig(config: WhatsAppConfig): void {
|
|
4
|
+
if (!config.accessToken) {
|
|
5
|
+
throw new Error("WhatsApp access token is required");
|
|
6
|
+
}
|
|
7
|
+
if (!config.phoneNumberId) {
|
|
8
|
+
throw new Error("WhatsApp phone number ID is required");
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function validateMessage(message: WhatsAppMessage): void {
|
|
13
|
+
if (!message.to) {
|
|
14
|
+
throw new Error("Recipient phone number is required");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (!message.type) {
|
|
18
|
+
throw new Error("Message type is required");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (!message.content) {
|
|
22
|
+
throw new Error("Message content is required");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (message.type === "template") {
|
|
26
|
+
validateTemplate(message.content as WhatsAppTemplate);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function validateTemplate(template: WhatsAppTemplate): void {
|
|
31
|
+
if (!template.name) {
|
|
32
|
+
throw new Error("Template name is required");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (!template.language || !template.language.code) {
|
|
36
|
+
throw new Error("Template language code is required");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function validatePhoneNumber(phoneNumber: string): boolean {
|
|
41
|
+
// Basic phone number validation - can be enhanced based on requirements
|
|
42
|
+
const phoneRegex = /^\d{1,15}$/;
|
|
43
|
+
return phoneRegex.test(phoneNumber);
|
|
44
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../core/tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "./dist",
|
|
5
|
+
"rootDir": "src",
|
|
6
|
+
"baseUrl": ".",
|
|
7
|
+
"types": [
|
|
8
|
+
"node",
|
|
9
|
+
"jest"
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
"include": [
|
|
13
|
+
"src/**/*.ts"
|
|
14
|
+
],
|
|
15
|
+
"exclude": [
|
|
16
|
+
"node_modules",
|
|
17
|
+
"dist",
|
|
18
|
+
"**/*.test.ts"
|
|
19
|
+
]
|
|
20
|
+
}
|
package/tsup.config.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { defineConfig } from "tsup";
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
entry: ["src/index.ts"],
|
|
5
|
+
outDir: "dist",
|
|
6
|
+
sourcemap: true,
|
|
7
|
+
clean: true,
|
|
8
|
+
format: ["esm"], // Ensure you're targeting CommonJS
|
|
9
|
+
external: [
|
|
10
|
+
"dotenv", // Externalize dotenv to prevent bundling
|
|
11
|
+
"fs", // Externalize fs to use Node.js built-in module
|
|
12
|
+
"path", // Externalize other built-ins if necessary
|
|
13
|
+
"@reflink/reflink",
|
|
14
|
+
"@node-llama-cpp",
|
|
15
|
+
"https",
|
|
16
|
+
"http",
|
|
17
|
+
"agentkeepalive",
|
|
18
|
+
],
|
|
19
|
+
});
|