@rkitwork/whatsapp-ramukjar-cloud-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.
@@ -0,0 +1,8 @@
1
+ import { WhatsAppPayload } from './types';
2
+ export declare class WhatsAppClient {
3
+ private readonly token;
4
+ private readonly phoneNumberId;
5
+ private readonly apiVersion;
6
+ constructor(token: string, phoneNumberId: string, apiVersion?: string);
7
+ sendMessage(to: string, payload: WhatsAppPayload): Promise<any>;
8
+ }
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.WhatsAppClient = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ class WhatsAppClient {
9
+ constructor(token, phoneNumberId, apiVersion = 'v24.0') {
10
+ this.token = token;
11
+ this.phoneNumberId = phoneNumberId;
12
+ this.apiVersion = apiVersion;
13
+ }
14
+ async sendMessage(to, payload) {
15
+ const url = `https://graph.facebook.com/${this.apiVersion}/${this.phoneNumberId}/messages`;
16
+ const response = await axios_1.default.post(url, {
17
+ messaging_product: 'whatsapp',
18
+ to,
19
+ ...payload,
20
+ }, {
21
+ headers: {
22
+ Authorization: `Bearer ${this.token}`,
23
+ 'Content-Type': 'application/json',
24
+ },
25
+ });
26
+ return response.data;
27
+ }
28
+ }
29
+ exports.WhatsAppClient = WhatsAppClient;
@@ -0,0 +1,14 @@
1
+ import * as T from './types';
2
+ export declare const textMessage: (body: string, preview?: boolean) => T.TextPayload;
3
+ export declare const imageMessage: (link: string, caption?: string) => T.ImagePayload;
4
+ export declare const audioMessage: (link: string) => T.AudioPayload;
5
+ export declare const videoMessage: (link: string, caption?: string) => T.VideoPayload;
6
+ export declare const documentMessage: (link: string, filename: string, caption?: string) => T.DocumentPayload;
7
+ export declare const locationMessage: (latitude: number, longitude: number, name?: string, address?: string) => T.LocationPayload;
8
+ export declare const contactMessage: (firstName: string, phone: string, lastName?: string) => T.ContactPayload;
9
+ export declare const buttonMessage: (bodyText: string, buttons: {
10
+ id: string;
11
+ title: string;
12
+ }[]) => T.ButtonPayload;
13
+ export declare const listMessage: (bodyText: string, buttonText: string, sections: T.ListPayload["interactive"]["action"]["sections"]) => T.ListPayload;
14
+ export declare const templateMessage: (name: string, language?: string, components?: any[]) => T.TemplatePayload;
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.templateMessage = exports.listMessage = exports.buttonMessage = exports.contactMessage = exports.locationMessage = exports.documentMessage = exports.videoMessage = exports.audioMessage = exports.imageMessage = exports.textMessage = void 0;
4
+ const textMessage = (body, preview = false) => ({
5
+ type: 'text',
6
+ text: { body, preview_url: preview },
7
+ });
8
+ exports.textMessage = textMessage;
9
+ const imageMessage = (link, caption) => ({
10
+ type: 'image',
11
+ image: { link, caption },
12
+ });
13
+ exports.imageMessage = imageMessage;
14
+ const audioMessage = (link) => ({
15
+ type: 'audio',
16
+ audio: { link },
17
+ });
18
+ exports.audioMessage = audioMessage;
19
+ const videoMessage = (link, caption) => ({
20
+ type: 'video',
21
+ video: { link, caption },
22
+ });
23
+ exports.videoMessage = videoMessage;
24
+ const documentMessage = (link, filename, caption) => ({
25
+ type: 'document',
26
+ document: { link, filename, caption },
27
+ });
28
+ exports.documentMessage = documentMessage;
29
+ const locationMessage = (latitude, longitude, name, address) => ({
30
+ type: 'location',
31
+ location: { latitude, longitude, name, address },
32
+ });
33
+ exports.locationMessage = locationMessage;
34
+ const contactMessage = (firstName, phone, lastName) => ({
35
+ type: 'contacts',
36
+ contacts: [
37
+ {
38
+ name: { first_name: firstName, last_name: lastName },
39
+ phones: [{ phone }],
40
+ },
41
+ ],
42
+ });
43
+ exports.contactMessage = contactMessage;
44
+ const buttonMessage = (bodyText, buttons) => ({
45
+ type: 'interactive',
46
+ interactive: {
47
+ type: 'button',
48
+ body: { text: bodyText },
49
+ action: {
50
+ buttons: buttons.map((b) => ({
51
+ type: 'reply',
52
+ reply: b,
53
+ })),
54
+ },
55
+ },
56
+ });
57
+ exports.buttonMessage = buttonMessage;
58
+ const listMessage = (bodyText, buttonText, sections) => ({
59
+ type: 'interactive',
60
+ interactive: {
61
+ type: 'list',
62
+ body: { text: bodyText },
63
+ action: { button: buttonText, sections },
64
+ },
65
+ });
66
+ exports.listMessage = listMessage;
67
+ const templateMessage = (name, language = 'en_US', components = []) => ({
68
+ type: 'template',
69
+ template: { name, language: { code: language }, components },
70
+ });
71
+ exports.templateMessage = templateMessage;
@@ -0,0 +1,109 @@
1
+ export type LanguageCode = string;
2
+ export interface BasePayload {
3
+ type: string;
4
+ }
5
+ export interface TextPayload extends BasePayload {
6
+ type: 'text';
7
+ text: {
8
+ body: string;
9
+ preview_url?: boolean;
10
+ };
11
+ }
12
+ export interface ImagePayload extends BasePayload {
13
+ type: 'image';
14
+ image: {
15
+ link: string;
16
+ caption?: string;
17
+ };
18
+ }
19
+ export interface AudioPayload extends BasePayload {
20
+ type: 'audio';
21
+ audio: {
22
+ link: string;
23
+ };
24
+ }
25
+ export interface VideoPayload extends BasePayload {
26
+ type: 'video';
27
+ video: {
28
+ link: string;
29
+ caption?: string;
30
+ };
31
+ }
32
+ export interface DocumentPayload extends BasePayload {
33
+ type: 'document';
34
+ document: {
35
+ link: string;
36
+ filename: string;
37
+ caption?: string;
38
+ };
39
+ }
40
+ export interface LocationPayload extends BasePayload {
41
+ type: 'location';
42
+ location: {
43
+ latitude: number;
44
+ longitude: number;
45
+ name?: string;
46
+ address?: string;
47
+ };
48
+ }
49
+ export interface ContactPayload extends BasePayload {
50
+ type: 'contacts';
51
+ contacts: {
52
+ name: {
53
+ first_name: string;
54
+ last_name?: string;
55
+ };
56
+ phones: {
57
+ phone: string;
58
+ }[];
59
+ }[];
60
+ }
61
+ export interface ButtonPayload extends BasePayload {
62
+ type: 'interactive';
63
+ interactive: {
64
+ type: 'button';
65
+ body: {
66
+ text: string;
67
+ };
68
+ action: {
69
+ buttons: {
70
+ type: 'reply';
71
+ reply: {
72
+ id: string;
73
+ title: string;
74
+ };
75
+ }[];
76
+ };
77
+ };
78
+ }
79
+ export interface ListPayload extends BasePayload {
80
+ type: 'interactive';
81
+ interactive: {
82
+ type: 'list';
83
+ body: {
84
+ text: string;
85
+ };
86
+ action: {
87
+ button: string;
88
+ sections: {
89
+ title: string;
90
+ rows: {
91
+ id: string;
92
+ title: string;
93
+ description?: string;
94
+ }[];
95
+ }[];
96
+ };
97
+ };
98
+ }
99
+ export interface TemplatePayload extends BasePayload {
100
+ type: 'template';
101
+ template: {
102
+ name: string;
103
+ language: {
104
+ code: LanguageCode;
105
+ };
106
+ components?: any[];
107
+ };
108
+ }
109
+ export type WhatsAppPayload = TextPayload | ImagePayload | AudioPayload | VideoPayload | DocumentPayload | LocationPayload | ContactPayload | ButtonPayload | ListPayload | TemplatePayload;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,3 @@
1
+ import { Request, Response } from 'express';
2
+ export declare const verifyWebhook: (req: Request, res: Response) => Response<any, Record<string, any>>;
3
+ export declare const handleWebhook: (req: Request, res: Response) => void;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleWebhook = exports.verifyWebhook = void 0;
4
+ const verifyWebhook = (req, res) => {
5
+ const mode = req.query['hub.mode'];
6
+ const token = req.query['hub.verify_token'];
7
+ const challenge = req.query['hub.challenge'];
8
+ if (mode === 'subscribe' && token === process.env.WHATSAPP_VERIFY_TOKEN) {
9
+ return res.status(200).send(challenge);
10
+ }
11
+ return res.sendStatus(403);
12
+ };
13
+ exports.verifyWebhook = verifyWebhook;
14
+ const handleWebhook = (req, res) => {
15
+ console.log('Incoming webhook:', JSON.stringify(req.body, null, 2));
16
+ res.sendStatus(200);
17
+ };
18
+ exports.handleWebhook = handleWebhook;
@@ -0,0 +1,6 @@
1
+ export * from './core/WhatsAppClient';
2
+ export * from './core/payloads';
3
+ export * from './core/types';
4
+ export * from './express/webhook';
5
+ export * from './nest/whatsapp.module';
6
+ export * from './nest/whatsapp.service';
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./core/WhatsAppClient"), exports);
18
+ __exportStar(require("./core/payloads"), exports);
19
+ __exportStar(require("./core/types"), exports);
20
+ __exportStar(require("./express/webhook"), exports);
21
+ __exportStar(require("./nest/whatsapp.module"), exports);
22
+ __exportStar(require("./nest/whatsapp.service"), exports);
@@ -0,0 +1,6 @@
1
+ export declare class WebhookController {
2
+ verify(challenge: string): string;
3
+ handle(body: any): Promise<{
4
+ status: string;
5
+ }>;
6
+ }
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.WebhookController = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ let WebhookController = class WebhookController {
18
+ verify(challenge) {
19
+ return challenge;
20
+ }
21
+ handle(body) {
22
+ return Promise.resolve({ status: 'ok' });
23
+ }
24
+ };
25
+ exports.WebhookController = WebhookController;
26
+ __decorate([
27
+ (0, common_1.Get)(),
28
+ __param(0, (0, common_1.Query)('hub.challenge')),
29
+ __metadata("design:type", Function),
30
+ __metadata("design:paramtypes", [String]),
31
+ __metadata("design:returntype", String)
32
+ ], WebhookController.prototype, "verify", null);
33
+ __decorate([
34
+ (0, common_1.Post)(),
35
+ __metadata("design:type", Function),
36
+ __metadata("design:paramtypes", [Object]),
37
+ __metadata("design:returntype", Promise)
38
+ ], WebhookController.prototype, "handle", null);
39
+ exports.WebhookController = WebhookController = __decorate([
40
+ (0, common_1.Controller)('webhook')
41
+ ], WebhookController);
@@ -0,0 +1,2 @@
1
+ export declare class WhatsAppModule {
2
+ }
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.WhatsAppModule = void 0;
10
+ const common_1 = require("@nestjs/common");
11
+ const whatsapp_service_1 = require("./whatsapp.service");
12
+ const webhook_controller_1 = require("./webhook.controller");
13
+ let WhatsAppModule = class WhatsAppModule {
14
+ };
15
+ exports.WhatsAppModule = WhatsAppModule;
16
+ exports.WhatsAppModule = WhatsAppModule = __decorate([
17
+ (0, common_1.Module)({
18
+ providers: [whatsapp_service_1.WhatsAppService],
19
+ exports: [whatsapp_service_1.WhatsAppService],
20
+ controllers: [webhook_controller_1.WebhookController],
21
+ })
22
+ ], WhatsAppModule);
@@ -0,0 +1,4 @@
1
+ export declare class WhatsAppService {
2
+ private client;
3
+ sendMessage(to: string, payload: any): Promise<any>;
4
+ }
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.WhatsAppService = void 0;
10
+ const common_1 = require("@nestjs/common");
11
+ const WhatsAppClient_1 = require("../core/WhatsAppClient");
12
+ let WhatsAppService = class WhatsAppService {
13
+ constructor() {
14
+ this.client = new WhatsAppClient_1.WhatsAppClient(process.env.WHATSAPP_TOKEN, process.env.WHATSAPP_PHONE_ID);
15
+ }
16
+ sendMessage(to, payload) {
17
+ return this.client.sendMessage(to, payload);
18
+ }
19
+ };
20
+ exports.WhatsAppService = WhatsAppService;
21
+ exports.WhatsAppService = WhatsAppService = __decorate([
22
+ (0, common_1.Injectable)()
23
+ ], WhatsAppService);
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@rkitwork/whatsapp-ramukjar-cloud-sdk",
3
+ "version": "1.0.0",
4
+ "description": "A secure WhatsApp Cloud API SDK for NestJS and Express",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "prepublishOnly": "npm run build"
10
+ },
11
+ "keywords": ["whatsapp", "sdk", "nestjs", "express", "cloud-api"],
12
+ "author": "rkitwork",
13
+ "license": "MIT",
14
+ "peerDependencies": {
15
+ "@nestjs/common": ">=9.0.0",
16
+ "@nestjs/core": ">=9.0.0",
17
+ "express": ">=4.17.0"
18
+ },
19
+ "devDependencies": {
20
+ "typescript": "^5.3.3",
21
+ "@types/express": "^4.17.21",
22
+ "@types/node": "^20.0.0"
23
+ },
24
+ "dependencies": {
25
+ "axios": "^1.7.0"
26
+ }
27
+ }
@@ -0,0 +1,31 @@
1
+ import axios from 'axios';
2
+ import { WhatsAppPayload } from './types';
3
+
4
+ export class WhatsAppClient {
5
+ constructor(
6
+ private readonly token: string,
7
+ private readonly phoneNumberId: string,
8
+ private readonly apiVersion = 'v24.0'
9
+ ) {}
10
+
11
+ async sendMessage(to: string, payload: WhatsAppPayload) {
12
+ const url = `https://graph.facebook.com/${this.apiVersion}/${this.phoneNumberId}/messages`;
13
+
14
+ const response = await axios.post(
15
+ url,
16
+ {
17
+ messaging_product: 'whatsapp',
18
+ to,
19
+ ...payload,
20
+ },
21
+ {
22
+ headers: {
23
+ Authorization: `Bearer ${this.token}`,
24
+ 'Content-Type': 'application/json',
25
+ },
26
+ }
27
+ );
28
+
29
+ return response.data;
30
+ }
31
+ }
@@ -0,0 +1,93 @@
1
+ import * as T from './types';
2
+
3
+ export const textMessage = (body: string, preview = false): T.TextPayload => ({
4
+ type: 'text',
5
+ text: { body, preview_url: preview },
6
+ });
7
+
8
+ export const imageMessage = (link: string, caption?: string): T.ImagePayload => ({
9
+ type: 'image',
10
+ image: { link, caption },
11
+ });
12
+
13
+ export const audioMessage = (link: string): T.AudioPayload => ({
14
+ type: 'audio',
15
+ audio: { link },
16
+ });
17
+
18
+ export const videoMessage = (link: string, caption?: string): T.VideoPayload => ({
19
+ type: 'video',
20
+ video: { link, caption },
21
+ });
22
+
23
+ export const documentMessage = (
24
+ link: string,
25
+ filename: string,
26
+ caption?: string
27
+ ): T.DocumentPayload => ({
28
+ type: 'document',
29
+ document: { link, filename, caption },
30
+ });
31
+
32
+ export const locationMessage = (
33
+ latitude: number,
34
+ longitude: number,
35
+ name?: string,
36
+ address?: string
37
+ ): T.LocationPayload => ({
38
+ type: 'location',
39
+ location: { latitude, longitude, name, address },
40
+ });
41
+
42
+ export const contactMessage = (
43
+ firstName: string,
44
+ phone: string,
45
+ lastName?: string
46
+ ): T.ContactPayload => ({
47
+ type: 'contacts',
48
+ contacts: [
49
+ {
50
+ name: { first_name: firstName, last_name: lastName },
51
+ phones: [{ phone }],
52
+ },
53
+ ],
54
+ });
55
+
56
+ export const buttonMessage = (
57
+ bodyText: string,
58
+ buttons: { id: string; title: string }[]
59
+ ): T.ButtonPayload => ({
60
+ type: 'interactive',
61
+ interactive: {
62
+ type: 'button',
63
+ body: { text: bodyText },
64
+ action: {
65
+ buttons: buttons.map((b) => ({
66
+ type: 'reply',
67
+ reply: b,
68
+ })),
69
+ },
70
+ },
71
+ });
72
+
73
+ export const listMessage = (
74
+ bodyText: string,
75
+ buttonText: string,
76
+ sections: T.ListPayload['interactive']['action']['sections']
77
+ ): T.ListPayload => ({
78
+ type: 'interactive',
79
+ interactive: {
80
+ type: 'list',
81
+ body: { text: bodyText },
82
+ action: { button: buttonText, sections },
83
+ },
84
+ });
85
+
86
+ export const templateMessage = (
87
+ name: string,
88
+ language = 'en_US',
89
+ components: any[] = []
90
+ ): T.TemplatePayload => ({
91
+ type: 'template',
92
+ template: { name, language: { code: language }, components },
93
+ });
@@ -0,0 +1,102 @@
1
+ export type LanguageCode = string;
2
+
3
+ export interface BasePayload {
4
+ type: string;
5
+ }
6
+
7
+ export interface TextPayload extends BasePayload {
8
+ type: 'text';
9
+ text: { body: string; preview_url?: boolean };
10
+ }
11
+
12
+ export interface ImagePayload extends BasePayload {
13
+ type: 'image';
14
+ image: { link: string; caption?: string };
15
+ }
16
+
17
+ export interface AudioPayload extends BasePayload {
18
+ type: 'audio';
19
+ audio: { link: string };
20
+ }
21
+
22
+ export interface VideoPayload extends BasePayload {
23
+ type: 'video';
24
+ video: { link: string; caption?: string };
25
+ }
26
+
27
+ export interface DocumentPayload extends BasePayload {
28
+ type: 'document';
29
+ document: { link: string; filename: string; caption?: string };
30
+ }
31
+
32
+ export interface LocationPayload extends BasePayload {
33
+ type: 'location';
34
+ location: {
35
+ latitude: number;
36
+ longitude: number;
37
+ name?: string;
38
+ address?: string;
39
+ };
40
+ }
41
+
42
+ export interface ContactPayload extends BasePayload {
43
+ type: 'contacts';
44
+ contacts: {
45
+ name: { first_name: string; last_name?: string };
46
+ phones: { phone: string }[];
47
+ }[];
48
+ }
49
+
50
+ export interface ButtonPayload extends BasePayload {
51
+ type: 'interactive';
52
+ interactive: {
53
+ type: 'button';
54
+ body: { text: string };
55
+ action: {
56
+ buttons: {
57
+ type: 'reply';
58
+ reply: { id: string; title: string };
59
+ }[];
60
+ };
61
+ };
62
+ }
63
+
64
+ export interface ListPayload extends BasePayload {
65
+ type: 'interactive';
66
+ interactive: {
67
+ type: 'list';
68
+ body: { text: string };
69
+ action: {
70
+ button: string;
71
+ sections: {
72
+ title: string;
73
+ rows: {
74
+ id: string;
75
+ title: string;
76
+ description?: string;
77
+ }[];
78
+ }[];
79
+ };
80
+ };
81
+ }
82
+
83
+ export interface TemplatePayload extends BasePayload {
84
+ type: 'template';
85
+ template: {
86
+ name: string;
87
+ language: { code: LanguageCode };
88
+ components?: any[];
89
+ };
90
+ }
91
+
92
+ export type WhatsAppPayload =
93
+ | TextPayload
94
+ | ImagePayload
95
+ | AudioPayload
96
+ | VideoPayload
97
+ | DocumentPayload
98
+ | LocationPayload
99
+ | ContactPayload
100
+ | ButtonPayload
101
+ | ListPayload
102
+ | TemplatePayload;
@@ -0,0 +1,18 @@
1
+ import { Request, Response } from 'express';
2
+
3
+ export const verifyWebhook = (req: Request, res: Response) => {
4
+ const mode = req.query['hub.mode'];
5
+ const token = req.query['hub.verify_token'];
6
+ const challenge = req.query['hub.challenge'];
7
+
8
+ if (mode === 'subscribe' && token === process.env.WHATSAPP_VERIFY_TOKEN) {
9
+ return res.status(200).send(challenge);
10
+ }
11
+
12
+ return res.sendStatus(403);
13
+ };
14
+
15
+ export const handleWebhook = (req: Request, res: Response) => {
16
+ console.log('Incoming webhook:', JSON.stringify(req.body, null, 2));
17
+ res.sendStatus(200);
18
+ };
package/src/index.ts ADDED
@@ -0,0 +1,8 @@
1
+ export * from './core/WhatsAppClient';
2
+ export * from './core/payloads';
3
+ export * from './core/types';
4
+
5
+ export * from './express/webhook';
6
+
7
+ export * from './nest/whatsapp.module';
8
+ export * from './nest/whatsapp.service';
@@ -0,0 +1,16 @@
1
+ import { Controller, Get, Post, Query, Body } from '@nestjs/common';
2
+
3
+ @Controller('webhook')
4
+ export class WebhookController {
5
+
6
+ @Get()
7
+ verify(@Query('hub.challenge') challenge: string): string {
8
+ return challenge;
9
+ }
10
+
11
+ @Post()
12
+ handle(body: any): Promise<{ status: string }> {
13
+ return Promise.resolve({ status: 'ok' });
14
+ }
15
+
16
+ }
@@ -0,0 +1,10 @@
1
+ import { Module } from '@nestjs/common';
2
+ import { WhatsAppService } from './whatsapp.service';
3
+ import { WebhookController } from './webhook.controller';
4
+
5
+ @Module({
6
+ providers: [WhatsAppService],
7
+ exports: [WhatsAppService],
8
+ controllers: [WebhookController],
9
+ })
10
+ export class WhatsAppModule {}
@@ -0,0 +1,14 @@
1
+ import { Injectable } from '@nestjs/common';
2
+ import { WhatsAppClient } from '../core/WhatsAppClient';
3
+
4
+ @Injectable()
5
+ export class WhatsAppService {
6
+ private client = new WhatsAppClient(
7
+ process.env.WHATSAPP_TOKEN!,
8
+ process.env.WHATSAPP_PHONE_ID!
9
+ );
10
+
11
+ sendMessage(to: string, payload: any) {
12
+ return this.client.sendMessage(to, payload);
13
+ }
14
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "CommonJS",
5
+ "declaration": true,
6
+ "outDir": "dist",
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "experimentalDecorators": true,
12
+ "emitDecoratorMetadata": true
13
+ },
14
+ "include": ["src/**/*"]
15
+ }