@@ -31,7 +31,7 @@ import { DEFAULT_API_VERSION } from "./types.js";
31
31
/**
32
32
* The main API Class
33
33
*/
34
- export class WhatsAppAPI {
34
+ export class WhatsAppAPI < EmittersReturnType = void > {
35
35
//#region Properties
36
36
/**
37
37
* The API token
@@ -61,11 +61,6 @@ export class WhatsAppAPI {
61
61
* If true, API operations will return the fetch promise instead. Intended for low level debugging.
62
62
*/
63
63
private parsed : boolean ;
64
- /**
65
- * If false, the user functions won't be offloaded from the main event loop.
66
- * Intended for Serverless Environments where the process might be killed after the main function finished.
67
- */
68
- private offload_functions : boolean ;
69
64
/**
70
65
* If false, the API will be used in a less secure way, removing the need for appSecret. Defaults to true.
71
66
*/
@@ -88,9 +83,9 @@ export class WhatsAppAPI {
88
83
* ```
89
84
*/
90
85
public on : {
91
- message ?: OnMessage ;
86
+ message ?: OnMessage < EmittersReturnType > ;
92
87
sent ?: OnSent ;
93
- status ?: OnStatus ;
88
+ status ?: OnStatus < EmittersReturnType > ;
94
89
} = { } ;
95
90
//#endregion
96
91
@@ -125,7 +120,6 @@ export class WhatsAppAPI {
125
120
webhookVerifyToken,
126
121
v,
127
122
parsed = true ,
128
- offload_functions = true ,
129
123
secure = true ,
130
124
ponyfill = { }
131
125
} : WhatsAppAPIConstructorArguments ) {
@@ -176,7 +170,6 @@ export class WhatsAppAPI {
176
170
}
177
171
178
172
this . parsed = ! ! parsed ;
179
- this . offload_functions = ! ! offload_functions ;
180
173
}
181
174
182
175
//#region Message Operations
@@ -273,7 +266,7 @@ export class WhatsAppAPI {
273
266
response
274
267
} ;
275
268
276
- this . user_function ( this . on ?. sent , args ) ;
269
+ WhatsAppAPI . user_function ( this . on ?. sent , args ) ;
277
270
278
271
return response ?? promise ;
279
272
}
@@ -733,7 +726,7 @@ export class WhatsAppAPI {
733
726
*
734
727
* const token = "token";
735
728
* const appSecret = "appSecret";
736
- * const Whatsapp = new WhatsAppAPI(NodeNext({ token, appSecret }));
729
+ * const Whatsapp = new WhatsAppAPI<number> (NodeNext({ token, appSecret }));
737
730
*
738
731
* function handler(req, res) {
739
732
* if (req.method == "POST") {
@@ -755,8 +748,10 @@ export class WhatsAppAPI {
755
748
* } else res.writeHead(501).end();
756
749
* };
757
750
*
758
- * Whatsapp.on.message = ({ phoneID, from, message, name }) => {
751
+ * Whatsapp.on.message = ({ phoneID, from, message, name, reply, offload }) => {
759
752
* console.log(`User ${name} (${from}) sent to bot ${phoneID} a(n) ${message.type}`);
753
+ * offload(() => reply(new Text("Hello!")));
754
+ * return 202;
760
755
* };
761
756
*
762
757
* const server = createServer(handler);
@@ -766,19 +761,21 @@ export class WhatsAppAPI {
766
761
* @param data - The POSTed data object sent by Whatsapp
767
762
* @param raw_body - The raw body of the POST request
768
763
* @param signature - The x-hub-signature-256 (all lowercase) header signature sent by Whatsapp
769
- * @returns 200, it 's the expected http/s response code
764
+ * @returns The emitter 's return value, undefined if the corresponding emitter isn't set
770
765
* @throws 500 if secure and the appSecret isn't specified
771
766
* @throws 501 if secure and crypto.subtle or ponyfill isn't available
772
767
* @throws 400 if secure and the raw body is missing
773
768
* @throws 401 if secure and the signature is missing
774
769
* @throws 401 if secure and the signature doesn't match the hash
775
770
* @throws 400 if the POSTed data is not a valid Whatsapp API request
771
+ * @throws 500 if the user's callback throws an error
772
+ * @throws 200, if the POSTed data is valid but not a message or status update (ignored)
776
773
*/
777
774
async post (
778
775
data : PostData ,
779
776
raw_body ?: string ,
780
777
signature ?: string
781
- ) : Promise < 200 > {
778
+ ) : Promise < EmittersReturnType | undefined > {
782
779
//Validating the payload
783
780
if ( this . secure ) {
784
781
if ( ! this . appSecret ) throw 500 ;
@@ -841,10 +838,15 @@ export class WhatsAppAPI {
841
838
context ? message . id : undefined ,
842
839
biz_opaque_callback_data
843
840
) ,
841
+ offload : WhatsAppAPI . offload ,
844
842
Whatsapp : this
845
843
} ;
846
844
847
- this . user_function ( this . on ?. message , args ) ;
845
+ try {
846
+ return this . on ?. message ?.( args ) ;
847
+ } catch ( error ) {
848
+ throw 500 ;
849
+ }
848
850
} else if ( "statuses" in value ) {
849
851
const statuses = value . statuses [ 0 ] ;
850
852
@@ -867,15 +869,20 @@ export class WhatsAppAPI {
867
869
pricing,
868
870
error,
869
871
biz_opaque_callback_data,
872
+ offload : WhatsAppAPI . offload ,
870
873
raw : data
871
874
} ;
872
875
873
- this . user_function ( this . on ?. status , args ) ;
876
+ try {
877
+ return this . on ?. status ?.( args ) ;
878
+ } catch ( error ) {
879
+ throw 500 ;
880
+ }
874
881
}
882
+
875
883
// If unknown payload, just ignore it
876
884
// Facebook doesn't care about your server's opinion
877
-
878
- return 200 ;
885
+ throw 200 ;
879
886
}
880
887
881
888
/**
@@ -993,27 +1000,22 @@ export class WhatsAppAPI {
993
1000
* @param f - The user function to call
994
1001
* @param a - The arguments to pass to the function
995
1002
*/
996
- private user_function < A , F extends ( ( ...a : A [ ] ) => unknown ) | undefined > (
997
- f : F ,
1003
+ private static async user_function < A , F extends ( ...a : A [ ] ) => unknown > (
1004
+ f ? : F ,
998
1005
...a : A [ ]
999
1006
) {
1000
1007
if ( f ) {
1001
- if ( this . offload_functions ) {
1002
- this . offload ( f , ...a ) ;
1003
- } else {
1004
- f ( ...a ) ;
1005
- }
1008
+ WhatsAppAPI . offload ( f , ...a ) ;
1006
1009
}
1007
1010
}
1008
1011
1009
1012
/**
1010
1013
* Offload a function to the next tick of the event loop
1011
1014
*
1012
- * @internal
1013
1015
* @param f - The function to offload from the main thread
1014
1016
* @param a - The arguments to pass to the function
1015
1017
*/
1016
- private offload < A , F extends ( ...a : A [ ] ) => unknown > ( f : F , ...a : A [ ] ) {
1018
+ static offload < A , F extends ( ...a : A [ ] ) => unknown > ( f : F , ...a : A [ ] ) {
1017
1019
// Thanks @RahulLanjewar 93
1018
1020
Promise . resolve ( ) . then ( ( ) => f ( ...a ) ) ;
1019
1021
}
0 commit comments