fix(notifications): auto-request 'default' permission at most once per page

A pending approval/clarify prompt re-surfaces on every 1.5s poll tick, and
with permission still 'default' (second browser/device) each tick issued a
non-gesture Notification.requestPermission() and toasted 'notifications
denied'. Auto requests are now made once per page; the explicit Send-test
path still always asks. Release-gate hardening on top of #7493.
This commit is contained in:
nesquena-hermes committed 2026-09-24 03:15:09 +00:00
1 parent ea5f7730be
commit 16acb63a6d
2 files changed
+34

No files matched your search

+8
View File
@@ -9643,6 +9643,14 @@ function sendBrowserNotification(title,body,options={}){
if(force&&typeof showToast==='function') showToast(t('notifications_denied'),3500,'error');
return false;
}
// Permission still 'default': prompt-card owners retry on every 1.5s poll
// tick while pending, so an automatic (non-gesture) request is made at most
// once per page — otherwise each tick re-prompts and re-toasts "denied".
// The explicit "Send test" (force) path always asks.
if(!force){
if(sendBrowserNotification._autoPermissionRequested) return false;
sendBrowserNotification._autoPermissionRequested=true;
}
return requestNotificationPermission().then(p => p==='granted' ? deliver() : false).catch(() => false);
}
@@ -134,3 +134,29 @@ console.log(JSON.stringify({shown}));
''', ('_startClarifyFallbackPoll',))
assert result == dict(shown=[])
def test_default_permission_is_auto_requested_once_not_every_poll_tick():
"""A pending prompt re-surfaces on every 1.5s poll tick; with permission still
'default' (a second browser/device) the automatic, non-gesture request must be
made at most once per page, so the user is not re-prompted and re-toasted
"notifications denied" on every tick. The explicit Send-test path still asks."""
result = run(r'''
const window=global.window={_notificationsEnabled:true};
let requests=0; const toasts=[];
global.t=(k)=>k;
global.showToast=(msg)=>toasts.push(msg);
global.updateNotificationPermissionStatus=()=>{};
window.Notification=global.Notification=function(){};
Notification.permission='default';
Notification.requestPermission=()=>{requests++;return Promise.resolve('default');};
global.assistantDisplayName=()=> 'Hermes';
global._notificationOptions=()=>({});
Object.defineProperty(global,'navigator',{value:{}});
const p={approval_id:'id'};
for (let i=0;i<5;i++){ _notifyPromptCard('approval','s',p); await flush(); await flush(); }
const autoRequests=requests, autoToasts=toasts.length, seenAfterAuto=_promptNotifySeen.size;
await sendBrowserNotification('Test','body',{force:true}); await flush();
console.log(JSON.stringify({autoRequests,autoToasts,seenAfterAuto,forcedRequests:requests-autoRequests}));
''', ('sendBrowserNotification', '_showPwaNotification', 'requestNotificationPermission'))
assert result == dict(autoRequests=1, autoToasts=1, seenAfterAuto=0, forcedRequests=1)