// Most of these imports are here only for types checks
const { Contacts } = require('./types/contacts');
const { Interactive } = require("./types/interactive");
const { Audio, Document, Image, Sticker, Video } = require('./types/media');
const Location = require('./types/location');
const { Template } = require('./types/template');
const Text = require('./types/text');
const api = require('./fetch');
const { Request } = api;
/**
* The main API object
*
* @property {String} token The API token
* @property {String} v The API version to use
*/
class WhatsAppAPI {
/**
* Initiate the Whatsapp API app
*
* @param {String} token The API token, given at setup. It can be either a temporal token or a permanent one.
* @param {String} v The version of the API, defaults to v14.0
* @throws {Error} If token is not specified
*/
constructor(token, v = "v14.0") {
if (!token) throw new Error("Token must be specified");
this.token = token;
this.v = v;
}
/**
* Callback function after a sendMessage request is sent
*
* @callback Logger
* @param {String} phoneID The bot's phoneID from where the message was sent
* @param {String} to The user's phone number
* @param {(Text|Audio|Document|Image|Sticker|Video|Location|Contacts|Interactive|Template)} object The message object
* @param {Request} raw The raw body sent to the server
*/
/**
* Set a callback function for sendMessage
*
* @param {Logger} callback The callback function to set
* @returns {WhatsAppAPI} The API object, for chaining
* @throws {Error} If callback is truthy and is not a function
*/
logSentMessages(callback) {
if (callback && typeof callback !== "function") throw new TypeError("Callback must be a function");
this._register = callback;
return this;
}
/**
* Send a Whatsapp message
*
* @param {String} phoneID The bot's phone ID
* @param {String} to The user's phone number
* @param {(Text|Audio|Document|Image|Sticker|Video|Location|Contacts|Interactive|Template)} object A Whatsapp component, built using the corresponding module for each type of message.
* @param {String} [context] The message ID of the message to reply to
* @returns {Promise} The fetch promise
* @throws {Error} If phoneID is not specified
* @throws {Error} If to is not specified
* @throws {Error} If object is not specified
*/
sendMessage(phoneID, to, object, context = "") {
if (!phoneID) throw new Error("Phone ID must be specified");
if (!to) throw new Error("To must be specified");
if (!object) throw new Error("Message must have a message object");
const { request, promise } = api.sendMessage(this.token, this.v, phoneID, to, object, context);
if (this._register) this._register(phoneID, request.to, JSON.parse(request[request.type]), request);
return promise;
}
/**
* Mark a message as read
*
* @param {String} phoneID The bot's phone ID
* @param {String} messageId The message ID
* @returns {Promise} The fetch promise
* @throws {Error} If phoneID is not specified
* @throws {Error} If messageId is not specified
*/
markAsRead(phoneID, messageId) {
if (!phoneID) throw new Error("Phone ID must be specified");
if (!messageId) throw new Error("To must be specified");
return api.readMessage(this.token, this.v, phoneID, messageId);
}
/**
* Generate a QR code for sharing the bot
*
* @param {String} phoneID The bot's phone ID
* @param {String} message The quick message on the QR code
* @param {String} format The format of the QR code (png or svn)
* @returns {Promise} The fetch promise
* @throws {Error} If phoneID is not specified
* @throws {Error} If message is not specified
* @throws {Error} If format is not either 'png' or 'svn'
*/
createQR(phoneID, message, format = "png") {
if (!phoneID) throw new Error("Phone ID must be specified");
if (!message) throw new Error("Message must be specified");
if (!["png", "svg"].includes(format)) throw new Error("Format must be either 'png' or 'svg'");
return api.makeQR(this.token, this.v, phoneID, message, format);
}
/**
* Get one or many QR codes of the bot
*
* @param {String} phoneID The bot's phone ID
* @param {String} [id] The QR's id to find. If not specified, all QRs will be returned
* @returns {Promise} The fetch promise
* @throws {Error} If phoneID is not specified
*/
retrieveQR(phoneID, id) {
if (!phoneID) throw new Error("Phone ID must be specified");
return api.getQR(this.token, this.v, phoneID, id);
}
/**
* Update a QR code of the bot
*
* @param {String} phoneID The bot's phone ID
* @param {String} id The QR's id to edit
* @param {String} message The new quick message for the QR code
* @returns {Promise} The fetch promise
* @throws {Error} If phoneID is not specified
* @throws {Error} If id is not specified
* @throws {Error} If message is not specified
*/
updateQR(phoneID, id, message) {
if (!phoneID) throw new Error("Phone ID must be specified");
if (!id) throw new Error("ID must be specified");
if (!message) throw new Error("Message must be specified");
return api.updateQR(this.token, this.v, phoneID, id, message);
}
/**
* Delete a QR code of the bot
*
* @param {String} phoneID The bot's phone ID
* @param {String} id The QR's id to delete
* @returns {Promise} The fetch promise
* @throws {Error} If phoneID is not specified
* @throws {Error} If id is not specified
*/
deleteQR(phoneID, id) {
if (!phoneID) throw new Error("Phone ID must be specified");
if (!id) throw new Error("ID must be specified");
return api.deleteQR(this.token, this.v, phoneID, id);
}
}
/**
* @namespace Exports
* @property {WhatsAppAPI} WhatsAppAPI The main API object
* @property {Object} Handlers The handlers object
* @property {Function} Handlers.post The post handler
* @property {Function} Handlers.get The get handler
* @property {Object} Types The API types objects
* @property {Object} Types.Contacts The Contacts module
* @property {Contacts} Types.Contacts.Contacts The API Contacts type object
* @property {Address} Types.Contacts.Address The API Address type object
* @property {Birthday} Types.Contacts.Birthday The API Birthday type object
* @property {Email} Types.Contacts.Email The API Email type object
* @property {Name} Types.Contacts.Name The API Name type object
* @property {Organization} Types.Contacts.Organization The API Organization type object
* @property {Phone} Types.Contacts.Phone The API Phone type object
* @property {Url} Types.Contacts.Url The API Url type object
* @property {Object} Types.Interactive The Interactive module
* @property {Interactive} Types.Interactive.Interactive The API Interactive type object
* @property {Body} Types.Interactive.Body The API Body type object
* @property {Footer} Types.Interactive.Footer The API Footer type object
* @property {Header} Types.Interactive.Header The API Header type object
* @property {ActionList} Types.Interactive.ActionList The API Action type object
* @property {Section} Types.Interactive.Section The API Section type object
* @property {Row} Types.Interactive.Row The API Row type object
* @property {ActionButtons} Types.Interactive.ActionButtons The API Action type object
* @property {Button} Types.Interactive.Button The API Button type object
* @property {Location} Types.Location The API Location type object
* @property {Object} Types.Media The Media module
* @property {Media} Types.Media.Media Placeholder, don't use
* @property {Audio} Types.Media.Audio The API Audio type object
* @property {Document} Types.Media.Document The API Document type object
* @property {Image} Types.Media.Image The API Image type object
* @property {Sticker} Types.Media.Sticker The API Sticker type object
* @property {Video} Types.Media.Video The API Video type object
* @property {Object} Types.Template The Template module
* @property {Template} Types.Template.Template The API Template type object
* @property {Language} Types.Template.Language The API Language type object
* @property {ButtonComponent} Types.Template.ButtonComponent The API ButtonComponent type object
* @property {ButtonParameter} Types.Template.ButtonParameter The API ButtonParameter type object
* @property {HeaderComponent} Types.Template.HeaderComponent The API HeaderComponent type object
* @property {BodyComponent} Types.Template.BodyComponent The API BodyComponent type object
* @property {Parameter} Types.Template.Parameter The API Parameter type object
* @property {Currency} Types.Template.Currency The API Currency type object
* @property {DateTime} Types.Template.DateTime The API DateTime type object
* @property {Text} Types.Text The API Text type object
*/
module.exports = {
WhatsAppAPI,
Handlers: require('./requests'),
Types: {
Contacts: require('./types/contacts'),
Interactive: require('./types/interactive'),
Location: require('./types/location'),
Media: require('./types/media'),
Template: require('./types/template'),
Text: require('./types/text'),
}
};