@natyapp/meta 1.6.6 → 1.6.7

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 CHANGED
@@ -1,68 +1,420 @@
1
- # SDK MICROSSERVIÇO SECRETARIA NATY / META
1
+ # @natyapp/meta
2
2
 
3
- ## `_UNDER DEVELOPMENT_`
3
+ A TypeScript SDK for integrating with Meta's WhatsApp Business API, providing a simple and elegant way to send messages, handle webhooks, and manage WhatsApp business communications.
4
4
 
5
- <!-- `(Will not work until March, please wait the Release)` -->
5
+ ## Features
6
6
 
7
- <!-- ## HOW WILL WORK -->
7
+ - 🚀 **Easy Integration** - Simple setup with your Meta app token
8
+ - 📱 **Rich Messaging** - Send text, images, documents, buttons, lists, and more
9
+ - 🎯 **Interactive Elements** - Support for buttons, menus, and quick replies
10
+ - 📍 **Location & Contacts** - Send location and contact information
11
+ - 🔔 **Webhook Support** - Handle incoming messages and events
12
+ - 📊 **Logging & Monitoring** - Built-in logging capabilities
13
+ - 🛡️ **Type Safety** - Full TypeScript support with type definitions
14
+ - ⚡ **Modern Architecture** - Built with async/await and promises
8
15
 
9
- ### First we will import and Initialize the sdk package
16
+ ## Installation
10
17
 
11
- #### 1. importing the package
18
+ ```bash
19
+ npm install @natyapp/meta
20
+ ```
21
+
22
+ ```bash
23
+ yarn add @natyapp/meta
24
+ ```
25
+
26
+ ```bash
27
+ pnpm add @natyapp/meta
28
+ ```
29
+
30
+ ## Quick Start
31
+
32
+ ### 1. Import the SDK
33
+
34
+ ```typescript
35
+ import NatyMeta, { WhatsappResponse } from '@natyapp/meta';
36
+ ```
37
+
38
+ ### 2. Environment Configuration
39
+
40
+ Set the API URL in your environment variables:
41
+
42
+ ```bash
43
+ API_META=https://api.meta.naty.app
44
+ ```
45
+
46
+ ### 3. Initialize the SDK
47
+
48
+ ```typescript
49
+ // Initialize without token
50
+ const sdk = new NatyMeta();
51
+
52
+ // Or initialize with token directly
53
+ const sdk = new NatyMeta('YOUR_APP_TOKEN');
54
+ ```
55
+
56
+ ### 4. Connect to the API
57
+
58
+ ```typescript
59
+ const connectResult = await sdk.connect({
60
+ appToken: 'YOUR_APP_TOKEN'
61
+ });
62
+
63
+ if (connectResult.isError) {
64
+ throw new Error(connectResult.isError.message);
65
+ }
66
+
67
+ console.log('Connected successfully:', connectResult.isSuccess);
68
+ ```
69
+
70
+ ## Usage Examples
71
+
72
+ ### Sending Messages
73
+
74
+ #### Text Message
75
+
76
+ ```typescript
77
+ import { Message } from '@natyapp/meta';
78
+
79
+ const message = new Message('PHONE_NUMBER', 'MESSAGE_ID', 'ACCESS_TOKEN');
80
+
81
+ // Send a simple text message
82
+ const response = await message.send_text_message('Hello, World!');
83
+ ```
84
+
85
+ #### Button Message
86
+
87
+ ```typescript
88
+ import { Button } from '@natyapp/meta';
89
+
90
+ const button = new Button({
91
+ type: 'button',
92
+ body: 'Choose an option:',
93
+ buttons: [
94
+ {
95
+ id: 'option1',
96
+ title: 'Option 1'
97
+ },
98
+ {
99
+ id: 'option2',
100
+ title: 'Option 2'
101
+ }
102
+ ]
103
+ });
104
+
105
+ const response = await message.send_button(button);
106
+ ```
107
+
108
+ #### List Message
109
+
110
+ ```typescript
111
+ import { List } from '@natyapp/meta';
112
+
113
+ const list = new List({
114
+ header: 'Our Services',
115
+ body: 'Please select a service:',
116
+ footer: 'Thank you for choosing us!',
117
+ button: 'View Services',
118
+ sections: [
119
+ {
120
+ title: 'Main Services',
121
+ rows: [
122
+ {
123
+ id: 'service1',
124
+ title: 'Web Development',
125
+ description: 'Custom web applications'
126
+ },
127
+ {
128
+ id: 'service2',
129
+ title: 'Mobile Apps',
130
+ description: 'iOS and Android applications'
131
+ }
132
+ ]
133
+ }
134
+ ]
135
+ });
136
+
137
+ const response = await message.send_list(list);
138
+ ```
139
+
140
+ #### Document Message
141
+
142
+ ```typescript
143
+ // Send document from URL
144
+ const response = await message.send_document(
145
+ 'https://example.com/document.pdf',
146
+ 'application/pdf',
147
+ {
148
+ fileName: 'report.pdf',
149
+ description: 'Monthly report'
150
+ }
151
+ );
152
+
153
+ // Send document from base64
154
+ const response = await message.send_document(
155
+ 'base64EncodedString',
156
+ 'application/pdf',
157
+ {
158
+ fileName: 'document.pdf',
159
+ description: 'Important document'
160
+ }
161
+ );
162
+ ```
163
+
164
+ #### Image Message
165
+
166
+ ```typescript
167
+ // Send image from URL
168
+ const response = await message.send_image('https://example.com/image.jpg');
169
+
170
+ // Send image from base64
171
+ const response = await message.send_image('base64EncodedString');
172
+ ```
173
+
174
+ #### Location Message
175
+
176
+ ```typescript
177
+ const response = await message.send_location({
178
+ lat: -23.5505,
179
+ long: -46.6333,
180
+ name: 'São Paulo',
181
+ address: 'São Paulo, Brazil'
182
+ });
183
+ ```
184
+
185
+ #### Contact Message
12
186
 
