
Security News
Re-Enabled GitHub Actions Expose Thousands of Repositories to Mini Shai-Hulud
Two compromised GitHub Actions were re-enabled with malicious tags intact, exposing thousands of downstream repositories to Mini Shai-Hulud.
@strav/notification
Advanced tools
Strav multi-channel notifications — NotificationManager fan-out across channel drivers (mail / database / log / webhook / broadcast / discord / sse). Manager+drivers shape; new channels register via `manager.extend(name, factory)`.
Multi-channel notifications for Strav 1.0. One fluent surface (notifications.send(notifiable, notification)) that fan-outs to ≥1 channel drivers — mail / database / log / webhook / broadcast / discord / sse today; SMS channel in a follow-up slice.
import { BaseNotification, type Notifiable, NotificationManager } from '@strav/notification'
class InvoicePaid extends BaseNotification {
override via(): readonly string[] {
return ['mail', 'database']
}
toMail(notifiable: Notifiable) {
return { to: [notifiable.email], subject: 'Invoice paid', text: '...' }
}
toDatabase(_notifiable: Notifiable) {
return { invoiceId: 'inv_42', amount: 4900 }
}
}
const notifications = container.resolve(NotificationManager)
await notifications.send(alice, new InvoicePaid())
Canonical docs live in docs/notification/README.md.
| Channel | Subpath | Notes |
|---|---|---|
@strav/notification/mail | Wraps @strav/mail's MailManager.send. | |
| Database | @strav/notification/database | Append-only notification ledger + NotificationRepository (unread() / markAsRead()). Tenanted variant under @strav/notification/tenanted. |
| Log | @strav/notification/log | Routes through @strav/kernel's Logger. Useful for dev + tests. |
| Webhook | @strav/notification/webhook | POSTs a signed JSON envelope (x-strav-signature: sha256=... over ${timestamp}.${body}) to a configured endpoint. Exports verifyWebhookSignature for receiver-side validation. |
| Broadcast | @strav/notification/broadcast | Publishes a BroadcastEvent via @strav/broadcast's Broadcaster. Pairs with router.sse(...) so live UI clients receive the same dispatch. |
| Discord | @strav/notification/discord | POSTs notification.toDiscord(notifiable) to a Discord webhook URL. Returns a string (shorthand for { content }) or a DiscordMessage with embeds / components / per-message webhookUrl override. Per-recipient URLs via notifiable.discordWebhookUrl. |
| SSE | @strav/notification/sse | In-process pub/sub. Reads notification.toSSE(notifiable) and pushes to every active subscriber for that notifiable. HTTP handlers consume subscriptions via driver.subscribe(id, { notifiableType? }) + sseResponse() from @strav/http. |
Deferred: SMS channel driver. Apps register custom channels via manager.extend(name, factory).
FAQs
Strav multi-channel notifications — NotificationManager fan-out across channel drivers (mail / database / log / webhook / broadcast / discord / sse). Manager+drivers shape; new channels register via `manager.extend(name, factory)`.
We found that @strav/notification demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
Two compromised GitHub Actions were re-enabled with malicious tags intact, exposing thousands of downstream repositories to Mini Shai-Hulud.

Research
/Security News
A malicious Firefox extension fetches its payload after installation to evade detection, steal Google session cookies, and automate account takeover.

Research
/Security News
The compromise affects MemTensor's MemOS, an open source memory framework for large language models (LLMs) and AI agents. Both npm package @memtensor/memos-cloud-openclaw-plugin and the PyPI package MemoryOS are compromised. They drop cross-platform Go binaries that exfiltrate developer secrets.