fix(push): stop pushes for read, silent and muted messages (#3033)

This commit is contained in:
Hampus authored and GitHub committed 2026-09-29 15:58:46 +02:00
1 parent 9908518f5b
commit b30ea361d3
45 files changed
+3393 -268

No files matched your search

@@ -19,6 +19,7 @@ import {
getBadgeCount,
getPushNotificationClientState,
isNotificationClearPayload,
isPushNotificationReadThrough,
matchesPushChannelNotification,
normalizePushPayload,
resolvePushChannelId,
@@ -227,7 +228,10 @@ const getShownPushNotifications = async (tag: string): Promise<ReadonlyArray<Not
return [];
}
};
const closePushNotificationsForChannel = async (channelId: string): Promise<number> => {
const closePushNotificationsForChannel = async (
channelId: string,
readThroughMessageId: string | undefined,
): Promise<number> => {
if (typeof self.registration.getNotifications !== 'function') {
return 0;
}
@@ -235,7 +239,10 @@ const closePushNotificationsForChannel = async (channelId: string): Promise<numb
const notifications = await self.registration.getNotifications();
let closedCount = 0;
for (const notification of notifications) {
if (matchesPushChannelNotification(notification, channelId)) {
if (
matchesPushChannelNotification(notification, channelId) &&
isPushNotificationReadThrough(notification, readThroughMessageId)
) {
notification.close();
closedCount++;
}
@@ -340,7 +347,7 @@ self.addEventListener('push', (event: PushEvent) => {
if (isNotificationClearPayload(payload)) {
const channelId = resolvePushChannelId(payload);
const closedCount = channelId
? await closePushNotificationsForChannel(channelId)
? await closePushNotificationsForChannel(channelId, resolvePushMessageId(payload))
: await closePushNotifications(tag);
await updateAppBadge(badgeCount);
await log('info', 'push clear received', {tag, channelId, closedCount, badgeCount});
@@ -89,6 +89,20 @@ export const matchesPushChannelNotification = (notification: Notification, chann
}
return typeof tag === 'string' && tag.startsWith(`${channelTag}:`);
};
const SNOWFLAKE_PATTERN = /^[1-9]\d*$/;
export const isPushNotificationReadThrough = (
notification: {readonly data?: unknown},
readThroughMessageId: string | undefined,
): boolean => {
if (readThroughMessageId === undefined || !SNOWFLAKE_PATTERN.test(readThroughMessageId)) {
return true;
}
const messageId = isRecord(notification.data) ? notification.data.message_id : undefined;
if (typeof messageId !== 'string' || !SNOWFLAKE_PATTERN.test(messageId)) {
return true;
}
return BigInt(messageId) <= BigInt(readThroughMessageId);
};
export const getPushNotificationClientState = (
clients: ReadonlyArray<{readonly visibilityState?: string}>,
): PushNotificationClientState => ({