13
- ```ts
14
- import SDKMeta from "NatyMeta"
187
+ ```typescript
188
+ const contacts = [
189
+ {
190
+ name: {
191
+ first_name: 'John',
192
+ last_name: 'Doe'
193
+ },
194
+ phones: [
195
+ {
196
+ phone: '+1234567890',
197
+ type: 'WORK'
198
+ }
199
+ ],
200
+ emails: [
201
+ {
202
+ email: 'john.doe@example.com',
203
+ type: 'WORK'
204
+ }
205
+ ]
206
+ }
207
+ ];
208
+
209
+ const response = await message.send_contacts(contacts);
210
+ ```
211
+
212
+ ### Message Reactions and Status
213
+
214
+ #### React to Message
215
+
216
+ ```typescript
217
+ // Send thumbs up reaction
218
+ const response = await message.send_reaction('👍');
219
+
220
+ // Send custom emoji
221
+ const response = await message.send_reaction('😊');
222
+ ```
223
+
224
+ #### Mark as Read
225
+
226
+ ```typescript
227
+ const success = await message.mark_as_read();
228
+ ```
229
+
230
+ #### Reply to Message
231
+
232
+ ```typescript
233
+ // Reply with text
234
+ const response = await message.reply({
235
+ type: 'text',
236
+ toReply: 'This is a reply message',
237
+ messageToReply: 'ORIGINAL_MESSAGE_ID'
238
+ });
239
+
240
+ // Reply with interactive element
241
+ const response = await message.reply({
242
+ type: 'interactive',
243
+ toReply: buttonObject,
244
+ messageToReply: 'ORIGINAL_MESSAGE_ID'
245
+ });
15
246
  ```
16
247
 
17
- #### 2. set environment variable
248
+ ### Webhook Handling
249
+
250
+ ```typescript
251
+ import { Webhook } from '@natyapp/meta';
18
252
 
19
- The API URL for the integration with the Meta API. The default value is `https://api.meta.naty.app`
253
+ // Initialize webhook handler
254
+ const webhook = new Webhook();
255
+
256
+ // Listen for incoming messages
257
+ sdk.on('message', (response: WhatsappResponse) => {
258
+ console.log('Received message:', response);
259
+
260
+ // Send automatic reply
261
+ response.send_text_message('Thank you for your message!');
262
+ });
263
+
264
+ // Setup webhook endpoint (if using Express)
265
+ import express from 'express';
266
+ const app = express();
267
+
268
+ app.use('/webhook', webhook.getRouter());
269
+ ```
20
270
 
21
- ```text
22
- API_META=https://api.meta.naty.app
23
- ```
271
+ ### Media Handling
24
272
 
25
- #### 3. initialize the class
273
+ ```typescript
274
+ // Get media URL from media ID
275
+ const mediaData = await message.get_media_url('MEDIA_ID');
276
+ console.log('Media URL:', mediaData.url);
26
277
 
