• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

cameri / nostream / 41232579328
77%

Build:
DEFAULT BRANCH: main
Ran 31 Oct 2026 07:09PM UTC
Jobs 2
Files 319
Run time 1min
Badge
Embed ▾
README BADGES
x

If you need to use a raster PNG badge, change the '.svg' to '.png' in the link

Markdown

Textile

RDoc

HTML

Rst

31 Oct 2026 07:05PM UTC coverage: 77.356% (+0.1%) from 77.211%
41232579328

push

github

web-flow
feat(payments): add per-plan event rate limits and retention (#922)



## Description
Builds on the subscription lifecycle (#909). Nothing changes unless
`payments.enabled` is true and a plan sets `limits.rateLimits` or
`limits.retentionMaxDays` (settings and validation already exist from
#849).

- Rate limits: `EventMessageHandler.isRateLimited` uses the limits of
the sender's plan in place of `limits.event.rateLimits` while the
subscription gives access (grace included). An empty list means no
limit. Everyone else, and a subscriber whose subscription ended or whose
plan was removed from the settings, keeps the global limits. Counters
are keyed exactly as before (`<pubkey>:events:<period>`), whitelists
still apply.
- The plan comes from the admission cache: it is cached under
`<pubkey>:subscription-plan` (`plan:<id>` or `none`) with a TTL that
never outlives access, and `isUserAdmitted` fills it when it reads the
subscription, so there is no extra database read per event. If a read
fails the global limits apply and nothing is cached.
- Retention: the purge (`deleteExpiredAndRetained`) takes
`planRetention`. Events of subscribers on a plan with `retentionMaxDays`
are purged at the plan's window, everyone else at the global one, with
the kind and pubkey whitelists unchanged. A subscriber counts only while
their access lasts, so once it ends their events fall back to the global
window at the next pass. The query is the same as before when no plan
sets a retention.
- `CONFIGURATION.md` describes both settings.

## Related Issue
Closes #921

## Motivation and Context
Rate limits and retention were global, so a premium subscriber got the
same limits as everyone else. This is the "higher tiers get better rate
limits and longer event retention" part of the tiered access.

A plan retention only applies while `limits.event.retention.maxDays` is
set (the purge does not run without it). Per-plan connection and
subscription-count limits are not part of this PR.

... (continued)

4384 of 6201 branches covered (70.7%)

Branch coverage included in aggregate %.

66 of 66 new or added lines in 3 files covered. (100.0%)

9554 of 11817 relevant lines covered (80.85%)

775.24 hits per line

Jobs
ID Job ID Ran Files Coverage
1 Integration - 41232579328.1 31 Oct 2026 07:09PM UTC 319
33.34
GitHub Action Run
2 Unit - 41232579328.2 31 Oct 2026 07:11PM UTC 319
74.74
GitHub Action Run
Source Files on build 41232579328
  • Tree
  • List 319
  • Changed 3
  • Source Changed 3
  • Coverage Changed 3
Coverage ∆ File Lines Relevant Covered Missed Hits/Line Branch Hits Branch Misses
  • Back to Repo
  • Github Actions Build #41232579328
  • b6634b0d on github
  • Prev Build on main (#41231981006)
  • Next Build on main (#41236831540)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc