UNPKG

whatsapp-api-js

Version:

A TypeScript server agnostic Whatsapp's Official API framework

747 lines 21.8 kB
/** * @module types * * @description * The types of the library. Mostly for internal use, * but if you want to "understand" the code under the hood, * feel free to read the docs :) */ import type { Text, Audio, Document, Image, Sticker, Video, Location, Interactive, Template, Reaction, Contacts } from "./messages/index.d.ts"; import type { AtLeastOne } from "./utils.d.ts"; export declare const DEFAULT_API_VERSION = "v21.0"; /** * The main constructor arguments for the API */ export type TheBasicConstructorArguments = { /** * The API token, given at setup. * You must provide an API token to use the framework. * * It can either be a temporal or permanent one. * * In order to create a permanent token, first make sure you have * linked your WhatsApp account to a Meta Commercial Account in * [Meta for Developers Dashboard](https://developers.facebook.com/apps). * * After that, head to [Bussiness Settings](https://business.facebook.com/settings/system-users), * select your app, create a new system user with `admin role`. * Then click "Add Actives", select Apps -\> Your App -\> App Administrator. * * And this was the point were Meta decided I was too sus because * I created a second bussiness to follow my own tutorial, * and as I didn't want to give them my ID, they banned my account. * * If you read until here, you probably will figure it out. * It's not that hard after getting in the right place. * * Really wish WhatsApp gets away from Meta soon... * * (Sorry for the rant, here's the [actual documentation](https://developers.facebook.com/docs/whatsapp/business-management-api/get-started) :) */ token: string; /** * The app secret, given at setup. * * The secret is used as a signature to validate payload's authenticity. * * To get your app secret, head to * [Meta for Developers Dashboard](https://developers.facebook.com/apps), * select your app and open Settings -\> Basic -\> App Secret -\> Show. * * If you want to skip the verification and remove the need to provide the secret, * set `secure` to `false`. */ appSecret?: string | never; /** * The webhook verify token, configured at setup. * Used exclusively to verify the server against WhatsApp's servers via the GET method. * * Not required by default, but calling this.get() without it will result in an error. */ webhookVerifyToken?: string; /** * The version of the API, defaults to {@link DEFAULT_API_VERSION}. */ v?: string; /** * Whether to return a pre-processed response from the API or the raw fetch response. * Intended for low level debugging. */ parsed?: boolean; /** * If set to false, none of the API checks will be performed, and it will be used in a less secure way. * * Defaults to true. */ secure?: boolean; /** * The ponyfills to use. * * This are meant to provide standard APIs implementations * on enviroments that don't have them. * * For example, if using Node 16, you will need to ponyfill * the fetch method with any spec complient fetch method. * * @remarks * With the additions of {@link setup} for the most common enviroments, * this parameter should no longer be configured manually. * * @example * ```ts * import { fetch } from "undici"; * import { subtle } from "node:crypto"; * * const api = new WhatsAppAPI({ * token: "my-token", * appSecret: "my-app-secret", * ponyfill: { * fetch, * subtle * } * }); * ``` */ ponyfill?: { /** * The fetch ponyfill to use for the requests. If not specified, it defaults to the fetch function from the enviroment. */ fetch?: typeof fetch; /** * The subtle ponyfill to use for the signatures. If not specified, it defaults to crypto.subtle from the enviroment. */ subtle?: Pick<typeof crypto.subtle, "importKey" | "sign">; }; }; /** * This switch allows TypeScript to cry if appSecret is not provided when secure is true. */ export type SecureLightSwitch = { secure?: true; appSecret: string; } | { secure: false; appSecret?: never; }; /** * Created this type if in the future the constructor needs more complex types. */ export type ExtraTypesThatMakeTypescriptWork = SecureLightSwitch; /** * Monkey patching TypeDoc inability to handle complex types. * * You should absolutely read {@link TheBasicConstructorArguments} in order to use the framework. */ export type WhatsAppAPIConstructorArguments = TheBasicConstructorArguments & ExtraTypesThatMakeTypescriptWork; /** * The base class of all the library messages * * Polymorphism is cool :] */ export declare abstract class ClientMessage { /** * The message type * * @internal */ abstract get _type(): ClientMessageNames; } export interface ClientTypedMessageComponent { /** * The message's component type * * @internal */ get _type(): string; } export interface ClientBuildableMessageComponent { /** * The message's component builder method * * @internal */ _build(..._: unknown[]): unknown; } export declare abstract class ClientLimitedMessageComponent<T, N extends number> { /** * Throws an error if the array length is greater than the specified number. * * @param p - The parent component name * @param c - The component name * @param a - The array to check the length of * @param n - The maximum length * @throws `${p} can't have more than ${n} ${c}` */ constructor(p: string, c: string, a: Array<T>, n: N); } /** * All sections are structured the same way, so this abstract class is used to reduce code duplication * * @remarks * - All sections must have between 1 and N elements * - All sections must have a title if more than 1 section is provided * * @typeParam T - The type of the components of the section * @typeParam N - The maximum number of elements in the section */ export declare abstract class Section<T, N extends number> extends ClientLimitedMessageComponent<T, N> { /** * The title of the section */ readonly title?: string; /** * Builds a section component * * @param name - The name of the section's type * @param keys_name - The name of the section's keys * @param elements - The elements of the section * @param max - The maximum number of elements in the section * @param title - The title of the section * @param title_length - The maximum length of the title * @throws If more than N elements are provided * @throws If title is over 24 characters if provided */ constructor(name: string, keys_name: string, elements: AtLeastOne<T>, max: N, title?: string, title_length?: number); } export declare abstract class ContactComponent implements ClientTypedMessageComponent, ClientBuildableMessageComponent { /** * @override * @internal */ _build(): unknown; /** * Whether the component can be repeated multiple times in a contact. * * @internal */ abstract get _many(): boolean; /** * @override * @internal */ abstract get _type(): string; } /** * A contact multiple component can be repeated multiple times in a contact. */ export declare abstract class ContactMultipleComponent extends ContactComponent { /** * @override * @internal */ get _many(): true; /** * @override * @internal */ abstract get _type(): string; } /** * A contact unique component can only be used once in a contact. */ export declare abstract class ContactUniqueComponent extends ContactComponent { /** * @override * @internal */ get _many(): false; /** * @override * @internal */ abstract get _type(): string; } /** * Polymorphism intensifies. Also helps with the _type typings :) */ export interface InteractiveAction extends ClientTypedMessageComponent { /** * @overload * @internal */ get _type(): "list" | "button" | "catalog_message" | "product" | "product_list" | "cta_url" | "flow" | "location_request_message"; } export interface TemplateComponent extends ClientBuildableMessageComponent { } export type ClientMessageNames = "text" | "audio" | "document" | "image" | "sticker" | "video" | "location" | "contacts" | "interactive" | "template" | "reaction"; export type ClientMessageRequest = { /** * The messaging product */ messaging_product: "whatsapp"; /** * The user's phone number */ to: string; /** * Currently you can only send messages to individuals */ recipient_type: "individual"; /** * The message to reply to */ context?: { /** * The message id to reply to */ message_id: string; }; /** * An arbitrary 512B string, useful for tracking. * * Any app subscribed to the messages webhook field on the WhatsApp Business Account can get this string, * as it is included in statuses object within webhook payloads. * * Cloud API does not process this field, it just returns it as part of sent/delivered/read message webhooks. */ biz_opaque_callback_data?: string; } & { [Type in ClientMessageNames]?: ClientMessage; } & ({ type: "text"; text: Text; } | { type: "audio"; audio: Audio; } | { type: "document"; document: Document; } | { type: "image"; image: Image; } | { type: "sticker"; sticker: Sticker; } | { type: "video"; video: Video; } | { type: "location"; location: Location; } | { type: "contacts"; contacts: Contacts; } | { type: "interactive"; interactive: Interactive; } | { type: "template"; template: Template; } | { type: "reaction"; reaction: Reaction; }); export type ServerTextMessage = { type: "text"; text: { body: string; }; }; export type ServerAudioMessage = { type: "audio"; audio: { mime_type: string; sha256: string; id: string; }; }; export type ServerDocumentMessage = { type: "document"; document: { caption?: string; filename: string; mime_type: string; sha256: string; id: string; }; }; export type ServerImageMessage = { type: "image"; image: { caption?: string; mime_type: string; sha256: string; id: string; }; }; export type ServerStickerMessage = { type: "sticker"; sticker: { id: string; animated: boolean; mime_type: "image/webp"; sha256: string; }; }; export type ServerVideoMessage = { type: "video"; video: { mime_type: string; sha256: string; id: string; }; }; export type ServerLocationMessage = { type: "location"; location: { latitude: string; longitude: string; name?: string; address?: string; }; }; export type ServerContactsMessage = { type: "contacts"; contacts: [ { addresses?: [ { city?: string; country?: string; country_code?: string; state?: string; street?: string; type?: string; zip?: string; } ]; birthday?: string; emails?: [ { email?: string; type?: string; } ]; name: { formatted_name: string; first_name?: string; last_name?: string; middle_name?: string; suffix?: string; prefix?: string; }; org?: { company?: string; department?: string; title?: string; }; phones?: [ { phone?: string; wa_id?: string; type?: string; } ]; urls?: [ { url?: string; type?: string; } ]; } ]; }; export type ServerInteractiveMessage = { type: "interactive"; interactive: { type: "button_reply"; button_reply: { id: string; title: string; }; list_reply: never; nfm_reply: never; } | { type: "list_reply"; list_reply: { id: string; title: string; description: string; }; button_reply: never; nfm_reply: never; } | { type: "nfm_reply"; nfm_reply: { name: "address_message"; body?: string; response_json: string; } | { name: "flow"; body: "Sent"; response_json: string; } | { name?: string; body?: string; response_json: string; }; button_reply: never; list_reply: never; }; }; export type ServerButtonMessage = { type: "button"; button: { text: string; payload: string; }; }; export type ServerReactionMessage = { type: "reaction"; reaction: { emoji: string; message_id: string; }; }; export type ServerOrderMessage = { type: "order"; order: { catalog_id: string; product_items: [ { product_retailer_id: string; quantity: string; item_price: string; currency: string; } ]; text?: string; }; }; export type ServerSystemMessage = { type: "system"; system: { body: string; identity: string; /** * @deprecated Since v12.0 it is undefined, use `wa_id` instead. * * I'm actually stunned this exists, since I started the library with v13 or 14. */ new_wa_id: number | string; wa_id: string; type: "customer_changed_number" | "customer_identity_changed" | string; customer: string; }; }; export type ServerRequestWelcomeMessage = { type: "request_welcome"; }; export type ServerUnknownMessage = { type: "unknown"; errors: [ { code: number; details: "Message type is not currently supported"; title: "Unsupported message type"; } ]; }; export type ServerMessageTypes = ServerTextMessage | ServerAudioMessage | ServerDocumentMessage | ServerImageMessage | ServerStickerMessage | ServerVideoMessage | ServerLocationMessage | ServerContactsMessage | ServerInteractiveMessage | ServerButtonMessage | ServerReactionMessage | ServerOrderMessage | ServerSystemMessage | ServerRequestWelcomeMessage | ServerUnknownMessage; export type ServerMessage = { from: string; id: string; timestamp: string; context?: { forwarded?: boolean; frequently_forwarded?: boolean; from?: string; id?: string; referred_product?: { catalog_id: string; product_retailer_id: string; }; }; identity?: { acknowledged: boolean; created_timestamp: string; hash: string; }; /** * Never saw this property on the wild, but it's documented */ errors?: [ServerError]; referral?: { source_url: string; source_id: string; source_type: "ad" | "post"; headline: string; body: string; ctwa_clid: string; media_type: "image" | "video"; } & ({ media_type: "image"; image_url: string; } | { media_type: "video"; video_url: string; thumbnail_url: string; }); } & ServerMessageTypes; export type ServerContacts = { profile: { name?: string; }; wa_id: string; }; export type ServerInitiation = "authentication" | "marketing" | "utility" | "service" | "referral_conversion"; export type ServerStatus = "sent" | "delivered" | "read" | "failed"; export type ServerPricing = { pricing_model: "CBP"; /** * @deprecated Since v16 with the release of the new pricing model */ billable?: boolean; category: ServerInitiation | "authentication-international"; }; export type ServerConversation = { id: string; expiration_timestamp: number; origin: { type: ServerInitiation; }; }; export type ServerError = { code: number; title: string; message: string; error_data: { details: string; }; }; export type GetParams = { "hub.mode": "subscribe"; "hub.verify_token": string; "hub.challenge": string; }; export type PostData = { object: "whatsapp_business_account"; entry: { id: string; changes: { value: { messaging_product: "whatsapp"; metadata: { display_phone_number: string; phone_number_id: string; }; } & ({ contacts?: [ServerContacts]; messages: [ServerMessage]; } | { statuses: [ { id: string; status: ServerStatus; timestamp: string; recipient_id: string; biz_opaque_callback_data?: string; } & ({ conversation: ServerConversation; pricing: ServerPricing; errors: undefined; } | { conversation: undefined; pricing: undefined; errors: [ServerError]; }) ]; }); field: "messages"; }[]; }[]; }; /** * @see https://developers.facebook.com/docs/whatsapp/cloud-api/support/error-codes */ export type ServerErrorResponse = { error: { message: string; type: string; code: number; error_data: { messaging_product: "whatsapp"; details: string; }; error_subcode: number; fbtrace_id: string; }; }; export type NoServerError = { error?: never; }; export type ServerSuccessResponse = { success: true; } & NoServerError; export type ServerSentMessageResponse = { messaging_product: "whatsapp"; contacts: [ { input: string; wa_id: string; } ]; messages: [ { id: string; message_status?: "accepted" | "held_for_quality_assessment"; } ]; }; export type ServerMessageResponse = (ServerSentMessageResponse & NoServerError) | ServerErrorResponse; export type ServerMarkAsReadResponse = ServerSuccessResponse | ServerErrorResponse; export type ServerQR = { code: string; prefilled_message: string; deep_link_url: string; qr_image_url?: string; }; export type ServerCreateQRResponse = (ServerQR & NoServerError) | ServerErrorResponse; export type ServerRetrieveQRResponse = ({ data: ServerQR[]; } & NoServerError) | ServerErrorResponse; export type ServerUpdateQRResponse = (ServerQR & NoServerError) | ServerErrorResponse; export type ServerDeleteQRResponse = ServerSuccessResponse | ServerErrorResponse; export type ServerMedia = { id: string; }; export type ServerMediaUploadResponse = (ServerMedia & NoServerError) | ServerErrorResponse; export type ValidMimeTypes = "audio/aac" | "audio/mp4" | "audio/mpeg" | "audio/amr" | "audio/ogg" | "text/plain" | "application/pdf" | "application/vnd.ms-powerpoint" | "application/msword" | "application/vnd.ms-excel" | "application/vnd.openxmlformats-officedocument.wordprocessingml.document" | "application/vnd.openxmlformats-officedocument.presentationml.presentation" | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" | "image/jpeg" | "image/png" | "video/mp4" | "video/3gp" | "image/webp"; export type ServerMediaRetrieveResponse = ({ messaging_product: "whatsapp"; url: string; mime_type: ValidMimeTypes; sha256: string; file_size: string; } & ServerMedia & NoServerError) | ServerErrorResponse; export type ServerMediaDeleteResponse = ServerSuccessResponse | ServerErrorResponse; export type ServerBlockedError = Pick<ServerErrorResponse["error"], "message" | "type" | "code"> & { error_data: { details: string; }; }; export type ServerBlockedUser = { input: string; wa_id: string; }; export type ServerBlockFailedUser = { input: string; errors: Omit<ServerBlockedError, "type">[]; }; export type ServerBlockResponse = { messaging_product: "whatsapp"; block_users: { added_users: ServerBlockedUser[]; failed_users?: ServerBlockFailedUser[]; }; errors?: ServerBlockedError; } | ServerErrorResponse; export type ServerUnblockResponse = { messaging_product: "whatsapp"; block_users: { removed_users: ServerBlockedUser[]; failed_users?: ServerBlockFailedUser[]; }; errors?: ServerBlockedError; } | ServerErrorResponse; //# sourceMappingURL=types.d.ts.map