UNPKG

whatsapp-api-js

Version:

A TypeScript server agnostic Whatsapp's Official API framework

556 lines (555 loc) 15.1 kB
import { ClientMessage, ClientLimitedMessageComponent, Section } from "../types.js"; class Interactive extends ClientMessage { /** * The action for the interactive message */ action; /** * The body for the interactive message */ body; /** * The header for the interactive message */ header; /** * The footer for the interactive message */ footer; /** * The type of the interactive message */ type; /** * @override * @internal */ get _type() { return "interactive"; } /** * Create an Interactive object for the API * * @param action - The action for the interactive message * @param body - The body for the interactive message, it may be undefined if not needed. * @param header - The header for the interactive message, it may be undefined if not needed. * @param footer - The footer for the interactive message, it may be undefined if not needed. * @throws If a header is provided for an {@link ActionList}, {@link ActionProductList}, {@link ActionCTA} or {@link ActionFlow} and it's not of type "text" */ constructor(action, body, header, footer) { super(); const require_text_header = [ "list", "product_list", "cta_url", "flow" ]; if (header && require_text_header.includes(action._type) && header.type !== "text") { throw new Error( `Header of type text is required for ${action._type} action` ); } this.type = action._type; this.action = action; if (body) this.body = body; if (header) this.header = header; if (footer) this.footer = footer; } } class Body { /** * The text of the body */ text; /** * Builds a body component for an Interactive message * * @param text - The text of the message. Maximum length: 1024 characters. * @throws If text is over 1024 characters */ constructor(text) { if (text.length > 1024) throw new Error("Body text must be less than 1024 characters"); this.text = text; } } class Footer { /** * The text of the footer */ text; /** * Builds a footer component for an Interactive message * * @param text - Text of the footer. Maximum length: 60 characters. * @throws If text is over 60 characters */ constructor(text) { if (text.length > 60) throw new Error("Footer text must be 60 characters or less"); this.text = text; } } class Header { /** * The type of the header */ type; /** * The text of the parameter */ text; /** * The image of the parameter */ image; /** * The document of the parameter */ document; /** * The video of the parameter */ video; /** * Builds a header component for an Interactive message * * @param object - The message object for the header * @throws If object is a string and is over 60 characters * @throws If object is a Media and has a caption */ constructor(object) { if (typeof object === "string") { if (object.length > 60) throw new Error("Header text must be 60 characters or less"); this.type = "text"; } else { this.type = object._type; if (object.caption) throw new Error(`Header ${this.type} must not have a caption`); } this[this.type] = object; } } class ActionButtons extends ClientLimitedMessageComponent { /** * The buttons of the action */ buttons; /** * @override * @internal */ get _type() { return "button"; } /** * Builds a reply buttons component for an Interactive message * * @param button - Buttons to be used in the reply buttons. Each button title must be unique within the message. Emojis are supported, markdown is not. Must be between 1 and 3 buttons. * @throws If more than 3 buttons are provided * @throws If two or more buttons have the same id * @throws If two or more buttons have the same title */ constructor(...button) { super("Reply buttons", "button", button, 3); const ids = button.map((b) => b[b.type].id); if (ids.length !== new Set(ids).size) throw new Error("Reply buttons must have unique ids"); const titles = button.map((b) => b[b.type].title); if (titles.length !== new Set(titles).size) throw new Error("Reply buttons must have unique titles"); this.buttons = button; } } class Button { /** * The type of the button */ type; /** * The reply object of the row */ reply; /** * Builds a button component for ActionButtons * * @param id - Unique identifier for your button. It cannot have leading or trailing spaces. This ID is returned in the webhook when the button is clicked by the user. Maximum length: 256 characters. * @param title - Button title. It cannot be an empty string and must be unique within the message. Emojis are supported, markdown is not. Maximum length: 20 characters. * @throws If id is over 256 characters * @throws If id is malformed * @throws If title is an empty string * @throws If title is over 20 characters */ constructor(id, title) { if (id.length > 256) throw new Error("Button id must be 256 characters or less"); if (/^ | $/.test(id)) throw new Error("Button id cannot have leading or trailing spaces"); if (!title.length) throw new Error("Button title cannot be an empty string"); if (title.length > 20) throw new Error("Button title must be 20 characters or less"); this.type = "reply"; this.reply = { title, id }; } } class ActionList extends ClientLimitedMessageComponent { /** * The button text */ button; /** * The sections of the action */ sections; /** * @override * @internal */ get _type() { return "list"; } /** * Builds an action component for an Interactive message * Required if interactive type is "list" * * @param button - Button content. It cannot be an empty string and must be unique within the message. Emojis are supported, markdown is not. Maximum length: 20 characters. * @param sections - Sections of the list * @throws If button is an empty string * @throws If button is over 20 characters * @throws If more than 10 sections are provided * @throws If more than 1 section is provided and at least one doesn't have a title */ constructor(button, ...sections) { super("Action", "sections", sections, 10); if (!button.length) throw new Error("Button content cannot be an empty string"); if (button.length > 20) throw new Error("Button content must be 20 characters or less"); if (sections.length > 1 && !sections.every((obj) => !!obj.title)) throw new Error( "All sections must have a title if more than 1 section is provided" ); this.button = button; this.sections = sections; } } class ListSection extends Section { /** * The rows of the section */ rows; /** * Builds a list section component for ActionList * * @param title - Title of the section, only required if there are more than one section * @param rows - Rows of the list section * @throws If title is over 24 characters if provided * @throws If more than 10 rows are provided */ constructor(title, ...rows) { super("ListSection", "rows", rows, 10, title); this.rows = rows; } } class Row { /** * The id of the row */ id; /** * The title of the row */ title; /** * The description of the row */ description; /** * Builds a row component for a ListSection * * @param id - The id of the row. Maximum length: 200 characters. * @param title - The title of the row. Maximum length: 24 characters. * @param description - The description of the row. Maximum length: 72 characters. * @throws If id is over 200 characters * @throws If title is over 24 characters * @throws If description is over 72 characters */ constructor(id, title, description) { if (id.length > 200) throw new Error("Row id must be 200 characters or less"); if (title.length > 24) throw new Error("Row title must be 24 characters or less"); if (description && description.length > 72) throw new Error("Row description must be 72 characters or less"); this.id = id; this.title = title; if (description) this.description = description; } } class ActionCatalog { /** * The name of the component */ name; /** * The thumbnail product to be shown in the catalog */ parameters; /** * @override * @internal */ get _type() { return "catalog_message"; } /** * Builds a catalog component for an Interactive message * * @remarks * Seems like the API throws an error if you try to send a catalog * message without a thumbnail, but the signature will keep the * optional parameter in case WhatsApp decides to make their API * work as expected :) * * @param thumbnail - The thumbnail product to be shown in the catalog. If not provided, the first product will be used (or so says the docs, but it doesn't work). */ constructor(thumbnail) { this.name = "catalog_message"; if (thumbnail) { this.parameters = { thumbnail_product_retailer_id: thumbnail.product_retailer_id }; } } } class ActionProduct { /** * The id of the catalog from where to get the products */ catalog_id; /** * The product to show in the message */ product_retailer_id; /** * @override * @internal */ get _type() { return "product"; } /** * Builds a Single Product component for an Interactive message * * @param product - The product to show in the message */ constructor(product) { this.catalog_id = product.catalog_id; this.product_retailer_id = product.product_retailer_id; } } class ActionProductList extends ClientLimitedMessageComponent { /** * The id of the catalog from where to get the products */ catalog_id; /** * The sections to show in the message */ sections; /** * @override * @internal */ get _type() { return "product_list"; } /** * Builds a Multi Product component for an Interactive message * * @param catalog_id - The catalog id * @param sections - The product sections to show in the message * @throws If more than 10 product sections are provided * @throws If more than 1 product section is provided and at least one section is missing a title */ constructor(catalog_id, ...sections) { super("ActionProductList", "sections", sections, 10); if (sections.length > 1) { for (const obj of sections) { if (!obj.title) { throw new Error( "All sections must have a title if more than 1 section is provided" ); } } } this.catalog_id = catalog_id; this.sections = sections; } } class ActionCTA { /** * The name of the component */ name = "cta_url"; /** * The CTA parameters */ parameters; /** * @override * @internal */ get _type() { return "cta_url"; } /** * Builds a call-to-action component for an Interactive message * * @param display_text - The text to be displayed in the CTA button * @param url - The url to be opened when the CTA button is clicked */ constructor(display_text, url) { this.parameters = { display_text, url }; } } class ActionFlow { /** * The name of the component */ name = "flow"; /** * The Flow parameters */ parameters; /** * @override * @internal */ get _type() { return "flow"; } /** * Builds a flow component for an Interactive message * * @note flow_message_version defaults to "3" * * @param parameters - The Flow parameters * @throws If parameters.flow_cta is empty or over 20 characters * @throws If parameters.flow_cta contains emojis */ constructor(parameters) { parameters = { flow_message_version: "3", ...parameters }; if (!parameters.flow_cta.length || parameters.flow_cta.length > 20) { throw new Error("Flow CTA must be between 1 and 20 characters"); } if (/\p{Extended_Pictographic}/u.test(parameters.flow_cta)) { throw new Error("Flow CTA must not contain emoji"); } if (parameters.flow_action === "navigate" && parameters.flow_action_payload.data && !Object.keys(parameters.flow_action_payload.data).length) { throw new Error( "Flow data must be a non-empty object when flow_action is navigate" ); } this.parameters = parameters; } } class ActionNavigateFlow extends ActionFlow { /** * Builds a navigate flow component for an Interactive message * * @param flow_token - Flow token that is generated by the business to serve as an identifier * @param flow_id - ID of the Flow provided by WhatsApp * @param flow_cta - Text on the CTA button, character limit - 20 characters (no emoji) * @param screen - The ID of the first Screen * @param data - Optional input data for the first Screen of the Flow. If provided, this must be a non-empty object. * @param mode - The Flow can be in either "draft" or "published" mode * @param flow_message_version - The Flow version, must be "3" * @throws If flow_cta is empty or over 20 characters * @throws If flow_cta contains emojis * @throws If data is provided and is an empty object */ constructor(flow_token, flow_id, flow_cta, screen, data, mode = "published", flow_message_version = "3") { super({ mode, flow_message_version, flow_token, flow_id, flow_cta, flow_action: "navigate", flow_action_payload: { screen, data } }); } } class ActionDataExchangeFlow extends ActionFlow { /** * Builds a data exchange flow component for an Interactive message * * @param flow_token - Flow token that is generated by the business to serve as an identifier * @param flow_id - ID of the Flow provided by WhatsApp * @param flow_cta - Text on the CTA button, character limit - 20 characters (no emoji) * @param mode - Must be "published" or "draft" * @param flow_message_version - Must be "3" */ constructor(flow_token, flow_id, flow_cta, mode = "published", flow_message_version = "3") { super({ mode, flow_message_version, flow_token, flow_id, flow_cta, flow_action: "data_exchange" }); } } class ActionLocation { /** * The name of the component */ name = "send_location"; /** * @override * @internal */ get _type() { return "location_request_message"; } } export { ActionButtons, ActionCTA, ActionCatalog, ActionDataExchangeFlow, ActionFlow, ActionList, ActionLocation, ActionNavigateFlow, ActionProduct, ActionProductList, Body, Button, Footer, Header, Interactive, ListSection, Row }; //# sourceMappingURL=interactive.js.map