Skip to content

Commit af36d28

Browse files
committed
fix(webpush): add logs for AggregateError error
Signed-off-by: 0xsysr3ll <[email protected]>
1 parent 954e535 commit af36d28

File tree

1 file changed

+45
-5
lines changed

1 file changed

+45
-5
lines changed

server/lib/notifications/agents/webpush.ts

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,21 @@ interface PushNotificationPayload {
2424
isAdmin?: boolean;
2525
}
2626

27+
interface WebPushError extends Error {
28+
statusCode?: number;
29+
status?: number;
30+
body?: string | unknown;
31+
response?: {
32+
body?: string | unknown;
33+
};
34+
errors?: {
35+
statusCode?: number;
36+
status?: number;
37+
message?: string;
38+
body?: string | unknown;
39+
}[];
40+
}
41+
2742
class WebPushAgent
2843
extends BaseAgent<NotificationAgentConfig>
2944
implements NotificationAgent
@@ -188,7 +203,34 @@ class WebPushAgent
188203
notificationPayload
189204
);
190205
} catch (e) {
191-
const statusCode = (e as any).statusCode || (e as any).status;
206+
// Extract status code from error or nested errors (for AggregateError)
207+
const webPushError = e as WebPushError;
208+
let statusCode = webPushError.statusCode || webPushError.status;
209+
let errorMessage = webPushError.message || String(e);
210+
let errorBody = webPushError.body || webPushError.response?.body;
211+
212+
// Handle AggregateError - check nested errors for status codes
213+
if (e instanceof AggregateError || webPushError.errors) {
214+
const errors = webPushError.errors || [];
215+
for (const nestedError of errors) {
216+
const nestedStatusCode =
217+
nestedError?.statusCode || nestedError?.status;
218+
if (nestedStatusCode) {
219+
statusCode = nestedStatusCode;
220+
}
221+
if (nestedError?.message && !errorMessage) {
222+
errorMessage = nestedError.message;
223+
}
224+
if (nestedError?.body && !errorBody) {
225+
errorBody = nestedError.body;
226+
}
227+
}
228+
}
229+
230+
// Permanent failure status codes per RFC 8030:
231+
// - 410 Gone: Subscription expired/invalid (Section 6.2)
232+
// - 404 Not Found: Subscription expired (Section 7.3)
233+
// All other errors (429 rate limiting, network issues, etc.) are transient
192234
const isPermanentFailure = statusCode === 410 || statusCode === 404;
193235

194236
logger.error(
@@ -200,15 +242,13 @@ class WebPushAgent
200242
recipient: pushSub.user.displayName,
201243
type: Notification[type],
202244
subject: payload.subject,
203-
errorMessage: (e as Error).message || String(e),
245+
errorMessage,
204246
statusCode: statusCode || 'unknown',
205-
errorBody: (e as any).body || (e as any).response?.body,
206-
endpoint: pushSub.endpoint.substring(0, 50) + '...',
207247
}
208248
);
209249

210250
// Only remove subscription for permanent failures
211-
// Transient errors should not remove the subscription
251+
// Transient errors (rate limiting, network issues, etc.) should not remove the subscription
212252
if (isPermanentFailure) {
213253
await userPushSubRepository.remove(pushSub);
214254
}

0 commit comments

Comments
 (0)