Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
0fae444
chore(deps): bump actions/upload-artifact from 4 to 6
dependabot[bot] Dec 15, 2025
a6035e3
chore(deps): bump JetBrains/qodana-action from 2025.2 to 2025.3
dependabot[bot] Dec 22, 2025
52fc2d9
docs: remove AGENTS.md and CLAUDE.md files
Dec 25, 2025
fb32af9
fix(nip44): use HKDF instead of PBKDF2 for key derivation
Dec 26, 2025
12f4cb1
chore(release): bump version to 1.2.0
Dec 26, 2025
5a3c903
fix(nip44): use proper HKDF-Extract for conversation key
Dec 26, 2025
f122745
chore(deps): bump org.sonatype.central:central-publishing-maven-plugin
dependabot[bot] Jan 12, 2026
de36c4d
docs: enhance coding guidelines with detailed principles and best pra…
Jan 21, 2026
64c186e
fix(Kind): improve error handling for unknown kind values
Jan 21, 2026
e3cb5a0
fix(ws): refactor response handling to use CompletableFuture for even…
Jan 21, 2026
2a53b78
chore(release): bump version to 1.2.1
Jan 21, 2026
4167c64
chore(docs): update PR template with standardized sections and guidel…
Jan 21, 2026
9a3ace0
fix(Kind): add safer Optional-based lookup and strict validation methods
Jan 21, 2026
737bee1
test(Kind): expand unit tests for improved validation coverage
Jan 21, 2026
88049cb
test(ws): enhance NIP-60 filter JSON serialization tests for improved…
Jan 21, 2026
adbee1d
fix(ws): introduce PendingRequest for thread-safe request handling
Jan 21, 2026
1e685e9
fix(ws): improve WebSocket client response handling and thread-safety
Jan 21, 2026
4722425
Merge pull request #501 from tcheeric/fix/ws-response-detection
tcheeric Jan 21, 2026
d418d3a
Merge pull request #497 from tcheeric/dependabot/github_actions/devel…
tcheeric Jan 21, 2026
40ca5c9
Merge pull request #496 from tcheeric/dependabot/github_actions/devel…
tcheeric Jan 21, 2026
80dae8b
Merge pull request #500 from tcheeric/dependabot/maven/develop/org.so…
tcheeric Jan 21, 2026
4963e6e
fix(ws): reject concurrent send() calls, enhance deserialization with…
Jan 21, 2026
a91fee9
fix(Kind): use valueOfStrict for improved error handling in KindFilter
Jan 21, 2026
a2d9242
fix(ws): prevent concurrent send() calls in StandardWebSocketClient
Jan 21, 2026
abb5ec9
fix(ws): prevent concurrent send() calls in StandardWebSocketClient
Jan 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 36 additions & 12 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,45 @@
## Summary
<!-- Explain the problem, context, and why this change is needed. Link to the issue. -->

Related issue: #____
<!-- Briefly explain the problem and why this change is needed. -->

Closes #____

## Type of change

<!-- Check all that apply -->

- [ ] `fix` - Bug fix (non-breaking)
- [ ] `feat` - New feature (non-breaking)
- [ ] `refactor` - Code change that neither fixes a bug nor adds a feature
- [ ] `docs` - Documentation only
- [ ] `test` - Adding or updating tests
- [ ] `perf` - Performance improvement
- [ ] `chore` - Build, CI, or tooling changes

## What changed?
<!-- Brief summary; suggest where to start reviewing if many files. -->

## BREAKING
<!-- If applicable, call it out explicitly. -->
<!-- ⚠️ BREAKING: Describe migration or impact. -->
<!-- Brief summary of changes. For large PRs, suggest where to start reviewing. -->

## Breaking changes

<!-- Delete this section if not applicable -->
<!-- ⚠️ BREAKING: Describe migration steps or impact on existing code. -->

## Testing

<!-- How was this tested? Include commands, test classes, or manual verification steps. -->