27
- ```ts
28
- const SDK = new NatyMeta()
29
- // you can use new sdk(`YOUR-APP-TOKEN`) to connect right on the class creation
278
+ // Create media from file
279
+ const mediaId = await message.createMedia(
280
+ 'base64EncodedContent',
281
+ 'image/jpeg'
282
+ );
30
283
  ```
31
284
 
32
- #### 4. connect your app token (if you dont use your token on class creation)
285
+ ### Connection Management
33
286
 
34
- ```ts
35
- const connectSDK = await SDK.connect( {apptoken: { `YOUR-APP-TOKEN` } } )
287
+ ```typescript
288
+ import { Connection } from '@natyapp/meta';
36
289
 
37
- if(connectSDK.isError) throw new Error(connectSDK.isError.message)
290
+ // Create new connection
291
+ const connection = new Connection();
38
292
 
39
- console.log(connectSDK.isSuccess)
40
- // Do what you need with the data... (connectSDK.isSuccess)
293
+ // Check connection status
294
+ const status = await connection.getStatus();
295
+
296
+ // Update connection settings
297
+ const updated = await connection.updateSettings({
298
+ webhookUrl: 'https://your-domain.com/webhook',
299
+ verifyToken: 'your-verify-token'
300
+ });
41
301
  ```
42
302
 
43
- #### 5. connect your app token (if you dont use your token on class creation)
303
+ ### Logging
304
+
305
+ ```typescript
306
+ import { Log } from '@natyapp/meta';
307
+
308
+ const logger = new Log();
44
309
 
45
- ```ts
46
- SDK.on('message', (res) => {
47
- res.sendTextMessage("teste");
310
+ // Log message activity
311
+ await logger.logMessage({
312
+ messageId: 'MESSAGE_ID',
313
+ phoneNumber: 'PHONE_NUMBER',
314
+ content: 'Message content',
315
+ type: 'outbound'
316
+ });
317
+
318
+ // Get message logs
319
+ const logs = await logger.getMessageLogs({
320
+ phoneNumber: 'PHONE_NUMBER',
321
+ startDate: new Date('2024-01-01'),
322
+ endDate: new Date('2024-12-31')
48
323
  });
49
324
  ```
50
325
 
51
- #### 6. than set your application context to use all the individual classes
326
+ ## Error Handling
327
+
328
+ The SDK uses a consistent error handling pattern:
329
+
330
+ ```typescript
331
+ const result = await sdk.someMethod();
332
+
333
+ if (result.isError) {
334
+ console.error('Error occurred:', result.isError.message);
335
+ // Handle error appropriately
336
+ return;
337
+ }
338
+
339
+ // Success case
340
+ console.log('Success:', result.isSuccess);
341
+ ```
342
+
343
+ ## TypeScript Support
344
+
345
+ The SDK is written in TypeScript and provides full type definitions:
346
+
347
+ ```typescript
348
+ import {
349
+ WhatsappResponse,
350
+ ISendMessageReturn,
351
+ ConnectProps,
352
+ Button,
353
+ List
354
+ } from '@natyapp/meta';
355
+
356
+ // All types are available for import
357
+ ```
358
+
359
+ ## Configuration
360
+
361
+ ### Environment Variables
362
+
363
+ | Variable | Description | Default |
364
+ |----------|-------------|---------|
365
+ | `API_META` | Meta API base URL | `https://api.meta.naty.app` |
366
+
367
+ ### Initialization Options
368
+
369
+ ```typescript
370
+ interface ConnectProps {
371
+ appToken: string;
372
+ pathname?: string; // Custom webhook path
373
+ app?: Express; // Express app instance
374
+ }
375
+ ```
376
+
377
+ ## API Reference
378
+
379
+ ### Classes
380
+
381
+ - **NatyMeta** - Main SDK class
382
+ - **Message** - Handle message operations
383
+ - **Webhook** - Webhook management
384
+ - **Connection** - Connection management
385
+ - **Log** - Logging functionality
386
+ - **WhatsappResponse** - Response handler
387
+
388
+ ### Elements
389
+
390
+ - **Button** - Interactive buttons
391
+ - **List** - List messages
392
+ - **Text** - Text messages
393
+ - **Image** - Image messages
394
+
395
+ ## Requirements
396
+
397
+ - Node.js >= 14
398
+ - TypeScript >= 4.9 (for development)
399
+
400
+ ## Contributing
401
+
402
+ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
403
+
404
+ ## License
405
+
406
+ ISC License - see [LICENSE](LICENSE) file for details.
407
+
408
+ ## Support
52
409
 
