@apostlejs/whatsapp 0.0.3 → 0.0.5
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.
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +7 -5
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
@@ -1 +1 @@
|
|
1
|
-
"use strict";var e=require("zod");function t(e){return e&&e.__esModule?e:{default:e}}var a=t(require("node:crypto")),n=Object.defineProperty,r=(e,t)=>{for(var a in t)n(e,a,{get:t[a],enumerable:!0})},s={};r(s,{endpoints:()=>c,flowAction:()=>p,flowCanSendMessageStatus:()=>w,flowCategory:()=>d,flowMediaData:()=>u,flowMetadata:()=>f,flowScreen:()=>m,flowStatus:()=>y,flowValidationError:()=>g,flowsEndpoints:()=>o,messagesEndpoints:()=>i,wabaEndpoints:()=>l});var o={create:{url:"/{waba_id}/flows",method:"post",headers:{"Content-Type":"application/json"},request:{body:null},response:null},updateMetadata:{url:"/{flow_id}",method:"post",headers:{"Content-Type":"application/json"},request:{body:null},response:null},readMany:{url:"/{waba_id}/flows",method:"get",response:null},delete:{url:"/{flow_id}",method:"delete",response:null},read:{url:"/{flow_id}",method:"get",request:{query:null},response:null},updateJson:{url:"/{flow_id}/assets",method:"post",request:{body:null},response:null},getPreview:{url:"/{flow_id}?fields=preview.invalidate(false)",method:"get",response:null},publish:{url:"/{flow_id}/publish",method:"post",response:null}},i={send:{url:"/{number_id}/messages",method:"post",headers:{"Content-Type":"application/json"},request:{body:null},response:null}},l={updateEncryption:{url:"/{number_id}/whatsapp_business_encryption",method:"post",headers:{"Content-Type":"application/x-www-form-urlencoded"},request:{body:null}},registerNumber:{url:"/{number_id}/register",method:"post",headers:{"Content-Type":"application/json"},request:{body:null}}},c={flows:o,messages:i,waba:l},p=e.z.enum(["INIT","BACK","data_exchange","navigate","ping"]),d=e.z.enum(["SIGN_UP","SIGN_IN","APPOINTMENT_BOOKING","LEAD_GENERATION","CONTACT_US","CUSTOMER_SUPPORT","SURVEY","OTHER"]),u=e.z.object({media_id:e.z.string(),cdn_url:e.z.string(),file_name:e.z.string(),encryption_metadata:e.z.object({encrypted_hash:e.z.string(),iv:e.z.string(),encryption_key:e.z.string(),hmac_key:e.z.string(),plaintext_hash:e.z.string()})}),f=e.z.object({name:e.z.string(),categories:e.z.array(d),application_id:e.z.string().optional(),endpoint_uri:e.z.string().optional()}),m=e.z.union([e.z.literal("SUCCESS"),e.z.string()]),y=e.z.enum(["DRAFT","PUBLISHED","DEPRECATED","BLOCKED","THROTTLED"]),w=e.z.enum(["AVAILABLE","LIMITED","BLOCKED"]),g=e.z.object({error:e.z.string(),error_type:e.z.string(),message:e.z.string(),line_start:e.z.number(),line_end:e.z.number(),column_start:e.z.number(),column_end:e.z.number()}),_={};r(_,{actions:()=>j,flows:()=>R,parsers:()=>K,security:()=>q,toGraphLanguageTag:()=>z,utils:()=>G});var h={};r(h,{create:()=>A,delete:()=>C,get:()=>N,getMany:()=>O,getPreview:()=>T,publish:()=>x,updateJson:()=>P,updateMetadata:()=>I});var b={};r(b,{settings:()=>E});var v={},E={setup:e=>{Object.assign(v,e)},get:e=>{const t=v[e]??process.env[e];if(!t)throw new Error(`Missing environment variable: ${e}`);return t}};async function S(e,t,a){const n=`https://graph.facebook.com/v${E.get("GRAPH_API_VERSION")}`,r={Authorization:`Bearer ${E.get("META_APP_ACCESS_TOKEN")}`};let s=e.url;const o={...r,...e.headers,...t.headers},i=new URLSearchParams(t.query).toString();"/"===s[0]&&(s=s.slice(1)),s=`${n}/${s}`,i&&(s=`${s}?${i}`);const l={waba_id:E.get("WHATSAPP_ACCOUNT_ID"),number_id:E.get("WHATSAPP_NUMBER_ID"),...t.params};for(const e in l)s=s.replace(`{${e}}`,l[e]);const c=t.body;let p;if(c&&a?.asFormData){const e=new FormData;for(const t in c)e.append(t,c[t]);p=e}else c&&a?.asUrlEncoded?p=new URLSearchParams(c).toString():c&&(p=JSON.stringify(c));return await fetch(s,{method:e.method,headers:o,body:p}).then((e=>e.json())).then((e=>{if("error"in e)throw{response:{data:e.error}};return e})).catch((async e=>{const t=e.response.data.message,a=e.response.data.error_data?.details||"",n=t.match(/^\(#\d+\)/),r=n?n[0]:"",s=t.replace(/^\(#\d+\)\s*/,""),o=a.startsWith(s)?`${r} ${a}`:`${t}: ${a}`;throw e.response.data.message=o,e.response.data}))}async function A(e){const t=c.flows.create;return await S(t,{body:e})}async function I(e,t){const a=c.flows.updateMetadata;return await S(a,{body:t,params:{flow_id:e}})}async function P(e,t){const a=c.flows.updateJson,n={name:"flow.json",asset_type:"FLOW_JSON",file:new Blob([JSON.stringify(t,null,2)],{type:"application/json"})};return await S(a,{params:{flow_id:e},body:n},{asFormData:!0})}async function T(e,t){const a=c.flows.getPreview,{preview:n}=await S(a,{params:{flow_id:e}}),r=n.preview_url.replaceAll("\\",""),s=Object.entries(t??{}).reduce(((e,[t,a])=>(e[t]="flow_action_payload"===t?encodeURIComponent(JSON.stringify(a)):a.toString(),e)),{});return`${r}&${new URLSearchParams(s).toString()}`}async function C(e){const t=c.flows.delete;return await S(t,{params:{flow_id:e}})}async function N(e,t){const a=c.flows.read;return await S(a,{params:{flow_id:e},query:{fields:t?.fields.join(",")??""}})}async function O(){const e=c.flows.readMany;return await S(e,{})}async function x(e){const t=c.flows.publish;return await S(t,{params:{flow_id:e}})}var B=e=>e.split("?")[0],R={createToken:({flow_name:e,flow_parameters:t,chatId:a})=>{const n=new URLSearchParams({chat_id:a});if(n.set("flow_identifier",crypto.randomUUID()),t)for(const[e,a]of Object.entries(t))n.set(e,a.toString());return`${e}?${decodeURIComponent(n.toString())}`},getName:B,destructureFlowToken:e=>{const t=B(e);let a=e.split("?")?.[1];"&"===a?.[0]&&(a=a.slice(1));const n=new URLSearchParams(a),r=n.get("chat_id")||n.get("chatId"),s=n.get("flow_identifier")||n.get("flowIdentifier"),o={};for(const[e,t]of n.entries())"chat_id"!==e&&"chatId"!==e&&"flow_identifier"!==e&&"flowIdentifier"!==e&&(o[e]=t);return{paramsString:a,flowName:t,chatId:r,flowIdentifier:s,flowParameters:o}}},U={"ar-SA":"ar","bn-BD":"bn","bn-IN":"bn","cs-CZ":"cs","da-DK":"da","de-AT":"de","de-CH":"de","de-DE":"de","el-GR":"el","en-AU":"en","en-CA":"en","en-GB":"en_GB","en-IE":"en","en-IN":"en","en-NZ":"en","en-ZA":"en","en-US":"en_US","es-AR":"es_AR","es-CL":"es","es-CO":"es","es-ES":"es_ES","es-MX":"es_MX","es-US":"es","fi-FI":"fi","fr-BE":"fr","fr-CA":"fr","fr-CH":"fr","fr-FR":"fr","he-IL":"he","hi-IN":"hi","hu-HU":"hu","id-ID":"id","it-CH":"it","it-IT":"it","ja-JP":"ja","ko-KR":"ko","nl-BE":"nl","nl-NL":"nl","no-NO":"nb","pl-PL":"pl","pt-PT":"pt_PT","pt-BR":"pt_BR","ro-RO":"ro","ru-RU":"ru","sk-SK":"sk","sv-SE":"sv","ta-IN":"ta","ta-LK":"ta","th-TH":"th","tr-TR":"tr","zh-CN":"zh_CN","zh-HK":"zh_HK","zh-TW":"zh_TW"},z=e=>{const t=U[e];return void 0===t?"en":t},M=e=>{const t={to:e.to,messaging_product:"whatsapp",recipient_type:"individual"};return e.reply&&(t.context={message_id:e.reply}),e.showUrlPreviewImage&&(t.preview_url=e.showUrlPreviewImage),t},D={flow:e=>{if("flow"!==e.message.type)throw new Error("Invalid type");const{message:t,...a}=e,{flow:n,...r}=t,s=M(a);n.mode||(n.mode=E.get("WHATSAPP_FLOWS_MODE"));const o=R.createToken({chatId:s.to,flow_name:n.name,flow_parameters:n.parameters});return{type:"interactive",...s,interactive:{...r,type:"flow",action:{name:"flow",parameters:{flow_name:n.name,flow_token:o,flow_message_version:"3",flow_cta:n.button,flow_action:n.action??"navigate",mode:n.mode,...n.payload&&{flow_action_payload:{...n.payload,screen:n.payload.screen.toUpperCase()}}}}}}},text:e=>{if("text"!==e.message.type)throw new Error("Invalid type");const{message:{text:t},...a}=e,n={type:"text",text:{body:t},...M(a)};return e.message.previewUrl&&n.text&&(n.text.preview_url=e.message.previewUrl),n},list:e=>{if("list"!==e.message.type)throw new Error("Invalid type");const{message:t,...a}=e,{list:n,type:r,...s}=t;return{...M(a),type:"interactive",interactive:{...s,type:r,action:n}}},button:e=>{if("button"!==e.message.type)throw new Error("Invalid type");const{message:t,...a}=e,{buttons:n,type:r,...s}=t;return{...M(a),type:"interactive",interactive:{...s,type:r,action:{buttons:n.map((e=>({reply:{id:e.id,title:e.text},type:"reply"})))}}}},template:e=>{if("template"!==e.message.type)throw new Error("Invalid type");const{message:{type:t,...a},...n}=e,r={...M(n),type:t,template:{...a,language:{code:z(a.language)}}};return r.template&&(r.template.namespace=process.env.WHATSAPP_MESSAGE_NAMESPACE),r},media:e=>{if("media"!==e.message.type)throw new Error("Invalid type");const{message:{type:t,...a},...n}=e,r=Object.entries(a)[0],[s,{ref:o,...i}]=r,l=i,c=M(n);return Number.isNaN(Number(o))?l.link=o:l.id=o,{type:s,[s]:l,...c}},contact:e=>{if("contact"!==e.message.type)throw new Error("Invalid type");const{message:{contacts:t},...a}=e;return{type:"contacts",contacts:t,...M(a)}}};function L(e){const{encrypted_aes_key:t,encrypted_flow_data:n,initial_vector:r}=e,s=a.default.createPrivateKey({key:E.get("WHATSAPP_ACCOUNT_ENCRYPTION_PRIVATE_KEY"),passphrase:E.get("WHATSAPP_ACCOUNT_ENCRYPTION_PASSPHRASE")}),o=a.default.privateDecrypt({key:s,padding:a.default.constants.RSA_PKCS1_OAEP_PADDING,oaepHash:"sha256"},Buffer.from(t,"base64")),i=Buffer.from(n,"base64"),l=Buffer.from(r,"base64"),c=i.subarray(0,-16),p=i.subarray(-16),d=a.default.createDecipheriv("aes-128-gcm",o,l);d.setAuthTag(p);const u=Buffer.concat([d.update(c),d.final()]).toString("utf-8");return{payload:JSON.parse(u),encryptionMetadata:{aesKeyBuffer:o,initialVectorBuffer:l}}}function H(e){const t=new URL(e.url).searchParams,a=t.get("hub.verify_token"),n=t.get("hub.challenge");return!(!a||!n)&&a===E.get("WHATSAPP_WEBHOOK_KEY")&&n}async function k(e,t){const n=e.headers.get("x-hub-signature-256");if(!n)return!1;const r=n.replace("sha256=",""),s=a.default.createHmac("sha256",E.get("WHATSAPP_WEBHOOK_KEY")).update(t,"utf-8").digest("hex");return!!a.default.timingSafeEqual(Buffer.from(r),Buffer.from(s))}var K={toGraph:{sendMessage:e=>D[e.message.type](e),flowResponse:(e,t)=>{if(!t.data)throw new Error("Missing data in flow response");if(!t.screen)throw new Error("Missing screen in flow response");if(t.screen=t.screen.toUpperCase(),"SUCCESS"===t.screen){const a=t.data??{};t.data={extension_message_response:{params:{flow_token:e,...a}}}}return t}},toSDK:{webhook:async function(e){try{if("GET"===e.method){const t=H(e);if(!t)throw new Error("Invalid request");return{type:"healthCheck",payload:t}}const a=await e.text(),n=JSON.parse(a);if("entry"in n){if(!k(e,a))throw new Error("Invalid Signature");const r=n.entry.flatMap((e=>e.changes)).filter((e=>"messages"===e.field)).flatMap((e=>e.value.messages)).filter(Boolean).map((e=>function(e){const t=e.from,a={id:e.id,type:e.type,timestamp:e.timestamp,metadata:{forwarded:e.context?.forwarded,frequentlyForwarded:e.context?.frequently_forwarded}},n=function(e){if(!(e.audio||e.document||e.video||e.image))return null;const t=e.audio?.id??e.document?.id??e.image?.id??e.video?.id,a=e.audio?.mime_type??e.document?.mime_type??e.image?.mime_type??e.video?.mime_type,n=["audio","document","image","video"].find((t=>e[t])),r=e.image?.sha256??e.document?.sha256??e.video?.sha256;return{id:t,type:n,caption:e.document?.caption??e.image?.caption??e.video?.caption??null,mime_type:a,sha256:r,filename:e.document?.filename??e.video?.filename}}(e),r=function(e){return e.text?.body??e.button?.text??e.interactive?.button_reply?.title??e.interactive?.list_reply?.title??e.document?.caption??null}(e),s=function(e){return e.interactive?{...e.interactive?.button_reply||e.button?{button:{id:e.interactive?.button_reply?.id??null,title:e.button?.text??e.interactive.button_reply?.title,payload:e.button?.payload??null}}:{},...e.interactive.list_reply?{selectedOption:{id:e.interactive.list_reply.id,title:e.interactive.list_reply.title,description:e.interactive.list_reply.description}}:{},...e.interactive.nfm_reply?{flowResponse:JSON.parse(e.interactive.nfm_reply.response_json)}:{}}:null}(e);return{...a,...s&&{interaction:s},...n&&{media:n},text:r,chatId:t}}(e)));return{type:"application",payload:{messageReceived:(t=r,t.length?t:void 0)}}}if("encrypted_flow_data"in n)return{type:"flowExchange",payload:{...L(n),pingResponse:{data:{status:"active"}}}};throw new Error("Unrecognized event")}catch{return{error:!0}}var t}}},j={messages:{send:async function(e){const t=K.toGraph.sendMessage(e),a=c.messages.send;return await S(a,{body:t})}},flows:{...h},waba:{registerNumber:async function({dataRegion:e,pin:t}){const a=c.waba.registerNumber,n={messaging_product:"whatsapp",pin:t};return e&&(n.data_localization_region=e),await S(a,{body:n},{asUrlEncoded:!0})},encryption:{upload:async function(e){const t=c.waba.updateEncryption,a={business_public_key:e};return await S(t,{body:a},{asUrlEncoded:!0})}}}};async function W(e){return await fetch(e).then((async e=>{const t=await e.arrayBuffer();return Buffer.from(t)}))}var q={verifyHub:H,verifySignature:k,generateWabaEncryption:async function(){const e=a.default.randomUUID(),{publicKey:t,privateKey:n}=a.default.generateKeyPairSync("rsa",{modulusLength:2048,publicKeyEncoding:{type:"spki",format:"pem"},privateKeyEncoding:{type:"pkcs8",format:"pem",cipher:"aes-256-cbc",passphrase:e}});return{passphrase:e,publicKey:t,privateKey:n}},decryptFlowBody:L,encryptFlowResponse:function(e,t){const n=[];for(const e of Buffer.from(t.initialVectorBuffer).entries())n.push(~e[1]);const r=a.default.createCipheriv("aes-128-gcm",Buffer.from(t.aesKeyBuffer),Buffer.from(n));return Buffer.concat([r.update(JSON.stringify(e),"utf-8"),r.final(),r.getAuthTag()]).toString("base64")},decryptFlowMedia:async function(e){const t=[];for(const n of e){let{cdn_url:e,encryption_metadata:r}=n;if("EXAMPLE_DATA__CDN_URL_WILL_COME_IN_THIS_FIELD"===e){e="https://picsum.photos/seed/picsum/200";const a=await W(e);t.push(a);continue}const s=await W(e),{iv:o,encryption_key:i,hmac_key:l,encrypted_hash:c,plaintext_hash:p}=r,d={iv:Buffer.from(o,"base64"),encryption_key:Buffer.from(i,"base64"),hmac_key:Buffer.from(l,"base64")};if(a.default.createHash("sha256").update(s).digest("base64")!==c)throw new Error("Encrypted hash validation failed");const u=s.subarray(0,s.length-10),f=s.subarray(-10);if(!a.default.createHmac("sha256",d.hmac_key).update(Buffer.concat([d.iv,u])).digest().subarray(0,10).equals(f))throw new Error("HMAC validation failed");const m=a.default.createDecipheriv("aes-256-cbc",d.encryption_key,d.iv),y=m.update(u),w=Buffer.concat([y,m.final()]);if(a.default.createHash("sha256").update(w).digest("base64")!==p)throw new Error("Decrypted media hash validation failed");t.push(w)}return t}},G={flows:R},$=null;exports.actions=j,exports.createWhatsapp=()=>$||($=(()=>{const{settings:e}=b,{actions:t,flows:a,parsers:n,security:r,utils:o,toGraphLanguageTag:i}=_,{endpoints:l}=s;return{settings:e,sdk:{actions:t,flows:a,parsers:n,security:r,utils:o,toGraphLanguageTag:i},graph:{endpoints:l}}})()),exports.endpoints=c,exports.flowAction=p,exports.flowCanSendMessageStatus=w,exports.flowCategory=d,exports.flowMediaData=u,exports.flowMetadata=f,exports.flowScreen=m,exports.flowStatus=y,exports.flowValidationError=g,exports.flows=R,exports.flowsEndpoints=o,exports.messagesEndpoints=i,exports.parsers=K,exports.security=q,exports.toGraphLanguageTag=z,exports.utils=G,exports.wabaEndpoints=l;
|
1
|
+
"use strict";var e=require("zod");function t(e){return e&&e.__esModule?e:{default:e}}var a=t(require("node:crypto")),n=Object.defineProperty,r=(e,t)=>{for(var a in t)n(e,a,{get:t[a],enumerable:!0})},o={};r(o,{endpoints:()=>c,flowAction:()=>p,flowCanSendMessageStatus:()=>w,flowCategory:()=>d,flowMediaData:()=>u,flowMetadata:()=>f,flowScreen:()=>m,flowStatus:()=>y,flowValidationError:()=>_,flowsEndpoints:()=>s,messagesEndpoints:()=>i,wabaEndpoints:()=>l});var s={create:{url:"/{waba_id}/flows",method:"post",headers:{"Content-Type":"application/json"},request:{body:null},response:null},updateMetadata:{url:"/{flow_id}",method:"post",headers:{"Content-Type":"application/json"},request:{body:null},response:null},readMany:{url:"/{waba_id}/flows",method:"get",response:null},delete:{url:"/{flow_id}",method:"delete",response:null},read:{url:"/{flow_id}",method:"get",request:{query:null},response:null},updateJson:{url:"/{flow_id}/assets",method:"post",request:{body:null},response:null},getPreview:{url:"/{flow_id}?fields=preview.invalidate(false)",method:"get",response:null},publish:{url:"/{flow_id}/publish",method:"post",response:null}},i={send:{url:"/{number_id}/messages",method:"post",headers:{"Content-Type":"application/json"},request:{body:null},response:null}},l={updateEncryption:{url:"/{number_id}/whatsapp_business_encryption",method:"post",headers:{"Content-Type":"application/x-www-form-urlencoded"},request:{body:null}},registerNumber:{url:"/{number_id}/register",method:"post",headers:{"Content-Type":"application/json"},request:{body:null}}},c={flows:s,messages:i,waba:l},p=e.z.enum(["INIT","BACK","data_exchange","navigate","ping"]),d=e.z.enum(["SIGN_UP","SIGN_IN","APPOINTMENT_BOOKING","LEAD_GENERATION","CONTACT_US","CUSTOMER_SUPPORT","SURVEY","OTHER"]),u=e.z.object({media_id:e.z.string(),cdn_url:e.z.string(),file_name:e.z.string(),encryption_metadata:e.z.object({encrypted_hash:e.z.string(),iv:e.z.string(),encryption_key:e.z.string(),hmac_key:e.z.string(),plaintext_hash:e.z.string()})}),f=e.z.object({name:e.z.string(),categories:e.z.array(d),application_id:e.z.string().optional(),endpoint_uri:e.z.string().optional()}),m=e.z.union([e.z.literal("SUCCESS"),e.z.string()]),y=e.z.enum(["DRAFT","PUBLISHED","DEPRECATED","BLOCKED","THROTTLED"]),w=e.z.enum(["AVAILABLE","LIMITED","BLOCKED"]),_=e.z.object({error:e.z.string(),error_type:e.z.string(),message:e.z.string(),line_start:e.z.number(),line_end:e.z.number(),column_start:e.z.number(),column_end:e.z.number()}),g={};r(g,{actions:()=>j,flows:()=>R,parsers:()=>K,security:()=>G,toGraphLanguageTag:()=>z,utils:()=>q});var h={};r(h,{create:()=>A,delete:()=>C,get:()=>N,getMany:()=>O,getPreview:()=>T,publish:()=>x,updateJson:()=>P,updateMetadata:()=>I});var b={};r(b,{settings:()=>E});var v={},E={setup:e=>{Object.assign(v,e)},get:e=>{const t=v[e]??process.env[e];if(!t)throw new Error(`Missing environment variable: ${e}`);return t}};async function S(e,t,a){const n=`https://graph.facebook.com/v${E.get("GRAPH_API_VERSION")}`,r={Authorization:`Bearer ${E.get("META_APP_ACCESS_TOKEN")}`};let o=e.url;const s={...r,...e.headers,...t.headers},i=new URLSearchParams(t.query).toString();"/"===o[0]&&(o=o.slice(1)),o=`${n}/${o}`,i&&(o=`${o}?${i}`);const l={waba_id:E.get("WHATSAPP_ACCOUNT_ID"),number_id:E.get("WHATSAPP_NUMBER_ID"),...t.params};for(const e in l)o=o.replace(`{${e}}`,l[e]);const c=t.body;let p;if(c&&a?.asFormData){const e=new FormData;for(const t in c)e.append(t,c[t]);p=e}else c&&a?.asUrlEncoded?p=new URLSearchParams(c).toString():c&&(p=JSON.stringify(c));return await fetch(o,{method:e.method,headers:s,body:p}).then((e=>e.json())).then((e=>{if("error"in e)throw{response:{data:e.error}};return e})).catch((async e=>{const t=e.response.data.message,a=e.response.data.error_data?.details||"",n=t.match(/^\(#\d+\)/),r=n?n[0]:"",o=t.replace(/^\(#\d+\)\s*/,""),s=a.startsWith(o)?`${r} ${a}`:`${t}: ${a}`;throw e.response.data.message=s,e.response.data}))}async function A(e){const t=c.flows.create;return await S(t,{body:{name:e.name,categories:e.categories,clone_flow_id:e.clone_flow_id,endpoint_uri:e.endpoint_uri,publish:e.publish,flow_json:JSON.stringify(e.flow_json,null,2)}})}async function I(e,t){const a=c.flows.updateMetadata;return await S(a,{body:t,params:{flow_id:e}})}async function P(e,t){const a=c.flows.updateJson,n={name:"flow.json",asset_type:"FLOW_JSON",file:new Blob([JSON.stringify(t,null,2)],{type:"application/json"})};return await S(a,{params:{flow_id:e},body:n},{asFormData:!0})}async function T(e,t){const a=c.flows.getPreview,{preview:n}=await S(a,{params:{flow_id:e}}),r=n.preview_url.replaceAll("\\",""),o=Object.entries(t??{}).reduce(((e,[t,a])=>(e[t]="flow_action_payload"===t?encodeURIComponent(JSON.stringify(a)):a.toString(),e)),{});return`${r}&${new URLSearchParams(o).toString()}`}async function C(e){const t=c.flows.delete;return await S(t,{params:{flow_id:e}})}async function N(e,t){const a=c.flows.read;return await S(a,{params:{flow_id:e},query:{fields:t?.fields.join(",")??""}})}async function O(){const e=c.flows.readMany;return await S(e,{})}async function x(e){const t=c.flows.publish;return await S(t,{params:{flow_id:e}})}var B=e=>e.split("?")[0],R={createToken:({flow_name:e,flow_parameters:t,chatId:a})=>{const n=new URLSearchParams({chat_id:a});if(n.set("flow_identifier",crypto.randomUUID()),t)for(const[e,a]of Object.entries(t))n.set(e,a.toString());return`${e}?${decodeURIComponent(n.toString())}`},getName:B,destructureFlowToken:e=>{const t=B(e);let a=e.split("?")?.[1];"&"===a?.[0]&&(a=a.slice(1));const n=new URLSearchParams(a),r=n.get("chat_id")||n.get("chatId"),o=n.get("flow_identifier")||n.get("flowIdentifier"),s={};for(const[e,t]of n.entries())"chat_id"!==e&&"chatId"!==e&&"flow_identifier"!==e&&"flowIdentifier"!==e&&(s[e]=t);return{paramsString:a,flowName:t,chatId:r,flowIdentifier:o,flowParameters:s}}},U={"ar-SA":"ar","bn-BD":"bn","bn-IN":"bn","cs-CZ":"cs","da-DK":"da","de-AT":"de","de-CH":"de","de-DE":"de","el-GR":"el","en-AU":"en","en-CA":"en","en-GB":"en_GB","en-IE":"en","en-IN":"en","en-NZ":"en","en-ZA":"en","en-US":"en_US","es-AR":"es_AR","es-CL":"es","es-CO":"es","es-ES":"es_ES","es-MX":"es_MX","es-US":"es","fi-FI":"fi","fr-BE":"fr","fr-CA":"fr","fr-CH":"fr","fr-FR":"fr","he-IL":"he","hi-IN":"hi","hu-HU":"hu","id-ID":"id","it-CH":"it","it-IT":"it","ja-JP":"ja","ko-KR":"ko","nl-BE":"nl","nl-NL":"nl","no-NO":"nb","pl-PL":"pl","pt-PT":"pt_PT","pt-BR":"pt_BR","ro-RO":"ro","ru-RU":"ru","sk-SK":"sk","sv-SE":"sv","ta-IN":"ta","ta-LK":"ta","th-TH":"th","tr-TR":"tr","zh-CN":"zh_CN","zh-HK":"zh_HK","zh-TW":"zh_TW"},z=e=>{const t=U[e];return void 0===t?"en":t},M=e=>{const t={to:e.to,messaging_product:"whatsapp",recipient_type:"individual"};return e.reply&&(t.context={message_id:e.reply}),e.showUrlPreviewImage&&(t.preview_url=e.showUrlPreviewImage),t},D={flow:e=>{if("flow"!==e.message.type)throw new Error("Invalid type");const{message:t,...a}=e,{flow:n,...r}=t,o=M(a);n.mode||(n.mode=E.get("WHATSAPP_FLOWS_MODE"));const s=R.createToken({chatId:o.to,flow_name:n.name,flow_parameters:n.parameters});return{type:"interactive",...o,interactive:{...r,type:"flow",action:{name:"flow",parameters:{flow_name:n.name,flow_token:s,flow_message_version:"3",flow_cta:n.button,flow_action:n.action??"navigate",mode:n.mode,...n.payload&&{flow_action_payload:{...n.payload,screen:n.payload.screen.toUpperCase()}}}}}}},text:e=>{if("text"!==e.message.type)throw new Error("Invalid type");const{message:{text:t},...a}=e,n={type:"text",text:{body:t},...M(a)};return e.message.previewUrl&&n.text&&(n.text.preview_url=e.message.previewUrl),n},list:e=>{if("list"!==e.message.type)throw new Error("Invalid type");const{message:t,...a}=e,{list:n,type:r,...o}=t;return{...M(a),type:"interactive",interactive:{...o,type:r,action:n}}},button:e=>{if("button"!==e.message.type)throw new Error("Invalid type");const{message:t,...a}=e,{buttons:n,type:r,...o}=t;return{...M(a),type:"interactive",interactive:{...o,type:r,action:{buttons:n.map((e=>({reply:{id:e.id,title:e.text},type:"reply"})))}}}},template:e=>{if("template"!==e.message.type)throw new Error("Invalid type");const{message:{type:t,...a},...n}=e,r={...M(n),type:t,template:{...a,language:{code:z(a.language)}}};return r.template&&(r.template.namespace=process.env.WHATSAPP_MESSAGE_NAMESPACE),r},media:e=>{if("media"!==e.message.type)throw new Error("Invalid type");const{message:{type:t,...a},...n}=e,r=Object.entries(a)[0],[o,{ref:s,...i}]=r,l=i,c=M(n);return Number.isNaN(Number(s))?l.link=s:l.id=s,{type:o,[o]:l,...c}},contact:e=>{if("contact"!==e.message.type)throw new Error("Invalid type");const{message:{contacts:t},...a}=e;return{type:"contacts",contacts:t,...M(a)}}};function k(e){const{encrypted_aes_key:t,encrypted_flow_data:n,initial_vector:r}=e,o=a.default.createPrivateKey({key:E.get("WHATSAPP_ACCOUNT_ENCRYPTION_PRIVATE_KEY"),passphrase:E.get("WHATSAPP_ACCOUNT_ENCRYPTION_PASSPHRASE")}),s=a.default.privateDecrypt({key:o,padding:a.default.constants.RSA_PKCS1_OAEP_PADDING,oaepHash:"sha256"},Buffer.from(t,"base64")),i=Buffer.from(n,"base64"),l=Buffer.from(r,"base64"),c=i.subarray(0,-16),p=i.subarray(-16),d=a.default.createDecipheriv("aes-128-gcm",s,l);d.setAuthTag(p);const u=Buffer.concat([d.update(c),d.final()]).toString("utf-8");return{payload:JSON.parse(u),encryptionMetadata:{aesKeyBuffer:s,initialVectorBuffer:l}}}function L(e){const t=new URL(e.url).searchParams,a=t.get("hub.verify_token"),n=t.get("hub.challenge");return!(!a||!n)&&a===E.get("WHATSAPP_WEBHOOK_KEY")&&n}async function H(e,t){const n=e.headers.get("x-hub-signature-256");if(!n)return!1;const r=n.replace("sha256=",""),o=a.default.createHmac("sha256",E.get("WHATSAPP_WEBHOOK_KEY")).update(t,"utf-8").digest("hex");return!!a.default.timingSafeEqual(Buffer.from(r),Buffer.from(o))}var K={toGraph:{sendMessage:e=>D[e.message.type](e),flowResponse:(e,t)=>{if(!t.data)throw new Error("Missing data in flow response");if(!t.screen)throw new Error("Missing screen in flow response");if(t.screen=t.screen.toUpperCase(),"SUCCESS"===t.screen){const a=t.data??{};t.data={extension_message_response:{params:{flow_token:e,...a}}}}return t}},toSDK:{webhook:async function(e){if("GET"===e.method){const t=L(e);if(!t)throw new Error("Invalid health check hub");return{type:"healthCheck",payload:t}}const t=await e.text(),a=JSON.parse(t);if("entry"in a){if(!H(e,t))throw new Error("Invalid application webhook signature");const r=a.entry.flatMap((e=>e.changes)).filter((e=>"messages"===e.field)).flatMap((e=>e.value.messages)).filter(Boolean).map((e=>function(e){const t=e.from,a={id:e.id,type:e.type,timestamp:e.timestamp,metadata:{forwarded:e.context?.forwarded,frequentlyForwarded:e.context?.frequently_forwarded}},n=function(e){if(!(e.audio||e.document||e.video||e.image))return null;const t=e.audio?.id??e.document?.id??e.image?.id??e.video?.id,a=e.audio?.mime_type??e.document?.mime_type??e.image?.mime_type??e.video?.mime_type,n=["audio","document","image","video"].find((t=>e[t])),r=e.image?.sha256??e.document?.sha256??e.video?.sha256;return{id:t,type:n,caption:e.document?.caption??e.image?.caption??e.video?.caption??null,mime_type:a,sha256:r,filename:e.document?.filename??e.video?.filename}}(e),r=function(e){return e.text?.body??e.button?.text??e.interactive?.button_reply?.title??e.interactive?.list_reply?.title??e.document?.caption??null}(e),o=function(e){return e.interactive?{...e.interactive?.button_reply||e.button?{button:{id:e.interactive?.button_reply?.id??null,title:e.button?.text??e.interactive.button_reply?.title,payload:e.button?.payload??null}}:{},...e.interactive.list_reply?{selectedOption:{id:e.interactive.list_reply.id,title:e.interactive.list_reply.title,description:e.interactive.list_reply.description}}:{},...e.interactive.nfm_reply?{flowResponse:JSON.parse(e.interactive.nfm_reply.response_json)}:{}}:null}(e);return{...a,...o&&{interaction:o},...n&&{media:n},text:r,chatId:t}}(e)));return{type:"application",payload:{messageReceived:(n=r,n.length?n:void 0)}}}var n;if("encrypted_flow_data"in a)return{type:"flowExchange",payload:{...k(a),pingResponse:{data:{status:"active"}}}};throw new Error("Unrecognized event")}}},j={messages:{send:async function(e){const t=K.toGraph.sendMessage(e),a=c.messages.send;return await S(a,{body:t})}},flows:{...h},waba:{registerNumber:async function({dataRegion:e,pin:t}){const a=c.waba.registerNumber,n={messaging_product:"whatsapp",pin:t};return e&&(n.data_localization_region=e),await S(a,{body:n},{asUrlEncoded:!0})},encryption:{upload:async function(e){const t=c.waba.updateEncryption,a={business_public_key:e};return await S(t,{body:a},{asUrlEncoded:!0})}}}};async function W(e){return await fetch(e).then((async e=>{const t=await e.arrayBuffer();return Buffer.from(t)}))}var G={verifyHub:L,verifySignature:H,generateWabaEncryption:async function(){const e=a.default.randomUUID(),{publicKey:t,privateKey:n}=a.default.generateKeyPairSync("rsa",{modulusLength:2048,publicKeyEncoding:{type:"spki",format:"pem"},privateKeyEncoding:{type:"pkcs8",format:"pem",cipher:"aes-256-cbc",passphrase:e}});return{passphrase:e,publicKey:t,privateKey:n}},decryptFlowBody:k,encryptFlowResponse:function(e,t){const n=[];for(const e of Buffer.from(t.initialVectorBuffer).entries())n.push(~e[1]);const r=a.default.createCipheriv("aes-128-gcm",Buffer.from(t.aesKeyBuffer),Buffer.from(n));return Buffer.concat([r.update(JSON.stringify(e),"utf-8"),r.final(),r.getAuthTag()]).toString("base64")},decryptFlowMedia:async function(e){const t=[];for(const n of e){let{cdn_url:e,encryption_metadata:r}=n;if("EXAMPLE_DATA__CDN_URL_WILL_COME_IN_THIS_FIELD"===e){e="https://picsum.photos/seed/picsum/200";const a=await W(e);t.push(a);continue}const o=await W(e),{iv:s,encryption_key:i,hmac_key:l,encrypted_hash:c,plaintext_hash:p}=r,d={iv:Buffer.from(s,"base64"),encryption_key:Buffer.from(i,"base64"),hmac_key:Buffer.from(l,"base64")};if(a.default.createHash("sha256").update(o).digest("base64")!==c)throw new Error("Encrypted hash validation failed");const u=o.subarray(0,o.length-10),f=o.subarray(-10);if(!a.default.createHmac("sha256",d.hmac_key).update(Buffer.concat([d.iv,u])).digest().subarray(0,10).equals(f))throw new Error("HMAC validation failed");const m=a.default.createDecipheriv("aes-256-cbc",d.encryption_key,d.iv),y=m.update(u),w=Buffer.concat([y,m.final()]);if(a.default.createHash("sha256").update(w).digest("base64")!==p)throw new Error("Decrypted media hash validation failed");t.push(w)}return t}},q={flows:R},$=null;exports.actions=j,exports.createWhatsapp=()=>$||($=(()=>{const{settings:e}=b,{actions:t,flows:a,parsers:n,security:r,utils:s,toGraphLanguageTag:i}=g,{endpoints:l}=o;return{settings:e,sdk:{actions:t,flows:a,parsers:n,security:r,utils:s,toGraphLanguageTag:i},graph:{endpoints:l}}})()),exports.endpoints=c,exports.flowAction=p,exports.flowCanSendMessageStatus=w,exports.flowCategory=d,exports.flowMediaData=u,exports.flowMetadata=f,exports.flowScreen=m,exports.flowStatus=y,exports.flowValidationError=_,exports.flows=R,exports.flowsEndpoints=s,exports.messagesEndpoints=i,exports.parsers=K,exports.security=G,exports.toGraphLanguageTag=z,exports.utils=q,exports.wabaEndpoints=l;
|
package/dist/index.d.cts
CHANGED
@@ -1984,9 +1984,7 @@ interface WaSDKEvent<T extends WaSDKEventType = WaSDKEventType> {
|
|
1984
1984
|
payload: WaSDKEventPayload[T];
|
1985
1985
|
}
|
1986
1986
|
|
1987
|
-
declare function webhook(request: Request): Promise<WaSDKEvent<"healthCheck"> | WaSDKEvent<"application"> | WaSDKEvent<"flowExchange"
|
1988
|
-
error: boolean;
|
1989
|
-
}>;
|
1987
|
+
declare function webhook(request: Request): Promise<WaSDKEvent<"healthCheck"> | WaSDKEvent<"application"> | WaSDKEvent<"flowExchange">>;
|
1990
1988
|
|
1991
1989
|
declare function uploadWabaEncryption(publicKey: string): Promise<unknown>;
|
1992
1990
|
|
@@ -2005,7 +2003,9 @@ declare const actions: {
|
|
2005
2003
|
send: typeof send;
|
2006
2004
|
};
|
2007
2005
|
flows: {
|
2008
|
-
create(body: WhatsappCreateFlowRequestBody
|
2006
|
+
create(body: Omit<WhatsappCreateFlowRequestBody, "flow_json"> & {
|
2007
|
+
flow_json: Record<string, AnyType>;
|
2008
|
+
}): Promise<WhatsappCreateFlowResponse>;
|
2009
2009
|
updateMetadata(flow_id: string, body: WhatsappFlowUpdateMetadataRequestBody): Promise<WhatsappFlowUpdateMetadataResponse>;
|
2010
2010
|
updateJson(flow_id: string, json: Record<string, AnyType>): Promise<WhatsappUpdateFlowJsonResponse>;
|
2011
2011
|
getPreview(flow_id: string, query?: WhatsappGetFlowWebPreviewPageRequestQuery): Promise<string>;
|
@@ -2107,7 +2107,9 @@ declare const createWhatsapp: () => {
|
|
2107
2107
|
send: typeof send;
|
2108
2108
|
};
|
2109
2109
|
flows: {
|
2110
|
-
create(body: WhatsappCreateFlowRequestBody
|
2110
|
+
create(body: Omit<WhatsappCreateFlowRequestBody, "flow_json"> & {
|
2111
|
+
flow_json: Record<string, AnyType>;
|
2112
|
+
}): Promise<WhatsappCreateFlowResponse>;
|
2111
2113
|
updateMetadata(flow_id: string, body: WhatsappFlowUpdateMetadataRequestBody): Promise<WhatsappFlowUpdateMetadataResponse>;
|
2112
2114
|
updateJson(flow_id: string, json: Record<string, AnyType>): Promise<WhatsappUpdateFlowJsonResponse>;
|
2113
2115
|
getPreview(flow_id: string, query?: WhatsappGetFlowWebPreviewPageRequestQuery): Promise<string>;
|