- [ ] Unit tests pass: `mvn test`
- [ ] Integration tests pass: `mvn verify` (requires Docker)

## Review focus
<!-- Ask for specific feedback, e.g., "Concurrency strategy OK?" or "API shape acceptable?" -->

<!-- Optional: Ask for specific feedback, e.g., "Is the error handling approach OK?" -->

## Checklist
- [ ] Scope ≤ 300 lines (or split/stack)
- [ ] Title is **verb + object** (e.g., “Refactor auth middleware to async”)
- [ ] Description links the issue and answers “why now?”
- [ ] **BREAKING** flagged if needed
- [ ] Tests/docs updated (if relevant)

- [ ] PR title follows conventional commits: `type(scope): description`
- [ ] Changes are focused and under 300 lines (or stacked PRs)
- [ ] Tests added/updated for new functionality
- [ ] No new compiler warnings introduced
- [ ] CHANGELOG.md updated (for user-facing changes)
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:

- name: Upload test reports and coverage (if present)
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: reports-jdk-${{ matrix.java-version }}
if-no-files-found: ignore
Expand Down Expand Up @@ -68,7 +68,7 @@ jobs:

- name: Upload IT reports and coverage
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: reports-integration
if-no-files-found: ignore
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/qodana_code_quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
ref: ${{ github.event.pull_request.head.sha }} # to check out the actual pull request commit, not the merge commit
fetch-depth: 0 # a full history is required for pull request analysis
- name: 'Qodana Scan'
uses: JetBrains/qodana-action@v2025.2
uses: JetBrains/qodana-action@v2025.3
with:
pr-mode: false
env:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ jobs:

- name: Upload coverage reports
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: reports-release
if-no-files-found: ignore
Expand Down
110 changes: 100 additions & 10 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,16 +98,106 @@ The URL format for the NIPs is https://github.com/nostr-protocol/nips/blob/maste


