Skip to content

Commit bc22677

Browse files
chore: release new version 🚀 (#1013)
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## nostream@3.10.1 ### Patch Changes - [#1011](#1011) [`fd7679b`](fd7679b) Thanks [@chappie-daemon](https://github.com/chappie-daemon)! - fix(rate-limit): send the backoff the strategy actually means, name an outage as an error, and bucket messages by type Three defects on one wire path, from the spike in [#1004](#1004). **The EWMA backoff was a half-life, sent as a delay.** `RateLimit.period` is the decay half-life under `ewma`, so the time until a limit lifts is `period · log2(R_new / rate)`, not `period`. With `rate: 6, period: 60000`, a client four times over the limit was told to wait 60 s and needed 120 s. The Lua script now returns its score instead of a yes/no, and the limiter returns `period · log2(score / rate)`. It was only accidentally safe before: the hash carried a TTL of exactly `period`, so a quiet client's state expired anyway — an unstated coupling that would break the moment anyone lengthened the TTL to keep state warm. **A limiter outage was announced as `rate-limited`.** A failing backend made every connected client back off for a fault on this side. It now answers `error: rate limiter unavailable` and still rejects the event; fail-closed behaviour is unchanged. **The message bucket ignored the message type.** One bucket per client meant a `REQ` could be refused because its `EVENT`s had filled it — the wrong message throttled, and the wrong one told to back off. The bucket key now carries the type, read from a bounded prefix of the frame because the limiter runs before validation. `IRateLimiter.hit` returns `IRateLimiterResult` (`limited`, plus `retryAfterMs` when the strategy can estimate one) so each strategy answers in its own terms; a caller with no estimate keeps sending the period. - [#1012](#1012) [`d8095de`](d8095de) Thanks [@chappie-daemon](https://github.com/chappie-daemon)! - fix(startup): print the banner as text, and let `LOG_FORMAT=json` opt out of it `docker compose logs nostream` showed the logo as a single log record with the newlines escaped. The banner and its centred facts now go to stdout as text. A pipeline that requires every line to parse sets `LOG_FORMAT=json`: the logo is then replaced by one `relay starting` record carrying the same facts as fields (`version`, `supportedNips`, `payments`, `eventStore`, `clientWorkers`, …). Any other value keeps the banner, which is what a person reading the logs wants.
2 parents c152368 + e2dabc8 commit bc22677

4 files changed

Lines changed: 23 additions & 25 deletions

File tree

‎.changeset/rate-limit-wire-correctness.md‎

Lines changed: 0 additions & 15 deletions
This file was deleted.

‎.changeset/startup-banner-stdout.md‎

Lines changed: 0 additions & 9 deletions
This file was deleted.

‎CHANGELOG.md‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,27 @@
11
# nostream
22

3+
## 3.10.1
4+
5+
### Patch Changes
6+
7+
- [#1011](https://github.com/cameri/nostream/pull/1011) [`fd7679b`](https://github.com/cameri/nostream/commit/fd7679bed7ba2b10f5148f50ece415e869814475) Thanks [@chappie-daemon](https://github.com/chappie-daemon)! - fix(rate-limit): send the backoff the strategy actually means, name an outage as an error, and bucket messages by type
8+
9+
Three defects on one wire path, from the spike in [#1004](https://github.com/cameri/nostream/issues/1004).
10+
11+
**The EWMA backoff was a half-life, sent as a delay.** `RateLimit.period` is the decay half-life under `ewma`, so the time until a limit lifts is `period · log2(R_new / rate)`, not `period`. With `rate: 6, period: 60000`, a client four times over the limit was told to wait 60 s and needed 120 s. The Lua script now returns its score instead of a yes/no, and the limiter returns `period · log2(score / rate)`. It was only accidentally safe before: the hash carried a TTL of exactly `period`, so a quiet client's state expired anyway — an unstated coupling that would break the moment anyone lengthened the TTL to keep state warm.
12+
13+
**A limiter outage was announced as `rate-limited`.** A failing backend made every connected client back off for a fault on this side. It now answers `error: rate limiter unavailable` and still rejects the event; fail-closed behaviour is unchanged.
14+
15+
**The message bucket ignored the message type.** One bucket per client meant a `REQ` could be refused because its `EVENT`s had filled it — the wrong message throttled, and the wrong one told to back off. The bucket key now carries the type, read from a bounded prefix of the frame because the limiter runs before validation.
16+
17+
`IRateLimiter.hit` returns `IRateLimiterResult` (`limited`, plus `retryAfterMs` when the strategy can estimate one) so each strategy answers in its own terms; a caller with no estimate keeps sending the period.
18+
19+
- [#1012](https://github.com/cameri/nostream/pull/1012) [`d8095de`](https://github.com/cameri/nostream/commit/d8095de9bdf8f5174c62cc2f1372472731e286ae) Thanks [@chappie-daemon](https://github.com/chappie-daemon)! - fix(startup): print the banner as text, and let `LOG_FORMAT=json` opt out of it
20+
21+
`docker compose logs nostream` showed the logo as a single log record with the newlines escaped. The banner and its centred facts now go to stdout as text.
22+
23+
A pipeline that requires every line to parse sets `LOG_FORMAT=json`: the logo is then replaced by one `relay starting` record carrying the same facts as fields (`version`, `supportedNips`, `payments`, `eventStore`, `clientWorkers`, …). Any other value keeps the banner, which is what a person reading the logs wants.
24+
325
## 3.10.0
426

527
### Minor Changes

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "nostream",
3-
"version": "3.10.0",
3+
"version": "3.10.1",
44
"packageManager": "pnpm@10.33.0",
55
"private": true,
66
"description": "A Nostr relay written in Typescript.",

0 commit comments

Comments
 (0)