Skip to content

Commit d847049

Browse files
committed
fix: push notification token cycling
1 parent be27ea7 commit d847049

1 file changed

Lines changed: 35 additions & 23 deletions

File tree

infrastructure/evault-core/src/services/NotificationService.ts

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,13 @@ export class NotificationService {
170170

171171
console.log(`[NOTIF] Sending push to ${allTokens.length} token(s) for eName: ${eName}`);
172172

173-
const pushResults = await Promise.allSettled(
174-
allTokens.map(async ({ token, platform }) => {
173+
// Cycle through tokens sequentially: try each one, remove bad tokens
174+
// inline, and keep going until at least one succeeds.
175+
const badTokens: string[] = [];
176+
let delivered = false;
177+
178+
for (const { token, platform } of allTokens) {
179+
try {
175180
const res = await fetch(`${triggerUrl}/api/send`, {
176181
method: "POST",
177182
headers: { "Content-Type": "application/json" },
@@ -183,31 +188,32 @@ export class NotificationService {
183188
signal: AbortSignal.timeout(10000),
184189
});
185190
const data = await res.json();
186-
if (!data.success) {
187-
throw new Error(data.error || "Push send failed");
191+
192+
if (data.success) {
193+
console.log(`[NOTIF] Push delivered via token ${token.slice(0, 8)}… for ${eName}`);
194+
delivered = true;
195+
// Keep sending to remaining tokens — user may have multiple
196+
// devices (phone + tablet) that should all receive the notif.
197+
continue;
188198
}
189-
return data;
190-
})
191-
);
192199

193-
const pushSucceeded = pushResults.filter(r => r.status === "fulfilled").length;
194-
const pushFailed = pushResults.filter(r => r.status === "rejected").length;
200+
// Send returned an explicit failure
201+
const error = data.error || "Push send failed";
202+
console.error(`[NOTIF] Push failed for token ${token.slice(0, 8)}…:`, error);
195203

196-
// Collect tokens that returned a known "bad token" error so we can purge them
197-
const badTokens: string[] = [];
198-
pushResults.forEach((r, i) => {
199-
if (r.status === "rejected") {
200-
console.error(`[NOTIF] Push failed for token index ${i}:`, r.reason);
201-
if (isBadTokenError(r.reason)) {
202-
badTokens.push(allTokens[i].token);
204+
if (isBadTokenError(error)) {
205+
badTokens.push(token);
206+
console.log(`[NOTIF] Bad token ${token.slice(0, 8)}… queued for removal, trying next…`);
203207
}
204-
}
205-
});
208+
} catch (err) {
209+
const msg = err instanceof Error ? err.message : String(err);
210+
console.error(`[NOTIF] Push error for token ${token.slice(0, 8)}…:`, msg);
206211

207-
if (pushFailed > 0) {
208-
console.log(`[NOTIF] Push results for ${eName}: ${pushSucceeded} sent, ${pushFailed} failed`);
209-
} else {
210-
console.log(`[NOTIF] Push sent successfully to ${pushSucceeded} token(s) for ${eName}`);
212+
if (isBadTokenError(err)) {
213+
badTokens.push(token);
214+
console.log(`[NOTIF] Bad token ${token.slice(0, 8)}… queued for removal, trying next…`);
215+
}
216+
}
211217
}
212218

213219
// Purge bad tokens from both Verification and DeviceToken tables
@@ -216,7 +222,13 @@ export class NotificationService {
216222
await this.removeBadTokens(eName, badTokens);
217223
}
218224

219-
return pushSucceeded > 0 || pushFailed === 0;
225+
if (delivered) {
226+
console.log(`[NOTIF] Push delivered for ${eName}`);
227+
} else {
228+
console.log(`[NOTIF] Push failed for all ${allTokens.length} token(s) for ${eName}`);
229+
}
230+
231+
return delivered;
220232
}
221233

222234
private async removeBadTokens(eName: string, badTokens: string[]): Promise<void> {

0 commit comments

Comments
 (0)