## Coding
- When writing code, follow the "Clean Code" principles:
- [Clean Code](https://dev.398ja.xyz/books/Clean_Architecture.pdf)
- Relevant chapters: 2, 3, 4, 7, 10, 17
- [Clean Architecture](https://dev.398ja.xyz/books/Clean_Code.pdf)
- Relevant chapters: All chapters in part III and IV, 7-14.
- [Design Patterns](https://github.com/iluwatar/java-design-patterns)
- Follow design patterns as described in the book, whenever possible.
- When commiting code, follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification.
- When adding new features, ensure they are compliant with the Cashu specification (NUTs) provided above.
- Make use of the lombok library to reduce boilerplate code.

When writing code, follow Clean Code and Clean Architecture principles:

### Meaningful Names
- Use intention-revealing names that explain why something exists, what it does, and how it's used
- Avoid disinformation: don't use names that could mislead (e.g., `accountList` for something that isn't a List)
- Make meaningful distinctions: avoid noise words like `Info`, `Data`, `Manager` unless they add real meaning
- Use pronounceable and searchable names; avoid single-letter variables except for loop counters
- Class names should be nouns (`Customer`, `Account`); method names should be verbs (`postPayment`, `save`)
- Pick one word per concept and stick with it (`fetch`, `retrieve`, `get` — pick one)

### Functions
- Keep functions small: ideally under 20 lines, rarely exceeding one screen
- Functions should do one thing, do it well, and do it only
- One level of abstraction per function: don't mix high-level policy with low-level details
- Use descriptive names: a long descriptive name is better than a short cryptic one
- Minimize arguments: zero is ideal, one or two are fine, three requires justification
- Avoid flag arguments (boolean parameters that change behavior)
- Functions should either do something or answer something, never both (Command-Query Separation)
- Prefer exceptions over error codes; extract try/catch blocks into their own functions

### Comments
- Comments are a failure to express intent in code; prefer self-documenting code
- Good comments: legal comments, explanation of intent, clarification, warning of consequences, TODO notes, Javadoc for public APIs
- Bad comments: redundant comments, misleading comments, mandated comments, journal comments, noise comments, commented-out code
- If you must comment, explain *why*, not *what* — the code shows what

### Error Handling
- Use exceptions rather than return codes
- Write try-catch-finally statements first when writing code that could throw
- Use unchecked exceptions; checked exceptions violate the Open/Closed Principle
- Provide context with exceptions: include operation attempted and failure type
- Define exception classes by how they're caught, not by their source
- Don't return null — throw an exception or return a Special Case object instead
- Don't pass null as arguments unless the API explicitly expects it

### Classes
- Classes should be small, measured by responsibilities (Single Responsibility Principle)
- A class should have only one reason to change
- High cohesion: methods and variables should be closely related
- Organize for change: isolate code that's likely to change from code that's stable
- Depend on abstractions, not concretions (Dependency Inversion)
- Classes should be open for extension but closed for modification (Open/Closed Principle)

### Code Smells and Heuristics
- Avoid comments that could be replaced by better naming or structure
- Eliminate dead code, duplicate code, and code at wrong levels of abstraction
- Keep configuration data at high levels; don't bury magic numbers
- Follow the Law of Demeter: modules shouldn't know about the innards of objects they manipulate
- Make logical dependencies physical: if one module depends on another, make that explicit
- Prefer polymorphism to if/else or switch/case chains
- Follow standard conventions for the project and language
- Replace magic numbers with named constants
- Be precise: don't be lazy about decisions — if you decide to use a list, be sure you need one
- Encapsulate conditionals: extract complex boolean expressions into well-named methods
- Avoid negative conditionals: `if (buffer.shouldCompact())` is clearer than `if (!buffer.shouldNotCompact())`
- Functions should descend one level of abstraction

### SOLID Design Principles

**Single Responsibility Principle (SRP)**
A module should have one, and only one, reason to change. Each class serves one actor or stakeholder. When requirements change for one actor, only the relevant module changes.

**Open/Closed Principle (OCP)**
Software entities should be open for extension but closed for modification. Achieve this through abstraction and polymorphism — add new behavior by adding new code, not changing existing code.

**Liskov Substitution Principle (LSP)**
Subtypes must be substitutable for their base types without altering program correctness. If S is a subtype of T, objects of type T may be replaced with objects of type S without breaking the program.

**Interface Segregation Principle (ISP)**
Clients should not be forced to depend on interfaces they don't use. Prefer many small, client-specific interfaces over one general-purpose interface.

**Dependency Inversion Principle (DIP)**
High-level modules should not depend on low-level modules; both should depend on abstractions. Abstractions should not depend on details; details should depend on abstractions.

### Component Principles

**Cohesion Principles:**
- **REP (Reuse/Release Equivalence)**: The granule of reuse is the granule of release — classes in a component should be releasable together
- **CCP (Common Closure)**: Gather classes that change for the same reasons at the same times; separate classes that change at different times for different reasons
- **CRP (Common Reuse)**: Don't force users to depend on things they don't need — classes in a component should be used together

**Coupling Principles:**
- **ADP (Acyclic Dependencies)**: No cycles in the component dependency graph; use Dependency Inversion to break cycles
- **SDP (Stable Dependencies)**: Depend in the direction of stability — volatile components should depend on stable ones
- **SAP (Stable Abstractions)**: Stable components should be abstract; instability should be concrete

### Design Patterns
Apply established patterns where appropriate:
- **Creational**: Factory Method, Abstract Factory, Builder, Singleton (use sparingly), Prototype
- **Structural**: Adapter, Bridge, Composite, Decorator, Facade, Proxy
- **Behavioral**: Strategy, Observer, Command, State, Template Method, Iterator, Chain of Responsibility

Choose patterns that simplify the design; don't force patterns where simpler solutions suffice.

### General Guidelines
- When committing code, follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification
- When adding new features, ensure they are compliant with the Nostr specification (NIPs) provided above
- Make use of the Lombok library to reduce boilerplate code
- Always rely on imports rather than fully qualified class names in code to keep implementations readable

## Documentation

Expand Down
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,31 @@ The format is inspired by Keep a Changelog, and this project adheres to semantic

No unreleased changes yet.

## [1.2.1] - 2026-01-21

### Fixed
- NIP-44 now correctly uses HKDF-Extract for conversation key derivation, ensuring proper cryptographic key generation.
- WebSocket client now correctly accumulates all relay responses (EVENT messages) before completing, waiting for termination signals (EOSE, OK, NOTICE, CLOSED) instead of returning after the first message.
- WebSocket client thread-safety improved by encapsulating pending request state, preventing potential race conditions when multiple threads call send() concurrently.
- WebSocket client now rejects concurrent send() calls with IllegalStateException instead of silently orphaning the previous request's future.
- KindFilter and ClassifiedListingEventDeserializer now use Kind.valueOfStrict() for fail-fast deserialization of unknown kind values.

### Changed
- Kind.valueOf(int) now returns null for unknown kind values instead of throwing, allowing graceful handling of custom or future NIP kinds during JSON deserialization.
- Added Kind.valueOfStrict(int) for callers who need fail-fast behavior on unknown kinds.
- Added Kind.findByValue(int) returning Optional<Kind> for safe, explicit handling of unknown kinds.

## [1.2.0] - 2025-12-26

### Fixed
- NIP-44 encryption now correctly uses HKDF instead of PBKDF2 for key derivation, as required by the specification. This fix enables DM interoperability between Java backend and JavaScript frontend implementations (e.g., nostr-tools).

### Changed
- Switched integration tests to use strfry relay for improved robustness.

### Removed
- Removed AGENTS.md and CLAUDE.md documentation files from the repository.

## [1.1.1] - 2025-12-24

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion nostr-java-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>xyz.tcheeric</groupId>
<artifactId>nostr-java</artifactId>
<version>1.1.1</version>
<version>1.2.1</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
75 changes: 75 additions & 0 deletions nostr-java-api/src/test/resources/strfry.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
##
## strfry config for integration testing (no whitelist)
##

db = "./strfry-db/"

dbParams {
maxreaders = 256
mapsize = 10995116277760
noReadAhead = false
}

events {
maxEventSize = 65536
rejectEventsNewerThanSeconds = 900
rejectEventsOlderThanSeconds = 94608000
rejectEphemeralEventsOlderThanSeconds = 60
ephemeralEventsLifetimeSeconds = 300
maxNumTags = 2000
maxTagValSize = 1024
}

relay {
bind = "0.0.0.0"
port = 7777
nofiles = 1000000
realIpHeader = ""

info {
name = "nostr-java test relay"
description = "strfry relay for nostr-java integration tests"
pubkey = ""
contact = ""
icon = ""
nips = ""
}

maxWebsocketPayloadSize = 131072
maxReqFilterSize = 200
autoPingSeconds = 55
enableTcpKeepalive = false
queryTimesliceBudgetMicroseconds = 10000
maxFilterLimit = 500
maxSubsPerConnection = 20

writePolicy {
# No write policy plugin - accept all events
plugin = ""
}

compression {
enabled = true
slidingWindow = true
}

logging {
dumpInAll = false
dumpInEvents = false
dumpInReqs = false
dbScanPerf = false
invalidEvents = true
}

numThreads {
ingester = 3
reqWorker = 3
reqMonitor = 3
negentropy = 2
}

negentropy {
enabled = true
maxSyncEvents = 1000000
}
}
2 changes: 1 addition & 1 deletion nostr-java-base/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>xyz.tcheeric</groupId>
<artifactId>nostr-java</artifactId>
<version>1.1.1</version>
<version>1.2.1</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
Loading
Loading