Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
20 changes: 19 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,22 @@ The URL format for the NIPs is https://github.com/nostr-protocol/nips/blob/maste
- Always follow the repository's PR submission guidelines and use the PR template located at `.github/pull_request_template.md`.
- Summarize the changes made and describe how they were tested.
- Include any limitations or known issues in the description.
- Ensure all new features are compliant with the Cashu specification (NUTs) provided above.
- Ensure all new features are compliant with the Nostr specification (NIPs) provided above.

## Versioning

- Follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html) for all releases.
- Update the version in the parent `pom.xml` and all module POMs when preparing a release.
- Use conventional commit types to signal version bumps (fix → patch, feat → minor, BREAKING CHANGE → major).

## Changelog Maintenance

- **Always update `CHANGELOG.md`** after any version change or significant code modification.
- Follow the [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) format:
- Group changes under: `Added`, `Changed`, `Deprecated`, `Removed`, `Fixed`, `Security`
- List versions in reverse chronological order (newest first)
- Use `[Unreleased]` section for changes not yet in a release
- Include the release date in ISO format: `## [1.0.0] - 2025-12-17`
- Each entry should be a concise, human-readable description of the change
- Reference related issues or PRs where applicable
- Update the changelog in the same commit as the version bump when possible
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,30 @@ The format is inspired by Keep a Changelog, and this project adheres to semantic

No unreleased changes yet.

## [1.1.1] - 2025-12-24

### Fixed
- StandardWebSocketClient now configures WebSocketContainer with a 1-hour idle timeout (configurable via `nostr.websocket.max-idle-timeout-ms`) to prevent premature connection closures when relays have periods of inactivity.

## [1.1.0] - 2025-12-23

### Added
- Public constructor `StandardWebSocketClient(String relayUri, long awaitTimeoutMs, long pollIntervalMs)` for programmatic timeout configuration outside Spring DI context.

### Changed
- Enhanced diagnostic logging for timeout configuration in StandardWebSocketClient.
- Simplified WebSocket client initialization and retry logic in tests.

### Fixed
- Updated `JsonDeserialize` builder reference in API module.
Comment on lines +16 to +26
Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CHANGELOG documents version 1.1.0 with a release date of 2025-12-23, but this version is not present in any of the POM files. The POM files jump directly from 1.0.1 to 1.1.1. Either version 1.1.0 should be added to the POM files if it was actually released, or the CHANGELOG should be updated to remove the 1.1.0 entry and consolidate its changes into 1.1.1.

Copilot uses AI. Check for mistakes.

## [1.0.1] - 2025-12-20

### Changed
- Updated project version and added artifact names in POM files.
- Added Sonatype Central server credentials configuration.
- Updated Maven command for central publishing.

## [1.0.0] - 2025-10-13

