@warriorteam/messenger-sdk 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/README.md +261 -0
- package/dist/index.cjs +3 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +341 -0
- package/dist/index.d.ts +341 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# @warriorteam/messenger-sdk
|
|
2
|
+
|
|
3
|
+
A modern TypeScript SDK for the Facebook Messenger Platform API, designed with simplicity and type safety in mind.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🚀 **Zero runtime dependencies** - Built with native fetch
|
|
8
|
+
- 📝 **Full TypeScript support** - Complete type definitions
|
|
9
|
+
- 🔄 **Dual module support** - ESM and CommonJS
|
|
10
|
+
- ✅ **Comprehensive validation** - Built-in message and template validation
|
|
11
|
+
- 🛡️ **Error handling** - Detailed error types and messages
|
|
12
|
+
- 📚 **Complete API coverage** - Send API, Templates, Attachments, Moderation
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @warriorteam/messenger-sdk
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Requirements
|
|
21
|
+
|
|
22
|
+
- Node.js 18+ (for native fetch support)
|
|
23
|
+
- A Facebook Page Access Token
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { Messenger } from '@warriorteam/messenger-sdk';
|
|
29
|
+
|
|
30
|
+
const messenger = new Messenger({
|
|
31
|
+
accessToken: 'YOUR_PAGE_ACCESS_TOKEN',
|
|
32
|
+
version: 'v23.0'
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Send a text message
|
|
36
|
+
const result = await messenger.send.message({
|
|
37
|
+
recipient: { id: 'USER_PSID' },
|
|
38
|
+
message: { text: 'Hello from RedAI Messenger SDK!' }
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
console.log('Message sent:', result.message_id);
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## API Reference
|
|
45
|
+
|
|
46
|
+
### Client Configuration
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
const messenger = new Messenger({
|
|
50
|
+
accessToken: string; // Required: Your page access token
|
|
51
|
+
version?: string; // Optional: API version (default: 'v23.0')
|
|
52
|
+
baseUrl?: string; // Optional: Custom base URL
|
|
53
|
+
timeout?: number; // Optional: Request timeout in ms (default: 30000)
|
|
54
|
+
maxRetries?: number; // Optional: Max retry attempts (default: 3)
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Send API
|
|
59
|
+
|
|
60
|
+
#### Send Text Message
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
await messenger.send.message({
|
|
64
|
+
recipient: { id: 'USER_PSID' },
|
|
65
|
+
message: { text: 'Hello World!' }
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
#### Send Message with Quick Replies
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
await messenger.send.message({
|
|
73
|
+
recipient: { id: 'USER_PSID' },
|
|
74
|
+
message: {
|
|
75
|
+
text: 'Pick a color:',
|
|
76
|
+
quick_replies: [
|
|
77
|
+
{ content_type: 'text', title: 'Red', payload: 'PICKED_RED' },
|
|
78
|
+
{ content_type: 'text', title: 'Blue', payload: 'PICKED_BLUE' }
|
|
79
|
+
]
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
#### Send Typing Indicators
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
await messenger.send.typingOn('USER_PSID');
|
|
88
|
+
await messenger.send.typingOff('USER_PSID');
|
|
89
|
+
await messenger.send.markSeen('USER_PSID');
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
#### Response Format
|
|
93
|
+
|
|
94
|
+
The Send API response includes a `message_id` and optionally a `recipient_id`:
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
const result = await messenger.send.message({...});
|
|
98
|
+
console.log('Message ID:', result.message_id); // Always present
|
|
99
|
+
console.log('Recipient ID:', result.recipient_id || 'Not provided'); // Optional
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Note**: `recipient_id` is only included when using `recipient.id` (PSID). It's not included when using `recipient.user_ref` or `recipient.phone_number`.
|
|
103
|
+
|
|
104
|
+
### Attachments API
|
|
105
|
+
|
|
106
|
+
#### Upload Attachment from URL
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
const attachment = await messenger.attachments.upload({
|
|
110
|
+
type: 'image',
|
|
111
|
+
url: 'https://example.com/image.jpg',
|
|
112
|
+
is_reusable: true
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Use the attachment ID to send
|
|
116
|
+
await messenger.send.message({
|
|
117
|
+
recipient: { id: 'USER_PSID' },
|
|
118
|
+
message: {
|
|
119
|
+
attachment: {
|
|
120
|
+
type: 'image',
|
|
121
|
+
payload: { attachment_id: attachment.attachment_id }
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### Send Attachment Directly
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
await messenger.send.message({
|
|
131
|
+
recipient: { id: 'USER_PSID' },
|
|
132
|
+
message: {
|
|
133
|
+
attachment: {
|
|
134
|
+
type: 'image',
|
|
135
|
+
payload: { url: 'https://example.com/image.jpg' }
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Templates API
|
|
142
|
+
|
|
143
|
+
#### Generic Template
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
await messenger.templates.generic({
|
|
147
|
+
recipient: { id: 'USER_PSID' },
|
|
148
|
+
elements: [{
|
|
149
|
+
title: 'Welcome',
|
|
150
|
+
subtitle: 'Check out our products',
|
|
151
|
+
image_url: 'https://example.com/image.jpg',
|
|
152
|
+
buttons: [{
|
|
153
|
+
type: 'web_url',
|
|
154
|
+
title: 'Shop Now',
|
|
155
|
+
url: 'https://example.com/shop'
|
|
156
|
+
}]
|
|
157
|
+
}]
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
#### Button Template
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
await messenger.templates.button({
|
|
165
|
+
recipient: { id: 'USER_PSID' },
|
|
166
|
+
text: 'What would you like to do?',
|
|
167
|
+
buttons: [{
|
|
168
|
+
type: 'postback',
|
|
169
|
+
title: 'Get Started',
|
|
170
|
+
payload: 'GET_STARTED'
|
|
171
|
+
}]
|
|
172
|
+
});
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Moderation API
|
|
176
|
+
|
|
177
|
+
#### User Moderation
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
// Block a user from messaging (can still see page content)
|
|
181
|
+
await messenger.moderation.blockUser('USER_PSID');
|
|
182
|
+
|
|
183
|
+
// Ban a user completely (no messaging + no Facebook interactions)
|
|
184
|
+
await messenger.moderation.banUser('USER_PSID');
|
|
185
|
+
|
|
186
|
+
// Move conversation to spam folder
|
|
187
|
+
await messenger.moderation.moveToSpam('USER_PSID');
|
|
188
|
+
|
|
189
|
+
// Block and spam (common combo)
|
|
190
|
+
await messenger.moderation.blockAndSpam('USER_PSID');
|
|
191
|
+
|
|
192
|
+
// Multiple users at once
|
|
193
|
+
await messenger.moderation.blockUser(['USER_1', 'USER_2', 'USER_3']);
|
|
194
|
+
|
|
195
|
+
// Unblock/unban users
|
|
196
|
+
await messenger.moderation.unblockUser('USER_PSID');
|
|
197
|
+
await messenger.moderation.unbanUser('USER_PSID');
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Error Handling
|
|
201
|
+
|
|
202
|
+
The SDK provides specific error types for different scenarios:
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
import {
|
|
206
|
+
MessengerAPIError,
|
|
207
|
+
MessengerNetworkError,
|
|
208
|
+
MessengerTimeoutError,
|
|
209
|
+
MessengerConfigError
|
|
210
|
+
} from '@warriorteam/messenger-sdk';
|
|
211
|
+
|
|
212
|
+
try {
|
|
213
|
+
await messenger.send.message({
|
|
214
|
+
recipient: { id: 'USER_PSID' },
|
|
215
|
+
message: { text: 'Hello!' }
|
|
216
|
+
});
|
|
217
|
+
} catch (error) {
|
|
218
|
+
if (error instanceof MessengerAPIError) {
|
|
219
|
+
console.error('API Error:', error.message, error.code);
|
|
220
|
+
} else if (error instanceof MessengerNetworkError) {
|
|
221
|
+
console.error('Network Error:', error.message);
|
|
222
|
+
} else if (error instanceof MessengerTimeoutError) {
|
|
223
|
+
console.error('Timeout Error:', error.timeout);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Examples
|
|
229
|
+
|
|
230
|
+
Check the `examples/` directory for complete usage examples:
|
|
231
|
+
|
|
232
|
+
- `send-message.ts` - Basic message sending
|
|
233
|
+
- `upload-attachment.ts` - Attachment handling
|
|
234
|
+
- `send-template.ts` - Template messages
|
|
235
|
+
|
|
236
|
+
## Development
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
# Install dependencies
|
|
240
|
+
npm install
|
|
241
|
+
|
|
242
|
+
# Build the project
|
|
243
|
+
npm run build
|
|
244
|
+
|
|
245
|
+
# Run tests
|
|
246
|
+
npm test
|
|
247
|
+
|
|
248
|
+
# Lint code
|
|
249
|
+
npm run lint
|
|
250
|
+
|
|
251
|
+
# Format code
|
|
252
|
+
npm run format
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## License
|
|
256
|
+
|
|
257
|
+
MIT
|
|
258
|
+
|
|
259
|
+
## Support
|
|
260
|
+
|
|
261
|
+
For issues and questions, please visit our [GitHub repository](https://github.com/warriorteam/messenger-sdk).
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
'use strict';var f="v23.0",R="https://graph.facebook.com";var p={MESSAGES:"/me/messages",MESSAGE_ATTACHMENTS:"/me/message_attachments",MODERATE_CONVERSATIONS:"/me/moderate_conversations"},E={TEXT_MESSAGE_MAX_CHARS:2e3},U={IMAGE_MAX_SIZE:8*1024*1024,OTHER_MAX_SIZE:25*1024*1024,VIDEO_TIMEOUT:75,OTHER_TIMEOUT:10},o={GENERIC_ELEMENTS_MAX:10,GENERIC_TITLE_MAX_CHARS:80,GENERIC_SUBTITLE_MAX_CHARS:80,BUTTON_TEXT_MAX_CHARS:640,BUTTONS_MAX_COUNT:3,BUTTON_TITLE_MAX_CHARS:20,POSTBACK_PAYLOAD_MAX_CHARS:1e3,MEDIA_ELEMENTS_COUNT:1,MEDIA_BUTTONS_MAX_COUNT:3};var c=class extends Error{code;type;subcode;fbtrace_id;statusCode;response;constructor(e,s,r){super(e.message),this.name="MessengerAPIError",this.code=e.code,this.type=e.type,this.subcode=e.error_subcode,this.fbtrace_id=e.fbtrace_id,this.statusCode=s,this.response=r;}},l=class extends Error{cause;constructor(e,s){super(e),this.name="MessengerNetworkError",this.cause=s;}},u=class extends Error{timeout;constructor(e){super(`Request timed out after ${e}ms`),this.name="MessengerTimeoutError",this.timeout=e;}},m=class extends Error{constructor(e){super(e),this.name="MessengerConfigError";}};var S=class{config;constructor(e){this.config={accessToken:e.accessToken,version:e.version,baseUrl:e.baseUrl||R,timeout:e.timeout||3e4,maxRetries:e.maxRetries||3};}async request(e){let s=this.buildUrl(e.path,e.query),r;for(let i=0;i<=this.config.maxRetries;i++)try{let a=await this.makeRequest(s,e);return await this.handleResponse(a)}catch(a){if(r=a,a instanceof c&&a.statusCode>=400&&a.statusCode<500||i===this.config.maxRetries)throw a;await this.delay(1e3*(i+1));}throw r||new Error("Unknown error occurred")}buildUrl(e,s){let r=new URL(`${this.config.baseUrl}/${this.config.version}${e}`);return r.searchParams.append("access_token",this.config.accessToken),s&&Object.entries(s).forEach(([i,a])=>{r.searchParams.append(i,String(a));}),r.toString()}async makeRequest(e,s){let r=new AbortController,i=setTimeout(()=>r.abort(),this.config.timeout);try{let a={method:s.method,headers:{"Content-Type":"application/json"},signal:r.signal};return s.body&&(a.body=JSON.stringify(s.body)),await fetch(e,a)}catch(a){throw a instanceof Error?a.name==="AbortError"?new u(this.config.timeout):new l(`Network request failed: ${a.message}`,a):a}finally{clearTimeout(i);}}async handleResponse(e){let r=e.headers.get("content-type")?.includes("application/json");if(!e.ok)if(r){let i=await e.json();throw new c(i.error,e.status,i)}else {let i=await e.text();throw new c({message:i||`HTTP ${e.status} ${e.statusText}`,type:"http_error",code:e.status,fbtrace_id:""},e.status,i)}return r?await e.json():await e.text()}delay(e){return new Promise(s=>setTimeout(s,e))}};var T=class extends Error{constructor(e){super(e),this.name="MessageValidationError";}};function P(t){if(!t||t.trim()==="")throw new T("Text message cannot be empty");if(t.length>E.TEXT_MESSAGE_MAX_CHARS)throw new T(`Text message cannot exceed ${E.TEXT_MESSAGE_MAX_CHARS} characters`)}var d=class{constructor(e){this.httpClient=e;}async message(e){return e.message?.text&&P(e.message.text),this.httpClient.request({method:"POST",path:p.MESSAGES,body:e})}async action(e,s){return this.httpClient.request({method:"POST",path:p.MESSAGES,body:{recipient:{id:e},messaging_type:"RESPONSE",sender_action:s}})}async typingOn(e){return this.action(e,"typing_on")}async typingOff(e){return this.action(e,"typing_off")}async markSeen(e){return this.action(e,"mark_seen")}async attachment(e){return this.message({recipient:e.recipient,messaging_type:e.messaging_type??"RESPONSE",message:{attachment:{type:e.type,payload:{attachment_id:e.attachment_id}}}})}async attachmentFromUrl(e){return this.message({recipient:e.recipient,messaging_type:e.messaging_type??"RESPONSE",message:{attachment:{type:e.type,payload:{url:e.url}}}})}};var _=class{constructor(e){this.httpClient=e;}async upload(e){let s={message:{attachment:{type:e.type,payload:{url:e.url,is_reusable:e.is_reusable??true}}}};return this.httpClient.request({method:"POST",path:p.MESSAGE_ATTACHMENTS,body:s})}};var h=class{constructor(e){this.httpClient=e;}async moderate(e){return this.httpClient.request({method:"POST",path:p.MODERATE_CONVERSATIONS,body:e})}async blockUser(e){let s=Array.isArray(e)?e.map(r=>({id:r})):[{id:e}];return this.moderate({user_ids:s,actions:["block_user"]})}async unblockUser(e){let s=Array.isArray(e)?e.map(r=>({id:r})):[{id:e}];return this.moderate({user_ids:s,actions:["unblock_user"]})}async banUser(e){let s=Array.isArray(e)?e.map(r=>({id:r})):[{id:e}];return this.moderate({user_ids:s,actions:["ban_user"]})}async unbanUser(e){let s=Array.isArray(e)?e.map(r=>({id:r})):[{id:e}];return this.moderate({user_ids:s,actions:["unban_user"]})}async moveToSpam(e){let s=Array.isArray(e)?e.map(r=>({id:r})):[{id:e}];return this.moderate({user_ids:s,actions:["move_to_spam"]})}async blockAndSpam(e){let s=Array.isArray(e)?e.map(r=>({id:r})):[{id:e}];return this.moderate({user_ids:s,actions:["block_user","move_to_spam"]})}};var n=class extends Error{constructor(e){super(e),this.name="TemplateValidationError";}};function b(t){if(t.length===0)throw new n("Generic template must have at least 1 element");if(t.length>o.GENERIC_ELEMENTS_MAX)throw new n(`Generic template cannot have more than ${o.GENERIC_ELEMENTS_MAX} elements`);t.forEach((e,s)=>{I(e,s);});}function I(t,e){if(!t.title||t.title.trim()==="")throw new n(`Element ${e}: title is required`);if(t.title.length>o.GENERIC_TITLE_MAX_CHARS)throw new n(`Element ${e}: title cannot exceed ${o.GENERIC_TITLE_MAX_CHARS} characters`);if(t.subtitle&&t.subtitle.length>o.GENERIC_SUBTITLE_MAX_CHARS)throw new n(`Element ${e}: subtitle cannot exceed ${o.GENERIC_SUBTITLE_MAX_CHARS} characters`);if(t.image_url&&!y(t.image_url))throw new n(`Element ${e}: image_url must be HTTPS`);if(t.buttons&&A(t.buttons,`Element ${e}`),!!!(t.subtitle||t.image_url||t.default_action||t.buttons&&t.buttons.length>0))throw new n(`Element ${e}: must have at least one additional property beyond title`)}function w(t,e){if(!t||t.trim()==="")throw new n("Button template text is required");if(t.length>o.BUTTON_TEXT_MAX_CHARS)throw new n(`Button template text cannot exceed ${o.BUTTON_TEXT_MAX_CHARS} characters`);if(e.length===0)throw new n("Button template must have at least 1 button");A(e,"Button template");}function C(t){if(!t.media_type)throw new n("Media template element must have media_type");if(!t.url&&!t.attachment_id)throw new n("Media template element must have either url or attachment_id");if(t.url&&t.attachment_id)throw new n("Media template element cannot have both url and attachment_id");if(t.url&&!y(t.url))throw new n("Media template url must be HTTPS");if(t.buttons){if(t.buttons.length>o.MEDIA_BUTTONS_MAX_COUNT)throw new n(`Media template cannot have more than ${o.MEDIA_BUTTONS_MAX_COUNT} buttons`);A(t.buttons,"Media template");}}function A(t,e){if(t.length>o.BUTTONS_MAX_COUNT)throw new n(`${e} cannot have more than ${o.BUTTONS_MAX_COUNT} buttons`);t.forEach((s,r)=>{x(s,`${e} button ${r}`);});}function x(t,e){if(!t.type)throw new n(`${e}: type is required`);if(t.type!=="account_unlink"&&(!t.title||t.title.trim()===""))throw new n(`${e}: title is required for ${t.type} buttons`);if(t.title&&t.title.length>o.BUTTON_TITLE_MAX_CHARS)throw new n(`${e}: title cannot exceed ${o.BUTTON_TITLE_MAX_CHARS} characters`);switch(t.type){case "web_url":if(!t.url)throw new n(`${e}: url is required for web_url buttons`);if(!y(t.url))throw new n(`${e}: url must be HTTPS for web_url buttons`);break;case "postback":if(!t.payload)throw new n(`${e}: payload is required for postback buttons`);if(t.payload.length>o.POSTBACK_PAYLOAD_MAX_CHARS)throw new n(`${e}: payload cannot exceed ${o.POSTBACK_PAYLOAD_MAX_CHARS} characters`);break;case "phone_number":if(!t.payload)throw new n(`${e}: payload is required for phone_number buttons`);if(!t.payload.startsWith("+"))throw new n(`${e}: phone_number payload must start with + (e.g., +1234567890)`);break;case "game_play":break;case "account_link":if(!t.url)throw new n(`${e}: url is required for account_link buttons`);if(!y(t.url))throw new n(`${e}: url must be HTTPS for account_link buttons`);break;}if(t.type==="web_url"&&t.messenger_extensions&&t.fallback_url&&!y(t.fallback_url))throw new n(`${e}: fallback_url must be HTTPS`)}function y(t){try{return new URL(t).protocol==="https:"}catch{return false}}var g=class{constructor(e){this.httpClient=e;}async generic(e){b(e.elements);let s={template_type:"generic",elements:e.elements,image_aspect_ratio:e.image_aspect_ratio},r={recipient:e.recipient,messaging_type:e.messaging_type||"UPDATE",message:{attachment:{type:"template",payload:s}},notification_type:e.notification_type,tag:e.tag};return this.httpClient.request({method:"POST",path:p.MESSAGES,body:r})}async button(e){w(e.text,e.buttons);let s={template_type:"button",text:e.text,buttons:e.buttons},r={recipient:e.recipient,messaging_type:e.messaging_type||"UPDATE",message:{attachment:{type:"template",payload:s}},notification_type:e.notification_type,tag:e.tag};return this.httpClient.request({method:"POST",path:p.MESSAGES,body:r})}async media(e){C(e.element);let s={template_type:"media",elements:[e.element]},r={recipient:e.recipient,messaging_type:e.messaging_type||"UPDATE",message:{attachment:{type:"template",payload:s}},notification_type:e.notification_type,tag:e.tag};return this.httpClient.request({method:"POST",path:p.MESSAGES,body:r})}async product(e){let s={template_type:"product",elements:e.elements},r={recipient:e.recipient,messaging_type:e.messaging_type||"UPDATE",message:{attachment:{type:"template",payload:s}},notification_type:e.notification_type,tag:e.tag};return this.httpClient.request({method:"POST",path:p.MESSAGES,body:r})}};var M=class{send;attachments;moderation;templates;httpClient;constructor(e){this.validateConfig(e);let s={accessToken:e.accessToken,version:e.version||f,baseUrl:e.baseUrl,timeout:e.timeout,maxRetries:e.maxRetries};this.httpClient=new S(s),this.send=new d(this.httpClient),this.attachments=new _(this.httpClient),this.moderation=new h(this.httpClient),this.templates=new g(this.httpClient);}validateConfig(e){if(!e.accessToken)throw new m("Access token is required");if(typeof e.accessToken!="string"||e.accessToken.trim()==="")throw new m("Access token must be a non-empty string");if(e.version&&typeof e.version!="string")throw new m("API version must be a string");if(e.timeout&&(typeof e.timeout!="number"||e.timeout<=0))throw new m("Timeout must be a positive number");if(e.maxRetries&&(typeof e.maxRetries!="number"||e.maxRetries<0))throw new m("Max retries must be a non-negative number")}};
|
|
2
|
+
exports.ATTACHMENT_LIMITS=U;exports.AttachmentsAPI=_;exports.MESSAGE_LIMITS=E;exports.MessageValidationError=T;exports.Messenger=M;exports.MessengerAPIError=c;exports.MessengerConfigError=m;exports.MessengerNetworkError=l;exports.MessengerTimeoutError=u;exports.ModerationAPI=h;exports.SendAPI=d;exports.TEMPLATE_LIMITS=o;exports.TemplateValidationError=n;exports.TemplatesAPI=g;//# sourceMappingURL=index.cjs.map
|
|
3
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/constants.ts","../src/core/errors.ts","../src/core/http-client.ts","../src/utils/message-validators.ts","../src/resources/send.ts","../src/resources/attachments.ts","../src/resources/moderation.ts","../src/utils/validators.ts","../src/resources/templates.ts","../src/client.ts"],"names":["DEFAULT_API_VERSION","BASE_URL","API_ENDPOINTS","MESSAGE_LIMITS","ATTACHMENT_LIMITS","TEMPLATE_LIMITS","MessengerAPIError","error","statusCode","response","MessengerNetworkError","message","cause","MessengerTimeoutError","timeout","MessengerConfigError","HTTPClient","config","options","url","lastError","attempt","path","query","key","value","controller","timeoutId","fetchOptions","isJson","errorData","text","ms","resolve","MessageValidationError","validateTextMessage","SendAPI","httpClient","request","recipientId","action","AttachmentsAPI","body","ModerationAPI","userIds","user_ids","id","TemplateValidationError","validateGenericTemplate","elements","element","index","validateGenericElement","isHttpsUrl","validateButtons","validateButtonTemplate","buttons","validateMediaTemplate","context","button","validateButton","TemplatesAPI","payload","Messenger","clientConfig"],"mappings":"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","file":"index.cjs","sourcesContent":["export const DEFAULT_API_VERSION = 'v23.0';\nexport const BASE_URL = 'https://graph.facebook.com';\nexport const DEFAULT_TIMEOUT = 30000; // 30 seconds\nexport const MAX_RETRY_ATTEMPTS = 3;\nexport const RETRY_DELAY_MS = 1000;\n\nexport const API_ENDPOINTS = {\n MESSAGES: '/me/messages',\n MESSAGE_ATTACHMENTS: '/me/message_attachments',\n MODERATE_CONVERSATIONS: '/me/moderate_conversations',\n PASS_THREAD_CONTROL: '/me/pass_thread_control',\n TAKE_THREAD_CONTROL: '/me/take_thread_control',\n REQUEST_THREAD_CONTROL: '/me/request_thread_control',\n} as const;\n\n// Validation constants\nexport const MESSAGE_LIMITS = {\n // Text messages\n TEXT_MESSAGE_MAX_CHARS: 2000,\n} as const;\n\nexport const ATTACHMENT_LIMITS = {\n // File size limits in bytes\n IMAGE_MAX_SIZE: 8 * 1024 * 1024, // 8MB\n OTHER_MAX_SIZE: 25 * 1024 * 1024, // 25MB (video, audio, file)\n \n // Timeout limits in seconds\n VIDEO_TIMEOUT: 75,\n OTHER_TIMEOUT: 10,\n} as const;\n\nexport const TEMPLATE_LIMITS = {\n // Generic Template\n GENERIC_ELEMENTS_MAX: 10,\n GENERIC_TITLE_MAX_CHARS: 80,\n GENERIC_SUBTITLE_MAX_CHARS: 80,\n \n // Button Template \n BUTTON_TEXT_MAX_CHARS: 640,\n BUTTONS_MAX_COUNT: 3,\n BUTTON_TITLE_MAX_CHARS: 20,\n \n // All Templates\n POSTBACK_PAYLOAD_MAX_CHARS: 1000,\n \n // Media Template\n MEDIA_ELEMENTS_COUNT: 1, // Exactly 1 element required\n MEDIA_BUTTONS_MAX_COUNT: 3,\n} as const;","import type { MessengerError } from '../types/responses.js';\n\nexport class MessengerAPIError extends Error {\n public readonly code: number;\n public readonly type: string;\n public readonly subcode?: number;\n public readonly fbtrace_id?: string;\n public readonly statusCode: number;\n public readonly response?: any;\n\n constructor(error: MessengerError, statusCode: number, response?: any) {\n super(error.message);\n this.name = 'MessengerAPIError';\n this.code = error.code;\n this.type = error.type;\n this.subcode = error.error_subcode;\n this.fbtrace_id = error.fbtrace_id;\n this.statusCode = statusCode;\n this.response = response;\n }\n}\n\nexport class MessengerNetworkError extends Error {\n public readonly cause?: Error;\n\n constructor(message: string, cause?: Error) {\n super(message);\n this.name = 'MessengerNetworkError';\n this.cause = cause;\n }\n}\n\nexport class MessengerTimeoutError extends Error {\n public readonly timeout: number;\n\n constructor(timeout: number) {\n super(`Request timed out after ${timeout}ms`);\n this.name = 'MessengerTimeoutError';\n this.timeout = timeout;\n }\n}\n\nexport class MessengerConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'MessengerConfigError';\n }\n}","import { BASE_URL, DEFAULT_TIMEOUT, MAX_RETRY_ATTEMPTS, RETRY_DELAY_MS } from './constants.js';\nimport { MessengerAPIError, MessengerNetworkError, MessengerTimeoutError } from './errors.js';\nimport type { ErrorResponse } from '../types/responses.js';\n\nexport interface ClientConfig {\n accessToken: string;\n version: string;\n baseUrl?: string;\n timeout?: number;\n maxRetries?: number;\n}\n\nexport interface RequestOptions {\n method: 'GET' | 'POST' | 'DELETE';\n path: string;\n body?: any;\n query?: Record<string, string | number | boolean>;\n}\n\nexport class HTTPClient {\n private readonly config: Required<ClientConfig>;\n\n constructor(config: ClientConfig) {\n this.config = {\n accessToken: config.accessToken,\n version: config.version,\n baseUrl: config.baseUrl || BASE_URL,\n timeout: config.timeout || DEFAULT_TIMEOUT,\n maxRetries: config.maxRetries || MAX_RETRY_ATTEMPTS,\n };\n }\n\n async request<T>(options: RequestOptions): Promise<T> {\n const url = this.buildUrl(options.path, options.query);\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {\n try {\n const response = await this.makeRequest(url, options);\n return await this.handleResponse<T>(response);\n } catch (error) {\n lastError = error as Error;\n \n // Don't retry on client errors (4xx)\n if (error instanceof MessengerAPIError && error.statusCode >= 400 && error.statusCode < 500) {\n throw error;\n }\n\n // Don't retry on timeout for the last attempt\n if (attempt === this.config.maxRetries) {\n throw error;\n }\n\n // Wait before retrying\n await this.delay(RETRY_DELAY_MS * (attempt + 1));\n }\n }\n\n throw lastError || new Error('Unknown error occurred');\n }\n\n private buildUrl(path: string, query?: Record<string, string | number | boolean>): string {\n const url = new URL(`${this.config.baseUrl}/${this.config.version}${path}`);\n \n // Always add access token\n url.searchParams.append('access_token', this.config.accessToken);\n \n // Add additional query parameters\n if (query) {\n Object.entries(query).forEach(([key, value]) => {\n url.searchParams.append(key, String(value));\n });\n }\n\n return url.toString();\n }\n\n private async makeRequest(url: string, options: RequestOptions): Promise<Response> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);\n\n try {\n const fetchOptions: RequestInit = {\n method: options.method,\n headers: {\n 'Content-Type': 'application/json',\n },\n signal: controller.signal,\n };\n\n if (options.body) {\n fetchOptions.body = JSON.stringify(options.body);\n }\n\n const response = await fetch(url, fetchOptions);\n return response;\n } catch (error) {\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n throw new MessengerTimeoutError(this.config.timeout);\n }\n throw new MessengerNetworkError(`Network request failed: ${error.message}`, error);\n }\n throw error;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n private async handleResponse<T>(response: Response): Promise<T> {\n const contentType = response.headers.get('content-type');\n const isJson = contentType?.includes('application/json');\n\n if (!response.ok) {\n if (isJson) {\n const errorData = await response.json() as ErrorResponse;\n throw new MessengerAPIError(errorData.error, response.status, errorData);\n } else {\n const text = await response.text();\n throw new MessengerAPIError(\n {\n message: text || `HTTP ${response.status} ${response.statusText}`,\n type: 'http_error',\n code: response.status,\n fbtrace_id: '',\n },\n response.status,\n text\n );\n }\n }\n\n if (isJson) {\n return await response.json() as T;\n }\n\n // For non-JSON responses, return the text\n return await response.text() as unknown as T;\n }\n\n private delay(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n}","import { MESSAGE_LIMITS } from '../core/constants.js';\n\nexport class MessageValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'MessageValidationError';\n }\n}\n\nexport function validateTextMessage(text: string): void {\n if (!text || text.trim() === '') {\n throw new MessageValidationError('Text message cannot be empty');\n }\n\n if (text.length > MESSAGE_LIMITS.TEXT_MESSAGE_MAX_CHARS) {\n throw new MessageValidationError(\n `Text message cannot exceed ${MESSAGE_LIMITS.TEXT_MESSAGE_MAX_CHARS} characters`\n );\n }\n}","import type { HTTPClient } from '../core/http-client.js';\nimport { API_ENDPOINTS } from '../core/constants.js';\nimport type { SendMessageRequest, SenderAction, Recipient } from '../types/messages.js';\nimport type { SendMessageResponse } from '../types/responses.js';\nimport type { AttachmentType } from '../types/attachments.js';\nimport { validateTextMessage } from '../utils/message-validators.js';\n\nexport class SendAPI {\n constructor(private httpClient: HTTPClient) {}\n\n async message(request: SendMessageRequest): Promise<SendMessageResponse> {\n // Validate text message length if present\n if (request.message?.text) {\n validateTextMessage(request.message.text);\n }\n\n return this.httpClient.request<SendMessageResponse>({\n method: 'POST',\n path: API_ENDPOINTS.MESSAGES,\n body: request,\n });\n }\n\n async action(recipientId: string, action: SenderAction): Promise<SendMessageResponse> {\n return this.httpClient.request<SendMessageResponse>({\n method: 'POST',\n path: API_ENDPOINTS.MESSAGES,\n body: {\n recipient: { id: recipientId },\n messaging_type: 'RESPONSE',\n sender_action: action,\n },\n });\n }\n\n async typingOn(recipientId: string): Promise<SendMessageResponse> {\n return this.action(recipientId, 'typing_on');\n }\n\n async typingOff(recipientId: string): Promise<SendMessageResponse> {\n return this.action(recipientId, 'typing_off');\n }\n\n async markSeen(recipientId: string): Promise<SendMessageResponse> {\n return this.action(recipientId, 'mark_seen');\n }\n\n // Convenience methods for sending attachments\n\n /**\n * Send an attachment using a previously uploaded attachment_id\n */\n async attachment(options: {\n recipient: Recipient;\n type: AttachmentType;\n attachment_id: string;\n messaging_type?: 'RESPONSE' | 'UPDATE' | 'MESSAGE_TAG';\n }): Promise<SendMessageResponse> {\n return this.message({\n recipient: options.recipient,\n messaging_type: options.messaging_type ?? 'RESPONSE',\n message: {\n attachment: {\n type: options.type,\n payload: {\n attachment_id: options.attachment_id,\n },\n },\n },\n });\n }\n\n /**\n * Upload and send an attachment from URL in a single request\n */\n async attachmentFromUrl(options: {\n recipient: Recipient;\n type: AttachmentType;\n url: string;\n messaging_type?: 'RESPONSE' | 'UPDATE' | 'MESSAGE_TAG';\n }): Promise<SendMessageResponse> {\n return this.message({\n recipient: options.recipient,\n messaging_type: options.messaging_type ?? 'RESPONSE',\n message: {\n attachment: {\n type: options.type,\n payload: {\n url: options.url,\n },\n },\n },\n });\n }\n}","import type { HTTPClient } from '../core/http-client.js';\nimport { API_ENDPOINTS } from '../core/constants.js';\nimport type { AttachmentUploadRequest, AttachmentUploadResponse } from '../types/attachments.js';\n\nexport class AttachmentsAPI {\n constructor(private httpClient: HTTPClient) {}\n\n async upload(request: AttachmentUploadRequest): Promise<AttachmentUploadResponse> {\n // Format according to official API - no message wrapper needed\n const body = {\n message: {\n attachment: {\n type: request.type,\n payload: {\n url: request.url,\n is_reusable: request.is_reusable ?? true,\n },\n },\n },\n };\n\n return this.httpClient.request<AttachmentUploadResponse>({\n method: 'POST',\n path: API_ENDPOINTS.MESSAGE_ATTACHMENTS,\n body,\n });\n }\n}","import type { HTTPClient } from '../core/http-client.js';\nimport { API_ENDPOINTS } from '../core/constants.js';\nimport type { \n ModerateConversationsRequest,\n ModerateConversationsResponse\n} from '../types/moderation.js';\n\nexport class ModerationAPI {\n constructor(private httpClient: HTTPClient) {}\n\n /**\n * Moderate conversations with specified actions\n * Up to 10 user IDs and up to 2 actions per request\n */\n async moderate(request: ModerateConversationsRequest): Promise<ModerateConversationsResponse> {\n return this.httpClient.request<ModerateConversationsResponse>({\n method: 'POST',\n path: API_ENDPOINTS.MODERATE_CONVERSATIONS,\n body: request,\n });\n }\n\n /**\n * Block a user from messaging the page\n * Prevents messaging but user can still interact with page content on Facebook\n */\n async blockUser(userIds: string | string[]): Promise<ModerateConversationsResponse> {\n const user_ids = Array.isArray(userIds) \n ? userIds.map(id => ({ id }))\n : [{ id: userIds }];\n\n return this.moderate({\n user_ids,\n actions: ['block_user'],\n });\n }\n\n /**\n * Unblock a user to allow messaging again\n */\n async unblockUser(userIds: string | string[]): Promise<ModerateConversationsResponse> {\n const user_ids = Array.isArray(userIds)\n ? userIds.map(id => ({ id }))\n : [{ id: userIds }];\n\n return this.moderate({\n user_ids,\n actions: ['unblock_user'],\n });\n }\n\n /**\n * Ban a user from both messaging and Facebook interactions\n * More restrictive than blocking - prevents all interactions\n * Note: Cannot ban user who was unbanned in last 48 hours\n */\n async banUser(userIds: string | string[]): Promise<ModerateConversationsResponse> {\n const user_ids = Array.isArray(userIds)\n ? userIds.map(id => ({ id }))\n : [{ id: userIds }];\n\n return this.moderate({\n user_ids,\n actions: ['ban_user'],\n });\n }\n\n /**\n * Unban a user to restore all interactions\n * Note: Banned user cannot be unblocked, they must be unbanned first\n */\n async unbanUser(userIds: string | string[]): Promise<ModerateConversationsResponse> {\n const user_ids = Array.isArray(userIds)\n ? userIds.map(id => ({ id }))\n : [{ id: userIds }];\n\n return this.moderate({\n user_ids,\n actions: ['unban_user'],\n });\n }\n\n /**\n * Move conversation to spam folder in Meta Business Suite Inbox\n */\n async moveToSpam(userIds: string | string[]): Promise<ModerateConversationsResponse> {\n const user_ids = Array.isArray(userIds)\n ? userIds.map(id => ({ id }))\n : [{ id: userIds }];\n\n return this.moderate({\n user_ids,\n actions: ['move_to_spam'],\n });\n }\n\n /**\n * Block user and move to spam (common moderation action)\n */\n async blockAndSpam(userIds: string | string[]): Promise<ModerateConversationsResponse> {\n const user_ids = Array.isArray(userIds)\n ? userIds.map(id => ({ id }))\n : [{ id: userIds }];\n\n return this.moderate({\n user_ids,\n actions: ['block_user', 'move_to_spam'],\n });\n }\n}","import { TEMPLATE_LIMITS } from '../core/constants.js';\nimport type { Button, GenericTemplateElement, MediaTemplateElement } from '../types/templates.js';\n\nexport class TemplateValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'TemplateValidationError';\n }\n}\n\nexport function validateGenericTemplate(elements: GenericTemplateElement[]): void {\n if (elements.length === 0) {\n throw new TemplateValidationError('Generic template must have at least 1 element');\n }\n\n if (elements.length > TEMPLATE_LIMITS.GENERIC_ELEMENTS_MAX) {\n throw new TemplateValidationError(\n `Generic template cannot have more than ${TEMPLATE_LIMITS.GENERIC_ELEMENTS_MAX} elements`\n );\n }\n\n elements.forEach((element, index) => {\n validateGenericElement(element, index);\n });\n}\n\nexport function validateGenericElement(element: GenericTemplateElement, index: number): void {\n if (!element.title || element.title.trim() === '') {\n throw new TemplateValidationError(`Element ${index}: title is required`);\n }\n\n if (element.title.length > TEMPLATE_LIMITS.GENERIC_TITLE_MAX_CHARS) {\n throw new TemplateValidationError(\n `Element ${index}: title cannot exceed ${TEMPLATE_LIMITS.GENERIC_TITLE_MAX_CHARS} characters`\n );\n }\n\n if (element.subtitle && element.subtitle.length > TEMPLATE_LIMITS.GENERIC_SUBTITLE_MAX_CHARS) {\n throw new TemplateValidationError(\n `Element ${index}: subtitle cannot exceed ${TEMPLATE_LIMITS.GENERIC_SUBTITLE_MAX_CHARS} characters`\n );\n }\n\n if (element.image_url && !isHttpsUrl(element.image_url)) {\n throw new TemplateValidationError(`Element ${index}: image_url must be HTTPS`);\n }\n\n if (element.buttons) {\n validateButtons(element.buttons, `Element ${index}`);\n }\n\n // Validate that element has at least one property beyond title\n const hasAdditionalProperty = !!(\n element.subtitle ||\n element.image_url ||\n element.default_action ||\n (element.buttons && element.buttons.length > 0)\n );\n\n if (!hasAdditionalProperty) {\n throw new TemplateValidationError(\n `Element ${index}: must have at least one additional property beyond title`\n );\n }\n}\n\nexport function validateButtonTemplate(text: string, buttons: Button[]): void {\n if (!text || text.trim() === '') {\n throw new TemplateValidationError('Button template text is required');\n }\n\n if (text.length > TEMPLATE_LIMITS.BUTTON_TEXT_MAX_CHARS) {\n throw new TemplateValidationError(\n `Button template text cannot exceed ${TEMPLATE_LIMITS.BUTTON_TEXT_MAX_CHARS} characters`\n );\n }\n\n if (buttons.length === 0) {\n throw new TemplateValidationError('Button template must have at least 1 button');\n }\n\n validateButtons(buttons, 'Button template');\n}\n\nexport function validateMediaTemplate(element: MediaTemplateElement): void {\n if (!element.media_type) {\n throw new TemplateValidationError('Media template element must have media_type');\n }\n\n if (!element.url && !element.attachment_id) {\n throw new TemplateValidationError('Media template element must have either url or attachment_id');\n }\n\n if (element.url && element.attachment_id) {\n throw new TemplateValidationError(\n 'Media template element cannot have both url and attachment_id'\n );\n }\n\n if (element.url && !isHttpsUrl(element.url)) {\n throw new TemplateValidationError('Media template url must be HTTPS');\n }\n\n if (element.buttons) {\n if (element.buttons.length > TEMPLATE_LIMITS.MEDIA_BUTTONS_MAX_COUNT) {\n throw new TemplateValidationError(\n `Media template cannot have more than ${TEMPLATE_LIMITS.MEDIA_BUTTONS_MAX_COUNT} buttons`\n );\n }\n validateButtons(element.buttons, 'Media template');\n }\n}\n\nexport function validateButtons(buttons: Button[], context: string): void {\n if (buttons.length > TEMPLATE_LIMITS.BUTTONS_MAX_COUNT) {\n throw new TemplateValidationError(\n `${context} cannot have more than ${TEMPLATE_LIMITS.BUTTONS_MAX_COUNT} buttons`\n );\n }\n\n buttons.forEach((button, index) => {\n validateButton(button, `${context} button ${index}`);\n });\n}\n\nexport function validateButton(button: Button, context: string): void {\n if (!button.type) {\n throw new TemplateValidationError(`${context}: type is required`);\n }\n\n // Title is required for most button types (not for account_unlink)\n if (button.type !== 'account_unlink' && (!button.title || button.title.trim() === '')) {\n throw new TemplateValidationError(`${context}: title is required for ${button.type} buttons`);\n }\n\n if (button.title && button.title.length > TEMPLATE_LIMITS.BUTTON_TITLE_MAX_CHARS) {\n throw new TemplateValidationError(\n `${context}: title cannot exceed ${TEMPLATE_LIMITS.BUTTON_TITLE_MAX_CHARS} characters`\n );\n }\n\n // Type-specific validations\n switch (button.type) {\n case 'web_url':\n if (!button.url) {\n throw new TemplateValidationError(`${context}: url is required for web_url buttons`);\n }\n if (!isHttpsUrl(button.url)) {\n throw new TemplateValidationError(`${context}: url must be HTTPS for web_url buttons`);\n }\n break;\n\n case 'postback':\n if (!button.payload) {\n throw new TemplateValidationError(`${context}: payload is required for postback buttons`);\n }\n if (button.payload.length > TEMPLATE_LIMITS.POSTBACK_PAYLOAD_MAX_CHARS) {\n throw new TemplateValidationError(\n `${context}: payload cannot exceed ${TEMPLATE_LIMITS.POSTBACK_PAYLOAD_MAX_CHARS} characters`\n );\n }\n break;\n\n case 'phone_number':\n if (!button.payload) {\n throw new TemplateValidationError(`${context}: payload is required for phone_number buttons`);\n }\n // Basic phone number validation (starts with +)\n if (!button.payload.startsWith('+')) {\n throw new TemplateValidationError(\n `${context}: phone_number payload must start with + (e.g., +1234567890)`\n );\n }\n break;\n\n case 'game_play':\n // game_play buttons may have optional game_metadata\n break;\n\n case 'account_link':\n if (!button.url) {\n throw new TemplateValidationError(`${context}: url is required for account_link buttons`);\n }\n if (!isHttpsUrl(button.url)) {\n throw new TemplateValidationError(`${context}: url must be HTTPS for account_link buttons`);\n }\n break;\n\n case 'account_unlink':\n // account_unlink buttons don't require additional properties\n break;\n }\n\n // Validate webview properties for web_url buttons\n if (button.type === 'web_url' && button.messenger_extensions && button.fallback_url) {\n if (!isHttpsUrl(button.fallback_url)) {\n throw new TemplateValidationError(`${context}: fallback_url must be HTTPS`);\n }\n }\n}\n\nfunction isHttpsUrl(url: string): boolean {\n try {\n const parsedUrl = new URL(url);\n return parsedUrl.protocol === 'https:';\n } catch {\n return false;\n }\n}","import type { HTTPClient } from '../core/http-client.js';\nimport { API_ENDPOINTS } from '../core/constants.js';\nimport type { Recipient, SendMessageRequest, MessagingType } from '../types/messages.js';\nimport type { SendMessageResponse } from '../types/responses.js';\nimport { validateGenericTemplate, validateButtonTemplate, validateMediaTemplate } from '../utils/validators.js';\nimport type {\n GenericTemplatePayload,\n ButtonTemplatePayload,\n MediaTemplatePayload,\n ProductTemplatePayload,\n GenericTemplateElement,\n Button,\n MediaTemplateElement,\n ProductTemplateElement,\n} from '../types/templates.js';\n\nexport class TemplatesAPI {\n constructor(private httpClient: HTTPClient) {}\n\n async generic(options: {\n recipient: Recipient;\n elements: GenericTemplateElement[];\n messaging_type?: MessagingType;\n image_aspect_ratio?: 'horizontal' | 'square';\n notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';\n tag?: string;\n }): Promise<SendMessageResponse> {\n // Validate template\n validateGenericTemplate(options.elements);\n\n const payload: GenericTemplatePayload = {\n template_type: 'generic',\n elements: options.elements,\n image_aspect_ratio: options.image_aspect_ratio,\n };\n\n const request: SendMessageRequest = {\n recipient: options.recipient,\n messaging_type: options.messaging_type || 'UPDATE',\n message: {\n attachment: {\n type: 'template',\n payload,\n },\n },\n notification_type: options.notification_type,\n tag: options.tag,\n };\n\n return this.httpClient.request<SendMessageResponse>({\n method: 'POST',\n path: API_ENDPOINTS.MESSAGES,\n body: request,\n });\n }\n\n async button(options: {\n recipient: Recipient;\n text: string;\n buttons: Button[];\n messaging_type?: MessagingType;\n notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';\n tag?: string;\n }): Promise<SendMessageResponse> {\n // Validate template\n validateButtonTemplate(options.text, options.buttons);\n\n const payload: ButtonTemplatePayload = {\n template_type: 'button',\n text: options.text,\n buttons: options.buttons,\n };\n\n const request: SendMessageRequest = {\n recipient: options.recipient,\n messaging_type: options.messaging_type || 'UPDATE',\n message: {\n attachment: {\n type: 'template',\n payload,\n },\n },\n notification_type: options.notification_type,\n tag: options.tag,\n };\n\n return this.httpClient.request<SendMessageResponse>({\n method: 'POST',\n path: API_ENDPOINTS.MESSAGES,\n body: request,\n });\n }\n\n async media(options: {\n recipient: Recipient;\n element: MediaTemplateElement;\n messaging_type?: MessagingType;\n notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';\n tag?: string;\n }): Promise<SendMessageResponse> {\n // Validate template\n validateMediaTemplate(options.element);\n\n const payload: MediaTemplatePayload = {\n template_type: 'media',\n elements: [options.element],\n };\n\n const request: SendMessageRequest = {\n recipient: options.recipient,\n messaging_type: options.messaging_type || 'UPDATE',\n message: {\n attachment: {\n type: 'template',\n payload,\n },\n },\n notification_type: options.notification_type,\n tag: options.tag,\n };\n\n return this.httpClient.request<SendMessageResponse>({\n method: 'POST',\n path: API_ENDPOINTS.MESSAGES,\n body: request,\n });\n }\n\n async product(options: {\n recipient: Recipient;\n elements: ProductTemplateElement[];\n messaging_type?: MessagingType;\n notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';\n tag?: string;\n }): Promise<SendMessageResponse> {\n const payload: ProductTemplatePayload = {\n template_type: 'product',\n elements: options.elements,\n };\n\n const request: SendMessageRequest = {\n recipient: options.recipient,\n messaging_type: options.messaging_type || 'UPDATE',\n message: {\n attachment: {\n type: 'template',\n payload,\n },\n },\n notification_type: options.notification_type,\n tag: options.tag,\n };\n\n return this.httpClient.request<SendMessageResponse>({\n method: 'POST',\n path: API_ENDPOINTS.MESSAGES,\n body: request,\n });\n }\n}","import { HTTPClient, type ClientConfig } from './core/http-client.js';\nimport { DEFAULT_API_VERSION } from './core/constants.js';\nimport { MessengerConfigError } from './core/errors.js';\nimport { SendAPI } from './resources/send.js';\nimport { AttachmentsAPI } from './resources/attachments.js';\nimport { ModerationAPI } from './resources/moderation.js';\nimport { TemplatesAPI } from './resources/templates.js';\n\nexport interface MessengerConfig {\n accessToken: string;\n version?: string;\n baseUrl?: string;\n timeout?: number;\n maxRetries?: number;\n}\n\nexport class Messenger {\n public readonly send: SendAPI;\n public readonly attachments: AttachmentsAPI;\n public readonly moderation: ModerationAPI;\n public readonly templates: TemplatesAPI;\n\n private readonly httpClient: HTTPClient;\n\n constructor(config: MessengerConfig) {\n this.validateConfig(config);\n\n const clientConfig: ClientConfig = {\n accessToken: config.accessToken,\n version: config.version || DEFAULT_API_VERSION,\n baseUrl: config.baseUrl,\n timeout: config.timeout,\n maxRetries: config.maxRetries,\n };\n\n this.httpClient = new HTTPClient(clientConfig);\n\n // Initialize API resources\n this.send = new SendAPI(this.httpClient);\n this.attachments = new AttachmentsAPI(this.httpClient);\n this.moderation = new ModerationAPI(this.httpClient);\n this.templates = new TemplatesAPI(this.httpClient);\n }\n\n private validateConfig(config: MessengerConfig): void {\n if (!config.accessToken) {\n throw new MessengerConfigError('Access token is required');\n }\n\n if (typeof config.accessToken !== 'string' || config.accessToken.trim() === '') {\n throw new MessengerConfigError('Access token must be a non-empty string');\n }\n\n if (config.version && typeof config.version !== 'string') {\n throw new MessengerConfigError('API version must be a string');\n }\n\n if (config.timeout && (typeof config.timeout !== 'number' || config.timeout <= 0)) {\n throw new MessengerConfigError('Timeout must be a positive number');\n }\n\n if (config.maxRetries && (typeof config.maxRetries !== 'number' || config.maxRetries < 0)) {\n throw new MessengerConfigError('Max retries must be a non-negative number');\n }\n }\n}"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
interface ClientConfig {
|
|
2
|
+
accessToken: string;
|
|
3
|
+
version: string;
|
|
4
|
+
baseUrl?: string;
|
|
5
|
+
timeout?: number;
|
|
6
|
+
maxRetries?: number;
|
|
7
|
+
}
|
|
8
|
+
interface RequestOptions {
|
|
9
|
+
method: 'GET' | 'POST' | 'DELETE';
|
|
10
|
+
path: string;
|
|
11
|
+
body?: any;
|
|
12
|
+
query?: Record<string, string | number | boolean>;
|
|
13
|
+
}
|
|
14
|
+
declare class HTTPClient {
|
|
15
|
+
private readonly config;
|
|
16
|
+
constructor(config: ClientConfig);
|
|
17
|
+
request<T>(options: RequestOptions): Promise<T>;
|
|
18
|
+
private buildUrl;
|
|
19
|
+
private makeRequest;
|
|
20
|
+
private handleResponse;
|
|
21
|
+
private delay;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface Recipient {
|
|
25
|
+
id?: string;
|
|
26
|
+
phone_number?: string;
|
|
27
|
+
user_ref?: string;
|
|
28
|
+
name?: {
|
|
29
|
+
first_name: string;
|
|
30
|
+
last_name: string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
interface QuickReply {
|
|
34
|
+
content_type: 'text' | 'user_phone_number' | 'user_email';
|
|
35
|
+
title?: string;
|
|
36
|
+
payload?: string;
|
|
37
|
+
image_url?: string;
|
|
38
|
+
}
|
|
39
|
+
interface Message {
|
|
40
|
+
text?: string;
|
|
41
|
+
attachment?: Attachment;
|
|
42
|
+
quick_replies?: QuickReply[];
|
|
43
|
+
metadata?: string;
|
|
44
|
+
}
|
|
45
|
+
interface Attachment {
|
|
46
|
+
type: 'image' | 'audio' | 'video' | 'file' | 'template';
|
|
47
|
+
payload: AttachmentPayload | TemplatePayload;
|
|
48
|
+
}
|
|
49
|
+
interface AttachmentPayload {
|
|
50
|
+
url?: string;
|
|
51
|
+
attachment_id?: string;
|
|
52
|
+
is_reusable?: boolean;
|
|
53
|
+
}
|
|
54
|
+
interface TemplatePayload {
|
|
55
|
+
template_type: 'generic' | 'button' | 'media' | 'product';
|
|
56
|
+
elements?: any[];
|
|
57
|
+
buttons?: any[];
|
|
58
|
+
[key: string]: any;
|
|
59
|
+
}
|
|
60
|
+
type SenderAction = 'mark_seen' | 'typing_on' | 'typing_off';
|
|
61
|
+
type MessagingType = 'RESPONSE' | 'UPDATE' | 'MESSAGE_TAG';
|
|
62
|
+
interface SendMessageRequest {
|
|
63
|
+
recipient: Recipient;
|
|
64
|
+
messaging_type: MessagingType;
|
|
65
|
+
message?: Message;
|
|
66
|
+
sender_action?: SenderAction;
|
|
67
|
+
notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';
|
|
68
|
+
tag?: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
interface SendMessageResponse {
|
|
72
|
+
recipient_id?: string;
|
|
73
|
+
message_id: string;
|
|
74
|
+
attachment_id?: string;
|
|
75
|
+
}
|
|
76
|
+
interface MessengerError {
|
|
77
|
+
message: string;
|
|
78
|
+
type: string;
|
|
79
|
+
code: number;
|
|
80
|
+
error_subcode?: number;
|
|
81
|
+
fbtrace_id: string;
|
|
82
|
+
}
|
|
83
|
+
interface ErrorResponse {
|
|
84
|
+
error: MessengerError;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
type AttachmentType = 'image' | 'audio' | 'video' | 'file';
|
|
88
|
+
interface AttachmentUploadRequest {
|
|
89
|
+
type: AttachmentType;
|
|
90
|
+
url: string;
|
|
91
|
+
is_reusable?: boolean;
|
|
92
|
+
}
|
|
93
|
+
interface AttachmentUploadResponse {
|
|
94
|
+
attachment_id: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
declare class SendAPI {
|
|
98
|
+
private httpClient;
|
|
99
|
+
constructor(httpClient: HTTPClient);
|
|
100
|
+
message(request: SendMessageRequest): Promise<SendMessageResponse>;
|
|
101
|
+
action(recipientId: string, action: SenderAction): Promise<SendMessageResponse>;
|
|
102
|
+
typingOn(recipientId: string): Promise<SendMessageResponse>;
|
|
103
|
+
typingOff(recipientId: string): Promise<SendMessageResponse>;
|
|
104
|
+
markSeen(recipientId: string): Promise<SendMessageResponse>;
|
|
105
|
+
/**
|
|
106
|
+
* Send an attachment using a previously uploaded attachment_id
|
|
107
|
+
*/
|
|
108
|
+
attachment(options: {
|
|
109
|
+
recipient: Recipient;
|
|
110
|
+
type: AttachmentType;
|
|
111
|
+
attachment_id: string;
|
|
112
|
+
messaging_type?: 'RESPONSE' | 'UPDATE' | 'MESSAGE_TAG';
|
|
113
|
+
}): Promise<SendMessageResponse>;
|
|
114
|
+
/**
|
|
115
|
+
* Upload and send an attachment from URL in a single request
|
|
116
|
+
*/
|
|
117
|
+
attachmentFromUrl(options: {
|
|
118
|
+
recipient: Recipient;
|
|
119
|
+
type: AttachmentType;
|
|
120
|
+
url: string;
|
|
121
|
+
messaging_type?: 'RESPONSE' | 'UPDATE' | 'MESSAGE_TAG';
|
|
122
|
+
}): Promise<SendMessageResponse>;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
declare class AttachmentsAPI {
|
|
126
|
+
private httpClient;
|
|
127
|
+
constructor(httpClient: HTTPClient);
|
|
128
|
+
upload(request: AttachmentUploadRequest): Promise<AttachmentUploadResponse>;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
interface UserId {
|
|
132
|
+
id: string;
|
|
133
|
+
}
|
|
134
|
+
type ModerationAction = 'block_user' | 'unblock_user' | 'ban_user' | 'unban_user' | 'move_to_spam';
|
|
135
|
+
interface ModerateConversationsRequest {
|
|
136
|
+
user_ids: UserId[];
|
|
137
|
+
actions: ModerationAction[];
|
|
138
|
+
}
|
|
139
|
+
interface ModerateConversationsResponse {
|
|
140
|
+
result: 'success' | 'failure';
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
declare class ModerationAPI {
|
|
144
|
+
private httpClient;
|
|
145
|
+
constructor(httpClient: HTTPClient);
|
|
146
|
+
/**
|
|
147
|
+
* Moderate conversations with specified actions
|
|
148
|
+
* Up to 10 user IDs and up to 2 actions per request
|
|
149
|
+
*/
|
|
150
|
+
moderate(request: ModerateConversationsRequest): Promise<ModerateConversationsResponse>;
|
|
151
|
+
/**
|
|
152
|
+
* Block a user from messaging the page
|
|
153
|
+
* Prevents messaging but user can still interact with page content on Facebook
|
|
154
|
+
*/
|
|
155
|
+
blockUser(userIds: string | string[]): Promise<ModerateConversationsResponse>;
|
|
156
|
+
/**
|
|
157
|
+
* Unblock a user to allow messaging again
|
|
158
|
+
*/
|
|
159
|
+
unblockUser(userIds: string | string[]): Promise<ModerateConversationsResponse>;
|
|
160
|
+
/**
|
|
161
|
+
* Ban a user from both messaging and Facebook interactions
|
|
162
|
+
* More restrictive than blocking - prevents all interactions
|
|
163
|
+
* Note: Cannot ban user who was unbanned in last 48 hours
|
|
164
|
+
*/
|
|
165
|
+
banUser(userIds: string | string[]): Promise<ModerateConversationsResponse>;
|
|
166
|
+
/**
|
|
167
|
+
* Unban a user to restore all interactions
|
|
168
|
+
* Note: Banned user cannot be unblocked, they must be unbanned first
|
|
169
|
+
*/
|
|
170
|
+
unbanUser(userIds: string | string[]): Promise<ModerateConversationsResponse>;
|
|
171
|
+
/**
|
|
172
|
+
* Move conversation to spam folder in Meta Business Suite Inbox
|
|
173
|
+
*/
|
|
174
|
+
moveToSpam(userIds: string | string[]): Promise<ModerateConversationsResponse>;
|
|
175
|
+
/**
|
|
176
|
+
* Block user and move to spam (common moderation action)
|
|
177
|
+
*/
|
|
178
|
+
blockAndSpam(userIds: string | string[]): Promise<ModerateConversationsResponse>;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
interface Button {
|
|
182
|
+
type: 'web_url' | 'postback' | 'phone_number' | 'game_play' | 'account_link' | 'account_unlink';
|
|
183
|
+
title?: string;
|
|
184
|
+
url?: string;
|
|
185
|
+
payload?: string;
|
|
186
|
+
webview_height_ratio?: 'compact' | 'tall' | 'full';
|
|
187
|
+
messenger_extensions?: boolean;
|
|
188
|
+
fallback_url?: string;
|
|
189
|
+
webview_share_button?: 'hide' | 'show';
|
|
190
|
+
game_metadata?: {
|
|
191
|
+
player_id?: string;
|
|
192
|
+
context_id?: string;
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
interface DefaultAction {
|
|
196
|
+
type: 'web_url';
|
|
197
|
+
url: string;
|
|
198
|
+
webview_height_ratio?: 'compact' | 'tall' | 'full';
|
|
199
|
+
messenger_extensions?: boolean;
|
|
200
|
+
fallback_url?: string;
|
|
201
|
+
webview_share_button?: 'hide' | 'show';
|
|
202
|
+
}
|
|
203
|
+
interface GenericTemplateElement {
|
|
204
|
+
title: string;
|
|
205
|
+
subtitle?: string;
|
|
206
|
+
image_url?: string;
|
|
207
|
+
default_action?: DefaultAction;
|
|
208
|
+
buttons?: Button[];
|
|
209
|
+
}
|
|
210
|
+
interface GenericTemplatePayload {
|
|
211
|
+
template_type: 'generic';
|
|
212
|
+
elements: GenericTemplateElement[];
|
|
213
|
+
image_aspect_ratio?: 'horizontal' | 'square';
|
|
214
|
+
}
|
|
215
|
+
interface ButtonTemplatePayload {
|
|
216
|
+
template_type: 'button';
|
|
217
|
+
text: string;
|
|
218
|
+
buttons: Button[];
|
|
219
|
+
}
|
|
220
|
+
interface MediaTemplateElement {
|
|
221
|
+
media_type: 'image' | 'video';
|
|
222
|
+
url?: string;
|
|
223
|
+
attachment_id?: string;
|
|
224
|
+
buttons?: Button[];
|
|
225
|
+
sharable?: boolean;
|
|
226
|
+
}
|
|
227
|
+
interface MediaTemplatePayload {
|
|
228
|
+
template_type: 'media';
|
|
229
|
+
elements: [MediaTemplateElement];
|
|
230
|
+
}
|
|
231
|
+
interface ProductTemplateElement {
|
|
232
|
+
id: string;
|
|
233
|
+
}
|
|
234
|
+
interface ProductTemplatePayload {
|
|
235
|
+
template_type: 'product';
|
|
236
|
+
elements: ProductTemplateElement[];
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
declare class TemplatesAPI {
|
|
240
|
+
private httpClient;
|
|
241
|
+
constructor(httpClient: HTTPClient);
|
|
242
|
+
generic(options: {
|
|
243
|
+
recipient: Recipient;
|
|
244
|
+
elements: GenericTemplateElement[];
|
|
245
|
+
messaging_type?: MessagingType;
|
|
246
|
+
image_aspect_ratio?: 'horizontal' | 'square';
|
|
247
|
+
notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';
|
|
248
|
+
tag?: string;
|
|
249
|
+
}): Promise<SendMessageResponse>;
|
|
250
|
+
button(options: {
|
|
251
|
+
recipient: Recipient;
|
|
252
|
+
text: string;
|
|
253
|
+
buttons: Button[];
|
|
254
|
+
messaging_type?: MessagingType;
|
|
255
|
+
notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';
|
|
256
|
+
tag?: string;
|
|
257
|
+
}): Promise<SendMessageResponse>;
|
|
258
|
+
media(options: {
|
|
259
|
+
recipient: Recipient;
|
|
260
|
+
element: MediaTemplateElement;
|
|
261
|
+
messaging_type?: MessagingType;
|
|
262
|
+
notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';
|
|
263
|
+
tag?: string;
|
|
264
|
+
}): Promise<SendMessageResponse>;
|
|
265
|
+
product(options: {
|
|
266
|
+
recipient: Recipient;
|
|
267
|
+
elements: ProductTemplateElement[];
|
|
268
|
+
messaging_type?: MessagingType;
|
|
269
|
+
notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';
|
|
270
|
+
tag?: string;
|
|
271
|
+
}): Promise<SendMessageResponse>;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
interface MessengerConfig {
|
|
275
|
+
accessToken: string;
|
|
276
|
+
version?: string;
|
|
277
|
+
baseUrl?: string;
|
|
278
|
+
timeout?: number;
|
|
279
|
+
maxRetries?: number;
|
|
280
|
+
}
|
|
281
|
+
declare class Messenger {
|
|
282
|
+
readonly send: SendAPI;
|
|
283
|
+
readonly attachments: AttachmentsAPI;
|
|
284
|
+
readonly moderation: ModerationAPI;
|
|
285
|
+
readonly templates: TemplatesAPI;
|
|
286
|
+
private readonly httpClient;
|
|
287
|
+
constructor(config: MessengerConfig);
|
|
288
|
+
private validateConfig;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
declare class MessengerAPIError extends Error {
|
|
292
|
+
readonly code: number;
|
|
293
|
+
readonly type: string;
|
|
294
|
+
readonly subcode?: number;
|
|
295
|
+
readonly fbtrace_id?: string;
|
|
296
|
+
readonly statusCode: number;
|
|
297
|
+
readonly response?: any;
|
|
298
|
+
constructor(error: MessengerError, statusCode: number, response?: any);
|
|
299
|
+
}
|
|
300
|
+
declare class MessengerNetworkError extends Error {
|
|
301
|
+
readonly cause?: Error;
|
|
302
|
+
constructor(message: string, cause?: Error);
|
|
303
|
+
}
|
|
304
|
+
declare class MessengerTimeoutError extends Error {
|
|
305
|
+
readonly timeout: number;
|
|
306
|
+
constructor(timeout: number);
|
|
307
|
+
}
|
|
308
|
+
declare class MessengerConfigError extends Error {
|
|
309
|
+
constructor(message: string);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
declare class TemplateValidationError extends Error {
|
|
313
|
+
constructor(message: string);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
declare class MessageValidationError extends Error {
|
|
317
|
+
constructor(message: string);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
declare const MESSAGE_LIMITS: {
|
|
321
|
+
readonly TEXT_MESSAGE_MAX_CHARS: 2000;
|
|
322
|
+
};
|
|
323
|
+
declare const ATTACHMENT_LIMITS: {
|
|
324
|
+
readonly IMAGE_MAX_SIZE: number;
|
|
325
|
+
readonly OTHER_MAX_SIZE: number;
|
|
326
|
+
readonly VIDEO_TIMEOUT: 75;
|
|
327
|
+
readonly OTHER_TIMEOUT: 10;
|
|
328
|
+
};
|
|
329
|
+
declare const TEMPLATE_LIMITS: {
|
|
330
|
+
readonly GENERIC_ELEMENTS_MAX: 10;
|
|
331
|
+
readonly GENERIC_TITLE_MAX_CHARS: 80;
|
|
332
|
+
readonly GENERIC_SUBTITLE_MAX_CHARS: 80;
|
|
333
|
+
readonly BUTTON_TEXT_MAX_CHARS: 640;
|
|
334
|
+
readonly BUTTONS_MAX_COUNT: 3;
|
|
335
|
+
readonly BUTTON_TITLE_MAX_CHARS: 20;
|
|
336
|
+
readonly POSTBACK_PAYLOAD_MAX_CHARS: 1000;
|
|
337
|
+
readonly MEDIA_ELEMENTS_COUNT: 1;
|
|
338
|
+
readonly MEDIA_BUTTONS_MAX_COUNT: 3;
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
export { ATTACHMENT_LIMITS, type AttachmentType, type AttachmentUploadRequest, type AttachmentUploadResponse, AttachmentsAPI, type Button, type ButtonTemplatePayload, type DefaultAction, type ErrorResponse, type GenericTemplateElement, type GenericTemplatePayload, MESSAGE_LIMITS, type MediaTemplateElement, type MediaTemplatePayload, type Message, MessageValidationError, type MessagingType, Messenger, MessengerAPIError, type MessengerConfig, MessengerConfigError, type MessengerError, MessengerNetworkError, MessengerTimeoutError, type ModerateConversationsRequest, type ModerateConversationsResponse, ModerationAPI, type ModerationAction, type ProductTemplateElement, type ProductTemplatePayload, type QuickReply, type Recipient, SendAPI, type SendMessageRequest, type SendMessageResponse, type SenderAction, TEMPLATE_LIMITS, TemplateValidationError, TemplatesAPI, type UserId };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
interface ClientConfig {
|
|
2
|
+
accessToken: string;
|
|
3
|
+
version: string;
|
|
4
|
+
baseUrl?: string;
|
|
5
|
+
timeout?: number;
|
|
6
|
+
maxRetries?: number;
|
|
7
|
+
}
|
|
8
|
+
interface RequestOptions {
|
|
9
|
+
method: 'GET' | 'POST' | 'DELETE';
|
|
10
|
+
path: string;
|
|
11
|
+
body?: any;
|
|
12
|
+
query?: Record<string, string | number | boolean>;
|
|
13
|
+
}
|
|
14
|
+
declare class HTTPClient {
|
|
15
|
+
private readonly config;
|
|
16
|
+
constructor(config: ClientConfig);
|
|
17
|
+
request<T>(options: RequestOptions): Promise<T>;
|
|
18
|
+
private buildUrl;
|
|
19
|
+
private makeRequest;
|
|
20
|
+
private handleResponse;
|
|
21
|
+
private delay;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface Recipient {
|
|
25
|
+
id?: string;
|
|
26
|
+
phone_number?: string;
|
|
27
|
+
user_ref?: string;
|
|
28
|
+
name?: {
|
|
29
|
+
first_name: string;
|
|
30
|
+
last_name: string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
interface QuickReply {
|
|
34
|
+
content_type: 'text' | 'user_phone_number' | 'user_email';
|
|
35
|
+
title?: string;
|
|
36
|
+
payload?: string;
|
|
37
|
+
image_url?: string;
|
|
38
|
+
}
|
|
39
|
+
interface Message {
|
|
40
|
+
text?: string;
|
|
41
|
+
attachment?: Attachment;
|
|
42
|
+
quick_replies?: QuickReply[];
|
|
43
|
+
metadata?: string;
|
|
44
|
+
}
|
|
45
|
+
interface Attachment {
|
|
46
|
+
type: 'image' | 'audio' | 'video' | 'file' | 'template';
|
|
47
|
+
payload: AttachmentPayload | TemplatePayload;
|
|
48
|
+
}
|
|
49
|
+
interface AttachmentPayload {
|
|
50
|
+
url?: string;
|
|
51
|
+
attachment_id?: string;
|
|
52
|
+
is_reusable?: boolean;
|
|
53
|
+
}
|
|
54
|
+
interface TemplatePayload {
|
|
55
|
+
template_type: 'generic' | 'button' | 'media' | 'product';
|
|
56
|
+
elements?: any[];
|
|
57
|
+
buttons?: any[];
|
|
58
|
+
[key: string]: any;
|
|
59
|
+
}
|
|
60
|
+
type SenderAction = 'mark_seen' | 'typing_on' | 'typing_off';
|
|
61
|
+
type MessagingType = 'RESPONSE' | 'UPDATE' | 'MESSAGE_TAG';
|
|
62
|
+
interface SendMessageRequest {
|
|
63
|
+
recipient: Recipient;
|
|
64
|
+
messaging_type: MessagingType;
|
|
65
|
+
message?: Message;
|
|
66
|
+
sender_action?: SenderAction;
|
|
67
|
+
notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';
|
|
68
|
+
tag?: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
interface SendMessageResponse {
|
|
72
|
+
recipient_id?: string;
|
|
73
|
+
message_id: string;
|
|
74
|
+
attachment_id?: string;
|
|
75
|
+
}
|
|
76
|
+
interface MessengerError {
|
|
77
|
+
message: string;
|
|
78
|
+
type: string;
|
|
79
|
+
code: number;
|
|
80
|
+
error_subcode?: number;
|
|
81
|
+
fbtrace_id: string;
|
|
82
|
+
}
|
|
83
|
+
interface ErrorResponse {
|
|
84
|
+
error: MessengerError;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
type AttachmentType = 'image' | 'audio' | 'video' | 'file';
|
|
88
|
+
interface AttachmentUploadRequest {
|
|
89
|
+
type: AttachmentType;
|
|
90
|
+
url: string;
|
|
91
|
+
is_reusable?: boolean;
|
|
92
|
+
}
|
|
93
|
+
interface AttachmentUploadResponse {
|
|
94
|
+
attachment_id: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
declare class SendAPI {
|
|
98
|
+
private httpClient;
|
|
99
|
+
constructor(httpClient: HTTPClient);
|
|
100
|
+
message(request: SendMessageRequest): Promise<SendMessageResponse>;
|
|
101
|
+
action(recipientId: string, action: SenderAction): Promise<SendMessageResponse>;
|
|
102
|
+
typingOn(recipientId: string): Promise<SendMessageResponse>;
|
|
103
|
+
typingOff(recipientId: string): Promise<SendMessageResponse>;
|
|
104
|
+
markSeen(recipientId: string): Promise<SendMessageResponse>;
|
|
105
|
+
/**
|
|
106
|
+
* Send an attachment using a previously uploaded attachment_id
|
|
107
|
+
*/
|
|
108
|
+
attachment(options: {
|
|
109
|
+
recipient: Recipient;
|
|
110
|
+
type: AttachmentType;
|
|
111
|
+
attachment_id: string;
|
|
112
|
+
messaging_type?: 'RESPONSE' | 'UPDATE' | 'MESSAGE_TAG';
|
|
113
|
+
}): Promise<SendMessageResponse>;
|
|
114
|
+
/**
|
|
115
|
+
* Upload and send an attachment from URL in a single request
|
|
116
|
+
*/
|
|
117
|
+
attachmentFromUrl(options: {
|
|
118
|
+
recipient: Recipient;
|
|
119
|
+
type: AttachmentType;
|
|
120
|
+
url: string;
|
|
121
|
+
messaging_type?: 'RESPONSE' | 'UPDATE' | 'MESSAGE_TAG';
|
|
122
|
+
}): Promise<SendMessageResponse>;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
declare class AttachmentsAPI {
|
|
126
|
+
private httpClient;
|
|
127
|
+
constructor(httpClient: HTTPClient);
|
|
128
|
+
upload(request: AttachmentUploadRequest): Promise<AttachmentUploadResponse>;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
interface UserId {
|
|
132
|
+
id: string;
|
|
133
|
+
}
|
|
134
|
+
type ModerationAction = 'block_user' | 'unblock_user' | 'ban_user' | 'unban_user' | 'move_to_spam';
|
|
135
|
+
interface ModerateConversationsRequest {
|
|
136
|
+
user_ids: UserId[];
|
|
137
|
+
actions: ModerationAction[];
|
|
138
|
+
}
|
|
139
|
+
interface ModerateConversationsResponse {
|
|
140
|
+
result: 'success' | 'failure';
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
declare class ModerationAPI {
|
|
144
|
+
private httpClient;
|
|
145
|
+
constructor(httpClient: HTTPClient);
|
|
146
|
+
/**
|
|
147
|
+
* Moderate conversations with specified actions
|
|
148
|
+
* Up to 10 user IDs and up to 2 actions per request
|
|
149
|
+
*/
|
|
150
|
+
moderate(request: ModerateConversationsRequest): Promise<ModerateConversationsResponse>;
|
|
151
|
+
/**
|
|
152
|
+
* Block a user from messaging the page
|
|
153
|
+
* Prevents messaging but user can still interact with page content on Facebook
|
|
154
|
+
*/
|
|
155
|
+
blockUser(userIds: string | string[]): Promise<ModerateConversationsResponse>;
|
|
156
|
+
/**
|
|
157
|
+
* Unblock a user to allow messaging again
|
|
158
|
+
*/
|
|
159
|
+
unblockUser(userIds: string | string[]): Promise<ModerateConversationsResponse>;
|
|
160
|
+
/**
|
|
161
|
+
* Ban a user from both messaging and Facebook interactions
|
|
162
|
+
* More restrictive than blocking - prevents all interactions
|
|
163
|
+
* Note: Cannot ban user who was unbanned in last 48 hours
|
|
164
|
+
*/
|
|
165
|
+
banUser(userIds: string | string[]): Promise<ModerateConversationsResponse>;
|
|
166
|
+
/**
|
|
167
|
+
* Unban a user to restore all interactions
|
|
168
|
+
* Note: Banned user cannot be unblocked, they must be unbanned first
|
|
169
|
+
*/
|
|
170
|
+
unbanUser(userIds: string | string[]): Promise<ModerateConversationsResponse>;
|
|
171
|
+
/**
|
|
172
|
+
* Move conversation to spam folder in Meta Business Suite Inbox
|
|
173
|
+
*/
|
|
174
|
+
moveToSpam(userIds: string | string[]): Promise<ModerateConversationsResponse>;
|
|
175
|
+
/**
|
|
176
|
+
* Block user and move to spam (common moderation action)
|
|
177
|
+
*/
|
|
178
|
+
blockAndSpam(userIds: string | string[]): Promise<ModerateConversationsResponse>;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
interface Button {
|
|
182
|
+
type: 'web_url' | 'postback' | 'phone_number' | 'game_play' | 'account_link' | 'account_unlink';
|
|
183
|
+
title?: string;
|
|
184
|
+
url?: string;
|
|
185
|
+
payload?: string;
|
|
186
|
+
webview_height_ratio?: 'compact' | 'tall' | 'full';
|
|
187
|
+
messenger_extensions?: boolean;
|
|
188
|
+
fallback_url?: string;
|
|
189
|
+
webview_share_button?: 'hide' | 'show';
|
|
190
|
+
game_metadata?: {
|
|
191
|
+
player_id?: string;
|
|
192
|
+
context_id?: string;
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
interface DefaultAction {
|
|
196
|
+
type: 'web_url';
|
|
197
|
+
url: string;
|
|
198
|
+
webview_height_ratio?: 'compact' | 'tall' | 'full';
|
|
199
|
+
messenger_extensions?: boolean;
|
|
200
|
+
fallback_url?: string;
|
|
201
|
+
webview_share_button?: 'hide' | 'show';
|
|
202
|
+
}
|
|
203
|
+
interface GenericTemplateElement {
|
|
204
|
+
title: string;
|
|
205
|
+
subtitle?: string;
|
|
206
|
+
image_url?: string;
|
|
207
|
+
default_action?: DefaultAction;
|
|
208
|
+
buttons?: Button[];
|
|
209
|
+
}
|
|
210
|
+
interface GenericTemplatePayload {
|
|
211
|
+
template_type: 'generic';
|
|
212
|
+
elements: GenericTemplateElement[];
|
|
213
|
+
image_aspect_ratio?: 'horizontal' | 'square';
|
|
214
|
+
}
|
|
215
|
+
interface ButtonTemplatePayload {
|
|
216
|
+
template_type: 'button';
|
|
217
|
+
text: string;
|
|
218
|
+
buttons: Button[];
|
|
219
|
+
}
|
|
220
|
+
interface MediaTemplateElement {
|
|
221
|
+
media_type: 'image' | 'video';
|
|
222
|
+
url?: string;
|
|
223
|
+
attachment_id?: string;
|
|
224
|
+
buttons?: Button[];
|
|
225
|
+
sharable?: boolean;
|
|
226
|
+
}
|
|
227
|
+
interface MediaTemplatePayload {
|
|
228
|
+
template_type: 'media';
|
|
229
|
+
elements: [MediaTemplateElement];
|
|
230
|
+
}
|
|
231
|
+
interface ProductTemplateElement {
|
|
232
|
+
id: string;
|
|
233
|
+
}
|
|
234
|
+
interface ProductTemplatePayload {
|
|
235
|
+
template_type: 'product';
|
|
236
|
+
elements: ProductTemplateElement[];
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
declare class TemplatesAPI {
|
|
240
|
+
private httpClient;
|
|
241
|
+
constructor(httpClient: HTTPClient);
|
|
242
|
+
generic(options: {
|
|
243
|
+
recipient: Recipient;
|
|
244
|
+
elements: GenericTemplateElement[];
|
|
245
|
+
messaging_type?: MessagingType;
|
|
246
|
+
image_aspect_ratio?: 'horizontal' | 'square';
|
|
247
|
+
notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';
|
|
248
|
+
tag?: string;
|
|
249
|
+
}): Promise<SendMessageResponse>;
|
|
250
|
+
button(options: {
|
|
251
|
+
recipient: Recipient;
|
|
252
|
+
text: string;
|
|
253
|
+
buttons: Button[];
|
|
254
|
+
messaging_type?: MessagingType;
|
|
255
|
+
notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';
|
|
256
|
+
tag?: string;
|
|
257
|
+
}): Promise<SendMessageResponse>;
|
|
258
|
+
media(options: {
|
|
259
|
+
recipient: Recipient;
|
|
260
|
+
element: MediaTemplateElement;
|
|
261
|
+
messaging_type?: MessagingType;
|
|
262
|
+
notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';
|
|
263
|
+
tag?: string;
|
|
264
|
+
}): Promise<SendMessageResponse>;
|
|
265
|
+
product(options: {
|
|
266
|
+
recipient: Recipient;
|
|
267
|
+
elements: ProductTemplateElement[];
|
|
268
|
+
messaging_type?: MessagingType;
|
|
269
|
+
notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';
|
|
270
|
+
tag?: string;
|
|
271
|
+
}): Promise<SendMessageResponse>;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
interface MessengerConfig {
|
|
275
|
+
accessToken: string;
|
|
276
|
+
version?: string;
|
|
277
|
+
baseUrl?: string;
|
|
278
|
+
timeout?: number;
|
|
279
|
+
maxRetries?: number;
|
|
280
|
+
}
|
|
281
|
+
declare class Messenger {
|
|
282
|
+
readonly send: SendAPI;
|
|
283
|
+
readonly attachments: AttachmentsAPI;
|
|
284
|
+
readonly moderation: ModerationAPI;
|
|
285
|
+
readonly templates: TemplatesAPI;
|
|
286
|
+
private readonly httpClient;
|
|
287
|
+
constructor(config: MessengerConfig);
|
|
288
|
+
private validateConfig;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
declare class MessengerAPIError extends Error {
|
|
292
|
+
readonly code: number;
|
|
293
|
+
readonly type: string;
|
|
294
|
+
readonly subcode?: number;
|
|
295
|
+
readonly fbtrace_id?: string;
|
|
296
|
+
readonly statusCode: number;
|
|
297
|
+
readonly response?: any;
|
|
298
|
+
constructor(error: MessengerError, statusCode: number, response?: any);
|
|
299
|
+
}
|
|
300
|
+
declare class MessengerNetworkError extends Error {
|
|
301
|
+
readonly cause?: Error;
|
|
302
|
+
constructor(message: string, cause?: Error);
|
|
303
|
+
}
|
|
304
|
+
declare class MessengerTimeoutError extends Error {
|
|
305
|
+
readonly timeout: number;
|
|
306
|
+
constructor(timeout: number);
|
|
307
|
+
}
|
|
308
|
+
declare class MessengerConfigError extends Error {
|
|
309
|
+
constructor(message: string);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
declare class TemplateValidationError extends Error {
|
|
313
|
+
constructor(message: string);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
declare class MessageValidationError extends Error {
|
|
317
|
+
constructor(message: string);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
declare const MESSAGE_LIMITS: {
|
|
321
|
+
readonly TEXT_MESSAGE_MAX_CHARS: 2000;
|
|
322
|
+
};
|
|
323
|
+
declare const ATTACHMENT_LIMITS: {
|
|
324
|
+
readonly IMAGE_MAX_SIZE: number;
|
|
325
|
+
readonly OTHER_MAX_SIZE: number;
|
|
326
|
+
readonly VIDEO_TIMEOUT: 75;
|
|
327
|
+
readonly OTHER_TIMEOUT: 10;
|
|
328
|
+
};
|
|
329
|
+
declare const TEMPLATE_LIMITS: {
|
|
330
|
+
readonly GENERIC_ELEMENTS_MAX: 10;
|
|
331
|
+
readonly GENERIC_TITLE_MAX_CHARS: 80;
|
|
332
|
+
readonly GENERIC_SUBTITLE_MAX_CHARS: 80;
|
|
333
|
+
readonly BUTTON_TEXT_MAX_CHARS: 640;
|
|
334
|
+
readonly BUTTONS_MAX_COUNT: 3;
|
|
335
|
+
readonly BUTTON_TITLE_MAX_CHARS: 20;
|
|
336
|
+
readonly POSTBACK_PAYLOAD_MAX_CHARS: 1000;
|
|
337
|
+
readonly MEDIA_ELEMENTS_COUNT: 1;
|
|
338
|
+
readonly MEDIA_BUTTONS_MAX_COUNT: 3;
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
export { ATTACHMENT_LIMITS, type AttachmentType, type AttachmentUploadRequest, type AttachmentUploadResponse, AttachmentsAPI, type Button, type ButtonTemplatePayload, type DefaultAction, type ErrorResponse, type GenericTemplateElement, type GenericTemplatePayload, MESSAGE_LIMITS, type MediaTemplateElement, type MediaTemplatePayload, type Message, MessageValidationError, type MessagingType, Messenger, MessengerAPIError, type MessengerConfig, MessengerConfigError, type MessengerError, MessengerNetworkError, MessengerTimeoutError, type ModerateConversationsRequest, type ModerateConversationsResponse, ModerationAPI, type ModerationAction, type ProductTemplateElement, type ProductTemplatePayload, type QuickReply, type Recipient, SendAPI, type SendMessageRequest, type SendMessageResponse, type SenderAction, TEMPLATE_LIMITS, TemplateValidationError, TemplatesAPI, type UserId };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
var f="v23.0",R="https://graph.facebook.com";var p={MESSAGES:"/me/messages",MESSAGE_ATTACHMENTS:"/me/message_attachments",MODERATE_CONVERSATIONS:"/me/moderate_conversations"},E={TEXT_MESSAGE_MAX_CHARS:2e3},U={IMAGE_MAX_SIZE:8*1024*1024,OTHER_MAX_SIZE:25*1024*1024,VIDEO_TIMEOUT:75,OTHER_TIMEOUT:10},o={GENERIC_ELEMENTS_MAX:10,GENERIC_TITLE_MAX_CHARS:80,GENERIC_SUBTITLE_MAX_CHARS:80,BUTTON_TEXT_MAX_CHARS:640,BUTTONS_MAX_COUNT:3,BUTTON_TITLE_MAX_CHARS:20,POSTBACK_PAYLOAD_MAX_CHARS:1e3,MEDIA_ELEMENTS_COUNT:1,MEDIA_BUTTONS_MAX_COUNT:3};var c=class extends Error{code;type;subcode;fbtrace_id;statusCode;response;constructor(e,s,r){super(e.message),this.name="MessengerAPIError",this.code=e.code,this.type=e.type,this.subcode=e.error_subcode,this.fbtrace_id=e.fbtrace_id,this.statusCode=s,this.response=r;}},l=class extends Error{cause;constructor(e,s){super(e),this.name="MessengerNetworkError",this.cause=s;}},u=class extends Error{timeout;constructor(e){super(`Request timed out after ${e}ms`),this.name="MessengerTimeoutError",this.timeout=e;}},m=class extends Error{constructor(e){super(e),this.name="MessengerConfigError";}};var S=class{config;constructor(e){this.config={accessToken:e.accessToken,version:e.version,baseUrl:e.baseUrl||R,timeout:e.timeout||3e4,maxRetries:e.maxRetries||3};}async request(e){let s=this.buildUrl(e.path,e.query),r;for(let i=0;i<=this.config.maxRetries;i++)try{let a=await this.makeRequest(s,e);return await this.handleResponse(a)}catch(a){if(r=a,a instanceof c&&a.statusCode>=400&&a.statusCode<500||i===this.config.maxRetries)throw a;await this.delay(1e3*(i+1));}throw r||new Error("Unknown error occurred")}buildUrl(e,s){let r=new URL(`${this.config.baseUrl}/${this.config.version}${e}`);return r.searchParams.append("access_token",this.config.accessToken),s&&Object.entries(s).forEach(([i,a])=>{r.searchParams.append(i,String(a));}),r.toString()}async makeRequest(e,s){let r=new AbortController,i=setTimeout(()=>r.abort(),this.config.timeout);try{let a={method:s.method,headers:{"Content-Type":"application/json"},signal:r.signal};return s.body&&(a.body=JSON.stringify(s.body)),await fetch(e,a)}catch(a){throw a instanceof Error?a.name==="AbortError"?new u(this.config.timeout):new l(`Network request failed: ${a.message}`,a):a}finally{clearTimeout(i);}}async handleResponse(e){let r=e.headers.get("content-type")?.includes("application/json");if(!e.ok)if(r){let i=await e.json();throw new c(i.error,e.status,i)}else {let i=await e.text();throw new c({message:i||`HTTP ${e.status} ${e.statusText}`,type:"http_error",code:e.status,fbtrace_id:""},e.status,i)}return r?await e.json():await e.text()}delay(e){return new Promise(s=>setTimeout(s,e))}};var T=class extends Error{constructor(e){super(e),this.name="MessageValidationError";}};function P(t){if(!t||t.trim()==="")throw new T("Text message cannot be empty");if(t.length>E.TEXT_MESSAGE_MAX_CHARS)throw new T(`Text message cannot exceed ${E.TEXT_MESSAGE_MAX_CHARS} characters`)}var d=class{constructor(e){this.httpClient=e;}async message(e){return e.message?.text&&P(e.message.text),this.httpClient.request({method:"POST",path:p.MESSAGES,body:e})}async action(e,s){return this.httpClient.request({method:"POST",path:p.MESSAGES,body:{recipient:{id:e},messaging_type:"RESPONSE",sender_action:s}})}async typingOn(e){return this.action(e,"typing_on")}async typingOff(e){return this.action(e,"typing_off")}async markSeen(e){return this.action(e,"mark_seen")}async attachment(e){return this.message({recipient:e.recipient,messaging_type:e.messaging_type??"RESPONSE",message:{attachment:{type:e.type,payload:{attachment_id:e.attachment_id}}}})}async attachmentFromUrl(e){return this.message({recipient:e.recipient,messaging_type:e.messaging_type??"RESPONSE",message:{attachment:{type:e.type,payload:{url:e.url}}}})}};var _=class{constructor(e){this.httpClient=e;}async upload(e){let s={message:{attachment:{type:e.type,payload:{url:e.url,is_reusable:e.is_reusable??true}}}};return this.httpClient.request({method:"POST",path:p.MESSAGE_ATTACHMENTS,body:s})}};var h=class{constructor(e){this.httpClient=e;}async moderate(e){return this.httpClient.request({method:"POST",path:p.MODERATE_CONVERSATIONS,body:e})}async blockUser(e){let s=Array.isArray(e)?e.map(r=>({id:r})):[{id:e}];return this.moderate({user_ids:s,actions:["block_user"]})}async unblockUser(e){let s=Array.isArray(e)?e.map(r=>({id:r})):[{id:e}];return this.moderate({user_ids:s,actions:["unblock_user"]})}async banUser(e){let s=Array.isArray(e)?e.map(r=>({id:r})):[{id:e}];return this.moderate({user_ids:s,actions:["ban_user"]})}async unbanUser(e){let s=Array.isArray(e)?e.map(r=>({id:r})):[{id:e}];return this.moderate({user_ids:s,actions:["unban_user"]})}async moveToSpam(e){let s=Array.isArray(e)?e.map(r=>({id:r})):[{id:e}];return this.moderate({user_ids:s,actions:["move_to_spam"]})}async blockAndSpam(e){let s=Array.isArray(e)?e.map(r=>({id:r})):[{id:e}];return this.moderate({user_ids:s,actions:["block_user","move_to_spam"]})}};var n=class extends Error{constructor(e){super(e),this.name="TemplateValidationError";}};function b(t){if(t.length===0)throw new n("Generic template must have at least 1 element");if(t.length>o.GENERIC_ELEMENTS_MAX)throw new n(`Generic template cannot have more than ${o.GENERIC_ELEMENTS_MAX} elements`);t.forEach((e,s)=>{I(e,s);});}function I(t,e){if(!t.title||t.title.trim()==="")throw new n(`Element ${e}: title is required`);if(t.title.length>o.GENERIC_TITLE_MAX_CHARS)throw new n(`Element ${e}: title cannot exceed ${o.GENERIC_TITLE_MAX_CHARS} characters`);if(t.subtitle&&t.subtitle.length>o.GENERIC_SUBTITLE_MAX_CHARS)throw new n(`Element ${e}: subtitle cannot exceed ${o.GENERIC_SUBTITLE_MAX_CHARS} characters`);if(t.image_url&&!y(t.image_url))throw new n(`Element ${e}: image_url must be HTTPS`);if(t.buttons&&A(t.buttons,`Element ${e}`),!!!(t.subtitle||t.image_url||t.default_action||t.buttons&&t.buttons.length>0))throw new n(`Element ${e}: must have at least one additional property beyond title`)}function w(t,e){if(!t||t.trim()==="")throw new n("Button template text is required");if(t.length>o.BUTTON_TEXT_MAX_CHARS)throw new n(`Button template text cannot exceed ${o.BUTTON_TEXT_MAX_CHARS} characters`);if(e.length===0)throw new n("Button template must have at least 1 button");A(e,"Button template");}function C(t){if(!t.media_type)throw new n("Media template element must have media_type");if(!t.url&&!t.attachment_id)throw new n("Media template element must have either url or attachment_id");if(t.url&&t.attachment_id)throw new n("Media template element cannot have both url and attachment_id");if(t.url&&!y(t.url))throw new n("Media template url must be HTTPS");if(t.buttons){if(t.buttons.length>o.MEDIA_BUTTONS_MAX_COUNT)throw new n(`Media template cannot have more than ${o.MEDIA_BUTTONS_MAX_COUNT} buttons`);A(t.buttons,"Media template");}}function A(t,e){if(t.length>o.BUTTONS_MAX_COUNT)throw new n(`${e} cannot have more than ${o.BUTTONS_MAX_COUNT} buttons`);t.forEach((s,r)=>{x(s,`${e} button ${r}`);});}function x(t,e){if(!t.type)throw new n(`${e}: type is required`);if(t.type!=="account_unlink"&&(!t.title||t.title.trim()===""))throw new n(`${e}: title is required for ${t.type} buttons`);if(t.title&&t.title.length>o.BUTTON_TITLE_MAX_CHARS)throw new n(`${e}: title cannot exceed ${o.BUTTON_TITLE_MAX_CHARS} characters`);switch(t.type){case "web_url":if(!t.url)throw new n(`${e}: url is required for web_url buttons`);if(!y(t.url))throw new n(`${e}: url must be HTTPS for web_url buttons`);break;case "postback":if(!t.payload)throw new n(`${e}: payload is required for postback buttons`);if(t.payload.length>o.POSTBACK_PAYLOAD_MAX_CHARS)throw new n(`${e}: payload cannot exceed ${o.POSTBACK_PAYLOAD_MAX_CHARS} characters`);break;case "phone_number":if(!t.payload)throw new n(`${e}: payload is required for phone_number buttons`);if(!t.payload.startsWith("+"))throw new n(`${e}: phone_number payload must start with + (e.g., +1234567890)`);break;case "game_play":break;case "account_link":if(!t.url)throw new n(`${e}: url is required for account_link buttons`);if(!y(t.url))throw new n(`${e}: url must be HTTPS for account_link buttons`);break;}if(t.type==="web_url"&&t.messenger_extensions&&t.fallback_url&&!y(t.fallback_url))throw new n(`${e}: fallback_url must be HTTPS`)}function y(t){try{return new URL(t).protocol==="https:"}catch{return false}}var g=class{constructor(e){this.httpClient=e;}async generic(e){b(e.elements);let s={template_type:"generic",elements:e.elements,image_aspect_ratio:e.image_aspect_ratio},r={recipient:e.recipient,messaging_type:e.messaging_type||"UPDATE",message:{attachment:{type:"template",payload:s}},notification_type:e.notification_type,tag:e.tag};return this.httpClient.request({method:"POST",path:p.MESSAGES,body:r})}async button(e){w(e.text,e.buttons);let s={template_type:"button",text:e.text,buttons:e.buttons},r={recipient:e.recipient,messaging_type:e.messaging_type||"UPDATE",message:{attachment:{type:"template",payload:s}},notification_type:e.notification_type,tag:e.tag};return this.httpClient.request({method:"POST",path:p.MESSAGES,body:r})}async media(e){C(e.element);let s={template_type:"media",elements:[e.element]},r={recipient:e.recipient,messaging_type:e.messaging_type||"UPDATE",message:{attachment:{type:"template",payload:s}},notification_type:e.notification_type,tag:e.tag};return this.httpClient.request({method:"POST",path:p.MESSAGES,body:r})}async product(e){let s={template_type:"product",elements:e.elements},r={recipient:e.recipient,messaging_type:e.messaging_type||"UPDATE",message:{attachment:{type:"template",payload:s}},notification_type:e.notification_type,tag:e.tag};return this.httpClient.request({method:"POST",path:p.MESSAGES,body:r})}};var M=class{send;attachments;moderation;templates;httpClient;constructor(e){this.validateConfig(e);let s={accessToken:e.accessToken,version:e.version||f,baseUrl:e.baseUrl,timeout:e.timeout,maxRetries:e.maxRetries};this.httpClient=new S(s),this.send=new d(this.httpClient),this.attachments=new _(this.httpClient),this.moderation=new h(this.httpClient),this.templates=new g(this.httpClient);}validateConfig(e){if(!e.accessToken)throw new m("Access token is required");if(typeof e.accessToken!="string"||e.accessToken.trim()==="")throw new m("Access token must be a non-empty string");if(e.version&&typeof e.version!="string")throw new m("API version must be a string");if(e.timeout&&(typeof e.timeout!="number"||e.timeout<=0))throw new m("Timeout must be a positive number");if(e.maxRetries&&(typeof e.maxRetries!="number"||e.maxRetries<0))throw new m("Max retries must be a non-negative number")}};
|
|
2
|
+
export{U as ATTACHMENT_LIMITS,_ as AttachmentsAPI,E as MESSAGE_LIMITS,T as MessageValidationError,M as Messenger,c as MessengerAPIError,m as MessengerConfigError,l as MessengerNetworkError,u as MessengerTimeoutError,h as ModerationAPI,d as SendAPI,o as TEMPLATE_LIMITS,n as TemplateValidationError,g as TemplatesAPI};//# sourceMappingURL=index.js.map
|
|
3
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/constants.ts","../src/core/errors.ts","../src/core/http-client.ts","../src/utils/message-validators.ts","../src/resources/send.ts","../src/resources/attachments.ts","../src/resources/moderation.ts","../src/utils/validators.ts","../src/resources/templates.ts","../src/client.ts"],"names":["DEFAULT_API_VERSION","BASE_URL","API_ENDPOINTS","MESSAGE_LIMITS","ATTACHMENT_LIMITS","TEMPLATE_LIMITS","MessengerAPIError","error","statusCode","response","MessengerNetworkError","message","cause","MessengerTimeoutError","timeout","MessengerConfigError","HTTPClient","config","options","url","lastError","attempt","path","query","key","value","controller","timeoutId","fetchOptions","isJson","errorData","text","ms","resolve","MessageValidationError","validateTextMessage","SendAPI","httpClient","request","recipientId","action","AttachmentsAPI","body","ModerationAPI","userIds","user_ids","id","TemplateValidationError","validateGenericTemplate","elements","element","index","validateGenericElement","isHttpsUrl","validateButtons","validateButtonTemplate","buttons","validateMediaTemplate","context","button","validateButton","TemplatesAPI","payload","Messenger","clientConfig"],"mappings":"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","file":"index.js","sourcesContent":["export const DEFAULT_API_VERSION = 'v23.0';\nexport const BASE_URL = 'https://graph.facebook.com';\nexport const DEFAULT_TIMEOUT = 30000; // 30 seconds\nexport const MAX_RETRY_ATTEMPTS = 3;\nexport const RETRY_DELAY_MS = 1000;\n\nexport const API_ENDPOINTS = {\n MESSAGES: '/me/messages',\n MESSAGE_ATTACHMENTS: '/me/message_attachments',\n MODERATE_CONVERSATIONS: '/me/moderate_conversations',\n PASS_THREAD_CONTROL: '/me/pass_thread_control',\n TAKE_THREAD_CONTROL: '/me/take_thread_control',\n REQUEST_THREAD_CONTROL: '/me/request_thread_control',\n} as const;\n\n// Validation constants\nexport const MESSAGE_LIMITS = {\n // Text messages\n TEXT_MESSAGE_MAX_CHARS: 2000,\n} as const;\n\nexport const ATTACHMENT_LIMITS = {\n // File size limits in bytes\n IMAGE_MAX_SIZE: 8 * 1024 * 1024, // 8MB\n OTHER_MAX_SIZE: 25 * 1024 * 1024, // 25MB (video, audio, file)\n \n // Timeout limits in seconds\n VIDEO_TIMEOUT: 75,\n OTHER_TIMEOUT: 10,\n} as const;\n\nexport const TEMPLATE_LIMITS = {\n // Generic Template\n GENERIC_ELEMENTS_MAX: 10,\n GENERIC_TITLE_MAX_CHARS: 80,\n GENERIC_SUBTITLE_MAX_CHARS: 80,\n \n // Button Template \n BUTTON_TEXT_MAX_CHARS: 640,\n BUTTONS_MAX_COUNT: 3,\n BUTTON_TITLE_MAX_CHARS: 20,\n \n // All Templates\n POSTBACK_PAYLOAD_MAX_CHARS: 1000,\n \n // Media Template\n MEDIA_ELEMENTS_COUNT: 1, // Exactly 1 element required\n MEDIA_BUTTONS_MAX_COUNT: 3,\n} as const;","import type { MessengerError } from '../types/responses.js';\n\nexport class MessengerAPIError extends Error {\n public readonly code: number;\n public readonly type: string;\n public readonly subcode?: number;\n public readonly fbtrace_id?: string;\n public readonly statusCode: number;\n public readonly response?: any;\n\n constructor(error: MessengerError, statusCode: number, response?: any) {\n super(error.message);\n this.name = 'MessengerAPIError';\n this.code = error.code;\n this.type = error.type;\n this.subcode = error.error_subcode;\n this.fbtrace_id = error.fbtrace_id;\n this.statusCode = statusCode;\n this.response = response;\n }\n}\n\nexport class MessengerNetworkError extends Error {\n public readonly cause?: Error;\n\n constructor(message: string, cause?: Error) {\n super(message);\n this.name = 'MessengerNetworkError';\n this.cause = cause;\n }\n}\n\nexport class MessengerTimeoutError extends Error {\n public readonly timeout: number;\n\n constructor(timeout: number) {\n super(`Request timed out after ${timeout}ms`);\n this.name = 'MessengerTimeoutError';\n this.timeout = timeout;\n }\n}\n\nexport class MessengerConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'MessengerConfigError';\n }\n}","import { BASE_URL, DEFAULT_TIMEOUT, MAX_RETRY_ATTEMPTS, RETRY_DELAY_MS } from './constants.js';\nimport { MessengerAPIError, MessengerNetworkError, MessengerTimeoutError } from './errors.js';\nimport type { ErrorResponse } from '../types/responses.js';\n\nexport interface ClientConfig {\n accessToken: string;\n version: string;\n baseUrl?: string;\n timeout?: number;\n maxRetries?: number;\n}\n\nexport interface RequestOptions {\n method: 'GET' | 'POST' | 'DELETE';\n path: string;\n body?: any;\n query?: Record<string, string | number | boolean>;\n}\n\nexport class HTTPClient {\n private readonly config: Required<ClientConfig>;\n\n constructor(config: ClientConfig) {\n this.config = {\n accessToken: config.accessToken,\n version: config.version,\n baseUrl: config.baseUrl || BASE_URL,\n timeout: config.timeout || DEFAULT_TIMEOUT,\n maxRetries: config.maxRetries || MAX_RETRY_ATTEMPTS,\n };\n }\n\n async request<T>(options: RequestOptions): Promise<T> {\n const url = this.buildUrl(options.path, options.query);\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {\n try {\n const response = await this.makeRequest(url, options);\n return await this.handleResponse<T>(response);\n } catch (error) {\n lastError = error as Error;\n \n // Don't retry on client errors (4xx)\n if (error instanceof MessengerAPIError && error.statusCode >= 400 && error.statusCode < 500) {\n throw error;\n }\n\n // Don't retry on timeout for the last attempt\n if (attempt === this.config.maxRetries) {\n throw error;\n }\n\n // Wait before retrying\n await this.delay(RETRY_DELAY_MS * (attempt + 1));\n }\n }\n\n throw lastError || new Error('Unknown error occurred');\n }\n\n private buildUrl(path: string, query?: Record<string, string | number | boolean>): string {\n const url = new URL(`${this.config.baseUrl}/${this.config.version}${path}`);\n \n // Always add access token\n url.searchParams.append('access_token', this.config.accessToken);\n \n // Add additional query parameters\n if (query) {\n Object.entries(query).forEach(([key, value]) => {\n url.searchParams.append(key, String(value));\n });\n }\n\n return url.toString();\n }\n\n private async makeRequest(url: string, options: RequestOptions): Promise<Response> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);\n\n try {\n const fetchOptions: RequestInit = {\n method: options.method,\n headers: {\n 'Content-Type': 'application/json',\n },\n signal: controller.signal,\n };\n\n if (options.body) {\n fetchOptions.body = JSON.stringify(options.body);\n }\n\n const response = await fetch(url, fetchOptions);\n return response;\n } catch (error) {\n if (error instanceof Error) {\n if (error.name === 'AbortError') {\n throw new MessengerTimeoutError(this.config.timeout);\n }\n throw new MessengerNetworkError(`Network request failed: ${error.message}`, error);\n }\n throw error;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n private async handleResponse<T>(response: Response): Promise<T> {\n const contentType = response.headers.get('content-type');\n const isJson = contentType?.includes('application/json');\n\n if (!response.ok) {\n if (isJson) {\n const errorData = await response.json() as ErrorResponse;\n throw new MessengerAPIError(errorData.error, response.status, errorData);\n } else {\n const text = await response.text();\n throw new MessengerAPIError(\n {\n message: text || `HTTP ${response.status} ${response.statusText}`,\n type: 'http_error',\n code: response.status,\n fbtrace_id: '',\n },\n response.status,\n text\n );\n }\n }\n\n if (isJson) {\n return await response.json() as T;\n }\n\n // For non-JSON responses, return the text\n return await response.text() as unknown as T;\n }\n\n private delay(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n}","import { MESSAGE_LIMITS } from '../core/constants.js';\n\nexport class MessageValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'MessageValidationError';\n }\n}\n\nexport function validateTextMessage(text: string): void {\n if (!text || text.trim() === '') {\n throw new MessageValidationError('Text message cannot be empty');\n }\n\n if (text.length > MESSAGE_LIMITS.TEXT_MESSAGE_MAX_CHARS) {\n throw new MessageValidationError(\n `Text message cannot exceed ${MESSAGE_LIMITS.TEXT_MESSAGE_MAX_CHARS} characters`\n );\n }\n}","import type { HTTPClient } from '../core/http-client.js';\nimport { API_ENDPOINTS } from '../core/constants.js';\nimport type { SendMessageRequest, SenderAction, Recipient } from '../types/messages.js';\nimport type { SendMessageResponse } from '../types/responses.js';\nimport type { AttachmentType } from '../types/attachments.js';\nimport { validateTextMessage } from '../utils/message-validators.js';\n\nexport class SendAPI {\n constructor(private httpClient: HTTPClient) {}\n\n async message(request: SendMessageRequest): Promise<SendMessageResponse> {\n // Validate text message length if present\n if (request.message?.text) {\n validateTextMessage(request.message.text);\n }\n\n return this.httpClient.request<SendMessageResponse>({\n method: 'POST',\n path: API_ENDPOINTS.MESSAGES,\n body: request,\n });\n }\n\n async action(recipientId: string, action: SenderAction): Promise<SendMessageResponse> {\n return this.httpClient.request<SendMessageResponse>({\n method: 'POST',\n path: API_ENDPOINTS.MESSAGES,\n body: {\n recipient: { id: recipientId },\n messaging_type: 'RESPONSE',\n sender_action: action,\n },\n });\n }\n\n async typingOn(recipientId: string): Promise<SendMessageResponse> {\n return this.action(recipientId, 'typing_on');\n }\n\n async typingOff(recipientId: string): Promise<SendMessageResponse> {\n return this.action(recipientId, 'typing_off');\n }\n\n async markSeen(recipientId: string): Promise<SendMessageResponse> {\n return this.action(recipientId, 'mark_seen');\n }\n\n // Convenience methods for sending attachments\n\n /**\n * Send an attachment using a previously uploaded attachment_id\n */\n async attachment(options: {\n recipient: Recipient;\n type: AttachmentType;\n attachment_id: string;\n messaging_type?: 'RESPONSE' | 'UPDATE' | 'MESSAGE_TAG';\n }): Promise<SendMessageResponse> {\n return this.message({\n recipient: options.recipient,\n messaging_type: options.messaging_type ?? 'RESPONSE',\n message: {\n attachment: {\n type: options.type,\n payload: {\n attachment_id: options.attachment_id,\n },\n },\n },\n });\n }\n\n /**\n * Upload and send an attachment from URL in a single request\n */\n async attachmentFromUrl(options: {\n recipient: Recipient;\n type: AttachmentType;\n url: string;\n messaging_type?: 'RESPONSE' | 'UPDATE' | 'MESSAGE_TAG';\n }): Promise<SendMessageResponse> {\n return this.message({\n recipient: options.recipient,\n messaging_type: options.messaging_type ?? 'RESPONSE',\n message: {\n attachment: {\n type: options.type,\n payload: {\n url: options.url,\n },\n },\n },\n });\n }\n}","import type { HTTPClient } from '../core/http-client.js';\nimport { API_ENDPOINTS } from '../core/constants.js';\nimport type { AttachmentUploadRequest, AttachmentUploadResponse } from '../types/attachments.js';\n\nexport class AttachmentsAPI {\n constructor(private httpClient: HTTPClient) {}\n\n async upload(request: AttachmentUploadRequest): Promise<AttachmentUploadResponse> {\n // Format according to official API - no message wrapper needed\n const body = {\n message: {\n attachment: {\n type: request.type,\n payload: {\n url: request.url,\n is_reusable: request.is_reusable ?? true,\n },\n },\n },\n };\n\n return this.httpClient.request<AttachmentUploadResponse>({\n method: 'POST',\n path: API_ENDPOINTS.MESSAGE_ATTACHMENTS,\n body,\n });\n }\n}","import type { HTTPClient } from '../core/http-client.js';\nimport { API_ENDPOINTS } from '../core/constants.js';\nimport type { \n ModerateConversationsRequest,\n ModerateConversationsResponse\n} from '../types/moderation.js';\n\nexport class ModerationAPI {\n constructor(private httpClient: HTTPClient) {}\n\n /**\n * Moderate conversations with specified actions\n * Up to 10 user IDs and up to 2 actions per request\n */\n async moderate(request: ModerateConversationsRequest): Promise<ModerateConversationsResponse> {\n return this.httpClient.request<ModerateConversationsResponse>({\n method: 'POST',\n path: API_ENDPOINTS.MODERATE_CONVERSATIONS,\n body: request,\n });\n }\n\n /**\n * Block a user from messaging the page\n * Prevents messaging but user can still interact with page content on Facebook\n */\n async blockUser(userIds: string | string[]): Promise<ModerateConversationsResponse> {\n const user_ids = Array.isArray(userIds) \n ? userIds.map(id => ({ id }))\n : [{ id: userIds }];\n\n return this.moderate({\n user_ids,\n actions: ['block_user'],\n });\n }\n\n /**\n * Unblock a user to allow messaging again\n */\n async unblockUser(userIds: string | string[]): Promise<ModerateConversationsResponse> {\n const user_ids = Array.isArray(userIds)\n ? userIds.map(id => ({ id }))\n : [{ id: userIds }];\n\n return this.moderate({\n user_ids,\n actions: ['unblock_user'],\n });\n }\n\n /**\n * Ban a user from both messaging and Facebook interactions\n * More restrictive than blocking - prevents all interactions\n * Note: Cannot ban user who was unbanned in last 48 hours\n */\n async banUser(userIds: string | string[]): Promise<ModerateConversationsResponse> {\n const user_ids = Array.isArray(userIds)\n ? userIds.map(id => ({ id }))\n : [{ id: userIds }];\n\n return this.moderate({\n user_ids,\n actions: ['ban_user'],\n });\n }\n\n /**\n * Unban a user to restore all interactions\n * Note: Banned user cannot be unblocked, they must be unbanned first\n */\n async unbanUser(userIds: string | string[]): Promise<ModerateConversationsResponse> {\n const user_ids = Array.isArray(userIds)\n ? userIds.map(id => ({ id }))\n : [{ id: userIds }];\n\n return this.moderate({\n user_ids,\n actions: ['unban_user'],\n });\n }\n\n /**\n * Move conversation to spam folder in Meta Business Suite Inbox\n */\n async moveToSpam(userIds: string | string[]): Promise<ModerateConversationsResponse> {\n const user_ids = Array.isArray(userIds)\n ? userIds.map(id => ({ id }))\n : [{ id: userIds }];\n\n return this.moderate({\n user_ids,\n actions: ['move_to_spam'],\n });\n }\n\n /**\n * Block user and move to spam (common moderation action)\n */\n async blockAndSpam(userIds: string | string[]): Promise<ModerateConversationsResponse> {\n const user_ids = Array.isArray(userIds)\n ? userIds.map(id => ({ id }))\n : [{ id: userIds }];\n\n return this.moderate({\n user_ids,\n actions: ['block_user', 'move_to_spam'],\n });\n }\n}","import { TEMPLATE_LIMITS } from '../core/constants.js';\nimport type { Button, GenericTemplateElement, MediaTemplateElement } from '../types/templates.js';\n\nexport class TemplateValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'TemplateValidationError';\n }\n}\n\nexport function validateGenericTemplate(elements: GenericTemplateElement[]): void {\n if (elements.length === 0) {\n throw new TemplateValidationError('Generic template must have at least 1 element');\n }\n\n if (elements.length > TEMPLATE_LIMITS.GENERIC_ELEMENTS_MAX) {\n throw new TemplateValidationError(\n `Generic template cannot have more than ${TEMPLATE_LIMITS.GENERIC_ELEMENTS_MAX} elements`\n );\n }\n\n elements.forEach((element, index) => {\n validateGenericElement(element, index);\n });\n}\n\nexport function validateGenericElement(element: GenericTemplateElement, index: number): void {\n if (!element.title || element.title.trim() === '') {\n throw new TemplateValidationError(`Element ${index}: title is required`);\n }\n\n if (element.title.length > TEMPLATE_LIMITS.GENERIC_TITLE_MAX_CHARS) {\n throw new TemplateValidationError(\n `Element ${index}: title cannot exceed ${TEMPLATE_LIMITS.GENERIC_TITLE_MAX_CHARS} characters`\n );\n }\n\n if (element.subtitle && element.subtitle.length > TEMPLATE_LIMITS.GENERIC_SUBTITLE_MAX_CHARS) {\n throw new TemplateValidationError(\n `Element ${index}: subtitle cannot exceed ${TEMPLATE_LIMITS.GENERIC_SUBTITLE_MAX_CHARS} characters`\n );\n }\n\n if (element.image_url && !isHttpsUrl(element.image_url)) {\n throw new TemplateValidationError(`Element ${index}: image_url must be HTTPS`);\n }\n\n if (element.buttons) {\n validateButtons(element.buttons, `Element ${index}`);\n }\n\n // Validate that element has at least one property beyond title\n const hasAdditionalProperty = !!(\n element.subtitle ||\n element.image_url ||\n element.default_action ||\n (element.buttons && element.buttons.length > 0)\n );\n\n if (!hasAdditionalProperty) {\n throw new TemplateValidationError(\n `Element ${index}: must have at least one additional property beyond title`\n );\n }\n}\n\nexport function validateButtonTemplate(text: string, buttons: Button[]): void {\n if (!text || text.trim() === '') {\n throw new TemplateValidationError('Button template text is required');\n }\n\n if (text.length > TEMPLATE_LIMITS.BUTTON_TEXT_MAX_CHARS) {\n throw new TemplateValidationError(\n `Button template text cannot exceed ${TEMPLATE_LIMITS.BUTTON_TEXT_MAX_CHARS} characters`\n );\n }\n\n if (buttons.length === 0) {\n throw new TemplateValidationError('Button template must have at least 1 button');\n }\n\n validateButtons(buttons, 'Button template');\n}\n\nexport function validateMediaTemplate(element: MediaTemplateElement): void {\n if (!element.media_type) {\n throw new TemplateValidationError('Media template element must have media_type');\n }\n\n if (!element.url && !element.attachment_id) {\n throw new TemplateValidationError('Media template element must have either url or attachment_id');\n }\n\n if (element.url && element.attachment_id) {\n throw new TemplateValidationError(\n 'Media template element cannot have both url and attachment_id'\n );\n }\n\n if (element.url && !isHttpsUrl(element.url)) {\n throw new TemplateValidationError('Media template url must be HTTPS');\n }\n\n if (element.buttons) {\n if (element.buttons.length > TEMPLATE_LIMITS.MEDIA_BUTTONS_MAX_COUNT) {\n throw new TemplateValidationError(\n `Media template cannot have more than ${TEMPLATE_LIMITS.MEDIA_BUTTONS_MAX_COUNT} buttons`\n );\n }\n validateButtons(element.buttons, 'Media template');\n }\n}\n\nexport function validateButtons(buttons: Button[], context: string): void {\n if (buttons.length > TEMPLATE_LIMITS.BUTTONS_MAX_COUNT) {\n throw new TemplateValidationError(\n `${context} cannot have more than ${TEMPLATE_LIMITS.BUTTONS_MAX_COUNT} buttons`\n );\n }\n\n buttons.forEach((button, index) => {\n validateButton(button, `${context} button ${index}`);\n });\n}\n\nexport function validateButton(button: Button, context: string): void {\n if (!button.type) {\n throw new TemplateValidationError(`${context}: type is required`);\n }\n\n // Title is required for most button types (not for account_unlink)\n if (button.type !== 'account_unlink' && (!button.title || button.title.trim() === '')) {\n throw new TemplateValidationError(`${context}: title is required for ${button.type} buttons`);\n }\n\n if (button.title && button.title.length > TEMPLATE_LIMITS.BUTTON_TITLE_MAX_CHARS) {\n throw new TemplateValidationError(\n `${context}: title cannot exceed ${TEMPLATE_LIMITS.BUTTON_TITLE_MAX_CHARS} characters`\n );\n }\n\n // Type-specific validations\n switch (button.type) {\n case 'web_url':\n if (!button.url) {\n throw new TemplateValidationError(`${context}: url is required for web_url buttons`);\n }\n if (!isHttpsUrl(button.url)) {\n throw new TemplateValidationError(`${context}: url must be HTTPS for web_url buttons`);\n }\n break;\n\n case 'postback':\n if (!button.payload) {\n throw new TemplateValidationError(`${context}: payload is required for postback buttons`);\n }\n if (button.payload.length > TEMPLATE_LIMITS.POSTBACK_PAYLOAD_MAX_CHARS) {\n throw new TemplateValidationError(\n `${context}: payload cannot exceed ${TEMPLATE_LIMITS.POSTBACK_PAYLOAD_MAX_CHARS} characters`\n );\n }\n break;\n\n case 'phone_number':\n if (!button.payload) {\n throw new TemplateValidationError(`${context}: payload is required for phone_number buttons`);\n }\n // Basic phone number validation (starts with +)\n if (!button.payload.startsWith('+')) {\n throw new TemplateValidationError(\n `${context}: phone_number payload must start with + (e.g., +1234567890)`\n );\n }\n break;\n\n case 'game_play':\n // game_play buttons may have optional game_metadata\n break;\n\n case 'account_link':\n if (!button.url) {\n throw new TemplateValidationError(`${context}: url is required for account_link buttons`);\n }\n if (!isHttpsUrl(button.url)) {\n throw new TemplateValidationError(`${context}: url must be HTTPS for account_link buttons`);\n }\n break;\n\n case 'account_unlink':\n // account_unlink buttons don't require additional properties\n break;\n }\n\n // Validate webview properties for web_url buttons\n if (button.type === 'web_url' && button.messenger_extensions && button.fallback_url) {\n if (!isHttpsUrl(button.fallback_url)) {\n throw new TemplateValidationError(`${context}: fallback_url must be HTTPS`);\n }\n }\n}\n\nfunction isHttpsUrl(url: string): boolean {\n try {\n const parsedUrl = new URL(url);\n return parsedUrl.protocol === 'https:';\n } catch {\n return false;\n }\n}","import type { HTTPClient } from '../core/http-client.js';\nimport { API_ENDPOINTS } from '../core/constants.js';\nimport type { Recipient, SendMessageRequest, MessagingType } from '../types/messages.js';\nimport type { SendMessageResponse } from '../types/responses.js';\nimport { validateGenericTemplate, validateButtonTemplate, validateMediaTemplate } from '../utils/validators.js';\nimport type {\n GenericTemplatePayload,\n ButtonTemplatePayload,\n MediaTemplatePayload,\n ProductTemplatePayload,\n GenericTemplateElement,\n Button,\n MediaTemplateElement,\n ProductTemplateElement,\n} from '../types/templates.js';\n\nexport class TemplatesAPI {\n constructor(private httpClient: HTTPClient) {}\n\n async generic(options: {\n recipient: Recipient;\n elements: GenericTemplateElement[];\n messaging_type?: MessagingType;\n image_aspect_ratio?: 'horizontal' | 'square';\n notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';\n tag?: string;\n }): Promise<SendMessageResponse> {\n // Validate template\n validateGenericTemplate(options.elements);\n\n const payload: GenericTemplatePayload = {\n template_type: 'generic',\n elements: options.elements,\n image_aspect_ratio: options.image_aspect_ratio,\n };\n\n const request: SendMessageRequest = {\n recipient: options.recipient,\n messaging_type: options.messaging_type || 'UPDATE',\n message: {\n attachment: {\n type: 'template',\n payload,\n },\n },\n notification_type: options.notification_type,\n tag: options.tag,\n };\n\n return this.httpClient.request<SendMessageResponse>({\n method: 'POST',\n path: API_ENDPOINTS.MESSAGES,\n body: request,\n });\n }\n\n async button(options: {\n recipient: Recipient;\n text: string;\n buttons: Button[];\n messaging_type?: MessagingType;\n notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';\n tag?: string;\n }): Promise<SendMessageResponse> {\n // Validate template\n validateButtonTemplate(options.text, options.buttons);\n\n const payload: ButtonTemplatePayload = {\n template_type: 'button',\n text: options.text,\n buttons: options.buttons,\n };\n\n const request: SendMessageRequest = {\n recipient: options.recipient,\n messaging_type: options.messaging_type || 'UPDATE',\n message: {\n attachment: {\n type: 'template',\n payload,\n },\n },\n notification_type: options.notification_type,\n tag: options.tag,\n };\n\n return this.httpClient.request<SendMessageResponse>({\n method: 'POST',\n path: API_ENDPOINTS.MESSAGES,\n body: request,\n });\n }\n\n async media(options: {\n recipient: Recipient;\n element: MediaTemplateElement;\n messaging_type?: MessagingType;\n notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';\n tag?: string;\n }): Promise<SendMessageResponse> {\n // Validate template\n validateMediaTemplate(options.element);\n\n const payload: MediaTemplatePayload = {\n template_type: 'media',\n elements: [options.element],\n };\n\n const request: SendMessageRequest = {\n recipient: options.recipient,\n messaging_type: options.messaging_type || 'UPDATE',\n message: {\n attachment: {\n type: 'template',\n payload,\n },\n },\n notification_type: options.notification_type,\n tag: options.tag,\n };\n\n return this.httpClient.request<SendMessageResponse>({\n method: 'POST',\n path: API_ENDPOINTS.MESSAGES,\n body: request,\n });\n }\n\n async product(options: {\n recipient: Recipient;\n elements: ProductTemplateElement[];\n messaging_type?: MessagingType;\n notification_type?: 'REGULAR' | 'SILENT_PUSH' | 'NO_PUSH';\n tag?: string;\n }): Promise<SendMessageResponse> {\n const payload: ProductTemplatePayload = {\n template_type: 'product',\n elements: options.elements,\n };\n\n const request: SendMessageRequest = {\n recipient: options.recipient,\n messaging_type: options.messaging_type || 'UPDATE',\n message: {\n attachment: {\n type: 'template',\n payload,\n },\n },\n notification_type: options.notification_type,\n tag: options.tag,\n };\n\n return this.httpClient.request<SendMessageResponse>({\n method: 'POST',\n path: API_ENDPOINTS.MESSAGES,\n body: request,\n });\n }\n}","import { HTTPClient, type ClientConfig } from './core/http-client.js';\nimport { DEFAULT_API_VERSION } from './core/constants.js';\nimport { MessengerConfigError } from './core/errors.js';\nimport { SendAPI } from './resources/send.js';\nimport { AttachmentsAPI } from './resources/attachments.js';\nimport { ModerationAPI } from './resources/moderation.js';\nimport { TemplatesAPI } from './resources/templates.js';\n\nexport interface MessengerConfig {\n accessToken: string;\n version?: string;\n baseUrl?: string;\n timeout?: number;\n maxRetries?: number;\n}\n\nexport class Messenger {\n public readonly send: SendAPI;\n public readonly attachments: AttachmentsAPI;\n public readonly moderation: ModerationAPI;\n public readonly templates: TemplatesAPI;\n\n private readonly httpClient: HTTPClient;\n\n constructor(config: MessengerConfig) {\n this.validateConfig(config);\n\n const clientConfig: ClientConfig = {\n accessToken: config.accessToken,\n version: config.version || DEFAULT_API_VERSION,\n baseUrl: config.baseUrl,\n timeout: config.timeout,\n maxRetries: config.maxRetries,\n };\n\n this.httpClient = new HTTPClient(clientConfig);\n\n // Initialize API resources\n this.send = new SendAPI(this.httpClient);\n this.attachments = new AttachmentsAPI(this.httpClient);\n this.moderation = new ModerationAPI(this.httpClient);\n this.templates = new TemplatesAPI(this.httpClient);\n }\n\n private validateConfig(config: MessengerConfig): void {\n if (!config.accessToken) {\n throw new MessengerConfigError('Access token is required');\n }\n\n if (typeof config.accessToken !== 'string' || config.accessToken.trim() === '') {\n throw new MessengerConfigError('Access token must be a non-empty string');\n }\n\n if (config.version && typeof config.version !== 'string') {\n throw new MessengerConfigError('API version must be a string');\n }\n\n if (config.timeout && (typeof config.timeout !== 'number' || config.timeout <= 0)) {\n throw new MessengerConfigError('Timeout must be a positive number');\n }\n\n if (config.maxRetries && (typeof config.maxRetries !== 'number' || config.maxRetries < 0)) {\n throw new MessengerConfigError('Max retries must be a non-negative number');\n }\n }\n}"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@warriorteam/messenger-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "TypeScript SDK for Facebook Messenger Platform API",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsup",
|
|
21
|
+
"dev": "tsup --watch",
|
|
22
|
+
"test": "vitest",
|
|
23
|
+
"lint": "eslint src --ext .ts",
|
|
24
|
+
"format": "prettier --write src/**/*.ts"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"facebook",
|
|
28
|
+
"messenger",
|
|
29
|
+
"sdk",
|
|
30
|
+
"api",
|
|
31
|
+
"typescript",
|
|
32
|
+
"chatbot",
|
|
33
|
+
"messaging"
|
|
34
|
+
],
|
|
35
|
+
"author": "RedAI",
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "https://github.com/warriorteam/messenger-sdk"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://github.com/warriorteam/messenger-sdk#readme",
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/warriorteam/messenger-sdk/issues"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=18.0.0"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "^24.1.0",
|
|
50
|
+
"@typescript-eslint/eslint-plugin": "^8.38.0",
|
|
51
|
+
"@typescript-eslint/parser": "^8.38.0",
|
|
52
|
+
"eslint": "^9.32.0",
|
|
53
|
+
"prettier": "^3.6.2",
|
|
54
|
+
"tsup": "^8.5.0",
|
|
55
|
+
"typescript": "^5.8.3",
|
|
56
|
+
"vitest": "^3.2.4"
|
|
57
|
+
}
|
|
58
|
+
}
|