Documentation
¶
Overview ¶
Package webpush sends browser push notifications (RFC 8030/8291) to every subscription this control plane's dashboard has registered, backing the "webpush" notification-channel kind in internal/alerting: an operator gets a deploy/alert notification even with no dashboard tab focused or open, something none of the other 17 channel kinds (all webhooks or email) can do on their own.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func EnsureVAPIDKeys ¶
EnsureVAPIDKeys returns this control plane's VAPID keypair, generating and persisting one through keys the first time it's called. Call once at startup, before anything can register a subscription against the public half: regenerating the pair later would silently orphan every subscription already registered against the old one (the browser's applicationServerKey would no longer match what this control plane signs with).
Types ¶
type KeyStore ¶
type KeyStore interface {
Exists(ctx context.Context, serviceName, envKey string) (bool, error)
SetValue(ctx context.Context, serviceName, envKey, plaintext string) error
Resolve(ctx context.Context, serviceName, envKey string) (string, error)
}
KeyStore is the narrow internal/secrets surface EnsureVAPIDKeys needs. *secrets.Manager satisfies it structurally, the same "narrow, consumer-defined interface" shape VaultSecrets (internal/api) already establishes.
type Sender ¶
type Sender struct {
// contains filtered or unexported fields
}
Sender sends one notification to every registered browser subscription. It satisfies alerting.PushSender structurally (that package takes a narrow Send(ctx, title, body) interface rather than importing this one, the same "consumer defines the interface it needs" shape email.Sender's own consumers already follow).
func NewSender ¶
func NewSender(subs Subscriptions, publicKey, privateKey, subscriber string, client *http.Client, logger *slog.Logger) *Sender
NewSender builds a Sender. subscriber is the VAPID JWT "sub" claim a push service may contact if this control plane's server is sending too aggressively; an https:// URL or an email address, per RFC 8292.
func (*Sender) Send ¶
Send pushes one notification to every registered subscription. A per-subscription failure never aborts the loop: one dead or revoked browser must not silence every other one. Returns an error only when no registered subscription exists at all, or every send attempt failed, mirroring email.Sender's own "nothing configured" failure shape that NewDeployDispatcher's doc comment already describes for every other channel kind.
type Subscriptions ¶
type Subscriptions interface {
ListPushSubscriptions(ctx context.Context) ([]store.PushSubscription, error)
DeletePushSubscriptionByID(ctx context.Context, id string) error
}
Subscriptions is the store surface Sender needs: every registered subscription, and a way to prune one a push service has reported permanently gone. *store.DB satisfies this structurally.