53
- #### In this example
410
+ - 📧 **Email**: <support@naty.app>
411
+ - 🐛 **Issues**: [GitHub Issues](https://github.com/your-org/sdk-meta/issues)
412
+ - 📚 **Documentation**: [Full Documentation](https://docs.naty.app)
54
413
 
55
- - Retun of any Promise is {isSuccess:AuthReturnType, isError:ErrorHandlingType}
56
- - If successed method (like the SDK.connect example too),
57
- the sdk will abstract and will handle properly with the token for you,
58
- the token will be automatic joined into axios instance header
59
- - ErrorHandling type { code: number, message: string | Object }
60
- - On the exemple, we are using "throw new Error" on every ErrorHandling to
61
- stop and handle it on a simple way, but u can work at your way like
62
- returning an alert using some alert lib like toastfy for the user.
414
+ ## Authors
63
415
 
64
- <!-- ## Click on [NatyMeta](https://whatsapp.secretarianaty.com) for more information. -->
416
+ - **IkiraDev** - *Initial work*
65
417
 
66
- ##### (The link will be avalible soon)
418
+ ---
67
419
 
68
- ###### All Rights Reserved for Ikiradev
420
+ Made with ❤️ by the Naty team
@@ -2,3 +2,4 @@ export * from "./button";
2
2
  export * from "./list";
3
3
  export * from "./text";
4
4
  export * from "./textTemplate";
5
+ export * from "./mediaTemplate";
@@ -18,3 +18,4 @@ __exportStar(require("./button"), exports);
18
18
  __exportStar(require("./list"), exports);
19
19
  __exportStar(require("./text"), exports);
20
20
  __exportStar(require("./textTemplate"), exports);
21
+ __exportStar(require("./mediaTemplate"), exports);
@@ -0,0 +1,45 @@
1
+ export declare class MediaTemplate {
2
+ messaging_product: string;
3
+ recipient_type: string;
4
+ to: string;
5
+ type: string;
6
+ template: {
7
+ name: string;
8
+ language: {
9
+ code: string;
10
+ };
11
+ components: Array<{
12
+ type: string;
13
+ parameters: Array<{
14
+ type: string;
15
+ image?: {
16
+ link: string;
17
+ };
18
+ video?: {
19
+ link: string;
20
+ };
21
+ document?: {
22
+ link: string;
23
+ filename?: string;
24
+ };
25
+ text: string;
26
+ }>;
27
+ }>;
28
+ };
29
+ constructor({ template, language, to, header, bodyParameters }: {
30
+ template: string;
31
+ to: string;
32
+ language: string;
33
+ header?: {
34
+ type: "image" | "video" | "document";
35
+ media: {
36
+ link: string;
37
+ filename?: string;
38
+ };
39
+ };
40
+ bodyParameters?: Array<{
41
+ type: string;
42
+ text: string;
43
+ }>;
44
+ });
45
+ }
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MediaTemplate = void 0;
4
+ class MediaTemplate {
5
+ constructor({ template, language, to, header, bodyParameters }) {
6
+ this.messaging_product = "whatsapp";
7
+ this.recipient_type = "individual";
8
+ this.to = to;
9
+ this.type = "template";
10
+ const components = [];
11
+ if (header) {
12
+ const headerParam = {
13
+ type: header.type
14
+ };
15
+ if (header.type === "image") {
16
+ headerParam.image = { link: header.media.link };
17
+ }
18
+ else if (header.type === "video") {
19
+ headerParam.video = { link: header.media.link };
20
+ }
21
+ else if (header.type === "document") {
22
+ headerParam.document = Object.assign({ link: header.media.link }, (header.media.filename && { filename: header.media.filename }));
23
+ }
24
+ components.push({
25
+ type: "header",
26
+ parameters: [headerParam]
27
+ });
28
+ }
29
+ if (bodyParameters && bodyParameters.length > 0) {
30
+ components.push({
31
+ type: "body",
32
+ parameters: bodyParameters.map(param => ({
33
+ type: param.type,
34
+ text: param.text
35
+ }))
36
+ });
37
+ }
38
+ this.template = {
39
+ name: template,
40
+ language: {
41
+ code: language,
42
+ },
43
+ components
44
+ };
45
+ }
46
+ }
47
+ exports.MediaTemplate = MediaTemplate;
@@ -8,10 +8,21 @@ export declare class TextTemplate {
8
8
  language: {
9
9
  code: string;
10
10
  };
11
+ components?: Array<{
12
+ type: string;
13
+ parameters: Array<{
14
+ type: string;
15
+ text: string;
16
+ }>;
17
+ }>;
11
18
  };
12
- constructor({ template, language, to }: {
19
+ constructor({ template, language, to, bodyParameters }: {
13
20
  template: string;
14
21
  to: string;
15
22
  language: string;
23
+ bodyParameters?: Array<{
24
+ type: string;
25
+ text: string;
26
+ }>;
16
27
  });
17
28
  }
@@ -2,17 +2,24 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TextTemplate = void 0;
4
4
  class TextTemplate {
5
- constructor({ template, language, to }) {
5
+ constructor({ template, language, to, bodyParameters }) {
6
6
  this.messaging_product = "whatsapp";
7
7
  this.recipient_type = "individual";
8
8
  this.to = to;
9
9
  this.type = "template";
10
- this.template = {
11
- name: template,
12
- language: {
10
+ const components = [];
11
+ if (bodyParameters && bodyParameters.length > 0) {
12
+ components.push({
13
+ type: "body",
14
+ parameters: bodyParameters.map(param => ({
15
+ type: param.type,
16
+ text: param.text
17
+ }))
18
+ });
19
+ }
20
+ this.template = Object.assign({ name: template, language: {
13
21
  code: language,
14
- },
15
- };
22
+ } }, (components.length > 0 && { components }));
16
23
  }
17
24
  }
18
25
  exports.TextTemplate = TextTemplate;
@@ -60,5 +60,21 @@ export declare class WhatsappResponse {
60
60
  download_media(url: string, mimetype: string): Promise<any>;
61
61
  get_media_url(media_id: string): Promise<any>;
62
62
  update_long_lived_token(client_id: string, client_secret: string, fb_exchange_token: string): Promise<string | undefined>;
63
- send_template_text_message(template: string, language: string): Promise<ISendMessageReturn | null>;
63
+ send_template_text_message(template: string, language: string, bodyParameters?: Array<{
64
+ type: string;
65
+ text: string;
66
+ }>): Promise<ISendMessageReturn | null>;
67
+ send_template_media_message(template: string, language: string, options: {
68
+ header?: {
69
+ type: "image" | "video" | "document";
70
+ media: {
71
+ link: string;
72
+ filename?: string;
73
+ };
74
+ };
75
+ bodyParameters?: Array<{
76
+ type: string;
77
+ text: string;
78
+ }>;
79
+ }): Promise<ISendMessageReturn | null>;
64
80
  }
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.WhatsappResponse = void 0;
7
7
  const axios_1 = __importDefault(require("axios"));
8
8
  const elements_1 = require("../../elements");
9
+ const mediaTemplate_1 = require("../../elements/mediaTemplate");
9
10
  const text_1 = require("../../elements/text");
10
11
  const services_1 = require("../../services");
11
12
  const parseError_1 = require("../../utils/parseError");
@@ -400,7 +401,7 @@ class WhatsappResponse {
400
401
  return undefined;
401
402
  }
402
403
  }
403
- async send_template_text_message(template, language) {
404
+ async send_template_text_message(template, language, bodyParameters) {
404
405
  try {
405
406
  if (!this.apiCall)
406
407
  await this.getApiInstanceToken();
@@ -408,11 +409,31 @@ class WhatsappResponse {
408
409
  to: this.clientNumber,
409
410
  template: template,
410
411
  language: language,
412
+ bodyParameters: bodyParameters,
411
413
  }));
412
414
  }
413
415
  catch (err) {
414
416
  return (0, parseError_1.throwParsedError)(err, "Não foi possível criar mensagem de texto");
415
417
  }
416
418
  }
419
+ async send_template_media_message(template, language, options) {
420
+ try {
421
+ if (!this.apiCall)
422
+ await this.getApiInstanceToken();
423
+ if (options.header && !options.header.media.link) {
424
+ throw new Error("É necessário fornecer 'link' para a mídia do template");
425
+ }
426
+ return await this.apiCall.post("/messages", new mediaTemplate_1.MediaTemplate({
427
+ to: this.clientNumber,
428
+ template: template,
429
+ language: language,
430
+ header: options.header,
431
+ bodyParameters: options.bodyParameters,
432
+ }));
433
+ }
434
+ catch (err) {
435
+ return (0, parseError_1.throwParsedError)(err, "Não foi possível criar template com mídia");
436
+ }
437
+ }
417
438
  }
418
439
  exports.WhatsappResponse = WhatsappResponse;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@natyapp/meta",
3
- "version": "1.6.6",
3
+ "version": "1.6.7",
4
4
  "description": "",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",