meta-cloud-api 0.0.3 → 0.0.4

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.
Files changed (43) hide show
  1. package/README.md +216 -0
  2. package/package.json +2 -2
  3. package/src/api/base.ts +0 -19
  4. package/src/api/encryption.ts +0 -34
  5. package/src/api/flow.ts +0 -253
  6. package/src/api/index.ts +0 -24
  7. package/src/api/media.ts +0 -52
  8. package/src/api/messages.ts +0 -160
  9. package/src/api/phoneNumber.ts +0 -59
  10. package/src/api/qrCode.ts +0 -64
  11. package/src/api/registration.ts +0 -38
  12. package/src/api/template.ts +0 -70
  13. package/src/api/twoStepVerification.ts +0 -24
  14. package/src/api/waba.ts +0 -55
  15. package/src/httpsClient.ts +0 -83
  16. package/src/index.ts +0 -3
  17. package/src/request.ts +0 -104
  18. package/src/types/base.ts +0 -5
  19. package/src/types/config.ts +0 -68
  20. package/src/types/encryption.ts +0 -11
  21. package/src/types/enums.ts +0 -563
  22. package/src/types/flow.ts +0 -274
  23. package/src/types/httpsClient.ts +0 -28
  24. package/src/types/index.ts +0 -16
  25. package/src/types/logger.ts +0 -7
  26. package/src/types/media.ts +0 -31
  27. package/src/types/messages.ts +0 -453
  28. package/src/types/phoneNumber.ts +0 -111
  29. package/src/types/qrCode.ts +0 -30
  30. package/src/types/registration.ts +0 -17
  31. package/src/types/request.ts +0 -66
  32. package/src/types/template.ts +0 -134
  33. package/src/types/twoStepVerification.ts +0 -9
  34. package/src/types/waba.ts +0 -18
  35. package/src/types/whatsapp.ts +0 -31
  36. package/src/utils/.gitkeep +0 -0
  37. package/src/utils/generateXHub256Sig.ts +0 -5
  38. package/src/utils/importConfig.ts +0 -55
  39. package/src/utils/index.ts +0 -2
  40. package/src/utils/isMetaError.ts +0 -44
  41. package/src/utils/logger.ts +0 -46
  42. package/src/utils/objectToQueryString.ts +0 -16
  43. package/src/whatsapp.ts +0 -96
