@@ -8,11 +8,14 @@ import {
88 injectReferenceId ,
99 injectReply ,
1010 injectSpinner ,
11+ injectTyping ,
1112 injectUserId ,
1213} from "./api.ts" ;
1314import type { ConversationEvent , TaskHandler } from "./index.ts" ;
1415import type { Endpoint } from "./taskBouncer.ts" ;
1516
17+ const apiVersion = "v21.0" ;
18+
1619const {
1720 anymap,
1821 filter,
@@ -44,7 +47,7 @@ export const sendWhatsappMessage =
4447 ( accessToken : string , fromNumberId : string ) => ( to : string ) =>
4548 pipe ( convertToWhatsAppFormat , ( body : string ) =>
4649 fetch (
47- `https://graph.facebook.com/v20.0 /${ fromNumberId } /messages` ,
50+ `https://graph.facebook.com/${ apiVersion } /${ fromNumberId } /messages` ,
4851 {
4952 method : "POST" ,
5053 body : JSON . stringify ( {
@@ -54,10 +57,7 @@ export const sendWhatsappMessage =
5457 to,
5558 text : { preview_url : false , body } ,
5659 } ) ,
57- headers : {
58- "Authorization" : `Bearer ${ accessToken } ` ,
59- "Content-Type" : "application/json" ,
60- } ,
60+ headers : makeHeaders ( accessToken ) ,
6161 } ,
6262 ) . then ( async ( response ) => {
6363 if ( ! response . ok ) throw new Error ( await response . text ( ) ) ;
@@ -84,34 +84,34 @@ export const sendWhatsappTemplate =
8484 langCode : string ,
8585 components : Component [ ] ,
8686 ) =>
87- fetch ( `https://graph.facebook.com/v20.0/ ${ fromNumberId } /messages` , {
88- method : "POST" ,
89- body : JSON . stringify ( {
90- recipient_type : "individual " ,
91- messaging_product : "whatsapp" ,
92- to ,
93- type : "template " ,
94- template : {
95- name ,
96- language : { code : langCode } ,
97- components : components . map ( ( c ) => ( {
98- ... c ,
99- parameters : c . parameters . map ( ( p ) =>
100- p . type === "text"
101- ? ( {
102- type : "text" ,
103- text : templateTextParamConstraints ( p . text ) ,
104- } )
105- : p
106- ) ,
107- } ) ) ,
108- } ,
109- } ) ,
110- headers : {
111- Authorization : `Bearer ${ accessToken } ` ,
112- "Content-Type" : "application/json" ,
87+ fetch (
88+ `https://graph.facebook.com/ ${ apiVersion } / ${ fromNumberId } /messages` ,
89+ {
90+ method : "POST " ,
91+ body : JSON . stringify ( {
92+ recipient_type : "individual" ,
93+ messaging_product : "whatsapp " ,
94+ to ,
95+ type : "template" ,
96+ template : {
97+ name ,
98+ language : { code : langCode } ,
99+ components : components . map ( ( c ) => ( {
100+ ... c ,
101+ parameters : c . parameters . map ( ( p ) =>
102+ p . type === "text"
103+ ? ( {
104+ type : "text" ,
105+ text : templateTextParamConstraints ( p . text ) ,
106+ } )
107+ : p
108+ ) ,
109+ } ) ) ,
110+ } ,
111+ } ) ,
112+ headers : makeHeaders ( accessToken ) ,
113113 } ,
114- } ) . then ( async ( response ) => {
114+ ) . then ( async ( response ) => {
115115 if ( ! response . ok ) throw new Error ( await response . text ( ) ) ;
116116 return ( await response . json ( ) ) as SentMessageResponse ;
117117 } ) ;
@@ -327,12 +327,9 @@ type MediaGetResponse = {
327327} ;
328328
329329const getMediaFromId = ( accessToken : string ) => ( id : string ) : Promise < string > =>
330- fetch ( `https://graph.facebook.com/v21.0 /${ id } ` , {
330+ fetch ( `https://graph.facebook.com/${ apiVersion } /${ id } ` , {
331331 method : "GET" ,
332- headers : {
333- "Authorization" : `Bearer ${ accessToken } ` ,
334- "Content-Type" : "application/json" ,
335- } ,
332+ headers : makeHeaders ( accessToken ) ,
336333 } )
337334 . then ( ( response ) => response . json ( ) as Promise < MediaGetResponse > )
338335 . then ( ( { url } ) =>
@@ -385,13 +382,23 @@ export const whatsappForBusinessInjectDepsAndRun =
385382 injectUserId ( ( ) => coerce ( fromNumber ( msg ) ) ) ,
386383 injectSpinner ( pipe ( send , ( _ ) => ( ) => Promise . resolve ( ) ) ) ,
387384 injectReply ( send ) ,
385+ injectTyping ( ( ) =>
386+ sendWhatsappTypingIndicator ( token , toNumberId ( msg ) ) (
387+ messageId ( msg ) ,
388+ )
389+ ) ,
388390 referenceId ( msg )
389391 ? injectReferenceId ( ( ) => referenceId ( msg ) )
390392 : identity ,
391393 ) ( doTask ) ( ) ,
392394 )
393395 : Promise . resolve ( ) ;
394396
397+ const makeHeaders = ( accessToken : string ) => ( {
398+ "Authorization" : `Bearer ${ accessToken } ` ,
399+ "Content-Type" : "application/json" ,
400+ } ) ;
401+
395402export const whatsappBusinessHandler = (
396403 token : string ,
397404 path : string ,
@@ -401,3 +408,22 @@ export const whatsappBusinessHandler = (
401408 predicate : ( { url, method } ) => url === path && method === "POST" ,
402409 handler : whatsappForBusinessInjectDepsAndRun ( token , doTask ) ,
403410} ) ;
411+
412+ export const sendWhatsappTypingIndicator =
413+ ( accessToken : string , fromNumberId : string ) => ( messageId : string ) =>
414+ fetch (
415+ `https://graph.facebook.com/${ apiVersion } /${ fromNumberId } /messages` ,
416+ {
417+ method : "POST" ,
418+ body : JSON . stringify ( {
419+ messaging_product : "whatsapp" ,
420+ status : "read" ,
421+ message_id : messageId ,
422+ typing_indicator : { type : "text" } ,
423+ } ) ,
424+ headers : makeHeaders ( accessToken ) ,
425+ } ,
426+ ) . then ( async ( response ) => {
427+ if ( ! response . ok ) throw new Error ( await response . text ( ) ) ;
428+ return response . json ( ) ;
429+ } ) ;
0 commit comments