UNPKG

whatsapp-api-js

Version:

A TypeScript server agnostic Whatsapp's Official API framework

3 lines (2 loc) 8.47 kB
"use strict";var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},__copyProps=(to,from,except,desc)=>{if(from&&typeof from=="object"||typeof from=="function")for(let key of __getOwnPropNames(from))!__hasOwnProp.call(to,key)&&key!==except&&__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:!0}),mod);var src_exports={};__export(src_exports,{default:()=>WhatsAppAPI});module.exports=__toCommonJS(src_exports);var import_utils=require("./utils.js");class WhatsAppAPI{token;appSecret;webhookVerifyToken;v;fetch;subtle;parsed;offload_functions;secure;on={};constructor({token,appSecret,webhookVerifyToken,v="v19.0",parsed=!0,offload_functions=!0,secure=!0,ponyfill={}}){if(this.token=token,this.secure=!!secure,this.secure){if(this.appSecret=appSecret,typeof ponyfill.subtle!="object"&&(typeof crypto!="object"||typeof crypto?.subtle!="object"))throw new Error("subtle is not defined in the enviroment. Consider using a setup helper, defined at 'whatsapp-api-js/setup', or provide a valid ponyfill object with the argument 'ponyfill.subtle'.");this.subtle=ponyfill.subtle||crypto.subtle}if(webhookVerifyToken&&(this.webhookVerifyToken=webhookVerifyToken),typeof ponyfill.fetch!="function"&&typeof fetch!="function")throw new Error("fetch is not defined in the enviroment. Consider using a setup helper, defined at 'whatsapp-api-js/setup', or provide a valid ponyfill object with the argument 'ponyfill.fetch'.");this.fetch=ponyfill.fetch||fetch,this.v=v,this.parsed=!!parsed,this.offload_functions=!!offload_functions}async sendMessage(phoneID,to,message,context,biz_opaque_callback_data){const type=message._type,request={messaging_product:"whatsapp",type,to};request[type]=message._build(),context&&(request.context={message_id:context}),biz_opaque_callback_data&&(request.biz_opaque_callback_data=biz_opaque_callback_data);const promise=this.fetch(`https://graph.facebook.com/${this.v}/${phoneID}/messages`,{method:"POST",headers:{Authorization:`Bearer ${this.token}`,"Content-Type":"application/json"},body:JSON.stringify(request)}),response=this.parsed?await(await promise).json():void 0,args={phoneID,to,type,message,request,id:response&&"messages"in response?response.messages[0].id:void 0,response};return this.user_function(this.on?.sent,args),response??promise}async broadcastMessage(phoneID,to,message,batch_size=50,delay=1e3){const responses=[];if(batch_size<1)throw new RangeError("batch_size must be greater than 0");if(delay<0)throw new RangeError("delay must be greater or equal to 0");for(let i=0;i<to.length;i+=batch_size){i!==0&&await new Promise(resolve=>setTimeout(resolve,delay));for(const u of to.slice(i,i+batch_size))responses.push(this.sendMessage(phoneID,u,message))}return responses}async markAsRead(phoneID,messageId){const promise=this.fetch(`https://graph.facebook.com/${this.v}/${phoneID}/messages`,{method:"POST",headers:{Authorization:`Bearer ${this.token}`,"Content-Type":"application/json"},body:JSON.stringify({messaging_product:"whatsapp",status:"read",message_id:messageId})});return this.getBody(promise)}async createQR(phoneID,message,format="png"){const promise=this.fetch(`https://graph.facebook.com/${this.v}/${phoneID}/message_qrdls?generate_qr_image=${format}&prefilled_message=${message}`,{method:"POST",headers:{Authorization:`Bearer ${this.token}`}});return this.getBody(promise)}async retrieveQR(phoneID,id){const promise=this.fetch(`https://graph.facebook.com/${this.v}/${phoneID}/message_qrdls/${id??""}`,{headers:{Authorization:`Bearer ${this.token}`}});return this.getBody(promise)}async updateQR(phoneID,id,message){const promise=this.fetch(`https://graph.facebook.com/${this.v}/${phoneID}/message_qrdls/${id}?prefilled_message=${message}`,{method:"POST",headers:{Authorization:`Bearer ${this.token}`}});return this.getBody(promise)}async deleteQR(phoneID,id){const promise=this.fetch(`https://graph.facebook.com/${this.v}/${phoneID}/message_qrdls/${id}`,{method:"DELETE",headers:{Authorization:`Bearer ${this.token}`}});return this.getBody(promise)}async retrieveMedia(id,phoneID){const params=phoneID?`phone_number_id=${phoneID}`:"",promise=this.fetch(`https://graph.facebook.com/${this.v}/${id}?${params}`,{headers:{Authorization:`Bearer ${this.token}`}});return this.getBody(promise)}async uploadMedia(phoneID,form,check=!0){if(check){if(!form||typeof form!="object"||!("get"in form)||typeof form.get!="function")throw new TypeError("File's Form must be an instance of FormData");const file=form.get("file");if(!file.type)throw new Error("File's Blob must have a type specified");if(!["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"].includes(file.type))throw new Error(`Invalid media type: ${file.type}`);const validMediaSizes={audio:16e6,text:1e8,application:1e8,image:5e6,video:16e6,sticker:5e5},mediaType=file.type==="image/webp"?"sticker":file.type.split("/")[0];if(file.size&&file.size>validMediaSizes[mediaType])throw new Error(`File is too big (${file.size} bytes) for a ${mediaType} (${validMediaSizes[mediaType]} bytes limit)`)}const promise=this.fetch(`https://graph.facebook.com/${this.v}/${phoneID}/media?messaging_product=whatsapp`,{method:"POST",body:form,headers:{Authorization:`Bearer ${this.token}`,"Content-Type":"multipart/form-data"}});return this.getBody(promise)}fetchMedia(url){return this._authenicatedRequest(new URL(url))}async deleteMedia(id,phoneID){const params=phoneID?`phone_number_id=${phoneID}`:"",promise=this.fetch(`https://graph.facebook.com/${this.v}/${id}?${params}`,{method:"DELETE",headers:{Authorization:`Bearer ${this.token}`}});return this.getBody(promise)}async post(data,raw_body,signature){if(this.secure){if(!this.appSecret)throw 500;if(!this.subtle)throw 501;if(!raw_body)throw 400;if(signature=signature?.split("sha256=")[1],!signature)throw 401;const encoder=new TextEncoder,keyBuffer=encoder.encode(this.appSecret),key=await this.subtle.importKey("raw",keyBuffer,{name:"HMAC",hash:"SHA-256"},!0,["sign","verify"]),data2=encoder.encode((0,import_utils.escapeUnicode)(raw_body)),result=await this.subtle.sign("HMAC",key,data2.buffer),check=Array.from(new Uint8Array(result)).map(b=>b.toString(16).padStart(2,"0")).join("");if(signature!==check)throw 401}if(!data.object)throw 400;const value=data.entry[0].changes[0].value,phoneID=value.metadata.phone_number_id;if("messages"in value){const message=value.messages[0],contact=value.contacts?.[0],from=contact?.wa_id??message.from,name=contact?.profile.name,args={phoneID,from,message,name,raw:data,reply:(response,context=!1,biz_opaque_callback_data)=>this.sendMessage(phoneID,from,response,context?message.id:void 0,biz_opaque_callback_data),Whatsapp:this};this.user_function(this.on?.message,args)}else if("statuses"in value){const statuses=value.statuses[0],phone=statuses.recipient_id,status=statuses.status,id=statuses.id,conversation=statuses.conversation,pricing=statuses.pricing,error=statuses.errors?.[0],biz_opaque_callback_data=statuses.biz_opaque_callback_data,args={phoneID,phone,status,id,conversation,pricing,error,biz_opaque_callback_data,raw:data};this.user_function(this.on?.status,args)}return 200}get(params){if(!this.webhookVerifyToken)throw 500;const{"hub.mode":mode,"hub.verify_token":token,"hub.challenge":challenge}=params;if(!mode||!token)throw 400;if(mode==="subscribe"&&token===this.webhookVerifyToken)return challenge;throw 403}_authenicatedRequest(url){if(!url)throw new Error("URL must be specified");return this.fetch(url,{headers:{Authorization:`Bearer ${this.token}`}})}async getBody(promise){return this.parsed?await(await promise).json():promise}user_function(f,...a){f&&(this.offload_functions?this.offload(f,...a):f(...a))}offload(f,...a){Promise.resolve().then(()=>f(...a))}} //# sourceMappingURL=index.js.map