### Added
Expand Down
168 changes: 168 additions & 0 deletions docs/TROUBLESHOOTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ This guide helps you diagnose and resolve common issues when using nostr-java.
- [Subscription Issues](#subscription-issues)
- [Encryption & Decryption Issues](#encryption--decryption-issues)
- [Performance Issues](#performance-issues)
- [Integration Testing Issues](#integration-testing-issues)

---

Expand Down Expand Up @@ -603,3 +604,170 @@ For Spring Boot applications, add to `application.properties`:
logging.level.nostr=DEBUG
logging.level.nostr.client=TRACE
```

---

## Integration Testing Issues

### Problem: Tests Timeout After 60 Seconds

**Symptom**: Integration tests hang and fail with `NoSuchElementException: No value present` or `No message received`

**Possible Causes & Solutions:**

#### 1. nostr-rs-relay Quanta Bug

The `scsibug/nostr-rs-relay` Docker image contains a known bug in the `quanta` crate that causes panics in Docker environments:

```
thread 'tokio-ws-10' panicked at quanta-0.9.3/src/lib.rs:274:13:
po2_denom was zero!
```

**Solution**: Use strfry relay instead:

```properties
# src/test/resources/relay-container.properties
relay.container.image=dockurr/strfry:latest
relay.container.port=7777
```

#### 2. Relay Container Not Starting

Check Docker is available and the container starts properly:

```bash
# Verify Docker is running
docker info

# Test the relay image manually
docker run --rm -p 7777:7777 dockurr/strfry:latest
```

### Problem: strfry Rejects All Events (Whitelist)

**Symptom**: Events return `success=false` with message `blocked: pubkey not in whitelist`

**Cause**: The default strfry Docker image has a write policy that whitelists specific pubkeys.

**Solution**: Create a custom strfry.conf that disables the whitelist:

```conf
# src/test/resources/strfry.conf
relay {
writePolicy {
plugin = "" # Disable write policy plugin
}
}
```

Mount this config in your test container:

```java
RELAY = new GenericContainer<>(image)
.withExposedPorts(relayPort)
.withClasspathResourceMapping(
"strfry.conf", "/etc/strfry.conf", BindMode.READ_ONLY)
.withTmpFs(Map.of("/app/strfry-db", "rw"))
.waitingFor(Wait.forLogMessage(".*Started websocket server on.*", 1));
```

### Problem: Filter Queries Return Empty Results

**Symptom**: Tests send events successfully but filter queries return only EOSE (no events)

**Cause**: Race condition - the relay needs time to index events before they can be queried.

**Solution**: Add a small delay between publishing and querying:

```java
// Send event
nip01.createTextNoteEvent(List.of(tag), "content").signAndSend(relays);

// Wait for relay to index the event
Thread.sleep(100);

// Now query
List<String> result = nip01.sendRequest(filters, subscriptionId);
```

### Problem: strfry Requires High File Descriptor Limits

**Symptom**: Container fails with `Unable to set NOFILES limit`

**Solution**: Configure ulimits in Testcontainers:

```java
import com.github.dockerjava.api.model.Ulimit;

RELAY = new GenericContainer<>(image)
.withCreateContainerCmdModifier(cmd -> cmd.getHostConfig()
.withUlimits(new Ulimit[] {new Ulimit("nofile", 1000000L, 1000000L)}))
// ... other configuration
```

### Problem: Tests Use Wrong Relay URL

**Symptom**: Tests connect to hardcoded URL instead of Testcontainers dynamic port

**Cause**: Tests may use `@Autowired` relays from properties file instead of dynamic container port.

**Solution**: Use a base test class that provides the dynamic relay URL:

```java
public abstract class BaseRelayIntegrationTest {
@Container
private static final GenericContainer<?> RELAY = /* ... */;

static Map<String, String> getTestRelays() {
String host = RELAY.getHost();
int port = RELAY.getMappedPort(7777);
return Map.of("relay", String.format("ws://%s:%d", host, port));
}
}

// In your test
@BeforeEach
void setUp() {
relays = getTestRelays(); // Use dynamic URL, not autowired
}
```

### Problem: Tests Fail in CI but Pass Locally

**Symptom**: Docker-based tests fail in CI environments

**Possible Causes:**

1. **Docker not available**: Skip tests when Docker is unavailable:

```java
@DisabledIfSystemProperty(named = "noDocker", matches = "true")
public class MyIntegrationTest extends BaseRelayIntegrationTest {
// ...
}
```

Run with: `mvn test -DnoDocker=true`

2. **Different Docker environments**: Some CI environments don't support certain CPU features (TSC) that cause the quanta bug.

3. **Resource constraints**: CI containers may have limited resources. Use tmpfs for relay storage:

```java
.withTmpFs(Map.of("/app/strfry-db", "rw"))
```

### Relay Configuration Reference

| Relay | Image | Port | Wait Strategy |
|-------|-------|------|---------------|
| strfry | `dockurr/strfry:latest` | 7777 | `Started websocket server on` |
| nostr-rs-relay | `scsibug/nostr-rs-relay:latest` | 8080 | `listening on:` (has quanta bug) |

Configure via `src/test/resources/relay-container.properties`:

```properties
relay.container.image=dockurr/strfry:latest
relay.container.port=7777
```
Loading
Loading