package/README.md ADDED
@@ -0,0 +1,216 @@
1
+ # Meta Cloud API
2
+
3
+ A TypeScript SDK for the Meta Cloud API that provides a clean, strongly-typed interface for interacting with WhatsApp's Cloud API and other Meta platform services.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/meta-cloud-api.svg)](https://www.npmjs.com/package/meta-cloud-api)
6
+ [![npm downloads](https://img.shields.io/npm/dm/meta-cloud-api.svg)](https://www.npmjs.com/package/meta-cloud-api)
7
+ [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/froggy1014/meta-cloud-api/blob/main/LICENSE)
8
+
9
+ ## Features
10
+
11
+ - **Strongly Typed**: Full TypeScript support with comprehensive type definitions
12
+ - **Modular Design**: API components are organized logically for ease of use
13
+ - **Error Handling**: Standardized error handling for Meta API responses
14
+ - **Complete API Coverage**: Support for all WhatsApp Cloud API functionality
15
+ - Messages API (text, templates, media, interactive, etc.)
16
+ - Templates API
17
+ - Media API
18
+ - Phone Number API
19
+ - Flow API
20
+ - QR Code API
21
+ - Registration API
22
+ - WABA (WhatsApp Business Account) API
23
+ - Two-Step Verification API
24
+ - Encryption API
25
+
26
+ ## Installation
27
+
28
+ ```bash
29
+ npm install meta-cloud-api
30
+ # or
31
+ yarn add meta-cloud-api
32
+ # or
33
+ pnpm add meta-cloud-api
34
+ ```
35
+
36
+ ## Quick Start
37
+
38
+ ```typescript
39
+ import WhatsApp from 'meta-cloud-api';
40
+
41
+ // Initialize with configuration object
42
+ const whatsapp = new WhatsApp({
43
+ phoneNumberId: YOUR_PHONE_NUMBER_ID,
44
+ accessToken: 'YOUR_ACCESS_TOKEN'
45
+ });
46
+
47
+ // You can also use environment variables (.env file)
48
+ // const whatsapp = new WhatsApp();
49
+
50
+ // Send a text message
51
+ async function sendMessage() {
52
+ try {
53
+ const response = await whatsapp.messages.text(
54
+ { body: "Hello from Meta Cloud API!" },
55
+ 15551234567
56
+ );
57
+ console.log(`Message sent successfully with ID: ${response.messages[0].id}`);
58
+ } catch (error) {
59
+ console.error('Error sending message:', error);
60
+ }
61
+ }
62
+ ```
63
+
64
+ ## Environment Variables
65
+
66
+ Create a `.env` file with your WhatsApp Cloud API credentials:
67
+
68
+ ```
69
+ WA_BASE_URL=graph.facebook.com
70
+ M4D_APP_ID=your_app_id
71
+ M4D_APP_SECRET=your_app_secret
72
+ WA_PHONE_NUMBER_ID=your_phone_number_id
73
+ WA_BUSINESS_ACCOUNT_ID=your_business_account_id
74
+ CLOUD_API_ACCESS_TOKEN=your_access_token
75
+ CLOUD_API_VERSION=17.0
76
+ ```
77
+
78
+ ## API Documentation
79
+
80
+ ### Messages API
81
+
82
+ Send various types of WhatsApp messages:
83
+
84
+ ```typescript
85
+ // Text message
86
+ await whatsapp.messages.text(
87
+ { body: "Hello world!" },
88
+ 15551234567
89
+ );
90
+
91
+ // Image message
92
+ await whatsapp.messages.image(
93
+ { link: "https://example.com/image.jpg" },
94
+ 15551234567
95
+ );
96
+
97
+ // Document message
98
+ await whatsapp.messages.document(
99
+ {
100
+ link: "https://example.com/document.pdf",
101
+ filename: "Important Document.pdf"
102
+ },
103
+ 15551234567
104
+ );
105
+
106
+ // Template message
107
+ await whatsapp.messages.template(
108
+ {
109
+ name: "sample_shipping_confirmation",
110
+ language: { code: "en_US" },
111
+ components: [
112
+ {
113
+ type: "body",
114
+ parameters: [
115
+ { type: "text", text: "John" },
116
+ { type: "text", text: "12345" }
117
+ ]
118
+ }
119
+ ]
120
+ },
121
+ 15551234567
122
+ );
123
+
124
+ // Interactive message with buttons
125
+ await whatsapp.messages.interactive(
126
+ {
127
+ type: "button",
128
+ body: { text: "Please select an option:" },
129
+ action: {
130
+ buttons: [
131
+ { type: "reply", reply: { id: "btn1", title: "Option 1" } },
132
+ { type: "reply", reply: { id: "btn2", title: "Option 2" } }
133
+ ]
134
+ }
135
+ },
136
+ 15551234567
137
+ );
138
+ ```
139
+
140
+ ### Templates API
141
+
142
+ Work with message templates:
143
+
144
+ ```typescript
145
+ // Get all templates
146
+ const templates = await whatsapp.template.getTemplates({
147
+ limit: 20
148
+ });
149
+
150
+ // Create a new template
151
+ await whatsapp.template.createTemplate({
152
+ name: "my_template",
153
+ category: "MARKETING",
154
+ language: "en_US",
155
+ components: [
156
+ {
157
+ type: "HEADER",
158
+ format: "TEXT",
159
+ text: "Special Offer"
160
+ },
161
+ {
162
+ type: "BODY",
163
+ text: "Hi {{1}}, check out our latest offer: {{2}}!"
164
+ }
165
+ ]
166
+ });
167
+ ```
168
+
169
+ ### Media API
170
+
171
+ Handle media files:
172
+
173
+ ```typescript
174
+ // Upload media
175
+ const mediaResponse = await whatsapp.media.uploadMedia(
176
+ new File(['...'], 'image.jpg', { type: 'image/jpeg' })
177
+ );
178
+
179
+ // Get media details
180
+ const mediaDetails = await whatsapp.media.getMediaById(mediaResponse.id);
181
+
182
+ // Delete media
183
+ await whatsapp.media.deleteMedia(mediaResponse.id);
184
+ ```
185
+
186
+ ## Error Handling
187
+
188
+ The package provides standard error handling for Meta API responses:
189
+
190
+ ```typescript
191
+ try {
192
+ await whatsapp.messages.text(
193
+ { body: "Hello world!" },
194
+ 15551234567
195
+ );
196
+ } catch (error) {
197
+ if (error.name === 'MetaError') {
198
+ console.error(`Meta API Error: ${error.error.message}`);
199
+ console.error(`Error Code: ${error.error.code}`);
200
+
201
+ if (error.error.error_data) {
202
+ console.error(`Details: ${error.error.error_data.details}`);
203
+ }
204
+ } else {
205
+ console.error('Unexpected error:', error);
206
+ }
207
+ }
208
+ ```
209
+
210
+ ## License
211
+
212
+ This project is licensed under the MIT License - see the [LICENSE](https://github.com/froggy1014/meta-cloud-api/blob/main/LICENSE) file for details.
213
+
214
+ ## Contributing
215
+
216
+ Contributions welcome! Please feel free to submit a Pull Request.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "meta-cloud-api",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "TypeScript SDK for WhatsApp Cloud API - simplified integration with Meta's WhatsApp Business Platform",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "files": [
34
34
  "dist",
35
- "src"
35
+ "README.md"
36
36
  ],
37
37
  "engines": {
38
38
  "node": ">=20"
package/src/api/base.ts DELETED
@@ -1,19 +0,0 @@
1
- import Logger from '../utils/logger';
2
- import type { BaseClass } from '../types/base';
3
- import type { WabaConfigType } from '../types/config';
4
- import type { RequesterClass } from '../types/request';
5
-
6
- const LIB_NAME = 'BaseAPI';
7
- const LOG_LOCAL = false;
8
- const LOGGER = new Logger(LIB_NAME, process.env.DEBUG === 'true' || LOG_LOCAL);
9
-
10
- export default class BaseAPI implements BaseClass {
11
- protected config: WabaConfigType;
12
- protected client: RequesterClass;
13
-
14
- constructor(config: WabaConfigType, client: RequesterClass) {
15
- this.config = config;
16
- this.client = client;
17
- LOGGER.log('Initialized with HTTPSClient');
18
- }
19
- }
@@ -1,34 +0,0 @@
1
- import { HttpMethodsEnum, WabaConfigEnum } from '../types/enums';
2
- import type { WabaConfigType } from '../types/config';
3
- import type { RequesterClass, RequesterResponseInterface, ResponseSuccess } from '../types/request';
4
- import BaseAPI from './base';
5
- import type { EncryptionClass, EncryptionPublicKeyResponse } from '../types/encryption';
6
-
7
- export default class EncryptionAPI extends BaseAPI implements EncryptionClass {
8
- private readonly endpoint = 'whatsapp_business_encryption';
9
-
10
- constructor(config: WabaConfigType, client: RequesterClass) {
11
- super(config, client);
12
- }
13
-
14
- async getEncryptionPublicKey(): Promise<RequesterResponseInterface<EncryptionPublicKeyResponse>> {
15
- return this.client.sendRequest(
16
- HttpMethodsEnum.Get,
17
- `${this.config[WabaConfigEnum.PhoneNumberId]}/${this.endpoint}`,
18
- this.config[WabaConfigEnum.RequestTimeout],
19
- null,
20
- );
21
- }
22
-
23
- async setEncryptionPublicKey(businessPublicKey: string): Promise<RequesterResponseInterface<ResponseSuccess>> {
24
- const formData = new FormData();
25
- formData.append('business_public_key', businessPublicKey);
26
-
27
- return this.client.sendRequest(
28
- HttpMethodsEnum.Post,
29
- `${this.config[WabaConfigEnum.PhoneNumberId]}/${this.endpoint}`,
30
- this.config[WabaConfigEnum.RequestTimeout],
31
- formData,
32
- );
33
- }
34
- }
package/src/api/flow.ts DELETED
@@ -1,253 +0,0 @@
1
- import BaseAPI from './base';
2
- import { WabaConfigType } from '../types/config';
3
- import { HttpMethodsEnum, WabaConfigEnum } from '../types/enums';
4
- import { RequesterClass, RequesterResponseInterface, ResponseSuccess } from '../types/request';
5
- import {
6
- FlowClass,
7
- FlowsListResponse,
8
- FlowCategoryEnum,
9
- Flow,
10
- FlowPreviewResponse,
11
- FlowAssetsResponse,
12
- FlowValidationError,
13
- FlowMigrationResponse,
14
- } from '../types/flow';
15
- import Logger from '../utils/logger';
16
-
17
- const LIB_NAME = 'FlowAPI';
18
- const LOG_LOCAL = false;
19
- const LOGGER = new Logger(LIB_NAME, process.env.DEBUG === 'true' || LOG_LOCAL);
20
-
21
- export default class FlowAPI extends BaseAPI implements FlowClass {
22
- constructor(config: WabaConfigType, client: RequesterClass) {
23
- super(config, client);
24
- LOGGER.log('FlowAPI initialized');
25
- }
26
-
27
- /**
28
- * List Flows
29
- *
30
- * @param wabaId - The WABA ID
31
- * @returns Promise with the list of flows
32
- */
33
- async listFlows(wabaId: string): Promise<RequesterResponseInterface<FlowsListResponse>> {
34
- return this.client.sendRequest(
35
- HttpMethodsEnum.Get,
36
- `/${wabaId}/flows`,
37
- this.config[WabaConfigEnum.RequestTimeout],
38
- null,
39
- );
40
- }
41
-
42
- /**
43
- * Create Flow
44
- *
45
- * @param wabaId - The WABA ID
46
- * @param data - The flow data including name, categories, endpoint_uri, and optional clone_flow_id
47
- * @returns Promise with the created flow ID
48
- */
49
- async createFlow(
50
- wabaId: string,
51
- data: {
52
- name: string;
53
- categories?: FlowCategoryEnum[];
54
- endpoint_uri?: string;
55
- clone_flow_id?: string;
56
- flow_json?: string;
57
- publish?: boolean;
58
- },
59
- ): Promise<
60
- RequesterResponseInterface<{ id: string; success: boolean; validation_errors?: FlowValidationError[] }>
61
- > {
62
- const formData = new FormData();
63
-
64
- if (data.name) formData.append('name', data.name);
65
- if (data.categories) formData.append('categories', JSON.stringify(data.categories));
66
- if (data.endpoint_uri) formData.append('endpoint_uri', data.endpoint_uri);
67
- if (data.clone_flow_id) formData.append('clone_flow_id', data.clone_flow_id);
68
- if (data.flow_json) formData.append('flow_json', data.flow_json);
69
- if (data.publish !== undefined) formData.append('publish', String(data.publish));
70
-
71
- return this.client.sendRequest(
72
- HttpMethodsEnum.Post,
73
- `/${wabaId}/flows`,
74
- this.config[WabaConfigEnum.RequestTimeout],
75
- formData,
76
- );
77
- }
78
-
79
- /**
80
- * Get Flow
81
- *
82
- * @param flowId - The flow ID
83
- * @param fields - Optional fields to return
84
- * @param dateFormat - Optional date format
85
- * @returns Promise with the flow details
86
- */
87
- async getFlow(
88
- flowId: string,
89
- fields?: string,
90
- dateFormat?: string,
91
- ): Promise<RequesterResponseInterface<Flow | FlowPreviewResponse>> {
92
- const params = new URLSearchParams();
93
- if (fields) params.append('fields', fields);
94
- if (dateFormat) params.append('date_format', dateFormat);
95
-
96
- const queryString = params.toString() ? `?${params.toString()}` : '';
97
- return this.client.sendRequest(
98
- HttpMethodsEnum.Get,
99
- `/${flowId}${queryString}`,
100
- this.config[WabaConfigEnum.RequestTimeout],
101
- null,
102
- );
103
- }
104
-
105
- /**
106
- * Update Flow Metadata
107
- *
108
- * @param flowId - The flow ID
109
- * @param data - The flow metadata to update
110
- * @returns Promise with the success status
111
- */
112
- async updateFlowMetadata(
113
- flowId: string,
114
- data: {
115
- name?: string;
116
- categories?: FlowCategoryEnum[];
117
- endpoint_uri?: string;
118
- application_id?: string;
119
- },
120
- ): Promise<RequesterResponseInterface<ResponseSuccess>> {
121
- const formData = new FormData();
122
-
123
- if (data.name) formData.append('name', data.name);
124
- if (data.categories) formData.append('categories', JSON.stringify(data.categories));
125
- if (data.endpoint_uri) formData.append('endpoint_uri', data.endpoint_uri);
126
- if (data.application_id) formData.append('application_id', data.application_id);
127
-
128
- return this.client.sendRequest(
129
- HttpMethodsEnum.Post,
130
- `/${flowId}`,
131
- this.config[WabaConfigEnum.RequestTimeout],
132
- formData,
133
- );
134
- }
135
-
136
- /**
137
- * Delete Flow
138
- *
139
- * @param flowId - The flow ID
140
- * @returns Promise with the success status
141
- */
142
- async deleteFlow(flowId: string): Promise<RequesterResponseInterface<ResponseSuccess>> {
143
- return this.client.sendRequest(
144
- HttpMethodsEnum.Delete,
145
- `/${flowId}`,
146
- this.config[WabaConfigEnum.RequestTimeout],
147
- null,
148
- );
149
- }
150
-
151
- /**
152
- * List Assets (Get Flow JSON URL)
153
- *
154
- * @param flowId - The flow ID
155
- * @returns Promise with the list of assets
156
- */
157
- async listAssets(flowId: string): Promise<RequesterResponseInterface<FlowAssetsResponse>> {
158
- return this.client.sendRequest(
159
- HttpMethodsEnum.Get,
160
- `/${flowId}/assets`,
161
- this.config[WabaConfigEnum.RequestTimeout],
162
- null,
163
- );
164
- }
165
-
166
- /**
167
- * Update Flow JSON
168
- *
169
- * @param flowId - The flow ID
170
- * @param data - The asset data including asset_type, file, and name
171
- * @returns Promise with the success status and validation errors
172
- */
173
- async updateFlowJson(
174
- flowId: string,
175
- data: {
176
- asset_type: 'FLOW_JSON';
177
- file: Blob;
178
- name: string;
179
- },
180
- ): Promise<RequesterResponseInterface<{ success: boolean; validation_errors?: FlowValidationError[] }>> {
181
- const formData = new FormData();
182
-
183
- formData.append('asset_type', data.asset_type);
184
- formData.append('file', data.file);
185
- formData.append('name', data.name);
186
-
187
- return this.client.sendRequest(
188
- HttpMethodsEnum.Post,
189
- `/${flowId}/assets`,
190
- this.config[WabaConfigEnum.RequestTimeout],
191
- formData,
192
- );
193
- }
194
-
195
- /**
196
- * Publish Flow
197
- *
198
- * @param flowId - The flow ID
199
- * @returns Promise with the success status
200
- */
201
- async publishFlow(flowId: string): Promise<RequesterResponseInterface<ResponseSuccess>> {
202
- return this.client.sendRequest(
203
- HttpMethodsEnum.Post,
204
- `/${flowId}/publish`,
205
- this.config[WabaConfigEnum.RequestTimeout],
206
- JSON.stringify({}),
207
- );
208
- }
209
-
210
- /**
211
- * Deprecate Flow
212
- *
213
- * @param flowId - The flow ID
214
- * @returns Promise with the success status
215
- */
216
- async deprecateFlow(flowId: string): Promise<RequesterResponseInterface<ResponseSuccess>> {
217
- return this.client.sendRequest(
218
- HttpMethodsEnum.Post,
219
- `/${flowId}/deprecate`,
220
- this.config[WabaConfigEnum.RequestTimeout],
221
- JSON.stringify({}),
222
- );
223
- }
224
-
225
- /**
226
- * Migrate Flows
227
- *
228
- * @param wabaId - The destination WABA ID
229
- * @param data - The migration data including source_waba_id and optional source_flow_names
230
- * @returns Promise with migration results
231
- */
232
- async migrateFlows(
233
- wabaId: string,
234
- data: {
235
- source_waba_id: string;
236
- source_flow_names?: string[];
237
- },
238
- ): Promise<RequesterResponseInterface<FlowMigrationResponse>> {
239
- const formData = new FormData();
240
-
241
- formData.append('source_waba_id', data.source_waba_id);
242
- if (data.source_flow_names) {
243
- formData.append('source_flow_names', JSON.stringify(data.source_flow_names));
244
- }
245
-
246
- return this.client.sendRequest(
247
- HttpMethodsEnum.Post,
248
- `/${wabaId}/migrate_flows`,
249
- this.config[WabaConfigEnum.RequestTimeout],
250
- formData,
251
- );
252
- }
253
- }
package/src/api/index.ts DELETED
@@ -1,24 +0,0 @@
1
- import MessagesAPI from './messages';
2
- import BaseAPI from './base';
3
- import PhoneNumberAPI from './phoneNumber';
4
- import TemplateAPI from './template';
5
- import RegistrationAPI from './registration';
6
- import TwoStepVerificationAPI from './twoStepVerification';
7
- import QrCodeAPI from './qrCode';
8
- import EncryptionAPI from './encryption';
9
- import WabaAPI from './waba';
10
- import MediaAPI from './media';
11
- import FlowAPI from './flow';
12
- export {
13
- MessagesAPI,
14
- BaseAPI,
15
- PhoneNumberAPI,
16
- TemplateAPI,
17
- RegistrationAPI,
18
- TwoStepVerificationAPI,
19
- QrCodeAPI,
20
- EncryptionAPI,
21
- WabaAPI,
22
- MediaAPI,
23
- FlowAPI,
24
- };
package/src/api/media.ts DELETED
@@ -1,52 +0,0 @@
1
- import { HttpMethodsEnum, WabaConfigEnum } from '../types/enums';
2
- import type { RequesterClass, RequesterResponseInterface, ResponseSuccess } from '../types/request';
3
- import type { WabaConfigType } from '../types/config';
4
- import type { MediaClass, MediaResponse, MediasResponse, UploadMediaResponse } from '../types/media';
5
- import BaseAPI from './base';
6
-
7
- export default class MediaAPI extends BaseAPI implements MediaClass {
8
- private readonly endpoint = 'media';
9
-
10
- constructor(config: WabaConfigType, client: RequesterClass) {
11
- super(config, client);
12
- }
13
-
14
- async getMediaById(mediaId: string): Promise<RequesterResponseInterface<MediaResponse>> {
15
- return this.client.sendRequest(
16
- HttpMethodsEnum.Get,
17
- `${mediaId}`,
18
- this.config[WabaConfigEnum.RequestTimeout],
19
- null,
20
- );
21
- }
22
-
23
- async uploadMedia(
24
- file: File,
25
- messagingProduct: string = 'whatsapp',
26
- ): Promise<RequesterResponseInterface<UploadMediaResponse>> {
27
- const formData = new FormData();
28
- formData.append('file', file);
29
- formData.append('messaging_product', messagingProduct);
30
- formData.append('type', file.type);
31
-
32
- return this.client.sendRequest(
33
- HttpMethodsEnum.Post,
34
- `${this.config[WabaConfigEnum.PhoneNumberId]}/${this.endpoint}`,
35
- this.config[WabaConfigEnum.RequestTimeout],
36
- formData,
37
- );
38
- }
39
-
40
- async deleteMedia(mediaId: string): Promise<RequesterResponseInterface<ResponseSuccess>> {
41
- return this.client.sendRequest(
42
- HttpMethodsEnum.Delete,
43
- `${mediaId}`,
44
- this.config[WabaConfigEnum.RequestTimeout],
45
- null,
46
- );
47
- }
48
-
49
- async downloadMedia(mediaUrl: string): Promise<RequesterResponseInterface<Blob>> {
50
- return this.client.sendRequest(HttpMethodsEnum.Get, mediaUrl, this.config[WabaConfigEnum.RequestTimeout], null);
51
- }
52
- }