@@ -8,6 +8,18 @@ export const API_KEY = import.meta.env.VITE_ONESIGNAL_API_KEY as string | undefi
88const ANDROID_CHANNEL_ID = import . meta. env . VITE_ONESIGNAL_ANDROID_CHANNEL_ID as string | undefined ;
99const DEFAULT_ANDROID_CHANNEL_ID = 'b3b015d9-c050-4042-8548-dcc34aa44aa4' ;
1010
11+ function isTransientSendFailure ( data : unknown ) : boolean {
12+ if ( ! data || typeof data !== 'object' ) return false ;
13+ const record = data as { id ?: unknown ; errors ?: unknown ; recipients ?: unknown } ;
14+ const errors = record . errors ;
15+ const hasErrors =
16+ ( Array . isArray ( errors ) && errors . length > 0 ) ||
17+ ( errors != null && typeof errors === 'object' && Object . keys ( errors ) . length > 0 ) ;
18+ const missingId = typeof record . id !== 'string' || record . id . length === 0 ;
19+ const zeroRecipients = typeof record . recipients === 'number' && record . recipients === 0 ;
20+ return hasErrors || missingId || zeroRecipients ;
21+ }
22+
1123class OneSignalApiService {
1224 private static instance : OneSignalApiService ;
1325
@@ -85,9 +97,13 @@ class OneSignalApiService {
8597 const maxAttempts = 5 ;
8698 const backoffMs = ( n : number ) => 2_000 * 2 ** ( n - 1 ) ;
8799
88- // Retry on `invalid_player_ids` to absorb the brief race where the
89- // subscription has been created locally but is not yet visible to the
90- // /notifications endpoint.
100+ // Retry while the OneSignal backend hasn't yet indexed the freshly
101+ // created subscription. The /notifications endpoint reports this race in
102+ // a few different shapes, all of which return HTTP 200:
103+ // {"errors":{"invalid_player_ids":[...]}}
104+ // {"id":"","errors":["All included players are not subscribed"]}
105+ // {"id":"","errors":[...]}
106+ // Treat any 200 response without a real notification id as transient.
91107 for ( let attempt = 1 ; attempt <= maxAttempts ; attempt ++ ) {
92108 try {
93109 const response = await CapacitorHttp . post ( {
@@ -104,15 +120,12 @@ class OneSignalApiService {
104120 return false ;
105121 }
106122
107- const invalidIds = response . data ?. errors ?. invalid_player_ids ;
108- if ( Array . isArray ( invalidIds ) && invalidIds . length > 0 ) {
123+ if ( isTransientSendFailure ( response . data ) ) {
109124 if ( attempt < maxAttempts ) {
110125 await new Promise ( ( resolve ) => setTimeout ( resolve , backoffMs ( attempt ) ) ) ;
111126 continue ;
112127 }
113- console . error (
114- `Send notification failed: invalid_player_ids ${ JSON . stringify ( invalidIds ) } ` ,
115- ) ;
128+ console . error ( `Send notification failed: ${ JSON . stringify ( response . data ) } ` ) ;
116129 return false ;
117130 }
118131
0 commit comments