nostream
3.5.0
Minor Changes
-
#823
82287d4Thanks @Ferryx349! - feat(website): add Astro marketing site with landing film, docs, changelog and community pagesAdds
website/site(nostream.dev) and updates the landing hero animation to sync NIP count and branding from the repo. Docs, changelog, version label and NIP list are read from the repository at build time. -
#830
f0bcdccThanks @Priyanshubhartistm! - feat(nip77): advertise NIP-77 in NIP-11 supported_nips while it is active and expose its settings in the admin console -
#818
7409006Thanks @Priyanshubhartistm! - feat(nip77): serve NEG-OPEN, NEG-MSG and NEG-CLOSE negentropy sync for the PostgreSQL event store
3.4.1
Patch Changes
-
#825
48fe9c4Thanks @chappie-daemon! - fix(settings): validateinfo.relay_urlis a usable absolute URLvalidateSettings()now rejects arelay_urlthat is not a valid absolute URL, parses with an empty host (scheme-only strings likelocalhost:8008), or uses a protocol other thanws/wss/http/https. Previously an invalid value started cleanly and then broke every HTTP request with500 TypeError: Invalid URL, including the Admin Console, leaving the bad setting fixable only by editing the file by hand. Found in #824.
3.4.0
Minor Changes
-
#821
36d2a30Thanks @Ferryx349! - feat(nip-01): send therate-limitedbackoff hint on CLOSEDWhen the per-IP message rate limit trips on a
REQorCOUNT, the relay now replies["CLOSED", <id>, "rate-limited: slow down", "<ms>"]with the tripped window’s period as the backoff, instead of aNOTICE. Other message types keep the existingNOTICE. -
#768
8a5600bThanks @Ferryx349! - docs(deploy): add deploy runbook and single-relay recreate script -
#809
4cf419fThanks @Priyanshubhartistm! - feat(nip77): add negentropy set-reconciliation core and a sorted event id query
Patch Changes
-
#810
0133088Thanks @chappie-daemon! - docs(readme): document Marmot Protocol MIP support -
#813
c81407dThanks @Ferryx349! - Reject settings where any rateLimits[].period is not greater than 0 -
#812
7e44de1Thanks @chappie-daemon! - feat(website): add the nostream 3.3.0 release film
3.3.0
Minor Changes
-
#806
0304b8aThanks @Anshumancanrock! - feat(storage): add aneventStore.backendsetting and build every event repository through one factoryDefaults to
postgres, the only backend for now. The backend is read once at startup and passed to every worker. -
#799
75d2a91Thanks @Ferryx349! - feat(admin): add NIP-11 vs probe mismatch warnings on Network HealthCloses #798
-
#807
f7d4b76Thanks @Ferryx349! - NIP-01: include an optional backoff (ms) as the fifth element ofrate-limitedOK messages -
#796
e861bebThanks @Ferryx349! - feat(nip66): add read/write RTT probes, NIP-42 detection, mirror targets, and enriched kind 30166 tagsExtends the relay monitor with WebSocket read/write probes, optional NIP-42 auth detection, probing of
mirroring.static[]peers, and richer NIP-66 discovery and monitor announcement events.Closes #794
3.2.0
Minor Changes
-
#777
3ea816cThanks @Ferryx349! - feat(deploy): add HAProxy blue/green compose stackTwo relays behind HAProxy with
/readyzhealth checks andoption redispatch, plus a rolling recreate script that replaces one relay at a time for zero-downtime image updates. Optional Redis stream fan-out (RELAY_BROADCAST_FANOUT) lets both relays share live WebSocket broadcasts while workers keep using clusterprocess.send. -
#788
ce368e8Thanks @Priyanshubhartistm! - feat: execute hide action for actionable NIP-56 reportsAdds
nip56.hideActionableReports(defaultfalse): when true, events matching anactionablereport (a trusted-moderator report against a valid target) are excluded from REQ/COUNT results. A pubkey-targeted report hides every event from that pubkey; an event-targeted report hides just that event. Requiresnip56.enabledto have any effect. Previously an actionable report was only ever recorded, never acted on.
Patch Changes
-
#740
b68919dThanks @Priyanshubhartistm! - fix(cli): stopnostream infoandnostream invite createfrom hanging indefinitely when the database is unreachable -
#792
29dbed8Thanks @Anshumancanrock! - fix: match filters with several tag names and apply limit per filter
3.1.0
Minor Changes
-
#756
570a7ccThanks @Priyanshubhartistm! - feat: add relay-load-aware adaptive PoW difficulty (NIP-13)Adds
limits.event.powsettings that scale the required proof-of-work difficulty between a configured floor and ceiling based on the observed event rate, in place of the existing staticeventId.minLeadingZeroBitsvalue (the staticpubkey.minLeadingZeroBitscheck is unaffected and still enforced independently). The event rate is tracked per worker process with the same EWMA shape already used by the relay’s rate limiter. Disabled by default (limits.event.pow.enabled: false), so existing static PoW configuration is unaffected unless explicitly opted in. -
#641
837540bThanks @Ferryx349! - feat: add disabled-by-default admin API with password auth, session, and health endpoints -
#666
44f3bb4Thanks @Ferryx349! - feat: add admin observability dashboard with Grafana embed and provisioned metrics panels -
#653
8ab4825Thanks @Ferryx349! - feat: add OpenTelemetry metrics bootstrap with OTLP export for Prometheus -
#661
237b1a4Thanks @Ferryx349! - feat: instrument event and websocket handlers with OpenTelemetry metrics -
#662
36d95ccThanks @Ferryx349! - feat: add Prometheus-backed admin metrics SSE endpoint -
#753
7c2875eThanks @Ferryx349! - feat(admin): add GET /admin/network-health endpoint -
#764
ff43cd3Thanks @Ferryx349! - feat(admin): add Network Health panel to observability dashboardAdds a dashboard section that renders the latest NIP-66 probe snapshot with per-target DNS, TLS, WebSocket RTT, and NIP-11 status.
-
#784
c6c4c4fThanks @Ferryx349! - feat(admin): add GET/PATCH /admin/notifications API for operator alert configCloses #760.
-
#787
de7c9dfThanks @Ferryx349! - feat(admin): add notifications console page for operator alertsAdds a Notifications view to the admin dashboard for configuring targets and event toggles, testing delivery, and browsing the delivery log via the admin API.
Closes #761
-
#690
f70adf2Thanks @Ferryx349! - feat: add authenticated admin settings API endpoints -
#706
841833fThanks @Ferryx349! - feat: add settings editor tab to admin dashboard UI -
#770
07524ebThanks @Priyanshubhartistm! - feat: add WoT-weighted NIP-56 content reportingAccepts and stores kind-1984 report events, weighting each report by the reporter’s WoT distance from
wot.seedPubkey(full weight for a direct follow, halving each additional hop, zero for a pubkey outside the trust graph). Reports from anip56.trustedModeratorspubkey always get maximum weight and are flagged actionable, ready for a future management-API surface to act on; every other report is stored for manual review only. Disabled by default (nip56.enabled: false). -
#734
fd7f56aThanks @Priyanshubhartistm! - feat(dvm): dispatch pending DVM jobs to worker processes and publish kind 6000-6999 results back -
#729
275c30cThanks @Priyanshubhartistm! - feat(dvm): trap NIP-90 job request events (kind 5000-5999) and record them via the job repository -
#727
d00eb42Thanks @Priyanshubhartistm! - feat(dvm): add job persistence migration and repository for DVM job state -
#737
9f36191Thanks @Priyanshubhartistm! - feat(dvm): add NIP-89 handler recommendation/information kinds and verify passive accept-and-serve -
#721
11ec673Thanks @Priyanshubhartistm! - feat(dvm): add worker registry settings and dvm-orchestrator process topology -
#587
30fa252Thanks @Anshumancanrock! - Add NIP-50 full-text search support with PostgreSQLtsvector/GINindexing.Clients can now include a
searchfield in REQ filter objects to perform full-text queries against event content. Results are ranked by relevance (ts_rank) instead of the usualcreated_atordering, per the NIP-50 specification.Features:
- New
searchfilter field accepted in REQ messages - PostgreSQL GIN index on
to_tsvector('simple', event_content)for fast full-text lookups - Configurable text-search language (defaults to
simple, supportsenglish,spanish, etc.) - Configurable max search query length for abuse prevention
- NIP-50 listed in NIP-11 relay information document
- Search can be combined with all existing filter fields (kinds, authors, tags, etc.)
- New
-
#702
e172cceThanks @Anshumancanrock! - feat(nip42): enforce authentication on reads for restricted event kinds (encrypted DMs, gift wraps) across REQ, live broadcasts and COUNT -
#716
2f5a1c0Thanks @Anshumancanrock! - feat(nip42): add session tracking with optional TTL and publish-time authRequired (NIP-11 restricted_writes) -
#732
d413bd6Thanks @Anshumancanrock! - Add a CLI to mint NIP-43 invite codes (nostream invite create) so operators can issue a claim without SQL. New codes honornip43.defaultMaxUsesandnip43.inviteCodeExpirySeconds. -
#650
3461dfeThanks @Anshumancanrock! - Add NIP-43 invite code foundation: InviteCodeRepository with atomic claimCode, invite_codes migration, and event kind/tag constants. -
#738
a0853dbThanks @Anshumancanrock! - feat(nip43): issue kind 28935 invite codes on requestNIP-43 kind 28935 is not an event clients publish — it is a REQ the relay answers by minting an invite code on the fly and returning a relay-signed ephemeral event. Nostream now serves those subscriptions, completing the membership flow: request a claim, join with kind 28934, publish.
Off by default. It requires
nip43.enabledand the newnip43.allowInviteRequests, a NIP-42 authenticated requester, aninfo.selfconsistent with the relay signing key, and a per-pubkey budget under the newlimits.invite.rateLimits(5/hour by default). This also makes the previously inertnip43.inviteRequestWhitelistsetting take effect. The minted event is never persisted and never broadcast: the claim tag is a bearer secret and is sent only to the socket that asked for it.Two fixes the flow depended on. The relay signs its own events with a key derived from
SECRET, butinfo.selfwas a hand-edited string that nothing validated — by default it was a placeholder that is not a pubkey at all, so any NIP-43 client verifying a relay-signed event againstselfwould reject it.info.selfis now optional: when unset or unparseable, NIP-11 advertises the derived signing pubkey instead, andnostream infoprints that pubkey so operators can pin it.Kind 28935 also sits in the ephemeral range, so a client-published one fell through to
EphemeralEventStrategyand was broadcast to every subscriber — including everyone subscribed to kind 28935 waiting for a real invite. Anyone could inject a forgedclaimtag into that subscription. It is now rejected with anOKfalse and never broadcast, and bypasses the NIP-43 admission gate so that rejection actually reaches non-members, who are the ones most likely to publish it by mistake while trying to obtain a code.CLI.md and README.md now describe the request flow. CLI.md previously claimed the relay “does not yet generate kind 28935 on
REQ”, and never mentioned thatnostream infoprints the signing pubkey that CONFIGURATION.md tells operators to pin. -
#676
0bfa0b5Thanks @Anshumancanrock! - Add NIP-43 join/leave request event strategies (kinds 28934/28936) with NIP-42 auth enforcement, created_at freshness validation, invite code claiming, and admission management. Whennip43.enabledis set, publishing is restricted to admitted members even without payments enabled, and NIP-43 is advertised in the NIP-11 document (hidden when disabled). Join/leave update the admission cache so membership changes take effect immediately. -
#675
5a70839Thanks @Ferryx349! - feat(nip66): add shared relay probe engine for DNS, TLS, WebSocket RTT, and NIP-11 checks -
#741
afa8999Thanks @Ferryx349! - feat(nip66): publish kind 30166 and 10166 relay health events after probe runsAfter each relay monitor probe run, sign and store NIP-66 relay discovery and monitor announcement events using the configured monitor identity, bootstrap kind 0/10002 on first run, and persist via the existing parameterized replaceable event path.
Fixes #696
-
#724
d14b1e9Thanks @Ferryx349! - feat(nip66): add RelayMonitorWorker cluster worker and probe scheduler -
#689
e294a71Thanks @Ferryx349! - Add NIP-66 relay monitor settings foundation with defaults for probe interval, timeouts, targets, monitor identity, and DNS cache TTL. -
#644
2f6d773Thanks @Anshumancanrock! - feat: reject NIP-70 protected events and reposts embedding them -
#730
ef4123eThanks @Anshumancanrock! - feat(admin): accept NIP-98 Authorization on protected admin API routes -
#722
cf5ea4fThanks @Anshumancanrock! - feat(nip98): add Authorization header event verifier for HTTP auth (kind 27235) -
#781
8d29f15Thanks @Ferryx349! - feat(admin): operator notification backend with Postgres outboxAdds transactional outbox dispatch for operator alerts (HTTP, Discord, Slack, Telegram), delivery log,
admin.notificationssettings, event hooks for admission invoices and settings changes, and admin test/history endpoints. Closes #759. -
#763
358763aThanks @Ferryx349! - feat(ops): add /readyz readiness probe for Postgres and RedisAdds a public readiness endpoint for zero-downtime deploy workflows. HAProxy (or similar) can use
/readyzto confirm an instance can serve traffic before cutover, while/healthzremains a lightweight liveness check. -
#672
595c0a6Thanks @Ferryx349! - refactor: extract shared settings-config module and guided schema for admin settings editor foundation -
#779
f6ee3e3Thanks @Priyanshubhartistm! - feat: wire the WoT graph into adaptive PoW difficultyAdds
limits.event.pow.wotThresholds, letting operators reduce (or bypass) the eventId PoW requirement for pubkeys within their configured WoT distance. A direct follow can post instantly under load while an unknown pubkey pays the full adaptive difficulty. Disabled by default (no thresholds configured); requireswot.enabledto have any effect, since a pubkey’s distance is otherwise always unknown. -
#745
276fe16Thanks @Priyanshubhartistm! - feat: add a Web of Trust graph service that tracks NIP-02 follow distance from an operator-configured seed pubkeyAdds a
WotGraphServicethat builds a trust graph rooted atwot.seedPubkey, updated in real time as kind-3 contact list events are ingested, with configurable depth (wot.maxDepth) and a minimum-followers threshold for 2+ hop trust (wot.minimumFollowers). ExposesgetDistance()andisTrusted()for other parts of the relay to query. Disabled by default (wot.enabled: false). -
#773
5577070Thanks @Ferryx349! - feat(shutdown): drain WebSocket clients on SIGTERMOn SIGTERM,
/readyzreturns 503, new WebSocket connections are rejected, and existing clients receive Nostr CLOSED messages before the socket closes. Drain is bounded byWS_DRAIN_TIMEOUT_MS(default 30s).
Patch Changes
-
#714
df1ed5dThanks @Ferryx349! - fix(admin): update aria-expanded and label when mobile menu is toggled -
#680
f92eabeThanks @Priyanshubhartistm! - fix: advertise NIP-13 (Proof of Work) support insupportedNips -
#750
f5c8dc8Thanks @Anshumancanrock! - deploy: run production migrations from the relay imageBake
migrations/andknexfile.jsinto the runtime image and point the prod compose migrate service at that image so schema cannot drift from the code that ships. -
#743
f36410aThanks @Ferryx349! - ci: build and push container image to GHCR after CI passes on mainAdds a GitHub Actions workflow that publishes
ghcr.io/cameri/nostream:mainand a per-commitsha-*tag once the CI Checks workflow succeeds for pushes tomain. -
#775
59b1e51Thanks @Anshumancanrock! - fix: return COUNT results for filters with generic tag queries (#e,#p,#g,#h), which projectedevent_idtwice and failed with “error: unable to count events” -
#646
eb64d8aThanks @dependabot! - chore(deps): bump js-yaml from 4.1.1 to 4.2.0 -
#647
68da3d4Thanks @dependabot! - chore(deps): bump ws from 8.20.1 to 8.21.0 -
#705
95a672eThanks @dependabot! - chore(deps): bump axios from 1.16.0 to 1.18.0 -
#751
8509aeaThanks @Ferryx349! - deploy: minimal server bootstrap with optional settings overridesAdd deploy/bootstrap.sh, document what operators must keep locally vs what ships in the image, and stop seeding a full settings.yaml on first boot so release defaults merge with optional overrides only.
-
#744
8fa72d6Thanks @Ferryx349! - deploy: add production Docker Compose stack for relay serversAdds a minimal prod compose file, migrate image Dockerfile, and server layout docs for deployments that pull
ghcr.io/cameri/nostream:maininstead of building on the host. -
#765
3690bd8Thanks @Ferryx349! - ci: disable CodeQL workflowRemoves the CodeQL Advanced GitHub Actions workflow, custom query pack, config, and route suppression comments to stop false-positive security alerts on admin routes that already use custom auth and rate limiting.
-
#694
7c4b728Thanks @Priyanshubhartistm! - fix: de-duplicate events returned by generic tag-filter subscriptionsEventRepository.findByFilters()left-joinsevent_tagsfor generic tag filters (#e,#p, etc.) without deduplicating the result. An event matching more than one tag row for the same filter (e.g.{"#p": ["a", "b"]}matching an event tagged with both) was returned once per matchingevent_tagsrow, so subscribers received the sameEVENTmessage multiple times. The query now selectsDISTINCT events.*for tag-filtered queries so each stored event is returned at most once. This also covers generic tag filters combined with a NIP-50searchterm (e.g.{"search": "...", "#p": ["a", "b"]}), which take the search branch and are now de-duplicated as well. -
#771
b07f9c3Thanks @chappie-daemon! - fix: enforcelimits.client.subscription.maxFilterValueson REQ and COUNT filtersFilters whose array criteria (
ids,authors,kinds,#<tag>) hold more thanmaxFilterValuesvalues in total are now rejected withToo many filter valuesinstead of being handed to PostgreSQL as an unboundedWHERE IN (...). The limit was previously defined in settings and surfaced in the admin settings editor while being read by nothing at all.The enforced limit is also advertised in the NIP-11
limitationobject asmax_filter_values, a non-standard extension since NIP-11 has no field for per-filter value counts. -
#703
7af0387Thanks @Priyanshubhartistm! - Fix the Content-Security-Policyconnect-srcdirective for relays served over plainws://.The web app factory derived an HTTP(S) origin from the relay’s WebSocket URL but mapped
ws:to the invalid scheme':', which the WHATWG URL API silently ignores. As a result theconnect-srcdirective kept aws://…entry instead of the intendedhttp://…origin for local/dev, Tor, or reverse-proxied setups. Thews:protocol now correctly maps tohttp:.Adds regression test coverage for the protocol mapping (
getWebProtocolForRelay, extracted fromcreateWebAppso it can be unit tested directly), since this file previously had no test coverage at all. -
#708
a76d0b5Thanks @Priyanshubhartistm! - fix: reject expiration timestamp 0 and millisecond-scale values, and accept safe-integer second-based timestamps up to the Postgres int4 max (2038-01-19T03:14:07Z) in getEventExpiration() -
#747
14cca60Thanks @Ferryx349! - fix(ci): publish container image after CI passes on mainRemoves the standalone publish workflow and its unsafe workflow_run trigger. Image publish now runs as the final job in checks.yml on pushes to main, after lint, build, and tests succeed.
-
#735
f0aab15Thanks @Ferryx349! - fix: include event id in expired and rate-limited rejection logsExpired and rate-limited event rejections logged
event %s rejected: ...without passingevent.id, so operators saw a literal%sinstead of the event id. -
#715
9361601Thanks @Priyanshubhartistm! - fix: abort in-flight streaming queries when a subscription is cancelled -
#746
7297b96Thanks @Anshumancanrock! - fix(payments): stop stale invoices from wedging payment pollingA relay could stop clearing payments entirely, needing
delete from invoicesto recover. Two things combined to cause it.Invoices created without an expiry could never be retired, because the expiry check treats a missing date as “not expired”, so the maintenance worker left them pending forever. The LNURL processor set no expiry on any invoice, making this certain there rather than incidental. Invoices now fall back to
payments.invoiceExpirySecondswhen the processor reports no expiry of its own, and existing pending rows without one are backfilled.Separately, each maintenance pass re-read the same oldest page of pending invoices, so one page of invoices that never resolve starved every newer one indefinitely. The worker now advances through the queue and wraps at the end, keeping the same per-pass cost while guaranteeing every pending invoice is eventually polled.
-
#786
e87e1afThanks @Priyanshubhartistm! - fix(nip56): skip targetless report rows, record every p/e target, batch report inserts in one transaction, and warm the WoT graph at boot instead of blocking the first report on a cold-start rebuild -
#733
9fb1c10Thanks @Ferryx349! - test(nip66): add integration tests for RelayMonitorWorker snapshot storage -
#725
849c3f7Thanks @Anshumancanrock! - feat(http): build absolute request URL from relay_url -
#726
3d3848eThanks @Anshumancanrock! - feat(redis): add setKeyIfNotExists for one-time claims -
#640
ca23be1Thanks @Anshumancanrock! - test: optimize nip05.spec.ts & nip03.spec.ts resource management- Lift sinon stub to
before/afterin verifyNip05Identifier tests (create once, reset between tests) - Extract SSRF guard callback once in
beforeinstead of per-testbeforeEach - Pre-build shared OTS buffers and attestations at module scope to eliminate redundant Buffer.concat calls
- Add shared event factory for extractNip05FromEvent tests
- Lift sinon stub to
-
#686
cb7daf6Thanks @Priyanshubhartistm! - fix: stop checking additional rate limit windows once a client is already rate-limitedisRateLimited()inEventMessageHandlerandWebSocketAdapterlooped through every configured rate limit window even after one had already tripped, callingrateLimiter.hit()(a Redis write) for each remaining window. Both now return as soon as the first exceeded window is found, avoiding redundant Redis writes for clients that are already being limited. -
#684
3648954Thanks @Priyanshubhartistm! - fix: await Redis EXISTS call in RedisAdapter.hasKey() so it reflects actual key presence instead of always returning true -
#711
220949dThanks @Priyanshubhartistm! - fix: include the actual error message in replaceable event rejection responsesReplaceableEventStrategy.execute()sent clients a bareerror:command result (with no message body) whenevereventRepository.upsert()failed for a reason other than a duplicate event id. The underlyingerror.messagewas caught but never included in the response, leaving clients with no actionable information about why the event was rejected. The command result now includeserror.message. -
#682
dc78df5Thanks @Priyanshubhartistm! - fix: prevent crash in NIP-11 relay information document when payments settings are absent
3.0.0
Major Changes
-
#524
b3effd1Thanks @vikashsiwach! - Use exact pubkey matching for fee-schedule whitelists and event pubkey whitelist/blacklist checks. -
#574
f1c1118Thanks @Mahmoud-s-Khedr! - Add a brand-new unifiednostreamCLI/TUI that replaces the legacyscripts/*shell wrappers for lifecycle, setup, info, config, data, and development workflows.Fixes - fixed some consistnacy issues after the migration from
npmtopnpm
Minor Changes
-
#522
7edd6c3Thanks @a-khushal! - added NIP-45 COUNT support with end-to-end handling (validation, handler routing, DB counting, and tests). -
#629
36f8badThanks @Anshumancanrock! - feat: NIP-42 AUTH handler and WebSocket session wiring -
#534
a07b0f6Thanks @archief2910! - Add hot-path PostgreSQL indexes for subscription, vanish, retention, and invoice queries; adddb:benchmarkanddb:verify-index-impacttooling; document index rationale and benchmarking. Closes #68. -
#556
d8f62b4Thanks @saniddhyaDubey! - perf: added k6 performance tests for connection and message rate limiting -
#623
54139edThanks @saniddhyaDubey! - new user-facing config field -
#476
49322a9Thanks @saniddhyaDubey! - Add EWMA rate limiter with configurable strategy support -
#602
d3ba328Thanks @CKodidela! - Add relay support for the Marmot Protocol (E2EE group messaging over Nostr).Supported MIPs: 00 (KeyPackages), 01 (Group Construction), 02 (Welcome Events), 03 (Group Messages).
- kind 443 (legacy KeyPackage): stored as a regular event
- kind 10051 (KeyPackage relay list): stored as a replaceable event
- kind 30443 (KeyPackage): stored as a parameterized-replaceable event with
d-tag deduplication - kind 444 (Welcome rumor): blocked from direct publishing; must travel inside a kind 1059 gift wrap
- kind 445 (Group Event): dedicated strategy validates the required
htag (nostr_group_id) before storing;#htag subscriptions work via the existing generic tag index - NIP-11 relay info now advertises
supported_mips: [0, 1, 2, 3]
-
#515
5c12f36Thanks @archief2910! - Add NIP-03 OpenTimestamps support for kind 1040 events: structural.otsvalidation, Bitcoin attestation requirement, digest match to the referencedetag, and relay metadata updates (#105). -
#589
25d5405Thanks @CKodidela! - Add NIP-25 Reactions support for kind 7 and kind 17 events: reaction utility helpers (isReactionEvent,isExternalContentReactionEvent,isLikeReaction,isDislikeReaction,parseReaction), schema validation enforcing requiredetag on kind 7 and requiredk/itags on kind 17, unit tests, and integration tests. -
#585
ce59383Thanks @CKodidela! - Add NIP-65 Relay List Metadata support for kind 10002 events: relay list utility withisRelayListEventandparseRelayListhelpers, unit tests, and relay information document updated to advertise NIP-65 (#577). -
#514
214bef5Thanks @Anshumancanrock! - Add gzip and xz compression support to event import/export flows.- Export supports
--compress/-zwith--format gzip|gz|xz. - Import auto-detects compressed input by extension and magic bytes and decompresses in a stream pipeline.
- Includes docs updates and unit/integration test coverage for compression paths.
- Export supports
-
#628
ce7b838Thanks @Ferryx349! - refactor(http): remove deprecated network.remote_ip_header fallback and rely on network.remoteIpHeader -
#539
bdd4f6bThanks @Justxd22! - Add NWC (NIP-47) as a payments processor for admission invoices, including configurable invoice expiry and reply timeout handling, compatibility for legacy NWC URI schemes, and docs/env updates. -
#497
e1a7bfbThanks @phoenix-server! - Release highlights:Features
- NIP-05 verification support (#463)
- NIP-17 & NIP-44 v2 Modern Direct Messages (#458)
- NIP-62 vanish event support (#418)
- Vanish optimization (#446)
- Export events to JSON Lines format (#451)
- Import .jsonl events into events table (#414)
- Opt-in event retention purge (#359, #412)
- Wipe events table script (#450)
- Nginx reverse proxy in docker-compose (#423)
- Docker DNS pre-flight check for connectivity verification (#398)
- Strict validation for payment callbacks (#426)
- Real home page with templated pages (#409)
Bug Fixes
- NIP-01 compliance: deterministic event ordering by event_id
- NIP-01 compliance: correct dedup keys for parametrized replaceable events (#480)
- NIP-01 replaceable event tiebreaker (#416)
- NIP-11 served only on root path instead of relay path (#399)
- Dockerfile: run database migrations in CMD (#422)
- Added expired_at filter to message pipeline (#403)
- Removed unsafe-inline and implemented script nonces for CSP hardening (#394)
- Axios upgraded to fix CVE-2025-62718 (#466)
Refactors & Chores
-
#622
6a0a5faThanks @Anshumancanrock! - feat: add NIP-42 types, schemas and constants
Patch Changes
-
#555
ddc811dThanks @Anshumancanrock! - Migrate project tooling from npm to pnpm across CI workflows, Docker setup, hooks, and contributor commands. -
#600
dfa2838Thanks @saniddhyaDubey! - fix: maxLimit checks added to subscription message handler -
#572
b718036Thanks @dependabot! - Bump dev dependency uuid from 8.3.2 to 14.0.0 -
#616
f9f6d64Thanks @Anshumancanrock! - fix: check payments.enabled in callback route middleware -
#597
7da1b9aThanks @Anshumancanrock! - refactor: only register OpenNode, LNbits, and Zebedee callback routes when their processor is active -
#438
f5ba023Thanks @tharu-jwd! - fix: close dead connections even if they have active subscriptions -
#546
faa7ed2Thanks @Justxd22! - Fix root HTML negotiation and subpath-aware template links behind trusted proxies. -
#613
36e5af8Thanks @dependabot! - chore(deps): bump axios from 1.15.1 to 1.15.2 -
#617
50822b9Thanks @dependabot! - chore(deps): bump fast-uri from 3.1.0 to 3.1.2 -
#618
c6368dbThanks @dependabot! - chore(deps): bump ws from 8.20.0 to 8.20.1 -
#620
dac92b4Thanks @dependabot! - chore(deps): bump uuid from 8.3.2 to 14.0.0 -
#630
1295272Thanks @dependabot! - chore(deps): bump axios from 1.15.2 to 1.16.0 -
#575
b7324a6Thanks @kanishka0411! - Expire stale pending invoices when LNbits no longer has the invoice or reports it as unpaid past its expiry time. -
#592
0119c74Thanks @Anshumancanrock! - Security: override serialize-javascript to >=7.0.3 (CVE RCE, GHSA-5c6j-r48x-rmvq) -
#553
3c78e61Thanks @Anshumancanrock! - Fix replaceable batch upserts to apply NIP-01 tie-breaker semantics when timestamps are equal by comparing event IDs. -
#583
321a9ccThanks @kanishka0411! - Allow generic tag filters to match empty string tag values. -
#586
2418209Thanks @kanishka0411! - Implement geohash wildcard/prefix behavior for#gfilters (closes #265): a criterion ending in*matches any eventgtag whose value starts with the prefix before*; exact matching (no*) is unchanged. Only normal geohash prefixes are intended as input. This is a Nostream extension, not part of NIP-12. -
#584
a6d32b1Thanks @Anshumancanrock! - Use timingSafeEqual for Nodeless webhook HMAC verification and guard against missing NODELESS_WEBHOOK_SECRET -
#591
f31be1cThanks @Priyanshubhartistm! - fix: add husky install fallback for non-dev environments -
#551
7fc0552Thanks @CKodidela! - Add unit tests for InvoiceRepository and UserRepository with sinon-stubbed DB client -
#538
9496685Thanks @saniddhyaDubey! - Fix: Restore CONFIGURATION.md with proper settings and remove duplicate changesets created during recovery -
#557
32a1ec5Thanks @a-khushal! - update NIP-11 relay info fields and CORS, with test and docs updates -
#593
f599b1dThanks @YashIIT0909! - fix: resolve TOCTOU race condition and key collisions in SlidingWindowRateLimiter -
#511
a38d402Thanks @Priyanshubhartistm! - Migrate runtime logging to pino across adapters, services, workers, and controllers, and stabilize CI-related fixes for coverage and integration workflows after rebasing. -
#552
25f9637Thanks @vikashsiwach! - Add integration tests for NIP-02 contact lists (Kind 3) -
#527
4d030c7Thanks @kanishka0411! - Add NIP-11 integration tests and fix max_filters mapping in relay information document. -
#547
664168aThanks @Priyanshubhartistm! - Improve NIP-22created_atlimit handling coverage and boundary reliability.This adds integration coverage for accepted and rejected events across configured positive and negative
created_atdeltas, and keeps rejection semantics consistent (rejected) for out-of-range timestamps. -
#537
a89a95eThanks @vikashsiwach! - Add NIP-62 integration tests for Request to Vanish -
#643
faf55f1Thanks @Anshumancanrock! - feat: add NIP-70 protected event detection utility -
#596
250c767Thanks @CKodidela! - Normalize runCommandWithOutput to return a CommandResult discriminated union instead of rejecting on spawn errors, fixing a crash ininfo --jsonwhen Docker is not installed. -
#625
69d6187Thanks @Ferryx349! - Refactor EventRepository query construction to reduce method complexity. -
#497
e1a7bfbThanks @phoenix-server! - Replace semantic-release with changesets for explicit PR-level version management. Contributors now add a changeset file per PR; the Changesets Release workflow handles version bumps and GitHub releases. -
#627
c87dd03Thanks @Ferryx349! - test(integration): verify response content-type across core HTTP paths -
#562
de14f3cThanks @Priyanshubhartistm! - Add integration test coverage for NIP-04 encrypted direct messages (kind 4). -
#525
b09e23aThanks @kushagra0902! - Dedup keys were taking multiple tags, that was not according to NIP-01 behaviour. -
#568
c0c1c35Thanks @tharu-jwd! - fix: static mirroring silently drops events when mirror has no limits configured -
#604
40abf66Thanks @phoenix-server! - Add unit tests for maintenance service factory instantiation and dependency wiring. -
#493
5bf1a58Thanks @kanishka0411! - Fix IP spoofing via unconditional trust of x-forwarded-for header -
#606
47a9f4eThanks @phoenix-server! - Add unit tests for maintenance-worker-factory with 100% code coverage -
#545
a9ae0cdThanks @Justxd22! - Fix Redis cache connection config to skip AUTH whenREDIS_PASSWORDis unset -
#548
00240a9Thanks @CKodidela! - Support uppercase tag filters (#A-Z) in filter schema validation -
#566
8eee70fThanks @a-khushal! - add support for NIP-14 subject tags in text notes, with units tests to validate parsing and repository behavior