@@ -78,9 +78,9 @@ export const isFCMCredentials = ajv.compile<FCMCredentials>(FCMCredentialsValida
7878// This type must match the type defined in the push gateway
7979type GatewayNotification = {
8080 uniqueId : string ;
81- from : string ;
82- title : string ;
83- text : string ;
81+ from ? : string ;
82+ title ? : string ;
83+ text ? : string ;
8484 badge ?: number ;
8585 sound ?: string ;
8686 notId ?: number ;
@@ -123,8 +123,7 @@ type GatewayNotification = {
123123export type NativeNotificationParameters = {
124124 userTokens : string | string [ ] ;
125125 notification : PendingPushNotification ;
126- _replaceToken : ( currentToken : IPushToken [ 'token' ] , newToken : IPushToken [ 'token' ] ) => void ;
127- _removeToken : ( token : IPushToken [ 'token' ] ) => void ;
126+ _removeToken : ( token : string ) => void ;
128127 options : RequiredField < PushOptions , 'gcm' > ;
129128} ;
130129
@@ -167,12 +166,10 @@ class PushClass {
167166 }
168167 }
169168
170- private replaceToken ( currentToken : IPushToken [ 'token' ] , newToken : IPushToken [ 'token' ] ) : void {
171- void PushToken . updateMany ( { token : currentToken } , { $set : { token : newToken } } ) ;
172- }
173-
174- private removeToken ( token : IPushToken [ 'token' ] ) : void {
175- void PushToken . deleteOne ( { token } ) ;
169+ private removeToken ( token : string ) : void {
170+ void PushToken . removeAllByTokenString ( token ) . catch ( ( err ) => {
171+ logger . error ( { msg : 'Failed to remove push token' , err } ) ;
172+ } ) ;
176173 }
177174
178175 private shouldUseGateway ( ) : boolean {
@@ -188,10 +185,13 @@ class PushClass {
188185 logger . debug ( { msg : 'send to token' , token : app . token } ) ;
189186
190187 if ( 'apn' in app . token && app . token . apn ) {
188+ const userToken = notification . voip ? app . voipToken : app . token . apn ;
189+ const topic = notification . voip ? `${ app . appName } .voip` : app . appName ;
190+
191191 countApn . push ( app . _id ) ;
192192 // Send to APN
193- if ( this . options . apn ) {
194- sendAPN ( { userToken : app . token . apn , notification : { topic : app . appName , ...notification } , _removeToken : this . removeToken } ) ;
193+ if ( this . options . apn && userToken ) {
194+ sendAPN ( { userToken, notification : { topic, ...notification } , _removeToken : this . removeToken } ) ;
195195 }
196196 } else if ( 'gcm' in app . token && app . token . gcm ) {
197197 countGcm . push ( app . _id ) ;
@@ -210,7 +210,6 @@ class PushClass {
210210 sendFCM ( {
211211 userTokens : app . token . gcm ,
212212 notification,
213- _replaceToken : this . replaceToken ,
214213 _removeToken : this . removeToken ,
215214 options : sendGCMOptions as RequiredField < PushOptions , 'gcm' > ,
216215 } ) ;
@@ -275,16 +274,7 @@ class PushClass {
275274
276275 if ( result . status === 406 ) {
277276 logger . info ( { msg : 'removing push token' , token } ) ;
278- await PushToken . deleteMany ( {
279- $or : [
280- {
281- 'token.apn' : token ,
282- } ,
283- {
284- 'token.gcm' : token ,
285- } ,
286- ] ,
287- } ) ;
277+ this . removeToken ( token ) ;
288278 return ;
289279 }
290280
@@ -340,8 +330,13 @@ class PushClass {
340330 logger . debug ( { msg : 'send to token' , token : app . token } ) ;
341331
342332 if ( 'apn' in app . token && app . token . apn ) {
343- countApn . push ( app . _id ) ;
344- return this . sendGatewayPush ( gateway , 'apn' , app . token . apn , { topic : app . appName , ...gatewayNotification } ) ;
333+ const token = notification . voip ? app . voipToken : app . token . apn ;
334+ const topic = notification . voip ? `${ app . appName } .voip` : app . appName ;
335+
336+ if ( token ) {
337+ countApn . push ( app . _id ) ;
338+ return this . sendGatewayPush ( gateway , 'apn' , token , { topic, ...gatewayNotification } ) ;
339+ }
345340 }
346341
347342 if ( 'gcm' in app . token && app . token . gcm ) {
@@ -373,12 +368,7 @@ class PushClass {
373368 userId : notification . userId ,
374369 } ) ;
375370
376- const query = {
377- userId : notification . userId ,
378- $or : [ { 'token.apn' : { $exists : true } } , { 'token.gcm' : { $exists : true } } ] ,
379- } ;
380-
381- const appTokens = PushToken . find ( query ) ;
371+ const appTokens = PushToken . findAllTokensByUserId ( notification . userId ) ;
382372
383373 for await ( const app of appTokens ) {
384374 logger . debug ( { msg : 'send to token' , token : app . token } ) ;
@@ -427,9 +417,9 @@ class PushClass {
427417 private _validateDocument ( notification : PendingPushNotification ) : void {
428418 // Check the general notification
429419 check ( notification , {
430- from : String ,
431- title : String ,
432- text : String ,
420+ from : Match . Optional ( String ) ,
421+ title : Match . Optional ( String ) ,
422+ text : Match . Optional ( String ) ,
433423 sent : Match . Optional ( Boolean ) ,
434424 sending : Match . Optional ( Match . Integer ) ,
435425 badge : Match . Optional ( Match . Integer ) ,
@@ -448,11 +438,24 @@ class PushClass {
448438 createdAt : Date ,
449439 createdBy : Match . OneOf ( String , null ) ,
450440 priority : Match . Optional ( Match . Integer ) ,
441+ voip : Match . Optional ( Boolean ) ,
451442 } ) ;
452443
453444 if ( ! notification . userId ) {
454445 throw new Error ( 'No userId found' ) ;
455446 }
447+
448+ if ( ! notification . voip ) {
449+ const { from, title, text } = notification ;
450+ check (
451+ { from, title, text } ,
452+ {
453+ from : String ,
454+ title : String ,
455+ text : String ,
456+ } ,
457+ ) ;
458+ }
456459 }
457460
458461 private hasApnOptions ( options : IPushNotificationConfig ) : options is RequiredField < IPushNotificationConfig , 'apn' > {
@@ -463,17 +466,31 @@ class PushClass {
463466 return Match . test ( options . gcm , Object ) ;
464467 }
465468
466- public async send ( options : IPushNotificationConfig ) {
467- const notification : PendingPushNotification = {
469+ private getPendingNotification ( options : IPushNotificationConfig ) : PendingPushNotification {
470+ const required = {
468471 createdAt : new Date ( ) ,
469472 // createdBy is no longer used, but the gateway still expects it
470473 createdBy : '<SERVER>' ,
471474 sent : false ,
472475 sending : 0 ,
476+ ...pick ( options , 'userId' , 'payload' , 'notId' , 'priority' ) ,
477+ } as const ;
478+
479+ if ( options . voip ) {
480+ return {
481+ ...required ,
482+ voip : true ,
483+ } ;
484+ }
485+
486+ return {
487+ voip : false ,
488+ ...required ,
489+
473490 title : truncateString ( options . title , PUSH_TITLE_LIMIT ) ,
474491 text : truncateString ( options . text , PUSH_MESSAGE_BODY_LIMIT ) ,
475492
476- ...pick ( options , 'from' , 'userId' , 'payload' , ' badge', 'sound' , 'notId' , 'priority ') ,
493+ ...pick ( options , 'from' , 'badge' , 'sound' ) ,
477494
478495 ...( this . hasApnOptions ( options )
479496 ? {
@@ -490,6 +507,10 @@ class PushClass {
490507 }
491508 : { } ) ,
492509 } ;
510+ }
511+
512+ public async send ( options : IPushNotificationConfig ) {
513+ const notification = this . getPendingNotification ( options ) ;
493514
494515 // Validate the notification
495516 this . _validateDocument ( notification ) ;
0 commit comments