R9 Web Push in decePub: one subscription per persona, each with its own token and registration
Build / Build (push) Successful in 56s
Build / Build (push) Successful in 56s
Settings gets "Notifications on this device" (PushEditor): personas, alerts in four groups, policy, a test
notification, after a one-time notice of what the push service learns. Each persona ticked gets its own service
worker registration (push-worker.js at push/{slot}/), so its own endpoint and keys, subscribed with its own token
(IHttpService's *As); nothing PrivaPub stores ties two personas together and the worker never reads the payload's
token. PushService follows the tokens (re-subscribing after a renewal), reconciles at every session start, turns
off before sign-out and drops deleted or suspended personas. A click opens that persona's notifications; the app
badge counts the unread ones. Exchanges now ask for the push scope.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WpVCoDeM1qUTRp4fXQdfof
This commit is contained in:
1 parent
d33697e3fc
commit
ab17959ed4
29 files changed
+2047
-67
No files matched your search
@@ -6,8 +6,10 @@ namespace decePubClient.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Asks a persona, once, before its first reaction or poll vote, and once before it first joins an event, to accept
|
||||
/// that these are public and visible as that persona (an owner decision). PublicNoticeHost shows the question; Confirm
|
||||
/// returns true at once for a persona that already accepted it, and false when the reader declines.
|
||||
/// that these are public and visible as that persona (an owner decision); and this device, once, before its first Web
|
||||
/// Push subscription, to accept that the browser's push service learns when notifications arrive (PublicAct.Push, told
|
||||
/// once for the device whichever persona asks). PublicNoticeHost shows the question; Confirm returns true at once for
|
||||
/// what was accepted already, and false when the reader declines.
|
||||
/// </summary>
|
||||
public class PublicNoticeService(ILocalStorageService localStorage)
|
||||
{
|
||||
@@ -22,11 +24,11 @@ namespace decePubClient.Services
|
||||
|
||||
public async Task<bool> Confirm(string personaId, PublicAct act = PublicAct.Reaction, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (string.IsNullOrEmpty(personaId))
|
||||
if (string.IsNullOrEmpty(personaId) && act != PublicAct.Push)
|
||||
return false;
|
||||
var seen = await localStorage.GetItemAsync<PublicActionNotices>(nameof(PublicActionNotices), cancellationToken) ?? new();
|
||||
var told = act == PublicAct.Participation ? seen.EventPersonaIds : seen.PersonaIds;
|
||||
if (told.Contains(personaId))
|
||||
if (act == PublicAct.Push ? seen.PushTold : told.Contains(personaId))
|
||||
return true;
|
||||
|
||||
Act = act;
|
||||
@@ -38,7 +40,10 @@ namespace decePubClient.Services
|
||||
if (!accepted)
|
||||
return false;
|
||||
|
||||
told.Add(personaId);
|
||||
if (act == PublicAct.Push)
|
||||
seen.PushTold = true;
|
||||
else
|
||||
told.Add(personaId);
|
||||
await localStorage.SetItemAsync(nameof(PublicActionNotices), seen, cancellationToken);
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user